Skip to content

Commit

Permalink
Re-enable ANN2 for setuptools
Browse files Browse the repository at this point in the history
  • Loading branch information
Avasam committed Oct 30, 2024
1 parent fcdaf02 commit 7a1006c
Show file tree
Hide file tree
Showing 20 changed files with 117 additions and 77 deletions.
5 changes: 0 additions & 5 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ ignore = [
]

[lint.per-file-ignores]
# Only enforcing return type annotations for public modules
"**/tests/**" = ["ANN2"]
"tools/**" = ["ANN2"]
# Temporarily disabling enforced return annotations for the setuptool package to progressively type from Typeshed
"setuptools/**" = ["ANN2"]
# Suppress nuisance warnings about module-import-not-at-top-of-file (E402) due to workaround for #4476
"setuptools/__init__.py" = ["E402"]
"pkg_resources/__init__.py" = ["E402"]
Expand Down
4 changes: 2 additions & 2 deletions setuptools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def _ensure_stringlike(self, option, what, default=None):
)
return val

def ensure_string_list(self, option: str):
def ensure_string_list(self, option: str) -> None:
r"""Ensure that 'option' is a list of strings. If 'option' is
currently a string, we split it either on /,\s*/ or /\s+/, so
"foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
Expand Down Expand Up @@ -226,7 +226,7 @@ def reinitialize_command(
) -> _Command:
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
vars(cmd).update(kw)
return cmd
return cmd # pyright: ignore[reportReturnType] # pypa/distutils#307

@abstractmethod
def initialize_options(self) -> None:
Expand Down
4 changes: 3 additions & 1 deletion setuptools/_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
import contextlib
import os
import sys
from typing import TYPE_CHECKING, Union
from typing import TYPE_CHECKING, TypeVar, Union

from more_itertools import unique_everseen

if TYPE_CHECKING:
from typing_extensions import TypeAlias

StrPath: TypeAlias = Union[str, os.PathLike[str]] # Same as _typeshed.StrPath
StrPathT = TypeVar("StrPathT", bound=Union[str, os.PathLike[str]])
else:
# Python 3.8 support
StrPath: TypeAlias = Union[str, os.PathLike]
StrPathT = TypeVar("StrPathT", bound=Union[str, os.PathLike])


def ensure_directory(path):
Expand Down
8 changes: 4 additions & 4 deletions setuptools/command/bdist_egg.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from setuptools import Command
from setuptools.extension import Library

from .._path import ensure_directory
from .._path import StrPathT, ensure_directory

from distutils import log
from distutils.dir_util import mkpath, remove_tree
Expand Down Expand Up @@ -440,13 +440,13 @@ def can_scan():


def make_zipfile(
zip_filename,
zip_filename: StrPathT,
base_dir,
verbose: bool = False,
dry_run: bool = False,
compress=True,
mode: _ZipFileMode = 'w',
):
) -> StrPathT:
"""Create a zip file from all the files under 'base_dir'. The output
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
Python module (if available) or the InfoZIP "zip" utility (if installed
Expand All @@ -455,7 +455,7 @@ def make_zipfile(
"""
import zipfile

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

def visit(z, dirname, names):
Expand Down
4 changes: 2 additions & 2 deletions setuptools/command/build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def link_shared_object(
extra_postargs=None,
build_temp=None,
target_lang=None,
):
) -> None:
self.link(
self.SHARED_LIBRARY,
objects,
Expand Down Expand Up @@ -450,7 +450,7 @@ def link_shared_object(
extra_postargs=None,
build_temp=None,
target_lang=None,
):
) -> None:
# XXX we need to either disallow these attrs on Library instances,
# or warn/abort here if set, or something...
# libraries=None, library_dirs=None, runtime_library_dirs=None,
Expand Down
13 changes: 6 additions & 7 deletions setuptools/command/build_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@

from more_itertools import unique_everseen

from setuptools._path import StrPath

from .._path import StrPath, StrPathT
from ..dist import Distribution
from ..warnings import SetuptoolsDeprecationWarning

Expand Down Expand Up @@ -50,20 +49,20 @@ def finalize_options(self):
del self.__dict__['data_files']
self.__updated_files = []

def copy_file( # type: ignore[override] # No overload, str support only
def copy_file( # type: ignore[override] # No overload, no bytes support
self,
infile: StrPath,
outfile: StrPath,
outfile: StrPathT,
preserve_mode: bool = True,
preserve_times: bool = True,
link: str | None = None,
level: object = 1,
):
) -> tuple[StrPathT | str, bool]:
# Overwrite base class to allow using links
if link:
infile = str(Path(infile).resolve())
outfile = str(Path(outfile).resolve())
return super().copy_file(
outfile = str(Path(outfile).resolve()) # type: ignore[assignment] # Re-assigning a str when outfile is StrPath is ok
return super().copy_file( # pyright: ignore[reportReturnType] # pypa/distutils#309
infile, outfile, preserve_mode, preserve_times, link, level
)

Expand Down
20 changes: 11 additions & 9 deletions setuptools/command/easy_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ def expand_dirs(self):
]
self._expand_attrs(dirs)

def run(self, show_deprecation: bool = True):
def run(self, show_deprecation: bool = True) -> None:
if show_deprecation:
self.announce(
"WARNING: The easy_install command is deprecated "
Expand Down Expand Up @@ -674,7 +674,7 @@ def _tmpdir(self):
finally:
os.path.exists(tmpdir) and _rmtree(tmpdir)

def easy_install(self, spec, deps: bool = False):
def easy_install(self, spec, deps: bool = False) -> Distribution | None:
with self._tmpdir() as tmpdir:
if not isinstance(spec, Requirement):
if URL_SCHEME(spec):
Expand Down Expand Up @@ -711,7 +711,9 @@ def easy_install(self, spec, deps: bool = False):
else:
return self.install_item(spec, dist.location, tmpdir, deps)

def install_item(self, spec, download, tmpdir, deps, install_needed: bool = False):
def install_item(
self, spec, download, tmpdir, deps, install_needed: bool = False
) -> Distribution | None:
# Installation is also needed if file in tmpdir or is not an egg
install_needed = install_needed or bool(self.always_copy)
install_needed = install_needed or os.path.dirname(download) == tmpdir
Expand Down Expand Up @@ -761,7 +763,7 @@ def process_distribution( # noqa: C901
dist,
deps: bool = True,
*info,
):
) -> None:
self.update_pth(dist)
self.package_index.add(dist)
if dist in self.local_index[dist.key]:
Expand Down Expand Up @@ -860,7 +862,7 @@ def _load_template(dev_path):
raw_bytes = resource_string('setuptools', name)
return raw_bytes.decode('utf-8')

def write_script(self, script_name, contents, mode: str = "t", blockers=()):
def write_script(self, script_name, contents, mode: str = "t", blockers=()) -> None:
"""Write an executable file to the scripts directory"""
self.delete_blockers( # clean up old .py/.pyw w/o a script
[os.path.join(self.script_dir, x) for x in blockers]
Expand All @@ -882,7 +884,7 @@ def write_script(self, script_name, contents, mode: str = "t", blockers=()):
f.write(contents)
chmod(target, 0o777 - mask)

def install_eggs(self, spec, dist_filename, tmpdir):
def install_eggs(self, spec, dist_filename, tmpdir) -> list[Distribution]:
# .egg dirs or files are already built, so just return them
installer_map = {
'.egg': self.install_egg,
Expand Down Expand Up @@ -1143,7 +1145,7 @@ def install_wheel(self, wheel_path, tmpdir):
"""
)

def installation_report(self, req, dist, what: str = "Installed"):
def installation_report(self, req, dist, what: str = "Installed") -> str:
"""Helpful installation message for display to package users"""
msg = "\n%(what)s %(eggloc)s%(extras)s"
if self.multi_version and not self.no_report:
Expand Down Expand Up @@ -2080,7 +2082,7 @@ def from_environment(cls):
return cls([cls._sys_executable()])

@classmethod
def from_string(cls, string: str):
def from_string(cls, string: str) -> Self:
"""
Construct a command spec from a simple string representing a command
line parseable by shlex.split.
Expand Down Expand Up @@ -2222,7 +2224,7 @@ def get_header(
cls,
script_text: str = "",
executable: str | CommandSpec | Iterable[str] | None = None,
):
) -> str:
"""Create a #! line, getting options (if any) from script_text"""
cmd = cls.command_spec_class.best().from_param(executable)
cmd.install_options(script_text)
Expand Down
4 changes: 2 additions & 2 deletions setuptools/command/egg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def _get_egg_basename(self, py_version=PY_MAJOR, platform=None):
"""Compute filename of the output egg. Private API."""
return _egg_basename(self.egg_name, self.egg_version, py_version, platform)

def write_or_delete_file(self, what, filename, data, force: bool = False):
def write_or_delete_file(self, what, filename, data, force: bool = False) -> None:
"""Write `data` to `filename` or delete if empty
If `data` is non-empty, this routine is the same as ``write_file()``.
Expand Down Expand Up @@ -690,7 +690,7 @@ def overwrite_arg(cmd, basename, filename):
write_arg(cmd, basename, filename, True)


def write_arg(cmd, basename, filename, force: bool = False):
def write_arg(cmd, basename, filename, force: bool = False) -> None:
argname = os.path.splitext(basename)[0]
value = getattr(cmd.distribution, argname, None)
if value is not None:
Expand Down
2 changes: 1 addition & 1 deletion setuptools/command/install_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def _install_ep_scripts(self):
for args in writer.get_args(dist, cmd.as_header()):
self.write_script(*args)

def write_script(self, script_name, contents, mode: str = "t", *ignored):
def write_script(self, script_name, contents, mode: str = "t", *ignored) -> None:
"""Write an executable file to the scripts directory"""
from setuptools.command.easy_install import chmod, current_umask

Expand Down
14 changes: 11 additions & 3 deletions setuptools/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import dis
import marshal
import sys
from types import CodeType

from packaging.version import Version

Expand Down Expand Up @@ -51,7 +52,9 @@ def version_ok(self, version):
and self.format(version) >= self.requested_version
)

def get_version(self, paths=None, default: str = "unknown"):
def get_version(
self, paths=None, default: str | int = "unknown"
) -> str | int | None:
"""Get version number of installed module, 'None', or 'default'
Search 'paths' for module. If not found, return 'None'. If found,
Expand Down Expand Up @@ -106,7 +109,9 @@ def empty():
# XXX it'd be better to test assertions about bytecode instead.
if not sys.platform.startswith('java') and sys.platform != 'cli':

def get_module_constant(module, symbol, default: str | int = -1, paths=None):
def get_module_constant(
module, symbol, default: str | int = -1, paths=None
) -> str | int | None:
"""Find 'module' by searching 'paths', and extract 'symbol'
Return 'None' if 'module' does not exist on 'paths', or it does not define
Expand Down Expand Up @@ -134,7 +139,9 @@ def get_module_constant(module, symbol, default: str | int = -1, paths=None):

return extract_constant(code, symbol, default)

def extract_constant(code, symbol, default: str | int = -1):
def extract_constant(
code: CodeType, symbol: str, default: str | int = -1
) -> str | int | None:
"""Extract the constant value of 'symbol' from 'code'
If the name 'symbol' is bound to a constant value by the Python code
Expand Down Expand Up @@ -163,6 +170,7 @@ def extract_constant(code, symbol, default: str | int = -1):
arg = byte_code.arg

if op == LOAD_CONST:
assert arg is not None
const = code.co_consts[arg]
elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
return const
Expand Down
22 changes: 13 additions & 9 deletions setuptools/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@
from packaging.specifiers import InvalidSpecifier, SpecifierSet
from packaging.version import Version

from setuptools._path import StrPath

from . import (
_entry_points,
_reqs,
command as _, # noqa: F401 # imported for side-effects
)
from ._importlib import metadata
from ._path import StrPath
from ._reqs import _StrOrIter
from .config import pyprojecttoml, setupcfg
from .discovery import ConfigDiscovery
Expand All @@ -52,6 +51,9 @@
if TYPE_CHECKING:
from typing_extensions import TypeAlias

from pkg_resources import Distribution as _pkg_resources_Distribution


__all__ = ['Distribution']

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

def warn_dash_deprecation(self, opt: str, section: str):
def warn_dash_deprecation(self, opt: str, section: str) -> str:
if section in (
'options.extras_require',
'options.data_files',
Expand Down Expand Up @@ -560,7 +562,7 @@ def _setuptools_commands(self):
# during bootstrapping, distribution doesn't exist
return []

def make_option_lowercase(self, opt: str, section: str):
def make_option_lowercase(self, opt: str, section: str) -> str:
if section != 'metadata' or opt.islower():
return opt

Expand Down Expand Up @@ -640,7 +642,7 @@ def parse_config_files(
self,
filenames: Iterable[StrPath] | None = None,
ignore_option_errors: bool = False,
):
) -> None:
"""Parses configuration files from various levels
and loads configuration.
"""
Expand All @@ -657,7 +659,9 @@ def parse_config_files(
self._finalize_requires()
self._finalize_license_files()

def fetch_build_eggs(self, requires: _StrOrIter):
def fetch_build_eggs(
self, requires: _StrOrIter
) -> list[_pkg_resources_Distribution]:
"""Resolve pre-setup requirements"""
from .installer import _fetch_build_eggs

Expand Down Expand Up @@ -728,7 +732,7 @@ def fetch_build_egg(self, req):

return fetch_build_egg(self, req)

def get_command_class(self, command: str):
def get_command_class(self, command: str) -> type[distutils.cmd.Command]: # type: ignore[override] # Not doing complex overrides yet
"""Pluggable version of get_command_class()"""
if command in self.cmdclass:
return self.cmdclass[command]
Expand Down Expand Up @@ -782,7 +786,7 @@ def include(self, **attrs):
else:
self._include_misc(k, v)

def exclude_package(self, package: str):
def exclude_package(self, package: str) -> None:
"""Remove packages, modules, and extensions in named package"""

pfx = package + '.'
Expand All @@ -803,7 +807,7 @@ def exclude_package(self, package: str):
if p.name != package and not p.name.startswith(pfx)
]

def has_contents_for(self, package: str):
def has_contents_for(self, package: str) -> bool:
"""Return true if 'exclude_package(package)' would do something"""

pfx = package + '.'
Expand Down
Loading

0 comments on commit 7a1006c

Please sign in to comment.