From 3ee8f10f1e8eb12448e9053f095f8443f97e249d Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 28 Oct 2024 17:59:00 -0400 Subject: [PATCH] Re-enable ANN2 for setuptools --- ruff.toml | 5 -- setuptools/__init__.py | 4 +- setuptools/_path.py | 4 +- setuptools/command/bdist_egg.py | 8 +-- setuptools/command/build_ext.py | 4 +- setuptools/command/build_py.py | 13 +++-- setuptools/command/easy_install.py | 20 ++++---- setuptools/command/egg_info.py | 4 +- setuptools/command/install_scripts.py | 2 +- setuptools/depends.py | 14 ++++-- setuptools/dist.py | 22 ++++---- setuptools/glob.py | 50 +++++++++++++------ setuptools/installer.py | 6 ++- setuptools/logging.py | 2 +- setuptools/package_index.py | 14 +++--- setuptools/sandbox.py | 6 ++- setuptools/tests/config/downloads/__init__.py | 8 +-- setuptools/tests/test_build_ext.py | 2 +- setuptools/tests/test_editable_install.py | 2 +- tools/build_launchers.py | 4 +- 20 files changed, 116 insertions(+), 78 deletions(-) diff --git a/ruff.toml b/ruff.toml index 438c048962..a1692aa5fd 100644 --- a/ruff.toml +++ b/ruff.toml @@ -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"] diff --git a/setuptools/__init__.py b/setuptools/__init__.py index eba86c4f9c..783e5e7591 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -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 @@ -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: diff --git a/setuptools/_path.py b/setuptools/_path.py index b749c6c6a0..0d99b0f539 100644 --- a/setuptools/_path.py +++ b/setuptools/_path.py @@ -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): diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 2881d8a9da..77aea56f45 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -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 @@ -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 @@ -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): diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index 1b9c313ff5..3e5e7dfc3a 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -415,7 +415,7 @@ def link_shared_object( extra_postargs=None, build_temp=None, target_lang=None, - ): + ) -> None: self.link( self.SHARED_LIBRARY, objects, @@ -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, diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index 628a20b40b..1c3259ae52 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -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 @@ -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 ) diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 5778020ccb..bffb8212ff 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -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 " @@ -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): @@ -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 @@ -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]: @@ -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] @@ -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, @@ -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: @@ -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. @@ -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) diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index f9b8c6df71..ba3bbb0e5a 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -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()``. @@ -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: diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py index f1ccc2bbf8..036d35662d 100644 --- a/setuptools/command/install_scripts.py +++ b/setuptools/command/install_scripts.py @@ -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 diff --git a/setuptools/depends.py b/setuptools/depends.py index e73f06808e..bd292a4905 100644 --- a/setuptools/depends.py +++ b/setuptools/depends.py @@ -4,6 +4,7 @@ import dis import marshal import sys +from types import CodeType from packaging.version import Version @@ -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, @@ -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 @@ -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 @@ -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 diff --git a/setuptools/dist.py b/setuptools/dist.py index 1348ca61c2..6c22998211 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -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 @@ -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 @@ -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', @@ -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 @@ -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. """ @@ -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 @@ -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] @@ -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 + '.' @@ -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 + '.' diff --git a/setuptools/glob.py b/setuptools/glob.py index 97aca44314..827e8433fa 100644 --- a/setuptools/glob.py +++ b/setuptools/glob.py @@ -6,14 +6,21 @@ * Hidden files are not ignored. """ +from __future__ import annotations + import fnmatch import os import re +from collections.abc import Iterator +from typing import TYPE_CHECKING, AnyStr, Iterable, overload + +if TYPE_CHECKING: + from _typeshed import BytesPath, StrOrBytesPath, StrPath __all__ = ["glob", "iglob", "escape"] -def glob(pathname, recursive: bool = False): +def glob(pathname: AnyStr, recursive: bool = False) -> list[AnyStr]: """Return a list of paths matching a pathname pattern. The pattern may contain simple shell-style wildcards a la @@ -27,7 +34,7 @@ def glob(pathname, recursive: bool = False): return list(iglob(pathname, recursive=recursive)) -def iglob(pathname, recursive: bool = False): +def iglob(pathname: AnyStr, recursive: bool = False) -> Iterator[AnyStr]: """Return an iterator which yields the paths matching a pathname pattern. The pattern may contain simple shell-style wildcards a la @@ -45,7 +52,7 @@ def iglob(pathname, recursive: bool = False): return it -def _iglob(pathname, recursive): +def _iglob(pathname: AnyStr, recursive: bool) -> Iterator[AnyStr]: dirname, basename = os.path.split(pathname) glob_in_dir = glob2 if recursive and _isrecursive(basename) else glob1 @@ -66,7 +73,7 @@ def _iglob(pathname, recursive): # drive or UNC path. Prevent an infinite recursion if a drive or UNC path # contains magic characters (i.e. r'\\?\C:'). if dirname != pathname and has_magic(dirname): - dirs = _iglob(dirname, recursive) + dirs: Iterable[AnyStr] = _iglob(dirname, recursive) else: dirs = [dirname] if not has_magic(basename): @@ -81,7 +88,11 @@ def _iglob(pathname, recursive): # takes a literal basename (so it only has to check for its existence). -def glob1(dirname, pattern): +@overload +def glob1(dirname: StrPath, pattern: str) -> list[str]: ... +@overload +def glob1(dirname: BytesPath, pattern: bytes) -> list[bytes]: ... +def glob1(dirname: StrOrBytesPath, pattern: str | bytes) -> list[str] | list[bytes]: if not dirname: if isinstance(pattern, bytes): dirname = os.curdir.encode('ASCII') @@ -91,7 +102,8 @@ def glob1(dirname, pattern): names = os.listdir(dirname) except OSError: return [] - return fnmatch.filter(names, pattern) + # mypy false-positives: str or bytes type possibility is always kept in sync + return fnmatch.filter(names, pattern) # type: ignore[type-var, return-value] def glob0(dirname, basename): @@ -110,14 +122,22 @@ def glob0(dirname, basename): # directory. -def glob2(dirname, pattern): +@overload +def glob2(dirname: StrPath, pattern: str) -> Iterator[str]: ... +@overload +def glob2(dirname: BytesPath, pattern: bytes) -> Iterator[bytes]: ... +def glob2(dirname: StrOrBytesPath, pattern: str | bytes) -> Iterator[str | bytes]: assert _isrecursive(pattern) yield pattern[:0] yield from _rlistdir(dirname) # Recursively yields relative pathnames inside a literal directory. -def _rlistdir(dirname): +@overload +def _rlistdir(dirname: StrPath) -> Iterator[str]: ... +@overload +def _rlistdir(dirname: BytesPath) -> Iterator[bytes]: ... +def _rlistdir(dirname: StrOrBytesPath) -> Iterator[str | bytes]: if not dirname: if isinstance(dirname, bytes): dirname = os.curdir.encode('ASCII') @@ -129,24 +149,24 @@ def _rlistdir(dirname): return for x in names: yield x - path = os.path.join(dirname, x) if dirname else x + # mypy false-positives: str or bytes type possibility is always kept in sync + path = os.path.join(dirname, x) if dirname else x # type: ignore[arg-type] for y in _rlistdir(path): - yield os.path.join(x, y) + yield os.path.join(x, y) # type: ignore[arg-type] magic_check = re.compile('([*?[])') magic_check_bytes = re.compile(b'([*?[])') -def has_magic(s): +def has_magic(s: str | bytes) -> bool: if isinstance(s, bytes): - match = magic_check_bytes.search(s) + return magic_check_bytes.search(s) is not None else: - match = magic_check.search(s) - return match is not None + return magic_check.search(s) is not None -def _isrecursive(pattern): +def _isrecursive(pattern: str | bytes) -> bool: if isinstance(pattern, bytes): return pattern == b'**' else: diff --git a/setuptools/installer.py b/setuptools/installer.py index ba2d808d49..64bc2def07 100644 --- a/setuptools/installer.py +++ b/setuptools/installer.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import glob import os import subprocess @@ -5,6 +7,8 @@ import tempfile from functools import partial +from pkg_resources import Distribution + from . import _reqs from ._reqs import _StrOrIter from .warnings import SetuptoolsDeprecationWarning @@ -31,7 +35,7 @@ def fetch_build_egg(dist, req): return _fetch_build_egg_no_warn(dist, req) -def _fetch_build_eggs(dist, requires: _StrOrIter): +def _fetch_build_eggs(dist, requires: _StrOrIter) -> list[Distribution]: import pkg_resources # Delay import to avoid unnecessary side-effects _DeprecatedInstaller.emit(stacklevel=3) diff --git a/setuptools/logging.py b/setuptools/logging.py index c6d25a6b1e..dd7fdaa7d9 100644 --- a/setuptools/logging.py +++ b/setuptools/logging.py @@ -35,6 +35,6 @@ def configure(): distutils.dist.log = distutils.log -def set_threshold(level: int): +def set_threshold(level: int) -> int: logging.root.setLevel(level * 10) return set_threshold.unpatched(level) diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 6b4a256dfc..619099bc8d 100644 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -1,5 +1,7 @@ """PyPI and direct package downloading.""" +from __future__ import annotations + import base64 import configparser import hashlib @@ -325,7 +327,7 @@ def add(self, dist): return super().add(dist) # FIXME: 'PackageIndex.process_url' is too complex (14) - def process_url(self, url, retrieve: bool = False): # noqa: C901 + def process_url(self, url, retrieve: bool = False) -> None: # noqa: C901 """Evaluate a URL as a possible download, and maybe retrieve it""" if url in self.scanned_urls and not retrieve: return @@ -378,7 +380,7 @@ def process_url(self, url, retrieve: bool = False): # noqa: C901 if url.startswith(self.index_url) and getattr(f, 'code', None) != 404: page = self.process_index(url, page) - def process_filename(self, fn, nested: bool = False): + def process_filename(self, fn, nested: bool = False) -> None: # process filenames or directories if not os.path.exists(fn): self.warn("Not found: %s", fn) @@ -394,7 +396,7 @@ def process_filename(self, fn, nested: bool = False): self.debug("Found: %s", fn) list(map(self.add, dists)) - def url_ok(self, url, fatal: bool = False): + def url_ok(self, url, fatal: bool = False) -> bool: s = URL_SCHEME(url) is_file = s and s.group(1).lower() == 'file' if is_file or self.allows(urllib.parse.urlparse(url)[1]): @@ -604,7 +606,7 @@ def fetch_distribution( # noqa: C901 # is too complex (14) # FIXME source: bool = False, develop_ok: bool = False, local_index=None, - ): + ) -> Distribution | None: """Obtain a distribution suitable for fulfilling `requirement` `requirement` must be a ``pkg_resources.Requirement`` instance. @@ -626,7 +628,7 @@ def fetch_distribution( # noqa: C901 # is too complex (14) # FIXME skipped = set() dist = None - def find(req, env=None): + def find(req, env: Environment | None = None): if env is None: env = self # Find a matching distribution; may be called more than once @@ -680,7 +682,7 @@ def find(req, env=None): def fetch( self, requirement, tmpdir, force_scan: bool = False, source: bool = False - ): + ) -> str | None: """Obtain a file suitable for fulfilling `requirement` DEPRECATED; use the ``fetch_distribution()`` method now instead. For diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 5dedeeb47f..43da85fa42 100644 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -19,7 +19,9 @@ from distutils.errors import DistutilsError -if sys.platform.startswith('java'): +if TYPE_CHECKING: + import os as _os +elif sys.platform.startswith('java'): import org.python.modules.posix.PosixModule as _os # pyright: ignore[reportMissingImports] else: _os = sys.modules[os.name] @@ -491,7 +493,7 @@ def _remap_pair(self, operation, src, dst, *args, **kw): self._violation(operation, src, dst, *args, **kw) return (src, dst) - def open(self, file, flags, mode: int = 0o777, *args, **kw): + def open(self, file, flags, mode: int = 0o777, *args, **kw) -> int: """Called for low-level os.open()""" if flags & WRITE_FLAGS and not self._ok(file): self._violation("os.open", file, flags, mode, *args, **kw) diff --git a/setuptools/tests/config/downloads/__init__.py b/setuptools/tests/config/downloads/__init__.py index 9fb9b14b02..00a16423f4 100644 --- a/setuptools/tests/config/downloads/__init__.py +++ b/setuptools/tests/config/downloads/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import time from pathlib import Path @@ -16,14 +18,14 @@ # ---------------------------------------------------------------------- -def output_file(url: str, download_dir: Path = DOWNLOAD_DIR): +def output_file(url: str, download_dir: Path = DOWNLOAD_DIR) -> Path: file_name = url.strip() for part in NAME_REMOVE: file_name = file_name.replace(part, '').strip().strip('/:').strip() return Path(download_dir, re.sub(r"[^\-_\.\w\d]+", "_", file_name)) -def retrieve_file(url: str, download_dir: Path = DOWNLOAD_DIR, wait: float = 5): +def retrieve_file(url: str, download_dir: Path = DOWNLOAD_DIR, wait: float = 5) -> Path: path = output_file(url, download_dir) if path.exists(): print(f"Skipping {url} (already exists: {path})") @@ -38,7 +40,7 @@ def retrieve_file(url: str, download_dir: Path = DOWNLOAD_DIR, wait: float = 5): return path -def urls_from_file(list_file: Path): +def urls_from_file(list_file: Path) -> list[str]: """``list_file`` should be a text file where each line corresponds to a URL to download. """ diff --git a/setuptools/tests/test_build_ext.py b/setuptools/tests/test_build_ext.py index f3e4ccd364..88318b26c5 100644 --- a/setuptools/tests/test_build_ext.py +++ b/setuptools/tests/test_build_ext.py @@ -178,7 +178,7 @@ def C(file): class TestBuildExtInplace: - def get_build_ext_cmd(self, optional: bool, **opts): + def get_build_ext_cmd(self, optional: bool, **opts) -> build_ext: files = { "eggs.c": "#include missingheader.h\n", ".build": {"lib": {}, "tmp": {}}, diff --git a/setuptools/tests/test_editable_install.py b/setuptools/tests/test_editable_install.py index bdbaa3c7e7..038dcadf93 100644 --- a/setuptools/tests/test_editable_install.py +++ b/setuptools/tests/test_editable_install.py @@ -1275,7 +1275,7 @@ def assert_path(pkg, expected): assert str(Path(path).resolve()) == expected -def assert_link_to(file: Path, other: Path): +def assert_link_to(file: Path, other: Path) -> None: if file.is_symlink(): assert str(file.resolve()) == str(other.resolve()) else: diff --git a/tools/build_launchers.py b/tools/build_launchers.py index a8b85c5f55..48609367a0 100644 --- a/tools/build_launchers.py +++ b/tools/build_launchers.py @@ -54,13 +54,13 @@ """ -def resolve_platform(platform: str): +def resolve_platform(platform: str) -> str: if platform in ["Win32", "x64"]: return platform[-2:] return platform -def get_executable_name(name, platform: str): +def get_executable_name(name, platform: str) -> str: return f"{name}-{resolve_platform(platform)}"