diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 8a2fbfa412..7ad39c3956 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -93,7 +93,7 @@ if TYPE_CHECKING: from _typeshed import BytesPath, StrOrBytesPath, StrPath from _typeshed.importlib import LoaderProtocol - from typing_extensions import Self, TypeAlias + from typing_extensions import Never, Self, TypeAlias warnings.warn( "pkg_resources is deprecated as an API. " @@ -2370,7 +2370,7 @@ class NoDists: def __bool__(self) -> Literal[False]: return False - def __call__(self, fullpath: object): + def __call__(self, fullpath: object) -> Iterator[Never]: return iter(()) @@ -3168,13 +3168,13 @@ def __str__(self) -> str: version = version or "[unknown version]" return f"{self.project_name} {version}" - def __getattr__(self, attr: str): + def __getattr__(self, attr: str) -> Any: """Delegate all unrecognized public attributes to .metadata provider""" if attr.startswith('_'): raise AttributeError(attr) return getattr(self._provider, attr) - def __dir__(self): + def __dir__(self) -> list[str]: return list( set(super().__dir__()) | set(attr for attr in self._provider.__dir__() if not attr.startswith('_')) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index cfc9b16c0f..770ce527c9 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -22,7 +22,7 @@ class EggRemover(str): - def __call__(self): + def __call__(self) -> None: if self in sys.path: sys.path.remove(self) if os.path.exists(self): diff --git a/pkg_resources/tests/test_working_set.py b/pkg_resources/tests/test_working_set.py index ed20c59dd3..8b18ea56fd 100644 --- a/pkg_resources/tests/test_working_set.py +++ b/pkg_resources/tests/test_working_set.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import functools import inspect import re import textwrap +from collections.abc import Iterable import pytest @@ -56,10 +59,10 @@ def parse_distributions(s): class FakeInstaller: - def __init__(self, installable_dists) -> None: + def __init__(self, installable_dists: Iterable[pkg_resources.Distribution]) -> None: self._installable_dists = installable_dists - def __call__(self, req): + def __call__(self, req) -> pkg_resources.Distribution | None: return next( iter(filter(lambda dist: dist in req, self._installable_dists)), None ) diff --git a/ruff.toml b/ruff.toml index 349d22cebd..56ca159dd9 100644 --- a/ruff.toml +++ b/ruff.toml @@ -65,7 +65,6 @@ ignore = [ "UP038", # Using `X | Y` in `isinstance` call is slower and more verbose https://github.com/astral-sh/ruff/issues/7871 # Only enforcing return type annotations for public functions "ANN202", # missing-return-type-private-function - "ANN204", # missing-return-type-special-method ] [lint.per-file-ignores] diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index 2f6fcb7cdc..4a3d0e7df8 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -9,6 +9,7 @@ from functools import partial from glob import glob from pathlib import Path +from typing import Any from more_itertools import unique_everseen @@ -81,7 +82,8 @@ def run(self) -> None: # output files are. self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=False)) - def __getattr__(self, attr: str): + # Should return "list[tuple[str, str, str, list[str]]] | Any" but can't do without typed distutils on Python 3.12+ + def __getattr__(self, attr: str) -> Any: "lazily compute data files" if attr == 'data_files': self.data_files = self._get_data_files() @@ -381,8 +383,8 @@ class _Warning(SetuptoolsDeprecationWarning): # _DUE_DATE: still not defined as this is particularly controversial. # Warning initially introduced in May 2022. See issue #3340 for discussion. - def __init__(self): - self._already_warned = set() + def __init__(self) -> None: + self._already_warned = set[str]() def is_module(self, file): return file.endswith(".py") and file[: -len(".py")].isidentifier() diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index 917d5f149b..2f733106d7 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -402,7 +402,9 @@ def __init__(self, dist: Distribution, name: str, path_entries: list[Path]) -> N self.name = name self.path_entries = path_entries - def __call__(self, wheel: WheelFile, files: list[str], mapping: Mapping[str, str]): + def __call__( + self, wheel: WheelFile, files: list[str], mapping: Mapping[str, str] + ) -> None: entries = "\n".join(str(p.resolve()) for p in self.path_entries) contents = _encode_pth(f"{entries}\n") wheel.writestr(f"__editable__.{self.name}.pth", contents) @@ -447,7 +449,9 @@ def __init__( self._file = dist.get_command_obj("build_py").copy_file super().__init__(dist, name, [self.auxiliary_dir]) - def __call__(self, wheel: WheelFile, files: list[str], mapping: Mapping[str, str]): + def __call__( + self, wheel: WheelFile, files: list[str], mapping: Mapping[str, str] + ) -> None: self._create_links(files, mapping) super().__call__(wheel, files, mapping) @@ -541,7 +545,9 @@ def get_implementation(self) -> Iterator[tuple[str, bytes]]: content = _encode_pth(f"import {finder}; {finder}.install()") yield (f"__editable__.{self.name}.pth", content) - def __call__(self, wheel: WheelFile, files: list[str], mapping: Mapping[str, str]): + def __call__( + self, wheel: WheelFile, files: list[str], mapping: Mapping[str, str] + ) -> None: for file, content in self.get_implementation(): wheel.writestr(file, content) diff --git a/setuptools/config/expand.py b/setuptools/config/expand.py index 531f965013..d9a2ded430 100644 --- a/setuptools/config/expand.py +++ b/setuptools/config/expand.py @@ -65,7 +65,7 @@ def _find_assignments(self) -> Iterator[tuple[ast.AST, ast.AST]]: elif isinstance(statement, ast.AnnAssign) and statement.value: yield (statement.target, statement.value) - def __getattr__(self, attr: str): + def __getattr__(self, attr: str) -> Any: """Attempt to load an attribute "statically", via :func:`ast.literal_eval`.""" try: return next( @@ -390,7 +390,7 @@ def __init__(self, distribution: Distribution) -> None: self._dist = distribution self._called = False - def __call__(self): + def __call__(self) -> None: """Trigger the automatic package discovery, if it is still necessary.""" if not self._called: self._called = True @@ -404,7 +404,7 @@ def __exit__( exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None, - ): + ) -> None: if self._called: self._dist.set_defaults.analyse_name() # Now we can set a default name diff --git a/setuptools/discovery.py b/setuptools/discovery.py index c888399185..606796c388 100644 --- a/setuptools/discovery.py +++ b/setuptools/discovery.py @@ -335,7 +335,7 @@ def _package_dir(self) -> dict[str, str]: def __call__( self, force: bool = False, name: bool = True, ignore_ext_modules: bool = False - ): + ) -> None: """Automatically discover missing configuration fields and modifies the given ``distribution`` object in-place. diff --git a/setuptools/tests/integration/helpers.py b/setuptools/tests/integration/helpers.py index 77b196e029..465ff72fc2 100644 --- a/setuptools/tests/integration/helpers.py +++ b/setuptools/tests/integration/helpers.py @@ -5,11 +5,14 @@ facilitate debugging. """ +from __future__ import annotations + import os import subprocess import tarfile +from collections.abc import Iterator from pathlib import Path -from zipfile import ZipFile +from zipfile import ZipFile, ZipInfo def run(cmd, env=None): @@ -35,7 +38,7 @@ def run(cmd, env=None): class Archive: """Compatibility layer for ZipFile/Info and TarFile/Info""" - def __init__(self, filename): + def __init__(self, filename) -> None: self._filename = filename if filename.endswith("tar.gz"): self._obj = tarfile.open(filename, "r:gz") @@ -44,7 +47,7 @@ def __init__(self, filename): else: raise ValueError(f"{filename} doesn't seem to be a zip or tar.gz") - def __iter__(self): + def __iter__(self) -> Iterator[ZipInfo] | Iterator[tarfile.TarInfo]: if hasattr(self._obj, "infolist"): return iter(self._obj.infolist()) return iter(self._obj) diff --git a/setuptools/tests/test_bdist_wheel.py b/setuptools/tests/test_bdist_wheel.py index 2ab4e9cfc6..68cc0c4d36 100644 --- a/setuptools/tests/test_bdist_wheel.py +++ b/setuptools/tests/test_bdist_wheel.py @@ -295,7 +295,7 @@ def test_preserve_unicode_metadata(monkeypatch, tmp_path): class simpler_bdist_wheel(bdist_wheel): """Avoid messing with setuptools/distutils internals""" - def __init__(self): + def __init__(self) -> None: pass @property diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index 57162fd6af..2cd0a0a8ed 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -35,7 +35,7 @@ class BuildBackendBase: - def __init__(self, cwd='.', env=None, backend_name='setuptools.build_meta'): + def __init__(self, cwd='.', env=None, backend_name='setuptools.build_meta') -> None: self.cwd = cwd self.env = env or {} self.backend_name = backend_name @@ -44,7 +44,7 @@ def __init__(self, cwd='.', env=None, backend_name='setuptools.build_meta'): class BuildBackend(BuildBackendBase): """PEP 517 Build Backend""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.pool = futures.ProcessPoolExecutor(max_workers=1) @@ -77,12 +77,12 @@ def _kill(self, pid): class BuildBackendCaller(BuildBackendBase): - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) (self.backend_name, _, self.backend_obj) = self.backend_name.partition(':') - def __call__(self, name, *args, **kw): + def __call__(self, name, *args, **kw) -> Any: """Handles arbitrary function invocations on the build backend.""" os.chdir(self.cwd) os.environ.update(self.env) diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py index 70165c608b..97e6ed8595 100644 --- a/setuptools/tests/test_wheel.py +++ b/setuptools/tests/test_wheel.py @@ -171,7 +171,7 @@ def _check_wheel_install( class Record: - def __init__(self, id, **kwargs): + def __init__(self, id, **kwargs) -> None: self._id = id self._fields = kwargs