diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 42ff96603b71f0557a97d88f7cd017c85a9740b9..2a070e9a49b97a80c3e4fd4644419e5ffda38719 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -32,7 +32,7 @@ repos:
         # TODO: remove autofixe-only rules when they are checked by ruff
         name: ruff-selected-autofixes
         alias: ruff-selected-autofixes
-        args: [--select, "ANN001,ANN204", --fix-only, --exit-non-zero-on-fix]
+        args: [--select, "ANN001,ANN2", --fix-only, --exit-non-zero-on-fix]
 -   repo: https://github.com/jendrikseipp/vulture
     rev: 'v2.10'
     hooks:
diff --git a/doc/make.py b/doc/make.py
index c4b7ab124f68f56f7cfed152e4c353effd4811a5..2583242786fc8b300668377510a2f27a7901d3b7 100755
--- a/doc/make.py
+++ b/doc/make.py
@@ -102,7 +102,7 @@ class DocBuilder:
             )
 
     @staticmethod
-    def _run_os(*args):
+    def _run_os(*args) -> None:
         """
         Execute a command as a OS terminal.
 
@@ -149,7 +149,7 @@ class DocBuilder:
         ]
         return subprocess.call(cmd)
 
-    def _open_browser(self, single_doc_html):
+    def _open_browser(self, single_doc_html) -> None:
         """
         Open a browser tab showing single
         """
@@ -183,7 +183,7 @@ class DocBuilder:
 
         return title.astext()
 
-    def _add_redirects(self):
+    def _add_redirects(self) -> None:
         """
         Create in the build directory an html file with a redirect,
         for every row in REDIRECTS_FILE.
@@ -272,14 +272,14 @@ class DocBuilder:
         return self.latex(force=True)
 
     @staticmethod
-    def clean():
+    def clean() -> None:
         """
         Clean documentation generated files.
         """
         shutil.rmtree(BUILD_PATH, ignore_errors=True)
         shutil.rmtree(os.path.join(SOURCE_PATH, "reference", "api"), ignore_errors=True)
 
-    def zip_html(self):
+    def zip_html(self) -> None:
         """
         Compress HTML documentation into a zip file.
         """
diff --git a/doc/scripts/eval_performance.py b/doc/scripts/eval_performance.py
index 559689ef5915b092ec731d03169a746eb7f94e55..dded8362a4cda43821e85ce1520422674c3aefee 100644
--- a/doc/scripts/eval_performance.py
+++ b/doc/scripts/eval_performance.py
@@ -64,7 +64,7 @@ def bench(mn=3, mx=7, num=100, engines=("python", "numexpr"), verbose=False):
     return ev, qu
 
 
-def plot_perf(df, engines, title, filename=None):
+def plot_perf(df, engines, title, filename=None) -> None:
     from matplotlib.pyplot import figure
 
     sns.set()
diff --git a/doc/source/conf.py b/doc/source/conf.py
index dbc764c88a6f3e599015dc8a6705bb5f2653794b..e7ce8511b76a18be2de050d682a478f0857cff81 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -502,7 +502,7 @@ class AccessorDocumenter(MethodDocumenter):
     # lower than MethodDocumenter so this is not chosen for normal methods
     priority = 0.6
 
-    def format_signature(self):
+    def format_signature(self) -> str:
         # this method gives an error/warning for the accessors, therefore
         # overriding it (accessor has no arguments)
         return ""
@@ -632,7 +632,7 @@ class PandasAutosummary(Autosummary):
 
 
 # based on numpy doc/source/conf.py
-def linkcode_resolve(domain, info):
+def linkcode_resolve(domain, info) -> str | None:
     """
     Determine the URL corresponding to Python object
     """
@@ -694,12 +694,12 @@ def linkcode_resolve(domain, info):
 
 # remove the docstring of the flags attribute (inherited from numpy ndarray)
 # because these give doc build errors (see GH issue 5331)
-def remove_flags_docstring(app, what, name, obj, options, lines):
+def remove_flags_docstring(app, what, name, obj, options, lines) -> None:
     if what == "attribute" and name.endswith(".flags"):
         del lines[:]
 
 
-def process_class_docstrings(app, what, name, obj, options, lines):
+def process_class_docstrings(app, what, name, obj, options, lines) -> None:
     """
     For those classes for which we use ::
 
@@ -751,7 +751,7 @@ _BUSINED_ALIASES = [
 ]
 
 
-def process_business_alias_docstrings(app, what, name, obj, options, lines):
+def process_business_alias_docstrings(app, what, name, obj, options, lines) -> None:
     """
     Starting with sphinx 3.4, the "autodoc-process-docstring" event also
     gets called for alias classes. This results in numpydoc adding the
@@ -774,7 +774,7 @@ if pattern:
     suppress_warnings.append("ref.ref")
 
 
-def rstjinja(app, docname, source):
+def rstjinja(app, docname, source) -> None:
     """
     Render our pages as a jinja template for fancy templating goodness.
     """
@@ -787,7 +787,7 @@ def rstjinja(app, docname, source):
     source[0] = rendered
 
 
-def setup(app):
+def setup(app) -> None:
     app.connect("source-read", rstjinja)
     app.connect("autodoc-process-docstring", remove_flags_docstring)
     app.connect("autodoc-process-docstring", process_class_docstrings)
diff --git a/generate_pxi.py b/generate_pxi.py
index 47648a3937b4c4df179fe35a969ea9b2ad678d7d..e7e85900aa6e9bf0e985f3c19d2bf0db3eb88f9a 100644
--- a/generate_pxi.py
+++ b/generate_pxi.py
@@ -4,7 +4,7 @@ import os
 from Cython import Tempita
 
 
-def process_tempita(pxifile, outfile):
+def process_tempita(pxifile, outfile) -> None:
     with open(pxifile, encoding="utf-8") as f:
         tmpl = f.read()
     pyxcontent = Tempita.sub(tmpl)
@@ -13,7 +13,7 @@ def process_tempita(pxifile, outfile):
         f.write(pyxcontent)
 
 
-def main():
+def main() -> None:
     parser = argparse.ArgumentParser()
     parser.add_argument("infile", type=str, help="Path to the input file")
     parser.add_argument("-o", "--outdir", type=str, help="Path to the output directory")
diff --git a/generate_version.py b/generate_version.py
index 06e38ce0fd978bbad091e279d4ae80cdf5570aae..7dc1bdcf329d0a80758bd9f1ed1aff3fc1eae781 100644
--- a/generate_version.py
+++ b/generate_version.py
@@ -10,7 +10,7 @@ import versioneer
 sys.path.insert(0, "")
 
 
-def write_version_info(path):
+def write_version_info(path) -> None:
     version = None
     git_version = None
 
@@ -29,7 +29,7 @@ def write_version_info(path):
         file.write(f'__git_version__="{git_version}"\n')
 
 
-def main():
+def main() -> None:
     parser = argparse.ArgumentParser()
     parser.add_argument(
         "-o",
diff --git a/scripts/tests/conftest.py b/scripts/tests/conftest.py
index a7976102eab98e4946b6d31209b2411af8d05199..d43741f925eb5b78a16908a9f9ce60b417c5d349 100644
--- a/scripts/tests/conftest.py
+++ b/scripts/tests/conftest.py
@@ -1,6 +1,6 @@
 # pyproject.toml defines addopts: --strict-data-files
 # strict-data-files is defined & used in pandas/conftest.py
-def pytest_addoption(parser):
+def pytest_addoption(parser) -> None:
     parser.addoption(
         "--strict-data-files",
         action="store_true",
diff --git a/scripts/tests/test_no_bool_in_generic.py b/scripts/tests/test_no_bool_in_generic.py
index a57612548dcc59ac3260155ed2b3f7f2fed71e8d..20ac214ce8a4a3784110b19bf9f5c299e302e836 100644
--- a/scripts/tests/test_no_bool_in_generic.py
+++ b/scripts/tests/test_no_bool_in_generic.py
@@ -4,7 +4,7 @@ BAD_FILE = "def foo(a: bool) -> bool:\n    return bool(0)\n"
 GOOD_FILE = "def foo(a: bool_t) -> bool_t:\n    return bool(0)\n"
 
 
-def test_bad_file_with_replace():
+def test_bad_file_with_replace() -> None:
     content = BAD_FILE
     mutated, result = check_for_bool_in_generic(content)
     expected = GOOD_FILE
@@ -12,7 +12,7 @@ def test_bad_file_with_replace():
     assert mutated
 
 
-def test_good_file_with_replace():
+def test_good_file_with_replace() -> None:
     content = GOOD_FILE
     mutated, result = check_for_bool_in_generic(content)
     expected = content
diff --git a/scripts/tests/test_sort_whatsnew_note.py b/scripts/tests/test_sort_whatsnew_note.py
index 95ba74bbe4030cb96da38d1002d2a7eeb9827057..6b8ea3ef972379f86e350949afee2ff9c63e1843 100644
--- a/scripts/tests/test_sort_whatsnew_note.py
+++ b/scripts/tests/test_sort_whatsnew_note.py
@@ -1,7 +1,7 @@
 from scripts.sort_whatsnew_note import sort_whatsnew_note
 
 
-def test_sort_whatsnew_note():
+def test_sort_whatsnew_note() -> None:
     content = (
         ".. _whatsnew_200:\n"
         "\n"
diff --git a/scripts/tests/test_use_io_common_urlopen.py b/scripts/tests/test_use_io_common_urlopen.py
index 4bba550a4cc0e5e7c4bc34dc8f0ddd1359b8ab68..c2c4a7fe9cb58c9607ca2b20d36c5d89643d9e6b 100644
--- a/scripts/tests/test_use_io_common_urlopen.py
+++ b/scripts/tests/test_use_io_common_urlopen.py
@@ -5,7 +5,7 @@ from scripts.use_io_common_urlopen import use_io_common_urlopen
 PATH = "t.py"
 
 
-def test_inconsistent_usage(capsys):
+def test_inconsistent_usage(capsys) -> None:
     content = "from urllib.request import urlopen"
     result_msg = (
         "t.py:1:0: Don't use urllib.request.urlopen, "
@@ -17,7 +17,7 @@ def test_inconsistent_usage(capsys):
     assert result_msg == expected_msg
 
 
-def test_consistent_usage():
+def test_consistent_usage() -> None:
     # should not raise
     content = "from pandas.io.common import urlopen"
     use_io_common_urlopen(content, PATH)
diff --git a/scripts/tests/test_use_pd_array_in_core.py b/scripts/tests/test_use_pd_array_in_core.py
index 8f13a6e7358991c884915f4c46c14d09eb7b1293..f58c92722caad5816895a18d10d17fec436ea4de 100644
--- a/scripts/tests/test_use_pd_array_in_core.py
+++ b/scripts/tests/test_use_pd_array_in_core.py
@@ -10,7 +10,7 @@ PATH = "t.py"
 
 
 @pytest.mark.parametrize("content", [BAD_FILE_0, BAD_FILE_1])
-def test_inconsistent_usage(content, capsys):
+def test_inconsistent_usage(content, capsys) -> None:
     result_msg = (
         "t.py:2:0: Don't use pd.array in core, import array as pd_array instead\n"
     )
@@ -21,6 +21,6 @@ def test_inconsistent_usage(content, capsys):
 
 
 @pytest.mark.parametrize("content", [GOOD_FILE_0, GOOD_FILE_1])
-def test_consistent_usage(content):
+def test_consistent_usage(content) -> None:
     # should not raise
     use_pd_array(content, PATH)
diff --git a/scripts/tests/test_validate_docstrings.py b/scripts/tests/test_validate_docstrings.py
index ffe1e9acd118539d53d06233b27d31ec8880b650..02c6808658a330b9dceeff2aa7e8744b38c091cf 100644
--- a/scripts/tests/test_validate_docstrings.py
+++ b/scripts/tests/test_validate_docstrings.py
@@ -9,12 +9,12 @@ from scripts import validate_docstrings
 class BadDocstrings:
     """Everything here has a bad docstring"""
 
-    def private_classes(self):
+    def private_classes(self) -> None:
         """
         This mentions NDFrame, which is not correct.
         """
 
-    def prefix_pandas(self):
+    def prefix_pandas(self) -> None:
         """
         Have `pandas` prefix in See Also section.
 
@@ -24,7 +24,7 @@ class BadDocstrings:
         DataFrame.head : The first `n` rows of the caller object.
         """
 
-    def redundant_import(self, paramx=None, paramy=None):
+    def redundant_import(self, paramx=None, paramy=None) -> None:
         """
         A sample DataFrame method.
 
@@ -45,7 +45,7 @@ class BadDocstrings:
         Series([], dtype: bool)
         """
 
-    def unused_import(self):
+    def unused_import(self) -> None:
         """
         Examples
         --------
@@ -53,7 +53,7 @@ class BadDocstrings:
         >>> df = pd.DataFrame(np.ones((3, 3)), columns=('a', 'b', 'c'))
         """
 
-    def missing_whitespace_around_arithmetic_operator(self):
+    def missing_whitespace_around_arithmetic_operator(self) -> None:
         """
         Examples
         --------
@@ -61,7 +61,7 @@ class BadDocstrings:
         7
         """
 
-    def indentation_is_not_a_multiple_of_four(self):
+    def indentation_is_not_a_multiple_of_four(self) -> None:
         """
         Examples
         --------
@@ -69,19 +69,19 @@ class BadDocstrings:
         ...   pass
         """
 
-    def missing_whitespace_after_comma(self):
+    def missing_whitespace_after_comma(self) -> None:
         """
         Examples
         --------
         >>> df = pd.DataFrame(np.ones((3,3)),columns=('a','b', 'c'))
         """
 
-    def write_array_like_with_hyphen_not_underscore(self):
+    def write_array_like_with_hyphen_not_underscore(self) -> None:
         """
         In docstrings, use array-like over array_like
         """
 
-    def leftover_files(self):
+    def leftover_files(self) -> None:
         """
         Examples
         --------
@@ -117,7 +117,7 @@ class TestValidator:
 
         return base_path
 
-    def test_bad_class(self, capsys):
+    def test_bad_class(self, capsys) -> None:
         errors = validate_docstrings.pandas_validate(
             self._import_path(klass="BadDocstrings")
         )["errors"]
@@ -192,20 +192,20 @@ class TestValidator:
             ),
         ],
     )
-    def test_bad_docstrings(self, capsys, klass, func, msgs):
+    def test_bad_docstrings(self, capsys, klass, func, msgs) -> None:
         result = validate_docstrings.pandas_validate(
             self._import_path(klass=klass, func=func)
         )
         for msg in msgs:
             assert msg in " ".join([err[1] for err in result["errors"]])
 
-    def test_leftover_files_raises(self):
+    def test_leftover_files_raises(self) -> None:
         with pytest.raises(Exception, match="The following files"):
             validate_docstrings.pandas_validate(
                 self._import_path(klass="BadDocstrings", func="leftover_files")
             )
 
-    def test_validate_all_ignore_functions(self, monkeypatch):
+    def test_validate_all_ignore_functions(self, monkeypatch) -> None:
         monkeypatch.setattr(
             validate_docstrings,
             "get_all_api_items",
@@ -231,7 +231,7 @@ class TestValidator:
         assert len(result) == 1
         assert "pandas.Index.all" in result
 
-    def test_validate_all_ignore_deprecated(self, monkeypatch):
+    def test_validate_all_ignore_deprecated(self, monkeypatch) -> None:
         monkeypatch.setattr(
             validate_docstrings,
             "pandas_validate",
@@ -303,7 +303,7 @@ class TestApiItems:
             (4, "random.randint"),
         ],
     )
-    def test_item_name(self, idx, name):
+    def test_item_name(self, idx, name) -> None:
         result = list(validate_docstrings.get_api_items(self.api_doc))
         assert result[idx][0] == name
 
@@ -311,7 +311,7 @@ class TestApiItems:
         "idx,func",
         [(0, "cycle"), (1, "count"), (2, "chain"), (3, "seed"), (4, "randint")],
     )
-    def test_item_function(self, idx, func):
+    def test_item_function(self, idx, func) -> None:
         result = list(validate_docstrings.get_api_items(self.api_doc))
         assert callable(result[idx][1])
         assert result[idx][1].__name__ == func
@@ -326,7 +326,7 @@ class TestApiItems:
             (4, "Random"),
         ],
     )
-    def test_item_section(self, idx, section):
+    def test_item_section(self, idx, section) -> None:
         result = list(validate_docstrings.get_api_items(self.api_doc))
         assert result[idx][2] == section
 
@@ -334,7 +334,7 @@ class TestApiItems:
         "idx,subsection",
         [(0, "Infinite"), (1, "Infinite"), (2, "Finite"), (3, "All"), (4, "All")],
     )
-    def test_item_subsection(self, idx, subsection):
+    def test_item_subsection(self, idx, subsection) -> None:
         result = list(validate_docstrings.get_api_items(self.api_doc))
         assert result[idx][3] == subsection
 
@@ -343,7 +343,7 @@ class TestPandasDocstringClass:
     @pytest.mark.parametrize(
         "name", ["pandas.Series.str.isdecimal", "pandas.Series.str.islower"]
     )
-    def test_encode_content_write_to_file(self, name):
+    def test_encode_content_write_to_file(self, name) -> None:
         # GH25466
         docstr = validate_docstrings.PandasDocstring(name).validate_pep8()
         # the list of pep8 errors should be empty
@@ -351,7 +351,7 @@ class TestPandasDocstringClass:
 
 
 class TestMainFunction:
-    def test_exit_status_for_main(self, monkeypatch):
+    def test_exit_status_for_main(self, monkeypatch) -> None:
         monkeypatch.setattr(
             validate_docstrings,
             "pandas_validate",
@@ -375,7 +375,7 @@ class TestMainFunction:
         )
         assert exit_status == 0
 
-    def test_exit_status_errors_for_validate_all(self, monkeypatch):
+    def test_exit_status_errors_for_validate_all(self, monkeypatch) -> None:
         monkeypatch.setattr(
             validate_docstrings,
             "validate_all",
@@ -406,7 +406,7 @@ class TestMainFunction:
         )
         assert exit_status == 5
 
-    def test_no_exit_status_noerrors_for_validate_all(self, monkeypatch):
+    def test_no_exit_status_noerrors_for_validate_all(self, monkeypatch) -> None:
         monkeypatch.setattr(
             validate_docstrings,
             "validate_all",
@@ -425,7 +425,7 @@ class TestMainFunction:
         )
         assert exit_status == 0
 
-    def test_exit_status_for_validate_all_json(self, monkeypatch):
+    def test_exit_status_for_validate_all_json(self, monkeypatch) -> None:
         print("EXECUTED")
         monkeypatch.setattr(
             validate_docstrings,
@@ -451,7 +451,7 @@ class TestMainFunction:
         )
         assert exit_status == 0
 
-    def test_errors_param_filters_errors(self, monkeypatch):
+    def test_errors_param_filters_errors(self, monkeypatch) -> None:
         monkeypatch.setattr(
             validate_docstrings,
             "validate_all",
diff --git a/scripts/tests/test_validate_exception_location.py b/scripts/tests/test_validate_exception_location.py
index 9d493ee04d1c2316d9246c6920e63ac474d138f9..18bd118549cb5beedf8fa3be77ba87fb364e9ac1 100644
--- a/scripts/tests/test_validate_exception_location.py
+++ b/scripts/tests/test_validate_exception_location.py
@@ -34,7 +34,7 @@ def error_type(request):
 
 def test_class_that_inherits_an_exception_and_is_not_in_the_testing_rst_is_flagged(
     capsys, error_type
-):
+) -> None:
     content = TEST_CODE.format(
         custom_name=CUSTOM_EXCEPTION_NOT_IN_TESTING_RST, error_type=error_type
     )
@@ -47,13 +47,13 @@ def test_class_that_inherits_an_exception_and_is_not_in_the_testing_rst_is_flagg
 
 def test_class_that_inherits_an_exception_but_is_in_the_testing_rst_is_not_flagged(
     capsys, error_type
-):
+) -> None:
     content = TEST_CODE.format(
         custom_name=CUSTOM_EXCEPTION__IN_TESTING_RST, error_type=error_type
     )
     validate_exception_and_warning_placement(PATH, content, ERRORS_IN_TESTING_RST)
 
 
-def test_class_that_does_not_inherit_an_exception_is_not_flagged(capsys):
+def test_class_that_does_not_inherit_an_exception_is_not_flagged(capsys) -> None:
     content = "class MyClass(NonExceptionClass): pass"
     validate_exception_and_warning_placement(PATH, content, ERRORS_IN_TESTING_RST)
diff --git a/scripts/tests/test_validate_min_versions_in_sync.py b/scripts/tests/test_validate_min_versions_in_sync.py
index ac33f8dcbffaf97ce850fcd4ec63d25eb2b5277b..b6e339c13889fdb7c42f1c238ea76c172e6e76d5 100644
--- a/scripts/tests/test_validate_min_versions_in_sync.py
+++ b/scripts/tests/test_validate_min_versions_in_sync.py
@@ -46,7 +46,7 @@ from scripts.validate_min_versions_in_sync import (
         ),
     ],
 )
-def test_pin_min_versions_to_yaml_file(src_toml, src_yaml, expected_yaml):
+def test_pin_min_versions_to_yaml_file(src_toml, src_yaml, expected_yaml) -> None:
     with open(src_toml, "rb") as toml_f:
         toml_map = tomllib.load(toml_f)
     with open(src_yaml, encoding="utf-8") as yaml_f:
diff --git a/scripts/tests/test_validate_unwanted_patterns.py b/scripts/tests/test_validate_unwanted_patterns.py
index b4423197e257369391d0287ea9c3d6d968619450..bef9d369a0a3caa0689f7c5e13c51b256d39f7e5 100644
--- a/scripts/tests/test_validate_unwanted_patterns.py
+++ b/scripts/tests/test_validate_unwanted_patterns.py
@@ -38,7 +38,7 @@ class TestBarePytestRaises:
             ),
         ],
     )
-    def test_pytest_raises(self, data):
+    def test_pytest_raises(self, data) -> None:
         fd = io.StringIO(data.strip())
         result = list(validate_unwanted_patterns.bare_pytest_raises(fd))
         assert result == []
@@ -147,7 +147,7 @@ class TestBarePytestRaises:
             ),
         ],
     )
-    def test_pytest_raises_raises(self, data, expected):
+    def test_pytest_raises_raises(self, data, expected) -> None:
         fd = io.StringIO(data.strip())
         result = list(validate_unwanted_patterns.bare_pytest_raises(fd))
         assert result == expected
@@ -200,7 +200,7 @@ class TestStringsWithWrongPlacedWhitespace:
             ),
         ],
     )
-    def test_strings_with_wrong_placed_whitespace(self, data):
+    def test_strings_with_wrong_placed_whitespace(self, data) -> None:
         fd = io.StringIO(data.strip())
         result = list(
             validate_unwanted_patterns.strings_with_wrong_placed_whitespace(fd)
@@ -369,7 +369,7 @@ class TestStringsWithWrongPlacedWhitespace:
             ),
         ],
     )
-    def test_strings_with_wrong_placed_whitespace_raises(self, data, expected):
+    def test_strings_with_wrong_placed_whitespace_raises(self, data, expected) -> None:
         fd = io.StringIO(data.strip())
         result = list(
             validate_unwanted_patterns.strings_with_wrong_placed_whitespace(fd)
@@ -401,7 +401,7 @@ b: lib.NoDefault = lib.no_default
             ),
         ],
     )
-    def test_nodefault_used_not_only_for_typing(self, data):
+    def test_nodefault_used_not_only_for_typing(self, data) -> None:
         fd = io.StringIO(data.strip())
         result = list(validate_unwanted_patterns.nodefault_used_not_only_for_typing(fd))
         assert result == []
@@ -440,7 +440,7 @@ if a is NoDefault:
             ),
         ],
     )
-    def test_nodefault_used_not_only_for_typing_raises(self, data, expected):
+    def test_nodefault_used_not_only_for_typing_raises(self, data, expected) -> None:
         fd = io.StringIO(data.strip())
         result = list(validate_unwanted_patterns.nodefault_used_not_only_for_typing(fd))
         assert result == expected
diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py
index 98b55f8d690cf8ee4b6c4a58bc37ae82418333f4..76d64d27b221cf588e7ee959eab0dd06787fc6c6 100755
--- a/scripts/validate_docstrings.py
+++ b/scripts/validate_docstrings.py
@@ -411,8 +411,8 @@ def print_validate_all_results(
     return exit_status
 
 
-def print_validate_one_results(func_name: str):
-    def header(title, width=80, char="#"):
+def print_validate_one_results(func_name: str) -> None:
+    def header(title, width=80, char="#") -> str:
         full_line = char * width
         side_len = (width - len(title) - 2) // 2
         adj = "" if len(title) % 2 == 0 else " "
diff --git a/scripts/validate_exception_location.py b/scripts/validate_exception_location.py
index fb0dc47252717e51f96a6a950c53b025004ba3f0..ecba1eb424ad50e5f494ceb4b1e9d6eb02ef6424 100644
--- a/scripts/validate_exception_location.py
+++ b/scripts/validate_exception_location.py
@@ -71,7 +71,7 @@ class Visitor(ast.NodeVisitor):
 
 def validate_exception_and_warning_placement(
     file_path: str, file_content: str, errors: set[str]
-):
+) -> None:
     tree = ast.parse(file_content)
     visitor = Visitor(file_path, errors)
     visitor.visit(tree)
diff --git a/setup.py b/setup.py
index d6fb4b775a3518e2f2a76bc3fa416ee2d2a65eca..c7c76d0f7636afbf6ef0ed477f8384969a770f40 100755
--- a/setup.py
+++ b/setup.py
@@ -75,7 +75,7 @@ for module, files in _pxi_dep_template.items():
 
 class build_ext(_build_ext):
     @classmethod
-    def render_templates(cls, pxifiles):
+    def render_templates(cls, pxifiles) -> None:
         for pxifile in pxifiles:
             # build pxifiles first, template extension must be .pxi.in
             assert pxifile.endswith(".pxi.in")
@@ -95,7 +95,7 @@ class build_ext(_build_ext):
             with open(outfile, "w", encoding="utf-8") as f:
                 f.write(pyxcontent)
 
-    def build_extensions(self):
+    def build_extensions(self) -> None:
         # if building from c files, don't need to
         # generate template output
         if _CYTHON_INSTALLED:
@@ -109,7 +109,7 @@ class CleanCommand(Command):
 
     user_options = [("all", "a", "")]
 
-    def initialize_options(self):
+    def initialize_options(self) -> None:
         self.all = True
         self._clean_me = []
         self._clean_trees = []
@@ -161,10 +161,10 @@ class CleanCommand(Command):
 
         self._clean_trees.append(d for d in ("build", "dist") if os.path.exists(d))
 
-    def finalize_options(self):
+    def finalize_options(self) -> None:
         pass
 
-    def run(self):
+    def run(self) -> None:
         for clean_me in self._clean_me:
             try:
                 os.unlink(clean_me)
@@ -227,10 +227,10 @@ class CheckSDist(sdist_class):
         "pandas/_libs/window/aggregations.pyx",
     ]
 
-    def initialize_options(self):
+    def initialize_options(self) -> None:
         sdist_class.initialize_options(self)
 
-    def run(self):
+    def run(self) -> None:
         if "cython" in cmdclass:
             self.run_command("cython")
         else:
@@ -254,7 +254,7 @@ class CheckingBuildExt(build_ext):
     Subclass build_ext to get clearer report if Cython is necessary.
     """
 
-    def check_cython_extensions(self, extensions):
+    def check_cython_extensions(self, extensions) -> None:
         for ext in extensions:
             for src in ext.sources:
                 if not os.path.exists(src):
@@ -266,7 +266,7 @@ class CheckingBuildExt(build_ext):
                 """
                     )
 
-    def build_extensions(self):
+    def build_extensions(self) -> None:
         self.check_cython_extensions(self.extensions)
         build_ext.build_extensions(self)
 
@@ -278,7 +278,7 @@ class CythonCommand(build_ext):
     C-compile method build_extension() with a no-op.
     """
 
-    def build_extension(self, ext):
+    def build_extension(self, ext) -> None:
         pass
 
 
@@ -287,13 +287,13 @@ class DummyBuildSrc(Command):
 
     user_options = []
 
-    def initialize_options(self):
+    def initialize_options(self) -> None:
         self.py_modules_dict = {}
 
-    def finalize_options(self):
+    def finalize_options(self) -> None:
         pass
 
-    def run(self):
+    def run(self) -> None:
         pass
 
 
diff --git a/web/tests/test_pandas_web.py b/web/tests/test_pandas_web.py
index 827c1d4dbea40f534a18f7cdcaa0f3ec1ed49591..a5f76875dfe23b79715b6f3b09217a8e9111bdb0 100644
--- a/web/tests/test_pandas_web.py
+++ b/web/tests/test_pandas_web.py
@@ -10,7 +10,7 @@ from web.pandas_web import Preprocessors
 
 
 class MockResponse:
-    def __init__(self, status_code: int, response: dict):
+    def __init__(self, status_code: int, response: dict) -> None:
         self.status_code = status_code
         self._resp = response
 
@@ -18,7 +18,7 @@ class MockResponse:
         return self._resp
 
     @staticmethod
-    def raise_for_status():
+    def raise_for_status() -> None:
         return
 
 
@@ -31,7 +31,7 @@ def context() -> dict:
 
 
 @pytest.fixture(scope="function")
-def mock_response(monkeypatch, request):
+def mock_response(monkeypatch, request) -> None:
     def mocked_resp(*args, **kwargs):
         status_code, response = request.param
         return MockResponse(status_code, response)
@@ -80,7 +80,7 @@ _releases_list = [
 
 
 @pytest.mark.parametrize("mock_response", [(200, _releases_list)], indirect=True)
-def test_web_preprocessor_creates_releases(mock_response, context):
+def test_web_preprocessor_creates_releases(mock_response, context) -> None:
     m = mock_open()
     with patch("builtins.open", m):
         context = Preprocessors.home_add_releases(context)