Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-enable ANN2 for setuptools #4709

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


@abstractmethod
def initialize_options(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions setuptools/_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
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]])


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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may or may not also be related to python/mypy#18075

return super().copy_file( # pyright: ignore[reportReturnType] # pypa/distutils#309
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 @@ -424,7 +424,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 @@ -673,7 +673,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 @@ -710,7 +710,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 @@ -760,7 +762,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 @@ -859,7 +861,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 @@ -881,7 +883,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 @@ -1142,7 +1144,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 @@ -2079,7 +2081,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 @@ -2221,7 +2223,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
17 changes: 14 additions & 3 deletions setuptools/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
import dis
import marshal
import sys
from types import CodeType
from typing import Any, Literal, TypeVar

from packaging.version import Version

from . import _imp
from ._imp import PY_COMPILED, PY_FROZEN, PY_SOURCE, find_module

_T = TypeVar("_T")

__all__ = ['Require', 'find_module']


Expand Down Expand Up @@ -51,7 +55,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: _T | Literal["unknown"] = "unknown"
) -> _T | Literal["unknown"] | None | Any:
"""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 +112,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: _T | int = -1, paths=None
) -> _T | int | None | Any:
"""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 +142,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: _T | int = -1
) -> _T | int | None | Any:
"""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 +173,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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is good this is inside a if TYPE_CHECKING block. Thank you!

Ideally we want to avoid importing pkg_resources in runtime because of the performance hit.

It is only acceptable to "lazily" import pkg_resources on deprecated code paths (but never eagerly).



__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
Loading