diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-03-28 11:49:43 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-03-28 11:59:36 +0300 |
commit | 4900300c1bfd2592c46ab2ff17bf007b3b502a77 (patch) | |
tree | 139bfa0aa47c21744d3dab91e8283f0ba5b608a6 | |
parent | c4e006fc945df7b2c1ff8c507943c2d1154f7a1e (diff) | |
download | ydb-4900300c1bfd2592c46ab2ff17bf007b3b502a77.tar.gz |
Intermediate changes
28 files changed, 246 insertions, 191 deletions
diff --git a/contrib/python/setuptools/py3/.dist-info/METADATA b/contrib/python/setuptools/py3/.dist-info/METADATA index 237cc66f13..3ccc19e703 100644 --- a/contrib/python/setuptools/py3/.dist-info/METADATA +++ b/contrib/python/setuptools/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: setuptools -Version: 69.1.1 +Version: 69.2.0 Summary: Easily download, build, install, upgrade, and uninstall Python packages Home-page: https://github.com/pypa/setuptools Author: Python Packaging Authority @@ -39,13 +39,12 @@ Provides-Extra: testing Requires-Dist: pytest >=6 ; extra == 'testing' Requires-Dist: pytest-checkdocs >=2.4 ; extra == 'testing' Requires-Dist: pytest-enabler >=2.2 ; extra == 'testing' -Requires-Dist: flake8-2020 ; extra == 'testing' Requires-Dist: virtualenv >=13.0.0 ; extra == 'testing' Requires-Dist: wheel ; extra == 'testing' Requires-Dist: pip >=19.1 ; extra == 'testing' Requires-Dist: packaging >=23.2 ; extra == 'testing' Requires-Dist: jaraco.envs >=2.2 ; extra == 'testing' -Requires-Dist: pytest-xdist ; extra == 'testing' +Requires-Dist: pytest-xdist >=3 ; extra == 'testing' Requires-Dist: jaraco.path >=3.2.0 ; extra == 'testing' Requires-Dist: build[virtualenv] ; extra == 'testing' Requires-Dist: filelock >=3.4.0 ; extra == 'testing' @@ -53,6 +52,9 @@ Requires-Dist: ini2toml[lite] >=0.9 ; extra == 'testing' Requires-Dist: tomli-w >=1.0.0 ; extra == 'testing' Requires-Dist: pytest-timeout ; extra == 'testing' Requires-Dist: pytest-home >=0.5 ; extra == 'testing' +Requires-Dist: mypy ==1.9 ; extra == 'testing' +Requires-Dist: tomli ; extra == 'testing' +Requires-Dist: importlib-metadata ; extra == 'testing' Provides-Extra: testing-integration Requires-Dist: pytest ; extra == 'testing-integration' Requires-Dist: pytest-xdist ; extra == 'testing-integration' diff --git a/contrib/python/setuptools/py3/pkg_resources/__init__.py b/contrib/python/setuptools/py3/pkg_resources/__init__.py index d83283ff1c..7b166f43b8 100644 --- a/contrib/python/setuptools/py3/pkg_resources/__init__.py +++ b/contrib/python/setuptools/py3/pkg_resources/__init__.py @@ -27,7 +27,7 @@ import io import time import re import types -from typing import Protocol +from typing import List, Protocol import zipfile import zipimport import warnings @@ -85,9 +85,7 @@ __import__('pkg_resources.extern.packaging.utils') require = None working_set = None add_activation_listener = None -resources_stream = None cleanup_resources = None -resource_dir = None resource_stream = None set_extraction_path = None resource_isdir = None @@ -491,19 +489,6 @@ def compatible_platforms(provided, required): return False -def run_script(dist_spec, script_name): - """Locate distribution `dist_spec` and run its `script_name` script""" - ns = sys._getframe(1).f_globals - name = ns['__name__'] - ns.clear() - ns['__name__'] = name - require(dist_spec)[0].run_script(script_name, ns) - - -# backward compatibility -run_main = run_script - - def get_distribution(dist): """Return a current distribution object for a Requirement or string""" if isinstance(dist, str): @@ -531,7 +516,7 @@ def get_entry_info(dist, group, name): class IMetadataProvider(Protocol): - def has_metadata(self, name): + def has_metadata(self, name) -> bool: """Does the package's distribution contain the named metadata?""" def get_metadata(self, name): @@ -543,7 +528,7 @@ class IMetadataProvider(Protocol): Leading and trailing whitespace is stripped from each line, and lines with ``#`` as the first non-blank character are omitted.""" - def metadata_isdir(self, name): + def metadata_isdir(self, name) -> bool: """Is the named metadata a directory? (like ``os.path.isdir()``)""" def metadata_listdir(self, name): @@ -566,8 +551,8 @@ class IResourceProvider(IMetadataProvider, Protocol): `manager` must be an ``IResourceManager``""" - def get_resource_string(self, manager, resource_name): - """Return a string containing the contents of `resource_name` + def get_resource_string(self, manager, resource_name) -> bytes: + """Return the contents of `resource_name` as :obj:`bytes` `manager` must be an ``IResourceManager``""" @@ -1203,8 +1188,8 @@ class ResourceManager: self, resource_name ) - def resource_string(self, package_or_requirement, resource_name): - """Return specified resource as a string""" + def resource_string(self, package_or_requirement, resource_name) -> bytes: + """Return specified resource as :obj:`bytes`""" return get_provider(package_or_requirement).get_resource_string( self, resource_name ) @@ -1339,7 +1324,7 @@ class ResourceManager: self.extraction_path = path - def cleanup_resources(self, force=False): + def cleanup_resources(self, force=False) -> List[str]: """ Delete all extracted resource files and directories, returning a list of the file and directory names that could not be successfully removed. @@ -1351,6 +1336,7 @@ class ResourceManager: directory used for extractions. """ # XXX + return [] def get_default_cache(): @@ -1479,7 +1465,7 @@ class NullProvider: def get_resource_stream(self, manager, resource_name): return io.BytesIO(self.get_resource_string(manager, resource_name)) - def get_resource_string(self, manager, resource_name): + def get_resource_string(self, manager, resource_name) -> bytes: return self._get(self._fn(self.module_path, resource_name)) def has_resource(self, resource_name): @@ -1488,9 +1474,9 @@ class NullProvider: def _get_metadata_path(self, name): return self._fn(self.egg_info, name) - def has_metadata(self, name): + def has_metadata(self, name) -> bool: if not self.egg_info: - return self.egg_info + return False path = self._get_metadata_path(name) return self._has(path) @@ -1514,8 +1500,8 @@ class NullProvider: def resource_isdir(self, resource_name): return self._isdir(self._fn(self.module_path, resource_name)) - def metadata_isdir(self, name): - return self.egg_info and self._isdir(self._fn(self.egg_info, name)) + def metadata_isdir(self, name) -> bool: + return bool(self.egg_info and self._isdir(self._fn(self.egg_info, name))) def resource_listdir(self, resource_name): return self._listdir(self._fn(self.module_path, resource_name)) @@ -1554,12 +1540,12 @@ class NullProvider: script_code = compile(script_text, script_filename, 'exec') exec(script_code, namespace, namespace) - def _has(self, path): + def _has(self, path) -> bool: raise NotImplementedError( "Can't perform this operation for unregistered loader type" ) - def _isdir(self, path): + def _isdir(self, path) -> bool: raise NotImplementedError( "Can't perform this operation for unregistered loader type" ) @@ -1649,7 +1635,7 @@ is not allowed. DeprecationWarning, ) - def _get(self, path): + def _get(self, path) -> bytes: if hasattr(self.loader, 'get_data'): return self.loader.get_data(path) raise NotImplementedError( @@ -1694,10 +1680,10 @@ class EggProvider(NullProvider): class DefaultProvider(EggProvider): """Provides access to package resources in the filesystem""" - def _has(self, path): + def _has(self, path) -> bool: return os.path.exists(path) - def _isdir(self, path): + def _isdir(self, path) -> bool: return os.path.isdir(path) def _listdir(self, path): @@ -1706,7 +1692,7 @@ class DefaultProvider(EggProvider): def get_resource_stream(self, manager, resource_name): return open(self._fn(self.module_path, resource_name), 'rb') - def _get(self, path): + def _get(self, path) -> bytes: with open(path, 'rb') as stream: return stream.read() @@ -1731,8 +1717,8 @@ class EmptyProvider(NullProvider): _isdir = _has = lambda self, path: False - def _get(self, path): - return '' + def _get(self, path) -> bytes: + return b'' def _listdir(self, path): return [] @@ -1939,11 +1925,11 @@ class ZipProvider(EggProvider): self._dirindex = ind return ind - def _has(self, fspath): + def _has(self, fspath) -> bool: zip_path = self._zipinfo_name(fspath) return zip_path in self.zipinfo or zip_path in self._index() - def _isdir(self, fspath): + def _isdir(self, fspath) -> bool: return self._zipinfo_name(fspath) in self._index() def _listdir(self, fspath): @@ -1977,7 +1963,7 @@ class FileMetadata(EmptyProvider): def _get_metadata_path(self, name): return self.path - def has_metadata(self, name): + def has_metadata(self, name) -> bool: return name == 'PKG-INFO' and os.path.isfile(self.path) def get_metadata(self, name): @@ -3207,7 +3193,9 @@ def _find_adapter(registry, ob): for t in types: if t in registry: return registry[t] - return None + # _find_adapter would previously return None, and immediately be called. + # So we're raising a TypeError to keep backward compatibility if anyone depended on that behaviour. + raise TypeError(f"Could not find adapter for {registry} and {ob}") def ensure_directory(path): diff --git a/contrib/python/setuptools/py3/setuptools/__init__.py b/contrib/python/setuptools/py3/setuptools/__init__.py index 563ca1c4ba..7c88c7e19b 100644 --- a/contrib/python/setuptools/py3/setuptools/__init__.py +++ b/contrib/python/setuptools/py3/setuptools/__init__.py @@ -3,6 +3,7 @@ import functools import os import re +from typing import TYPE_CHECKING import _distutils_hack.override # noqa: F401 import distutils.core @@ -105,8 +106,11 @@ def setup(**attrs): setup.__doc__ = distutils.core.setup.__doc__ - -_Command = monkey.get_unpatched(distutils.core.Command) +if TYPE_CHECKING: + # Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962 + _Command = distutils.core.Command +else: + _Command = monkey.get_unpatched(distutils.core.Command) class Command(_Command): @@ -165,8 +169,9 @@ class Command(_Command): """ command_consumes_arguments = False + distribution: Distribution # override distutils.dist.Distribution with setuptools.dist.Distribution - def __init__(self, dist, **kw): + def __init__(self, dist: Distribution, **kw): """ Construct the command for dist, updating vars(self) with any keyword parameters. diff --git a/contrib/python/setuptools/py3/setuptools/_core_metadata.py b/contrib/python/setuptools/py3/setuptools/_core_metadata.py index 4bf3c7c947..5dd97c7719 100644 --- a/contrib/python/setuptools/py3/setuptools/_core_metadata.py +++ b/contrib/python/setuptools/py3/setuptools/_core_metadata.py @@ -62,7 +62,7 @@ def _read_list_from_msg(msg: Message, field: str) -> Optional[List[str]]: def _read_payload_from_msg(msg: Message) -> Optional[str]: - value = msg.get_payload().strip() + value = str(msg.get_payload()).strip() if value == 'UNKNOWN' or not value: return None return value diff --git a/contrib/python/setuptools/py3/setuptools/_normalization.py b/contrib/python/setuptools/py3/setuptools/_normalization.py index 8f211b8bfb..e858052ccd 100644 --- a/contrib/python/setuptools/py3/setuptools/_normalization.py +++ b/contrib/python/setuptools/py3/setuptools/_normalization.py @@ -4,13 +4,9 @@ and core metadata """ import re -from pathlib import Path -from typing import Union from .extern import packaging -_Path = Union[str, Path] - # https://packaging.python.org/en/latest/specifications/core-metadata/#name _VALID_NAME = re.compile(r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.I) _UNSAFE_NAME_CHARS = re.compile(r"[^A-Z0-9._-]+", re.I) diff --git a/contrib/python/setuptools/py3/setuptools/_path.py b/contrib/python/setuptools/py3/setuptools/_path.py index b99d9dadcf..fb8ef0e198 100644 --- a/contrib/python/setuptools/py3/setuptools/_path.py +++ b/contrib/python/setuptools/py3/setuptools/_path.py @@ -2,7 +2,10 @@ import os import sys from typing import Union -_Path = Union[str, os.PathLike] +if sys.version_info >= (3, 9): + StrPath = Union[str, os.PathLike[str]] # Same as _typeshed.StrPath +else: + StrPath = Union[str, os.PathLike] def ensure_directory(path): @@ -11,7 +14,7 @@ def ensure_directory(path): os.makedirs(dirname, exist_ok=True) -def same_path(p1: _Path, p2: _Path) -> bool: +def same_path(p1: StrPath, p2: StrPath) -> bool: """Differs from os.path.samefile because it does not require paths to exist. Purely string based (no comparison between i-nodes). >>> same_path("a/b", "./a/b") @@ -30,7 +33,7 @@ def same_path(p1: _Path, p2: _Path) -> bool: return normpath(p1) == normpath(p2) -def normpath(filename: _Path) -> str: +def normpath(filename: StrPath) -> str: """Normalize a file/dir name for comparison purposes.""" # See pkg_resources.normalize_path for notes about cygwin file = os.path.abspath(filename) if sys.platform == 'cygwin' else filename diff --git a/contrib/python/setuptools/py3/setuptools/command/_requirestxt.py b/contrib/python/setuptools/py3/setuptools/command/_requirestxt.py index 7b732b11ab..b0c2d7059a 100644 --- a/contrib/python/setuptools/py3/setuptools/command/_requirestxt.py +++ b/contrib/python/setuptools/py3/setuptools/command/_requirestxt.py @@ -35,7 +35,7 @@ def _prepare( def _convert_extras_requirements( - extras_require: _StrOrIter, + extras_require: Mapping[str, _StrOrIter], ) -> Mapping[str, _Ordered[Requirement]]: """ Convert requirements in `extras_require` of the form diff --git a/contrib/python/setuptools/py3/setuptools/command/build_ext.py b/contrib/python/setuptools/py3/setuptools/command/build_ext.py index 780afe3aec..b5c98c86dc 100644 --- a/contrib/python/setuptools/py3/setuptools/command/build_ext.py +++ b/contrib/python/setuptools/py3/setuptools/command/build_ext.py @@ -16,7 +16,7 @@ from setuptools.extension import Extension, Library try: # Attempt to use Cython for building extensions, if available - from Cython.Distutils.build_ext import build_ext as _build_ext + from Cython.Distutils.build_ext import build_ext as _build_ext # type: ignore[import-not-found] # Cython not installed on CI tests # Additionally, assert that the compiler module will load # also. Ref #1229. @@ -26,7 +26,9 @@ except ImportError: # make sure _config_vars is initialized get_config_var("LDSHARED") -from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa +# Not publicly exposed in typeshed distutils stubs, but this is done on purpose +# See https://github.com/pypa/setuptools/pull/4228#issuecomment-1959856400 +from distutils.sysconfig import _config_vars as _CONFIG_VARS # type: ignore # noqa def _customize_compiler_for_shlib(compiler): @@ -58,7 +60,7 @@ if sys.platform == "darwin": use_stubs = True elif os.name != 'nt': try: - import dl + import dl # type: ignore[import-not-found] # https://github.com/python/mypy/issues/13002 use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') except ImportError: @@ -378,7 +380,10 @@ class build_ext(_build_ext): optimize = self.get_finalized_command('install_lib').optimize if optimize > 0: byte_compile( - [stub_file], optimize=optimize, force=True, dry_run=self.dry_run + [stub_file], + optimize=optimize, + force=True, + dry_run=self.dry_run, ) if os.path.exists(stub_file) and not self.dry_run: os.unlink(stub_file) diff --git a/contrib/python/setuptools/py3/setuptools/command/dist_info.py b/contrib/python/setuptools/py3/setuptools/command/dist_info.py index f5061afaaf..52c0721903 100644 --- a/contrib/python/setuptools/py3/setuptools/command/dist_info.py +++ b/contrib/python/setuptools/py3/setuptools/command/dist_info.py @@ -9,8 +9,10 @@ from contextlib import contextmanager from distutils import log from distutils.core import Command from pathlib import Path +from typing import cast from .. import _normalization +from .egg_info import egg_info as egg_info_cls class dist_info(Command): @@ -50,7 +52,7 @@ class dist_info(Command): project_dir = dist.src_root or os.curdir self.output_dir = Path(self.output_dir or project_dir) - egg_info = self.reinitialize_command("egg_info") + egg_info = cast(egg_info_cls, self.reinitialize_command("egg_info")) egg_info.egg_base = str(self.output_dir) if self.tag_date: diff --git a/contrib/python/setuptools/py3/setuptools/command/easy_install.py b/contrib/python/setuptools/py3/setuptools/command/easy_install.py index cc0c409123..858fb20f83 100644 --- a/contrib/python/setuptools/py3/setuptools/command/easy_install.py +++ b/contrib/python/setuptools/py3/setuptools/command/easy_install.py @@ -25,6 +25,7 @@ from distutils.spawn import find_executable from distutils.command import install import sys import os +from typing import Dict, List import zipimport import shutil import tempfile @@ -43,7 +44,6 @@ import io import configparser import sysconfig - from sysconfig import get_path from setuptools import Command @@ -74,7 +74,7 @@ from pkg_resources import ( DEVELOP_DIST, ) import pkg_resources -from ..compat import py311 +from ..compat import py39, py311 from .._path import ensure_directory from ..extern.jaraco.text import yield_lines @@ -491,7 +491,7 @@ class easy_install(Command): try: if test_exists: os.unlink(testfile) - open(testfile, 'w').close() + open(testfile, 'wb').close() os.unlink(testfile) except OSError: self.cant_write_to_target() @@ -576,7 +576,7 @@ class easy_install(Command): _one_liner( """ import os - f = open({ok_file!r}, 'w') + f = open({ok_file!r}, 'w', encoding="utf-8") f.write('OK') f.close() """ @@ -588,7 +588,8 @@ class easy_install(Command): os.unlink(ok_file) dirname = os.path.dirname(ok_file) os.makedirs(dirname, exist_ok=True) - f = open(pth_file, 'w') + f = open(pth_file, 'w', encoding=py39.LOCALE_ENCODING) + # ^-- Requires encoding="locale" instead of "utf-8" (python/cpython#77102). except OSError: self.cant_write_to_target() else: @@ -872,7 +873,7 @@ class easy_install(Command): ensure_directory(target) if os.path.exists(target): os.unlink(target) - with open(target, "w" + mode) as f: + with open(target, "w" + mode) as f: # TODO: is it safe to use utf-8? f.write(contents) chmod(target, 0o777 - mask) @@ -1016,7 +1017,7 @@ class easy_install(Command): # Write EGG-INFO/PKG-INFO if not os.path.exists(pkg_inf): - f = open(pkg_inf, 'w') + f = open(pkg_inf, 'w') # TODO: probably it is safe to use utf-8 f.write('Metadata-Version: 1.0\n') for k, v in cfg.items('metadata'): if k != 'target_version': @@ -1087,7 +1088,7 @@ class easy_install(Command): if locals()[name]: txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt') if not os.path.exists(txt): - f = open(txt, 'w') + f = open(txt, 'w') # TODO: probably it is safe to use utf-8 f.write('\n'.join(locals()[name]) + '\n') f.close() @@ -1277,7 +1278,9 @@ class easy_install(Command): filename = os.path.join(self.install_dir, 'setuptools.pth') if os.path.islink(filename): os.unlink(filename) - with open(filename, 'wt') as f: + + with open(filename, 'wt', encoding=py39.LOCALE_ENCODING) as f: + # Requires encoding="locale" instead of "utf-8" (python/cpython#77102). f.write(self.pth_file.make_relative(dist.location) + '\n') def unpack_progress(self, src, dst): @@ -1503,9 +1506,9 @@ def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME continue # Read the .pth file - f = open(os.path.join(dirname, name)) - lines = list(yield_lines(f)) - f.close() + with open(os.path.join(dirname, name), encoding=py39.LOCALE_ENCODING) as f: + # Requires encoding="locale" instead of "utf-8" (python/cpython#77102). + lines = list(yield_lines(f)) # Yield existing non-dupe, non-import directory lines from it for line in lines: @@ -1619,7 +1622,8 @@ class PthDistributions(Environment): paths = [] dirty = saw_import = False seen = dict.fromkeys(self.sitedirs) - f = open(self.filename, 'rt') + f = open(self.filename, 'rt', encoding=py39.LOCALE_ENCODING) + # ^-- Requires encoding="locale" instead of "utf-8" (python/cpython#77102). for line in f: path = line.rstrip() # still keep imports and empty/commented lines for formatting @@ -1690,7 +1694,8 @@ class PthDistributions(Environment): data = '\n'.join(lines) + '\n' if os.path.islink(self.filename): os.unlink(self.filename) - with open(self.filename, 'wt') as f: + with open(self.filename, 'wt', encoding=py39.LOCALE_ENCODING) as f: + # Requires encoding="locale" instead of "utf-8" (python/cpython#77102). f.write(data) elif os.path.exists(self.filename): log.debug("Deleting empty %s", self.filename) @@ -1765,7 +1770,7 @@ class RewritePthDistributions(PthDistributions): if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': - PthDistributions = RewritePthDistributions + PthDistributions = RewritePthDistributions # type: ignore[misc] # Overwriting type def _first_line_re(): @@ -2015,7 +2020,7 @@ try: from os import chmod as _chmod except ImportError: # Jython compatibility - def _chmod(*args): + def _chmod(*args: object, **kwargs: object) -> None: # type: ignore[misc] # Mypy re-uses the imported definition anyway pass @@ -2033,8 +2038,8 @@ class CommandSpec(list): those passed to Popen. """ - options = [] - split_args = dict() + options: List[str] = [] + split_args: Dict[str, bool] = dict() @classmethod def best(cls): diff --git a/contrib/python/setuptools/py3/setuptools/command/editable_wheel.py b/contrib/python/setuptools/py3/setuptools/command/editable_wheel.py index 8a4ae7928f..4d21e2253f 100644 --- a/contrib/python/setuptools/py3/setuptools/command/editable_wheel.py +++ b/contrib/python/setuptools/py3/setuptools/command/editable_wheel.py @@ -14,7 +14,6 @@ import logging import io import os import shutil -import sys import traceback from contextlib import suppress from enum import Enum @@ -33,7 +32,7 @@ from typing import ( Protocol, Tuple, TypeVar, - Union, + cast, ) from .. import ( @@ -43,6 +42,8 @@ from .. import ( errors, namespaces, ) +from .._path import StrPath +from ..compat import py39 from ..discovery import find_package_path from ..dist import Distribution from ..warnings import ( @@ -50,13 +51,17 @@ from ..warnings import ( SetuptoolsDeprecationWarning, SetuptoolsWarning, ) +from .build import build as build_cls from .build_py import build_py as build_py_cls +from .dist_info import dist_info as dist_info_cls +from .egg_info import egg_info as egg_info_cls +from .install import install as install_cls +from .install_scripts import install_scripts as install_scripts_cls if TYPE_CHECKING: - from wheel.wheelfile import WheelFile # noqa + from wheel.wheelfile import WheelFile # type:ignore[import-untyped] # noqa -_Path = Union[str, Path] -_P = TypeVar("_P", bound=_Path) +_P = TypeVar("_P", bound=StrPath) _logger = logging.getLogger(__name__) @@ -156,7 +161,7 @@ class editable_wheel(Command): def _ensure_dist_info(self): if self.dist_info_dir is None: - dist_info = self.reinitialize_command("dist_info") + dist_info = cast(dist_info_cls, self.reinitialize_command("dist_info")) dist_info.output_dir = self.dist_dir dist_info.ensure_finalized() dist_info.run() @@ -181,7 +186,7 @@ class editable_wheel(Command): return next(candidates, None) def _configure_build( - self, name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path + self, name: str, unpacked_wheel: StrPath, build_lib: StrPath, tmp_dir: StrPath ): """Configure commands to behave in the following ways: @@ -203,12 +208,18 @@ class editable_wheel(Command): scripts = str(Path(unpacked_wheel, f"{name}.data", "scripts")) # egg-info may be generated again to create a manifest (used for package data) - egg_info = dist.reinitialize_command("egg_info", reinit_subcommands=True) + egg_info = cast( + egg_info_cls, dist.reinitialize_command("egg_info", reinit_subcommands=True) + ) egg_info.egg_base = str(tmp_dir) egg_info.ignore_egg_info_in_manifest = True - build = dist.reinitialize_command("build", reinit_subcommands=True) - install = dist.reinitialize_command("install", reinit_subcommands=True) + build = cast( + build_cls, dist.reinitialize_command("build", reinit_subcommands=True) + ) + install = cast( + install_cls, dist.reinitialize_command("install", reinit_subcommands=True) + ) build.build_platlib = build.build_purelib = build.build_lib = build_lib install.install_purelib = install.install_platlib = install.install_lib = wheel @@ -216,12 +227,14 @@ class editable_wheel(Command): install.install_headers = headers install.install_data = data - install_scripts = dist.get_command_obj("install_scripts") + install_scripts = cast( + install_scripts_cls, dist.get_command_obj("install_scripts") + ) install_scripts.no_ep = True build.build_temp = str(tmp_dir) - build_py = dist.get_command_obj("build_py") + build_py = cast(build_py_cls, dist.get_command_obj("build_py")) build_py.compile = False build_py.existing_egg_info_dir = self._find_egg_info_dir() @@ -234,6 +247,7 @@ class editable_wheel(Command): """Set the ``editable_mode`` flag in the build sub-commands""" dist = self.distribution build = dist.get_command_obj("build") + # TODO: Update typeshed distutils stubs to overload non-None return type by default for cmd_name in build.get_sub_commands(): cmd = dist.get_command_obj(cmd_name) if hasattr(cmd, "editable_mode"): @@ -256,7 +270,11 @@ class editable_wheel(Command): return files, mapping def _run_build_commands( - self, dist_name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path + self, + dist_name: str, + unpacked_wheel: StrPath, + build_lib: StrPath, + tmp_dir: StrPath, ) -> Tuple[List[str], Dict[str, str]]: self._configure_build(dist_name, unpacked_wheel, build_lib, tmp_dir) self._run_build_subcommands() @@ -266,7 +284,7 @@ class editable_wheel(Command): self._run_install("data") return files, mapping - def _run_build_subcommands(self): + def _run_build_subcommands(self) -> None: """ Issue #3501 indicates that some plugins/customizations might rely on: @@ -280,7 +298,7 @@ class editable_wheel(Command): # TODO: Once plugins/customisations had the chance to catch up, replace # `self._run_build_subcommands()` with `self.run_command("build")`. # Also remove _safely_run, TestCustomBuildPy. Suggested date: Aug/2023. - build: Command = self.get_finalized_command("build") + build = self.get_finalized_command("build") for name in build.get_sub_commands(): cmd = self.get_finalized_command(name) if name == "build_py" and type(cmd) != build_py_cls: @@ -354,7 +372,7 @@ class editable_wheel(Command): self, name: str, tag: str, - build_lib: _Path, + build_lib: StrPath, ) -> "EditableStrategy": """Decides which strategy to use to implement an editable installation.""" build_name = f"__editable__.{name}-{tag}" @@ -424,12 +442,13 @@ class _LinkTree(_StaticPth): self, dist: Distribution, name: str, - auxiliary_dir: _Path, - build_lib: _Path, + auxiliary_dir: StrPath, + build_lib: StrPath, ): self.auxiliary_dir = Path(auxiliary_dir) self.build_lib = Path(build_lib).resolve() - self._file = dist.get_command_obj("build_py").copy_file + # TODO: Update typeshed distutils stubs to overload non-None return type by default + self._file = dist.get_command_obj("build_py").copy_file # type: ignore[union-attr] super().__init__(dist, name, [self.auxiliary_dir]) def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): @@ -447,7 +466,9 @@ class _LinkTree(_StaticPth): dest = self.auxiliary_dir / relative_output if not dest.parent.is_dir(): dest.parent.mkdir(parents=True) - self._file(src_file, dest, link=link) + # TODO: Update typeshed distutils stubs so distutils.cmd.Command.copy_file, accepts PathLike + # same with methods used by copy_file + self._file(src_file, dest, link=link) # type: ignore[arg-type] def _create_links(self, outputs, output_mapping): self.auxiliary_dir.mkdir(parents=True, exist_ok=True) @@ -537,9 +558,8 @@ def _encode_pth(content: str) -> bytes: (There seems to be some variety in the way different version of Python handle ``encoding=None``, not all of them use ``locale.getpreferredencoding(False)``). """ - encoding = "locale" if sys.version_info >= (3, 10) else None with io.BytesIO() as buffer: - wrapper = io.TextIOWrapper(buffer, encoding) + wrapper = io.TextIOWrapper(buffer, encoding=py39.LOCALE_ENCODING) wrapper.write(content) wrapper.flush() buffer.seek(0) @@ -567,7 +587,7 @@ def _can_symlink_files(base_dir: Path) -> bool: def _simple_layout( - packages: Iterable[str], package_dir: Dict[str, str], project_dir: Path + packages: Iterable[str], package_dir: Dict[str, str], project_dir: StrPath ) -> bool: """Return ``True`` if: - all packages are contained by the same parent directory, **and** @@ -649,7 +669,7 @@ def _find_top_level_modules(dist: Distribution) -> Iterator[str]: def _find_package_roots( packages: Iterable[str], package_dir: Mapping[str, str], - src_root: _Path, + src_root: StrPath, ) -> Dict[str, str]: pkg_roots: Dict[str, str] = { pkg: _absolute_root(find_package_path(pkg, package_dir, src_root)) @@ -659,7 +679,7 @@ def _find_package_roots( return _remove_nested(pkg_roots) -def _absolute_root(path: _Path) -> str: +def _absolute_root(path: StrPath) -> str: """Works for packages and top-level modules""" path_ = Path(path) parent = path_.parent diff --git a/contrib/python/setuptools/py3/setuptools/command/install.py b/contrib/python/setuptools/py3/setuptools/command/install.py index b97a9b4713..56c1155b50 100644 --- a/contrib/python/setuptools/py3/setuptools/command/install.py +++ b/contrib/python/setuptools/py3/setuptools/command/install.py @@ -3,9 +3,11 @@ import inspect import glob import platform import distutils.command.install as orig +from typing import cast import setuptools from ..warnings import SetuptoolsDeprecationWarning, SetuptoolsWarning +from .bdist_egg import bdist_egg as bdist_egg_cls # Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for # now. See https://github.com/pypa/setuptools/issues/199/ @@ -135,7 +137,8 @@ class install(orig.install): cmd.package_index.scan(glob.glob('*.egg')) self.run_command('bdist_egg') - args = [self.distribution.get_command_obj('bdist_egg').egg_output] + bdist_egg = cast(bdist_egg_cls, self.distribution.get_command_obj('bdist_egg')) + args = [bdist_egg.egg_output] if setuptools.bootstrap_install_from: # Bootstrap self-installation of setuptools diff --git a/contrib/python/setuptools/py3/setuptools/command/rotate.py b/contrib/python/setuptools/py3/setuptools/command/rotate.py index cfb78ce52d..6f73721c70 100644 --- a/contrib/python/setuptools/py3/setuptools/command/rotate.py +++ b/contrib/python/setuptools/py3/setuptools/command/rotate.py @@ -3,6 +3,7 @@ from distutils import log from distutils.errors import DistutilsOptionError import os import shutil +from typing import List from setuptools import Command @@ -17,7 +18,7 @@ class rotate(Command): ('keep=', 'k', "number of matching distributions to keep"), ] - boolean_options = [] + boolean_options: List[str] = [] def initialize_options(self): self.match = None diff --git a/contrib/python/setuptools/py3/setuptools/command/upload_docs.py b/contrib/python/setuptools/py3/setuptools/command/upload_docs.py index 32c9abd796..3fbbb62553 100644 --- a/contrib/python/setuptools/py3/setuptools/command/upload_docs.py +++ b/contrib/python/setuptools/py3/setuptools/command/upload_docs.py @@ -50,7 +50,7 @@ class upload_docs(upload): and metadata.entry_points(group='distutils.commands', name='build_sphinx') ) - sub_commands = [('build_sphinx', has_sphinx)] + sub_commands = [('build_sphinx', has_sphinx)] # type: ignore[list-item] # TODO: Fix in typeshed distutils stubs def initialize_options(self): upload.initialize_options(self) diff --git a/contrib/python/setuptools/py3/setuptools/compat/py39.py b/contrib/python/setuptools/py3/setuptools/compat/py39.py new file mode 100644 index 0000000000..04a4abe5a9 --- /dev/null +++ b/contrib/python/setuptools/py3/setuptools/compat/py39.py @@ -0,0 +1,9 @@ +import sys + +# Explicitly use the ``"locale"`` encoding in versions that support it, +# otherwise just rely on the implicit handling of ``encoding=None``. +# Since all platforms that support ``EncodingWarning`` also support +# ``encoding="locale"``, this can be used to suppress the warning. +# However, please try to use UTF-8 when possible +# (.pth files are the notorious exception: python/cpython#77102, pypa/setuptools#3937). +LOCALE_ENCODING = "locale" if sys.version_info >= (3, 10) else None diff --git a/contrib/python/setuptools/py3/setuptools/config/_apply_pyprojecttoml.py b/contrib/python/setuptools/py3/setuptools/config/_apply_pyprojecttoml.py index 32fb00131e..3626282a79 100644 --- a/contrib/python/setuptools/py3/setuptools/config/_apply_pyprojecttoml.py +++ b/contrib/python/setuptools/py3/setuptools/config/_apply_pyprojecttoml.py @@ -29,24 +29,24 @@ from typing import ( Union, cast, ) - +from .._path import StrPath from ..errors import RemovedConfigError from ..warnings import SetuptoolsWarning if TYPE_CHECKING: + from distutils.dist import _OptionsList from setuptools._importlib import metadata # noqa from setuptools.dist import Distribution # noqa EMPTY: Mapping = MappingProxyType({}) # Immutable dict-like -_Path = Union[os.PathLike, str] _DictOrStr = Union[dict, str] -_CorrespFn = Callable[["Distribution", Any, _Path], None] +_CorrespFn = Callable[["Distribution", Any, StrPath], None] _Correspondence = Union[str, _CorrespFn] _logger = logging.getLogger(__name__) -def apply(dist: "Distribution", config: dict, filename: _Path) -> "Distribution": +def apply(dist: "Distribution", config: dict, filename: StrPath) -> "Distribution": """Apply configuration dict read with :func:`read_configuration`""" if not config: @@ -68,7 +68,7 @@ def apply(dist: "Distribution", config: dict, filename: _Path) -> "Distribution" return dist -def _apply_project_table(dist: "Distribution", config: dict, root_dir: _Path): +def _apply_project_table(dist: "Distribution", config: dict, root_dir: StrPath): project_table = config.get("project", {}).copy() if not project_table: return # short-circuit @@ -85,7 +85,7 @@ def _apply_project_table(dist: "Distribution", config: dict, root_dir: _Path): _set_config(dist, corresp, value) -def _apply_tool_table(dist: "Distribution", config: dict, filename: _Path): +def _apply_tool_table(dist: "Distribution", config: dict, filename: StrPath): tool_table = config.get("tool", {}).get("setuptools", {}) if not tool_table: return # short-circuit @@ -153,7 +153,7 @@ def _guess_content_type(file: str) -> Optional[str]: raise ValueError(f"Undefined content type for {file}, {msg}") -def _long_description(dist: "Distribution", val: _DictOrStr, root_dir: _Path): +def _long_description(dist: "Distribution", val: _DictOrStr, root_dir: StrPath): from setuptools.config import expand if isinstance(val, str): @@ -174,7 +174,7 @@ def _long_description(dist: "Distribution", val: _DictOrStr, root_dir: _Path): dist._referenced_files.add(cast(str, file)) -def _license(dist: "Distribution", val: dict, root_dir: _Path): +def _license(dist: "Distribution", val: dict, root_dir: StrPath): from setuptools.config import expand if "file" in val: @@ -184,7 +184,7 @@ def _license(dist: "Distribution", val: dict, root_dir: _Path): _set_config(dist, "license", val["text"]) -def _people(dist: "Distribution", val: List[dict], _root_dir: _Path, kind: str): +def _people(dist: "Distribution", val: List[dict], _root_dir: StrPath, kind: str): field = [] email_field = [] for person in val: @@ -244,7 +244,7 @@ def _unify_entry_points(project_table: dict): # intentional (for resetting configurations that are missing `dynamic`). -def _copy_command_options(pyproject: dict, dist: "Distribution", filename: _Path): +def _copy_command_options(pyproject: dict, dist: "Distribution", filename: StrPath): tool_table = pyproject.get("tool", {}) cmdclass = tool_table.get("setuptools", {}).get("cmdclass", {}) valid_options = _valid_command_options(cmdclass) @@ -294,7 +294,7 @@ def _normalise_cmd_option_key(name: str) -> str: return json_compatible_key(name).strip("_=") -def _normalise_cmd_options(desc: List[Tuple[str, Optional[str], str]]) -> Set[str]: +def _normalise_cmd_options(desc: "_OptionsList") -> Set[str]: return {_normalise_cmd_option_key(fancy_option[0]) for fancy_option in desc} diff --git a/contrib/python/setuptools/py3/setuptools/config/_validate_pyproject/fastjsonschema_validations.py b/contrib/python/setuptools/py3/setuptools/config/_validate_pyproject/fastjsonschema_validations.py index b81d13c119..8b852bbfd4 100644 --- a/contrib/python/setuptools/py3/setuptools/config/_validate_pyproject/fastjsonschema_validations.py +++ b/contrib/python/setuptools/py3/setuptools/config/_validate_pyproject/fastjsonschema_validations.py @@ -1,5 +1,4 @@ # noqa -# type: ignore # flake8: noqa # pylint: skip-file # mypy: ignore-errors diff --git a/contrib/python/setuptools/py3/setuptools/config/expand.py b/contrib/python/setuptools/py3/setuptools/config/expand.py index b48fc1187e..0d8d58add8 100644 --- a/contrib/python/setuptools/py3/setuptools/config/expand.py +++ b/contrib/python/setuptools/py3/setuptools/config/expand.py @@ -46,7 +46,7 @@ from types import ModuleType from distutils.errors import DistutilsOptionError -from .._path import same_path as _same_path +from .._path import same_path as _same_path, StrPath from ..warnings import SetuptoolsWarning if TYPE_CHECKING: @@ -55,7 +55,6 @@ if TYPE_CHECKING: from distutils.dist import DistributionMetadata # noqa chain_iter = chain.from_iterable -_Path = Union[str, os.PathLike] _K = TypeVar("_K") _V = TypeVar("_V", covariant=True) @@ -64,7 +63,7 @@ class StaticModule: """Proxy to a module object that avoids executing arbitrary code.""" def __init__(self, name: str, spec: ModuleSpec): - module = ast.parse(pathlib.Path(spec.origin).read_bytes()) + module = ast.parse(pathlib.Path(spec.origin).read_bytes()) # type: ignore[arg-type] # Let it raise an error on None vars(self).update(locals()) del self.self @@ -88,7 +87,7 @@ class StaticModule: def glob_relative( - patterns: Iterable[str], root_dir: Optional[_Path] = None + patterns: Iterable[str], root_dir: Optional[StrPath] = None ) -> List[str]: """Expand the list of glob patterns, but preserving relative paths. @@ -120,7 +119,7 @@ def glob_relative( return expanded_values -def read_files(filepaths: Union[str, bytes, Iterable[_Path]], root_dir=None) -> str: +def read_files(filepaths: Union[str, bytes, Iterable[StrPath]], root_dir=None) -> str: """Return the content of the files concatenated using ``\n`` as str This function is sandboxed and won't reach anything outside ``root_dir`` @@ -138,7 +137,7 @@ def read_files(filepaths: Union[str, bytes, Iterable[_Path]], root_dir=None) -> ) -def _filter_existing_files(filepaths: Iterable[_Path]) -> Iterator[_Path]: +def _filter_existing_files(filepaths: Iterable[StrPath]) -> Iterator[StrPath]: for path in filepaths: if os.path.isfile(path): yield path @@ -146,12 +145,12 @@ def _filter_existing_files(filepaths: Iterable[_Path]) -> Iterator[_Path]: SetuptoolsWarning.emit(f"File {path!r} cannot be found") -def _read_file(filepath: Union[bytes, _Path]) -> str: +def _read_file(filepath: Union[bytes, StrPath]) -> str: with open(filepath, encoding='utf-8') as f: return f.read() -def _assert_local(filepath: _Path, root_dir: str): +def _assert_local(filepath: StrPath, root_dir: str): if Path(os.path.abspath(root_dir)) not in Path(os.path.abspath(filepath)).parents: msg = f"Cannot access {filepath!r} (or anything outside {root_dir!r})" raise DistutilsOptionError(msg) @@ -162,7 +161,7 @@ def _assert_local(filepath: _Path, root_dir: str): def read_attr( attr_desc: str, package_dir: Optional[Mapping[str, str]] = None, - root_dir: Optional[_Path] = None, + root_dir: Optional[StrPath] = None, ): """Reads the value of an attribute from a module. @@ -197,7 +196,7 @@ def read_attr( return getattr(module, attr_name) -def _find_spec(module_name: str, module_path: Optional[_Path]) -> ModuleSpec: +def _find_spec(module_name: str, module_path: Optional[StrPath]) -> ModuleSpec: spec = importlib.util.spec_from_file_location(module_name, module_path) spec = spec or importlib.util.find_spec(module_name) @@ -218,8 +217,8 @@ def _load_spec(spec: ModuleSpec, module_name: str) -> ModuleType: def _find_module( - module_name: str, package_dir: Optional[Mapping[str, str]], root_dir: _Path -) -> Tuple[_Path, Optional[str], str]: + module_name: str, package_dir: Optional[Mapping[str, str]], root_dir: StrPath +) -> Tuple[StrPath, Optional[str], str]: """Given a module (that could normally be imported by ``module_name`` after the build is complete), find the path to the parent directory where it is contained and the canonical name that could be used to import it @@ -254,7 +253,7 @@ def _find_module( def resolve_class( qualified_class_name: str, package_dir: Optional[Mapping[str, str]] = None, - root_dir: Optional[_Path] = None, + root_dir: Optional[StrPath] = None, ) -> Callable: """Given a qualified class name, return the associated class object""" root_dir = root_dir or os.getcwd() @@ -270,7 +269,7 @@ def resolve_class( def cmdclass( values: Dict[str, str], package_dir: Optional[Mapping[str, str]] = None, - root_dir: Optional[_Path] = None, + root_dir: Optional[StrPath] = None, ) -> Dict[str, Callable]: """Given a dictionary mapping command names to strings for qualified class names, apply :func:`resolve_class` to the dict values. @@ -282,7 +281,7 @@ def find_packages( *, namespaces=True, fill_package_dir: Optional[Dict[str, str]] = None, - root_dir: Optional[_Path] = None, + root_dir: Optional[StrPath] = None, **kwargs, ) -> List[str]: """Works similarly to :func:`setuptools.find_packages`, but with all @@ -331,7 +330,7 @@ def find_packages( return packages -def _nest_path(parent: _Path, path: _Path) -> str: +def _nest_path(parent: StrPath, path: StrPath) -> str: path = parent if path in {".", ""} else os.path.join(parent, path) return os.path.normpath(path) @@ -361,7 +360,7 @@ def canonic_package_data(package_data: dict) -> dict: def canonic_data_files( - data_files: Union[list, dict], root_dir: Optional[_Path] = None + data_files: Union[list, dict], root_dir: Optional[StrPath] = None ) -> List[Tuple[str, List[str]]]: """For compatibility with ``setup.py``, ``data_files`` should be a list of pairs instead of a dict. diff --git a/contrib/python/setuptools/py3/setuptools/config/pyprojecttoml.py b/contrib/python/setuptools/py3/setuptools/config/pyprojecttoml.py index 9b9788eff4..ff97679895 100644 --- a/contrib/python/setuptools/py3/setuptools/config/pyprojecttoml.py +++ b/contrib/python/setuptools/py3/setuptools/config/pyprojecttoml.py @@ -13,8 +13,9 @@ import logging import os from contextlib import contextmanager from functools import partial -from typing import TYPE_CHECKING, Callable, Dict, Mapping, Optional, Set, Union +from typing import TYPE_CHECKING, Callable, Dict, Mapping, Optional, Set +from .._path import StrPath from ..errors import FileError, InvalidConfigError from ..warnings import SetuptoolsWarning from . import expand as _expand @@ -23,19 +24,19 @@ from ._apply_pyprojecttoml import apply as _apply if TYPE_CHECKING: from setuptools.dist import Distribution # noqa + from typing_extensions import Self -_Path = Union[str, os.PathLike] _logger = logging.getLogger(__name__) -def load_file(filepath: _Path) -> dict: +def load_file(filepath: StrPath) -> dict: from ..compat.py310 import tomllib with open(filepath, "rb") as file: return tomllib.load(file) -def validate(config: dict, filepath: _Path) -> bool: +def validate(config: dict, filepath: StrPath) -> bool: from . import _validate_pyproject as validator trove_classifier = validator.FORMAT_FUNCTIONS.get("trove-classifier") @@ -58,7 +59,7 @@ def validate(config: dict, filepath: _Path) -> bool: def apply_configuration( dist: "Distribution", - filepath: _Path, + filepath: StrPath, ignore_option_errors=False, ) -> "Distribution": """Apply the configuration from a ``pyproject.toml`` file into an existing @@ -69,7 +70,7 @@ def apply_configuration( def read_configuration( - filepath: _Path, + filepath: StrPath, expand=True, ignore_option_errors=False, dist: Optional["Distribution"] = None, @@ -136,7 +137,7 @@ def read_configuration( def expand_configuration( config: dict, - root_dir: Optional[_Path] = None, + root_dir: Optional[StrPath] = None, ignore_option_errors: bool = False, dist: Optional["Distribution"] = None, ) -> dict: @@ -161,7 +162,7 @@ class _ConfigExpander: def __init__( self, config: dict, - root_dir: Optional[_Path] = None, + root_dir: Optional[StrPath] = None, ignore_option_errors: bool = False, dist: Optional["Distribution"] = None, ): @@ -271,7 +272,7 @@ class _ConfigExpander: def _expand_directive( self, specifier: str, directive, package_dir: Mapping[str, str] ): - from setuptools.extern.more_itertools import always_iterable # type: ignore + from setuptools.extern.more_itertools import always_iterable with _ignore_errors(self.ignore_option_errors): root_dir = self.root_dir @@ -401,7 +402,7 @@ class _EnsurePackagesDiscovered(_expand.EnsurePackagesDiscovered): self._project_cfg = project_cfg self._setuptools_cfg = setuptools_cfg - def __enter__(self): + def __enter__(self) -> "Self": """When entering the context, the values of ``packages``, ``py_modules`` and ``package_dir`` that are missing in ``dist`` are copied from ``setuptools_cfg``. """ diff --git a/contrib/python/setuptools/py3/setuptools/config/setupcfg.py b/contrib/python/setuptools/py3/setuptools/config/setupcfg.py index a7f02714cb..2912d3e143 100644 --- a/contrib/python/setuptools/py3/setuptools/config/setupcfg.py +++ b/contrib/python/setuptools/py3/setuptools/config/setupcfg.py @@ -30,6 +30,7 @@ from typing import ( Union, ) +from .._path import StrPath from ..errors import FileError, OptionError from ..extern.packaging.markers import default_environment as marker_env from ..extern.packaging.requirements import InvalidRequirement, Requirement @@ -43,7 +44,6 @@ if TYPE_CHECKING: from setuptools.dist import Distribution # noqa -_Path = Union[str, os.PathLike] SingleCommandOptions = Dict["str", Tuple["str", Any]] """Dict that associate the name of the options of a particular command to a tuple. The first element of the tuple indicates the origin of the option value @@ -55,7 +55,7 @@ Target = TypeVar("Target", bound=Union["Distribution", "DistributionMetadata"]) def read_configuration( - filepath: _Path, find_others=False, ignore_option_errors=False + filepath: StrPath, find_others=False, ignore_option_errors=False ) -> dict: """Read given configuration file and returns options from it as a dict. @@ -80,7 +80,7 @@ def read_configuration( return configuration_to_dict(handlers) -def apply_configuration(dist: "Distribution", filepath: _Path) -> "Distribution": +def apply_configuration(dist: "Distribution", filepath: StrPath) -> "Distribution": """Apply the configuration from a ``setup.cfg`` file into an existing distribution object. """ @@ -91,8 +91,8 @@ def apply_configuration(dist: "Distribution", filepath: _Path) -> "Distribution" def _apply( dist: "Distribution", - filepath: _Path, - other_files: Iterable[_Path] = (), + filepath: StrPath, + other_files: Iterable[StrPath] = (), ignore_option_errors: bool = False, ) -> Tuple["ConfigHandler", ...]: """Read configuration from ``filepath`` and applies to the ``dist`` object.""" @@ -108,7 +108,7 @@ def _apply( filenames = [*other_files, filepath] try: - _Distribution.parse_config_files(dist, filenames=filenames) + _Distribution.parse_config_files(dist, filenames=filenames) # type: ignore[arg-type] # TODO: fix in disutils stubs handlers = parse_configuration( dist, dist.command_options, ignore_option_errors=ignore_option_errors ) @@ -371,7 +371,7 @@ class ConfigHandler(Generic[Target]): return parser - def _parse_file(self, value, root_dir: _Path): + def _parse_file(self, value, root_dir: StrPath): """Represents value as a string, allowing including text from nearest files using `file:` directive. @@ -397,7 +397,7 @@ class ConfigHandler(Generic[Target]): self._referenced_files.update(filepaths) return expand.read_files(filepaths, root_dir) - def _parse_attr(self, value, package_dir, root_dir: _Path): + def _parse_attr(self, value, package_dir, root_dir: StrPath): """Represents value as a module attribute. Examples: @@ -475,7 +475,7 @@ class ConfigHandler(Generic[Target]): # Keep silent for a new option may appear anytime. self[name] = value - def parse(self): + def parse(self) -> None: """Parses configuration file items from one or more related sections. @@ -539,7 +539,7 @@ class ConfigMetadataHandler(ConfigHandler["DistributionMetadata"]): ignore_option_errors: bool, ensure_discovered: expand.EnsurePackagesDiscovered, package_dir: Optional[dict] = None, - root_dir: _Path = os.curdir, + root_dir: StrPath = os.curdir, ): super().__init__(target_obj, options, ignore_option_errors, ensure_discovered) self.package_dir = package_dir diff --git a/contrib/python/setuptools/py3/setuptools/discovery.py b/contrib/python/setuptools/py3/setuptools/discovery.py index 50a948750f..571be12bf4 100644 --- a/contrib/python/setuptools/py3/setuptools/discovery.py +++ b/contrib/python/setuptools/py3/setuptools/discovery.py @@ -51,15 +51,14 @@ from typing import ( Mapping, Optional, Tuple, - Union, ) import _distutils_hack.override # noqa: F401 +from ._path import StrPath from distutils import log from distutils.util import convert_path -_Path = Union[str, os.PathLike] StrIter = Iterator[str] chain_iter = itertools.chain.from_iterable @@ -68,7 +67,7 @@ if TYPE_CHECKING: from setuptools import Distribution # noqa -def _valid_name(path: _Path) -> bool: +def _valid_name(path: StrPath) -> bool: # Ignore invalid names that cannot be imported directly return os.path.basename(path).isidentifier() @@ -98,7 +97,7 @@ class _Finder: @classmethod def find( cls, - where: _Path = '.', + where: StrPath = '.', exclude: Iterable[str] = (), include: Iterable[str] = ('*',), ) -> List[str]: @@ -131,7 +130,7 @@ class _Finder: ) @classmethod - def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: + def _find_iter(cls, where: StrPath, exclude: _Filter, include: _Filter) -> StrIter: raise NotImplementedError @@ -143,7 +142,7 @@ class PackageFinder(_Finder): ALWAYS_EXCLUDE = ("ez_setup", "*__pycache__") @classmethod - def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: + def _find_iter(cls, where: StrPath, exclude: _Filter, include: _Filter) -> StrIter: """ All the packages found in 'where' that pass the 'include' filter, but not the 'exclude' filter. @@ -175,14 +174,14 @@ class PackageFinder(_Finder): dirs.append(dir) @staticmethod - def _looks_like_package(path: _Path, _package_name: str) -> bool: + def _looks_like_package(path: StrPath, _package_name: str) -> bool: """Does a directory look like a package?""" return os.path.isfile(os.path.join(path, '__init__.py')) class PEP420PackageFinder(PackageFinder): @staticmethod - def _looks_like_package(_path: _Path, _package_name: str) -> bool: + def _looks_like_package(_path: StrPath, _package_name: str) -> bool: return True @@ -192,7 +191,7 @@ class ModuleFinder(_Finder): """ @classmethod - def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: + def _find_iter(cls, where: StrPath, exclude: _Filter, include: _Filter) -> StrIter: for file in glob(os.path.join(where, "*.py")): module, _ext = os.path.splitext(os.path.basename(file)) @@ -255,7 +254,7 @@ class FlatLayoutPackageFinder(PEP420PackageFinder): """Reserved package names""" @staticmethod - def _looks_like_package(_path: _Path, package_name: str) -> bool: + def _looks_like_package(_path: StrPath, package_name: str) -> bool: names = package_name.split('.') # Consider PEP 561 root_pkg_is_valid = names[0].isidentifier() or names[0].endswith("-stubs") @@ -292,7 +291,7 @@ class FlatLayoutModuleFinder(ModuleFinder): """Reserved top-level module names""" -def _find_packages_within(root_pkg: str, pkg_dir: _Path) -> List[str]: +def _find_packages_within(root_pkg: str, pkg_dir: StrPath) -> List[str]: nested = PEP420PackageFinder.find(pkg_dir) return [root_pkg] + [".".join((root_pkg, n)) for n in nested] @@ -325,7 +324,7 @@ class ConfigDiscovery: self._skip_ext_modules = True @property - def _root_dir(self) -> _Path: + def _root_dir(self) -> StrPath: # The best is to wait until `src_root` is set in dist, before using _root_dir. return self.dist.src_root or os.curdir @@ -551,7 +550,7 @@ def remove_stubs(packages: List[str]) -> List[str]: def find_parent_package( - packages: List[str], package_dir: Mapping[str, str], root_dir: _Path + packages: List[str], package_dir: Mapping[str, str], root_dir: StrPath ) -> Optional[str]: """Find the parent package that is not a namespace.""" packages = sorted(packages, key=len) @@ -575,7 +574,7 @@ def find_parent_package( def find_package_path( - name: str, package_dir: Mapping[str, str], root_dir: _Path + name: str, package_dir: Mapping[str, str], root_dir: StrPath ) -> str: """Given a package name, return the path where it should be found on disk, considering the ``package_dir`` option. @@ -608,7 +607,7 @@ def find_package_path( return os.path.join(root_dir, *parent.split("/"), *parts) -def construct_package_dir(packages: List[str], package_path: _Path) -> Dict[str, str]: +def construct_package_dir(packages: List[str], package_path: StrPath) -> Dict[str, str]: parent_pkgs = remove_nested_packages(packages) prefix = Path(package_path).parts return {pkg: "/".join([*prefix, *pkg.split(".")]) for pkg in parent_pkgs} diff --git a/contrib/python/setuptools/py3/setuptools/dist.py b/contrib/python/setuptools/py3/setuptools/dist.py index d5787ed474..6350e38100 100644 --- a/contrib/python/setuptools/py3/setuptools/dist.py +++ b/contrib/python/setuptools/py3/setuptools/dist.py @@ -10,7 +10,7 @@ import sys from contextlib import suppress from glob import iglob from pathlib import Path -from typing import List, Optional, Set +from typing import TYPE_CHECKING, Dict, List, MutableMapping, Optional, Set, Tuple import distutils.cmd import distutils.command @@ -202,7 +202,11 @@ def check_packages(dist, attr, value): ) -_Distribution = get_unpatched(distutils.core.Distribution) +if TYPE_CHECKING: + # Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962 + _Distribution = distutils.core.Distribution +else: + _Distribution = get_unpatched(distutils.core.Distribution) class Distribution(_Distribution): @@ -283,12 +287,12 @@ class Distribution(_Distribution): dist._version = _normalization.safe_version(str(attrs['version'])) self._patched_dist = dist - def __init__(self, attrs=None): + def __init__(self, attrs: Optional[MutableMapping] = None) -> None: have_package_data = hasattr(self, "package_data") if not have_package_data: - self.package_data = {} + self.package_data: Dict[str, List[str]] = {} attrs = attrs or {} - self.dist_files = [] + self.dist_files: List[Tuple[str, str, str]] = [] # Filter-out setuptools' specific options. self.src_root = attrs.pop("src_root", None) self.patch_missing_pkg_info(attrs) @@ -381,7 +385,7 @@ class Distribution(_Distribution): k: list(map(str, _reqs.parse(v or []))) for k, v in extras_require.items() } - def _finalize_license_files(self): + def _finalize_license_files(self) -> None: """Compute names of all license files which should be included.""" license_files: Optional[List[str]] = self.metadata.license_files patterns: List[str] = license_files if license_files else [] @@ -394,7 +398,7 @@ class Distribution(_Distribution): # Default patterns match the ones wheel uses # See https://wheel.readthedocs.io/en/stable/user_guide.html # -> 'Including license files in the generated wheel file' - patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') + patterns = ['LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*'] self.metadata.license_files = list( unique_everseen(self._expand_patterns(patterns)) diff --git a/contrib/python/setuptools/py3/setuptools/extension.py b/contrib/python/setuptools/py3/setuptools/extension.py index 58c023f6b4..8caad78d4b 100644 --- a/contrib/python/setuptools/py3/setuptools/extension.py +++ b/contrib/python/setuptools/py3/setuptools/extension.py @@ -3,6 +3,7 @@ import functools import distutils.core import distutils.errors import distutils.extension +from typing import TYPE_CHECKING from .monkey import get_unpatched @@ -23,8 +24,11 @@ def _have_cython(): # for compatibility have_pyrex = _have_cython - -_Extension = get_unpatched(distutils.core.Extension) +if TYPE_CHECKING: + # Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962 + _Extension = distutils.core.Extension +else: + _Extension = get_unpatched(distutils.core.Extension) class Extension(_Extension): diff --git a/contrib/python/setuptools/py3/setuptools/monkey.py b/contrib/python/setuptools/py3/setuptools/monkey.py index da0993506c..fd07d91dec 100644 --- a/contrib/python/setuptools/py3/setuptools/monkey.py +++ b/contrib/python/setuptools/py3/setuptools/monkey.py @@ -8,11 +8,14 @@ import platform import sys import types from importlib import import_module +from typing import List, TypeVar import distutils.filelist -__all__ = [] +_T = TypeVar("_T") + +__all__: List[str] = [] """ Everything is private. Contact the project team if you think you need this functionality. @@ -33,7 +36,7 @@ def _get_mro(cls): return inspect.getmro(cls) -def get_unpatched(item): +def get_unpatched(item: _T) -> _T: lookup = ( get_unpatched_class if isinstance(item, type) diff --git a/contrib/python/setuptools/py3/setuptools/msvc.py b/contrib/python/setuptools/py3/setuptools/msvc.py index 53fe7b0de1..b2a0f2bebb 100644 --- a/contrib/python/setuptools/py3/setuptools/msvc.py +++ b/contrib/python/setuptools/py3/setuptools/msvc.py @@ -20,9 +20,11 @@ import platform import itertools import subprocess import distutils.errors +from typing import Dict, TYPE_CHECKING from setuptools.extern.more_itertools import unique_everseen -if platform.system() == 'Windows': +# https://github.com/python/mypy/issues/8166 +if not TYPE_CHECKING and platform.system() == 'Windows': import winreg from os import environ else: @@ -34,7 +36,7 @@ else: HKEY_LOCAL_MACHINE = None HKEY_CLASSES_ROOT = None - environ = dict() + environ: Dict[str, str] = dict() def _msvc14_find_vc2015(): diff --git a/contrib/python/setuptools/py3/setuptools/namespaces.py b/contrib/python/setuptools/py3/setuptools/namespaces.py index e8f2941d45..0185d55f94 100644 --- a/contrib/python/setuptools/py3/setuptools/namespaces.py +++ b/contrib/python/setuptools/py3/setuptools/namespaces.py @@ -2,6 +2,8 @@ import os from distutils import log import itertools +from .compat import py39 + flatten = itertools.chain.from_iterable @@ -23,7 +25,8 @@ class Installer: list(lines) return - with open(filename, 'wt') as f: + with open(filename, 'wt', encoding=py39.LOCALE_ENCODING) as f: + # Requires encoding="locale" instead of "utf-8" (python/cpython#77102). f.writelines(lines) def uninstall_namespaces(self): diff --git a/contrib/python/setuptools/py3/setuptools/sandbox.py b/contrib/python/setuptools/py3/setuptools/sandbox.py index 7634b1320b..6c095e029e 100644 --- a/contrib/python/setuptools/py3/setuptools/sandbox.py +++ b/contrib/python/setuptools/py3/setuptools/sandbox.py @@ -9,6 +9,7 @@ import contextlib import pickle import textwrap import builtins +from typing import Union, List import pkg_resources from distutils.errors import DistutilsError @@ -19,7 +20,7 @@ if sys.platform.startswith('java'): else: _os = sys.modules[os.name] try: - _file = file + _file = file # type: ignore[name-defined] # Check for global variable except NameError: _file = None _open = open @@ -298,7 +299,7 @@ class AbstractSandbox: with self: return func() - def _mk_dual_path_wrapper(name): + def _mk_dual_path_wrapper(name: str): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099 original = getattr(_os, name) def wrap(self, src, dst, *args, **kw): @@ -312,7 +313,7 @@ class AbstractSandbox: if hasattr(_os, name): locals()[name] = _mk_dual_path_wrapper(name) - def _mk_single_path_wrapper(name, original=None): + def _mk_single_path_wrapper(name: str, original=None): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099 original = original or getattr(_os, name) def wrap(self, path, *args, **kw): @@ -349,7 +350,7 @@ class AbstractSandbox: if hasattr(_os, name): locals()[name] = _mk_single_path_wrapper(name) - def _mk_single_with_return(name): + def _mk_single_with_return(name: str): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099 original = getattr(_os, name) def wrap(self, path, *args, **kw): @@ -364,7 +365,7 @@ class AbstractSandbox: if hasattr(_os, name): locals()[name] = _mk_single_with_return(name) - def _mk_query(name): + def _mk_query(name: str): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099 original = getattr(_os, name) def wrap(self, *args, **kw): @@ -424,7 +425,7 @@ class DirectorySandbox(AbstractSandbox): "tempnam", ]) - _exception_patterns = [] + _exception_patterns: List[Union[str, re.Pattern]] = [] "exempt writing to paths that match the pattern" def __init__(self, sandbox, exceptions=_EXCEPTIONS): diff --git a/contrib/python/setuptools/py3/ya.make b/contrib/python/setuptools/py3/ya.make index 4210fba192..4e2b62dbce 100644 --- a/contrib/python/setuptools/py3/ya.make +++ b/contrib/python/setuptools/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(69.1.1) +VERSION(69.2.0) LICENSE(MIT) @@ -216,6 +216,7 @@ PY_SRCS( setuptools/compat/__init__.py setuptools/compat/py310.py setuptools/compat/py311.py + setuptools/compat/py39.py setuptools/config/__init__.py setuptools/config/_apply_pyprojecttoml.py setuptools/config/_validate_pyproject/__init__.py |