Skip to content

Commit 39179c1

Browse files
authored
Re-enable ANN2 for setuptools (#4709)
2 parents a6e5b7e + f160c70 commit 39179c1

17 files changed

+104
-63
lines changed

ruff.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,6 @@ ignore = [
5858
]
5959

6060
[lint.per-file-ignores]
61-
# Only enforcing return type annotations for public modules
62-
"**/tests/**" = ["ANN2"]
63-
"tools/**" = ["ANN2"]
64-
# Temporarily disabling enforced return annotations for the setuptool package to progressively type from Typeshed
65-
"setuptools/**" = ["ANN2"]
6661
# Suppress nuisance warnings about module-import-not-at-top-of-file (E402) due to workaround for #4476
6762
"setuptools/__init__.py" = ["E402"]
6863
"pkg_resources/__init__.py" = ["E402"]

setuptools/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def reinitialize_command(
226226
) -> _Command:
227227
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
228228
vars(cmd).update(kw)
229-
return cmd
229+
return cmd # pyright: ignore[reportReturnType] # pypa/distutils#307
230230

231231
@abstractmethod
232232
def initialize_options(self) -> None:

setuptools/_path.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
import contextlib
44
import os
55
import sys
6-
from typing import TYPE_CHECKING, Union
6+
from typing import TYPE_CHECKING, TypeVar, Union
77

88
from more_itertools import unique_everseen
99

1010
if TYPE_CHECKING:
1111
from typing_extensions import TypeAlias
1212

13-
1413
StrPath: TypeAlias = Union[str, os.PathLike[str]] # Same as _typeshed.StrPath
14+
StrPathT = TypeVar("StrPathT", bound=Union[str, os.PathLike[str]])
1515

1616

1717
def ensure_directory(path):

setuptools/command/bdist_egg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from setuptools import Command
1717
from setuptools.extension import Library
1818

19-
from .._path import ensure_directory
19+
from .._path import StrPathT, ensure_directory
2020

2121
from distutils import log
2222
from distutils.dir_util import mkpath, remove_tree
@@ -440,13 +440,13 @@ def can_scan() -> bool:
440440

441441

442442
def make_zipfile(
443-
zip_filename,
443+
zip_filename: StrPathT,
444444
base_dir,
445445
verbose: bool = False,
446446
dry_run: bool = False,
447447
compress=True,
448448
mode: _ZipFileMode = 'w',
449-
):
449+
) -> StrPathT:
450450
"""Create a zip file from all the files under 'base_dir'. The output
451451
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
452452
Python module (if available) or the InfoZIP "zip" utility (if installed
@@ -455,7 +455,7 @@ def make_zipfile(
455455
"""
456456
import zipfile
457457

458-
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
458+
mkpath(os.path.dirname(zip_filename), dry_run=dry_run) # type: ignore[arg-type] # python/mypy#18075
459459
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
460460

461461
def visit(z, dirname, names):

setuptools/command/build_py.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212

1313
from more_itertools import unique_everseen
1414

15-
from setuptools._path import StrPath
16-
15+
from .._path import StrPath, StrPathT
1716
from ..dist import Distribution
1817
from ..warnings import SetuptoolsDeprecationWarning
1918

@@ -50,20 +49,20 @@ def finalize_options(self):
5049
del self.__dict__['data_files']
5150
self.__updated_files = []
5251

53-
def copy_file( # type: ignore[override] # No overload, str support only
52+
def copy_file( # type: ignore[override] # No overload, no bytes support
5453
self,
5554
infile: StrPath,
56-
outfile: StrPath,
55+
outfile: StrPathT,
5756
preserve_mode: bool = True,
5857
preserve_times: bool = True,
5958
link: str | None = None,
6059
level: object = 1,
61-
):
60+
) -> tuple[StrPathT | str, bool]:
6261
# Overwrite base class to allow using links
6362
if link:
6463
infile = str(Path(infile).resolve())
65-
outfile = str(Path(outfile).resolve())
66-
return super().copy_file(
64+
outfile = str(Path(outfile).resolve()) # type: ignore[assignment] # Re-assigning a str when outfile is StrPath is ok
65+
return super().copy_file( # pyright: ignore[reportReturnType] # pypa/distutils#309
6766
infile, outfile, preserve_mode, preserve_times, link, level
6867
)
6968

setuptools/command/easy_install.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ def _tmpdir(self):
673673
finally:
674674
os.path.exists(tmpdir) and _rmtree(tmpdir)
675675

676-
def easy_install(self, spec, deps: bool = False):
676+
def easy_install(self, spec, deps: bool = False) -> Distribution | None:
677677
with self._tmpdir() as tmpdir:
678678
if not isinstance(spec, Requirement):
679679
if URL_SCHEME(spec):
@@ -710,7 +710,9 @@ def easy_install(self, spec, deps: bool = False):
710710
else:
711711
return self.install_item(spec, dist.location, tmpdir, deps)
712712

713-
def install_item(self, spec, download, tmpdir, deps, install_needed: bool = False):
713+
def install_item(
714+
self, spec, download, tmpdir, deps, install_needed: bool = False
715+
) -> Distribution | None:
714716
# Installation is also needed if file in tmpdir or is not an egg
715717
install_needed = install_needed or bool(self.always_copy)
716718
install_needed = install_needed or os.path.dirname(download) == tmpdir
@@ -881,7 +883,7 @@ def write_script(self, script_name, contents, mode: str = "t", blockers=()) -> N
881883
f.write(contents)
882884
chmod(target, 0o777 - mask)
883885

884-
def install_eggs(self, spec, dist_filename, tmpdir):
886+
def install_eggs(self, spec, dist_filename, tmpdir) -> list[Distribution]:
885887
# .egg dirs or files are already built, so just return them
886888
installer_map = {
887889
'.egg': self.install_egg,
@@ -1142,7 +1144,7 @@ def install_wheel(self, wheel_path, tmpdir):
11421144
"""
11431145
)
11441146

1145-
def installation_report(self, req, dist, what: str = "Installed"):
1147+
def installation_report(self, req, dist, what: str = "Installed") -> str:
11461148
"""Helpful installation message for display to package users"""
11471149
msg = "\n%(what)s %(eggloc)s%(extras)s"
11481150
if self.multi_version and not self.no_report:
@@ -2079,7 +2081,7 @@ def from_environment(cls):
20792081
return cls([cls._sys_executable()])
20802082

20812083
@classmethod
2082-
def from_string(cls, string: str):
2084+
def from_string(cls, string: str) -> Self:
20832085
"""
20842086
Construct a command spec from a simple string representing a command
20852087
line parseable by shlex.split.
@@ -2221,7 +2223,7 @@ def get_header(
22212223
cls,
22222224
script_text: str = "",
22232225
executable: str | CommandSpec | Iterable[str] | None = None,
2224-
):
2226+
) -> str:
22252227
"""Create a #! line, getting options (if any) from script_text"""
22262228
cmd = cls.command_spec_class.best().from_param(executable)
22272229
cmd.install_options(script_text)

setuptools/depends.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
import dis
55
import marshal
66
import sys
7+
from types import CodeType
8+
from typing import Any, Literal, TypeVar
79

810
from packaging.version import Version
911

1012
from . import _imp
1113
from ._imp import PY_COMPILED, PY_FROZEN, PY_SOURCE, find_module
1214

15+
_T = TypeVar("_T")
16+
1317
__all__ = ['Require', 'find_module']
1418

1519

@@ -51,7 +55,9 @@ def version_ok(self, version):
5155
and self.format(version) >= self.requested_version
5256
)
5357

54-
def get_version(self, paths=None, default: str = "unknown"):
58+
def get_version(
59+
self, paths=None, default: _T | Literal["unknown"] = "unknown"
60+
) -> _T | Literal["unknown"] | None | Any:
5561
"""Get version number of installed module, 'None', or 'default'
5662
5763
Search 'paths' for module. If not found, return 'None'. If found,
@@ -106,7 +112,9 @@ def empty():
106112
# XXX it'd be better to test assertions about bytecode instead.
107113
if not sys.platform.startswith('java') and sys.platform != 'cli':
108114

109-
def get_module_constant(module, symbol, default: str | int = -1, paths=None):
115+
def get_module_constant(
116+
module, symbol, default: _T | int = -1, paths=None
117+
) -> _T | int | None | Any:
110118
"""Find 'module' by searching 'paths', and extract 'symbol'
111119
112120
Return 'None' if 'module' does not exist on 'paths', or it does not define
@@ -134,7 +142,9 @@ def get_module_constant(module, symbol, default: str | int = -1, paths=None):
134142

135143
return extract_constant(code, symbol, default)
136144

137-
def extract_constant(code, symbol, default: str | int = -1):
145+
def extract_constant(
146+
code: CodeType, symbol: str, default: _T | int = -1
147+
) -> _T | int | None | Any:
138148
"""Extract the constant value of 'symbol' from 'code'
139149
140150
If the name 'symbol' is bound to a constant value by the Python code
@@ -163,6 +173,7 @@ def extract_constant(code, symbol, default: str | int = -1):
163173
arg = byte_code.arg
164174

165175
if op == LOAD_CONST:
176+
assert arg is not None
166177
const = code.co_consts[arg]
167178
elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
168179
return const

setuptools/dist.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,13 @@
2525
from packaging.specifiers import InvalidSpecifier, SpecifierSet
2626
from packaging.version import Version
2727

28-
from setuptools._path import StrPath
29-
3028
from . import (
3129
_entry_points,
3230
_reqs,
3331
command as _, # noqa: F401 # imported for side-effects
3432
)
3533
from ._importlib import metadata
34+
from ._path import StrPath
3635
from ._reqs import _StrOrIter
3736
from .config import pyprojecttoml, setupcfg
3837
from .discovery import ConfigDiscovery
@@ -52,6 +51,9 @@
5251
if TYPE_CHECKING:
5352
from typing_extensions import TypeAlias
5453

54+
from pkg_resources import Distribution as _pkg_resources_Distribution
55+
56+
5557
__all__ = ['Distribution']
5658

5759
_sequence = tuple, list
@@ -518,7 +520,7 @@ def _parse_config_files(self, filenames=None): # noqa: C901
518520
except ValueError as e:
519521
raise DistutilsOptionError(e) from e
520522

521-
def warn_dash_deprecation(self, opt: str, section: str):
523+
def warn_dash_deprecation(self, opt: str, section: str) -> str:
522524
if section in (
523525
'options.extras_require',
524526
'options.data_files',
@@ -560,7 +562,7 @@ def _setuptools_commands(self):
560562
# during bootstrapping, distribution doesn't exist
561563
return []
562564

563-
def make_option_lowercase(self, opt: str, section: str):
565+
def make_option_lowercase(self, opt: str, section: str) -> str:
564566
if section != 'metadata' or opt.islower():
565567
return opt
566568

@@ -657,7 +659,9 @@ def parse_config_files(
657659
self._finalize_requires()
658660
self._finalize_license_files()
659661

660-
def fetch_build_eggs(self, requires: _StrOrIter):
662+
def fetch_build_eggs(
663+
self, requires: _StrOrIter
664+
) -> list[_pkg_resources_Distribution]:
661665
"""Resolve pre-setup requirements"""
662666
from .installer import _fetch_build_eggs
663667

@@ -728,7 +732,7 @@ def fetch_build_egg(self, req):
728732

729733
return fetch_build_egg(self, req)
730734

731-
def get_command_class(self, command: str):
735+
def get_command_class(self, command: str) -> type[distutils.cmd.Command]: # type: ignore[override] # Not doing complex overrides yet
732736
"""Pluggable version of get_command_class()"""
733737
if command in self.cmdclass:
734738
return self.cmdclass[command]

0 commit comments

Comments
 (0)