Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /python /lib /python3.10 /site-packages /setuptools /dist.py
| from __future__ import annotations | |
| import functools | |
| import io | |
| import itertools | |
| import numbers | |
| import os | |
| import re | |
| import sys | |
| from collections.abc import Iterable, Iterator, MutableMapping, Sequence | |
| from glob import glob | |
| from pathlib import Path | |
| from typing import TYPE_CHECKING, Any, Union | |
| from more_itertools import partition, unique_everseen | |
| from packaging.markers import InvalidMarker, Marker | |
| from packaging.specifiers import InvalidSpecifier, SpecifierSet | |
| from packaging.version import Version | |
| from . import ( | |
| _entry_points, | |
| _reqs, | |
| _static, | |
| command as _, # noqa: F401 # imported for side-effects | |
| ) | |
| from ._importlib import metadata | |
| from ._normalization import _canonicalize_license_expression | |
| from ._path import StrPath | |
| from ._reqs import _StrOrIter | |
| from .config import pyprojecttoml, setupcfg | |
| from .discovery import ConfigDiscovery | |
| from .errors import InvalidConfigError | |
| from .monkey import get_unpatched | |
| from .warnings import InformationOnly, SetuptoolsDeprecationWarning | |
| import distutils.cmd | |
| import distutils.command | |
| import distutils.core | |
| import distutils.dist | |
| import distutils.log | |
| from distutils.debug import DEBUG | |
| from distutils.errors import DistutilsOptionError, DistutilsSetupError | |
| from distutils.fancy_getopt import translate_longopt | |
| from distutils.util import strtobool | |
| if TYPE_CHECKING: | |
| from typing_extensions import TypeAlias | |
| __all__ = ['Distribution'] | |
| _sequence = tuple, list | |
| """ | |
| :meta private: | |
| Supported iterable types that are known to be: | |
| - ordered (which `set` isn't) | |
| - not match a str (which `Sequence[str]` does) | |
| - not imply a nested type (like `dict`) | |
| for use with `isinstance`. | |
| """ | |
| _Sequence: TypeAlias = Union[tuple[str, ...], list[str]] | |
| # This is how stringifying _Sequence would look in Python 3.10 | |
| _sequence_type_repr = "tuple[str, ...] | list[str]" | |
| _OrderedStrSequence: TypeAlias = Union[str, dict[str, Any], Sequence[str]] | |
| """ | |
| :meta private: | |
| Avoid single-use iterable. Disallow sets. | |
| A poor approximation of an OrderedSequence (dict doesn't match a Sequence). | |
| """ | |
| def __getattr__(name: str) -> Any: # pragma: no cover | |
| if name == "sequence": | |
| SetuptoolsDeprecationWarning.emit( | |
| "`setuptools.dist.sequence` is an internal implementation detail.", | |
| "Please define your own `sequence = tuple, list` instead.", | |
| due_date=(2025, 8, 28), # Originally added on 2024-08-27 | |
| ) | |
| return _sequence | |
| raise AttributeError(f"module {__name__!r} has no attribute {name!r}") | |
| def check_importable(dist, attr, value): | |
| try: | |
| ep = metadata.EntryPoint(value=value, name=None, group=None) | |
| assert not ep.extras | |
| except (TypeError, ValueError, AttributeError, AssertionError) as e: | |
| raise DistutilsSetupError( | |
| f"{attr!r} must be importable 'module:attrs' string (got {value!r})" | |
| ) from e | |
| def assert_string_list(dist, attr: str, value: _Sequence) -> None: | |
| """Verify that value is a string list""" | |
| try: | |
| # verify that value is a list or tuple to exclude unordered | |
| # or single-use iterables | |
| assert isinstance(value, _sequence) | |
| # verify that elements of value are strings | |
| assert ''.join(value) != value | |
| except (TypeError, ValueError, AttributeError, AssertionError) as e: | |
| raise DistutilsSetupError( | |
| f"{attr!r} must be of type <{_sequence_type_repr}> (got {value!r})" | |
| ) from e | |
| def check_nsp(dist, attr, value): | |
| """Verify that namespace packages are valid""" | |
| ns_packages = value | |
| assert_string_list(dist, attr, ns_packages) | |
| for nsp in ns_packages: | |
| if not dist.has_contents_for(nsp): | |
| raise DistutilsSetupError( | |
| f"Distribution contains no modules or packages for namespace package {nsp!r}" | |
| ) | |
| parent, _sep, _child = nsp.rpartition('.') | |
| if parent and parent not in ns_packages: | |
| distutils.log.warn( | |
| "WARNING: %r is declared as a package namespace, but %r" | |
| " is not: please correct this in setup.py", | |
| nsp, | |
| parent, | |
| ) | |
| SetuptoolsDeprecationWarning.emit( | |
| "The namespace_packages parameter is deprecated.", | |
| "Please replace its usage with implicit namespaces (PEP 420).", | |
| see_docs="references/keywords.html#keyword-namespace-packages", | |
| # TODO: define due_date, it may break old packages that are no longer | |
| # maintained (e.g. sphinxcontrib extensions) when installed from source. | |
| # Warning officially introduced in May 2022, however the deprecation | |
| # was mentioned much earlier in the docs (May 2020, see #2149). | |
| ) | |
| def check_extras(dist, attr, value): | |
| """Verify that extras_require mapping is valid""" | |
| try: | |
| list(itertools.starmap(_check_extra, value.items())) | |
| except (TypeError, ValueError, AttributeError) as e: | |
| raise DistutilsSetupError( | |
| "'extras_require' must be a dictionary whose values are " | |
| "strings or lists of strings containing valid project/version " | |
| "requirement specifiers." | |
| ) from e | |
| def _check_extra(extra, reqs): | |
| _name, _sep, marker = extra.partition(':') | |
| try: | |
| _check_marker(marker) | |
| except InvalidMarker: | |
| msg = f"Invalid environment marker: {marker} ({extra!r})" | |
| raise DistutilsSetupError(msg) from None | |
| list(_reqs.parse(reqs)) | |
| def _check_marker(marker): | |
| if not marker: | |
| return | |
| m = Marker(marker) | |
| m.evaluate() | |
| def assert_bool(dist, attr, value): | |
| """Verify that value is True, False, 0, or 1""" | |
| if bool(value) != value: | |
| raise DistutilsSetupError(f"{attr!r} must be a boolean value (got {value!r})") | |
| def invalid_unless_false(dist, attr, value): | |
| if not value: | |
| DistDeprecationWarning.emit(f"{attr} is ignored.") | |
| # TODO: should there be a `due_date` here? | |
| return | |
| raise DistutilsSetupError(f"{attr} is invalid.") | |
| def check_requirements(dist, attr: str, value: _OrderedStrSequence) -> None: | |
| """Verify that install_requires is a valid requirements list""" | |
| try: | |
| list(_reqs.parse(value)) | |
| if isinstance(value, set): | |
| raise TypeError("Unordered types are not allowed") | |
| except (TypeError, ValueError) as error: | |
| msg = ( | |
| f"{attr!r} must be a string or iterable of strings " | |
| f"containing valid project/version requirement specifiers; {error}" | |
| ) | |
| raise DistutilsSetupError(msg) from error | |
| def check_specifier(dist, attr, value): | |
| """Verify that value is a valid version specifier""" | |
| try: | |
| SpecifierSet(value) | |
| except (InvalidSpecifier, AttributeError) as error: | |
| msg = f"{attr!r} must be a string containing valid version specifiers; {error}" | |
| raise DistutilsSetupError(msg) from error | |
| def check_entry_points(dist, attr, value): | |
| """Verify that entry_points map is parseable""" | |
| try: | |
| _entry_points.load(value) | |
| except Exception as e: | |
| raise DistutilsSetupError(e) from e | |
| def check_package_data(dist, attr, value): | |
| """Verify that value is a dictionary of package names to glob lists""" | |
| if not isinstance(value, dict): | |
| raise DistutilsSetupError( | |
| f"{attr!r} must be a dictionary mapping package names to lists of " | |
| "string wildcard patterns" | |
| ) | |
| for k, v in value.items(): | |
| if not isinstance(k, str): | |
| raise DistutilsSetupError( | |
| f"keys of {attr!r} dict must be strings (got {k!r})" | |
| ) | |
| assert_string_list(dist, f'values of {attr!r} dict', v) | |
| def check_packages(dist, attr, value): | |
| for pkgname in value: | |
| if not re.match(r'\w+(\.\w+)*', pkgname): | |
| distutils.log.warn( | |
| "WARNING: %r not a valid package name; please use only " | |
| ".-separated package names in setup.py", | |
| pkgname, | |
| ) | |
| 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 | |
| from distutils.core import Distribution as _Distribution | |
| else: | |
| _Distribution = get_unpatched(distutils.core.Distribution) | |
| class Distribution(_Distribution): | |
| """Distribution with support for tests and package data | |
| This is an enhanced version of 'distutils.dist.Distribution' that | |
| effectively adds the following new optional keyword arguments to 'setup()': | |
| 'install_requires' -- a string or sequence of strings specifying project | |
| versions that the distribution requires when installed, in the format | |
| used by 'pkg_resources.require()'. They will be installed | |
| automatically when the package is installed. If you wish to use | |
| packages that are not available in PyPI, or want to give your users an | |
| alternate download location, you can add a 'find_links' option to the | |
| '[easy_install]' section of your project's 'setup.cfg' file, and then | |
| setuptools will scan the listed web pages for links that satisfy the | |
| requirements. | |
| 'extras_require' -- a dictionary mapping names of optional "extras" to the | |
| additional requirement(s) that using those extras incurs. For example, | |
| this:: | |
| extras_require = dict(reST = ["docutils>=0.3", "reSTedit"]) | |
| indicates that the distribution can optionally provide an extra | |
| capability called "reST", but it can only be used if docutils and | |
| reSTedit are installed. If the user installs your package using | |
| EasyInstall and requests one of your extras, the corresponding | |
| additional requirements will be installed if needed. | |
| 'package_data' -- a dictionary mapping package names to lists of filenames | |
| or globs to use to find data files contained in the named packages. | |
| If the dictionary has filenames or globs listed under '""' (the empty | |
| string), those names will be searched for in every package, in addition | |
| to any names for the specific package. Data files found using these | |
| names/globs will be installed along with the package, in the same | |
| location as the package. Note that globs are allowed to reference | |
| the contents of non-package subdirectories, as long as you use '/' as | |
| a path separator. (Globs are automatically converted to | |
| platform-specific paths at runtime.) | |
| In addition to these new keywords, this class also has several new methods | |
| for manipulating the distribution's contents. For example, the 'include()' | |
| and 'exclude()' methods can be thought of as in-place add and subtract | |
| commands that add or remove packages, modules, extensions, and so on from | |
| the distribution. | |
| """ | |
| _DISTUTILS_UNSUPPORTED_METADATA = { | |
| 'long_description_content_type': lambda: None, | |
| 'project_urls': dict, | |
| 'provides_extras': dict, # behaves like an ordered set | |
| 'license_expression': lambda: None, | |
| 'license_file': lambda: None, | |
| 'license_files': lambda: None, | |
| 'install_requires': list, | |
| 'extras_require': dict, | |
| } | |
| # Used by build_py, editable_wheel and install_lib commands for legacy namespaces | |
| namespace_packages: list[str] #: :meta private: DEPRECATED | |
| # Any: Dynamic assignment results in Incompatible types in assignment | |
| def __init__(self, attrs: MutableMapping[str, Any] | None = None) -> None: | |
| have_package_data = hasattr(self, "package_data") | |
| if not have_package_data: | |
| self.package_data: dict[str, list[str]] = {} | |
| attrs = attrs or {} | |
| self.dist_files: list[tuple[str, str, str]] = [] | |
| self.include_package_data: bool | None = None | |
| self.exclude_package_data: dict[str, list[str]] | None = None | |
| # Filter-out setuptools' specific options. | |
| self.src_root: str | None = attrs.pop("src_root", None) | |
| self.dependency_links: list[str] = attrs.pop('dependency_links', []) | |
| self.setup_requires: list[str] = attrs.pop('setup_requires', []) | |
| for ep in metadata.entry_points(group='distutils.setup_keywords'): | |
| vars(self).setdefault(ep.name, None) | |
| metadata_only = set(self._DISTUTILS_UNSUPPORTED_METADATA) | |
| metadata_only -= {"install_requires", "extras_require"} | |
| dist_attrs = {k: v for k, v in attrs.items() if k not in metadata_only} | |
| _Distribution.__init__(self, dist_attrs) | |
| # Private API (setuptools-use only, not restricted to Distribution) | |
| # Stores files that are referenced by the configuration and need to be in the | |
| # sdist (e.g. `version = file: VERSION.txt`) | |
| self._referenced_files = set[str]() | |
| self.set_defaults = ConfigDiscovery(self) | |
| self._set_metadata_defaults(attrs) | |
| self.metadata.version = self._normalize_version(self.metadata.version) | |
| self._finalize_requires() | |
| def _validate_metadata(self): | |
| required = {"name"} | |
| provided = { | |
| key | |
| for key in vars(self.metadata) | |
| if getattr(self.metadata, key, None) is not None | |
| } | |
| missing = required - provided | |
| if missing: | |
| msg = f"Required package metadata is missing: {missing}" | |
| raise DistutilsSetupError(msg) | |
| def _set_metadata_defaults(self, attrs): | |
| """ | |
| Fill-in missing metadata fields not supported by distutils. | |
| Some fields may have been set by other tools (e.g. pbr). | |
| Those fields (vars(self.metadata)) take precedence to | |
| supplied attrs. | |
| """ | |
| for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items(): | |
| vars(self.metadata).setdefault(option, attrs.get(option, default())) | |
| def _normalize_version(version): | |
| from . import sic | |
| if isinstance(version, numbers.Number): | |
| # Some people apparently take "version number" too literally :) | |
| version = str(version) | |
| elif isinstance(version, sic) or version is None: | |
| return version | |
| normalized = str(Version(version)) | |
| if version != normalized: | |
| InformationOnly.emit(f"Normalizing '{version}' to '{normalized}'") | |
| return normalized | |
| return version | |
| def _finalize_requires(self): | |
| """ | |
| Set `metadata.python_requires` and fix environment markers | |
| in `install_requires` and `extras_require`. | |
| """ | |
| if getattr(self, 'python_requires', None): | |
| self.metadata.python_requires = self.python_requires | |
| self._normalize_requires() | |
| self.metadata.install_requires = self.install_requires | |
| self.metadata.extras_require = self.extras_require | |
| if self.extras_require: | |
| for extra in self.extras_require.keys(): | |
| # Setuptools allows a weird "<name>:<env markers> syntax for extras | |
| extra = extra.split(':')[0] | |
| if extra: | |
| self.metadata.provides_extras.setdefault(extra) | |
| def _normalize_requires(self): | |
| """Make sure requirement-related attributes exist and are normalized""" | |
| install_requires = getattr(self, "install_requires", None) or [] | |
| extras_require = getattr(self, "extras_require", None) or {} | |
| # Preserve the "static"-ness of values parsed from config files | |
| list_ = _static.List if _static.is_static(install_requires) else list | |
| self.install_requires = list_(map(str, _reqs.parse(install_requires))) | |
| dict_ = _static.Dict if _static.is_static(extras_require) else dict | |
| self.extras_require = dict_( | |
| (k, list(map(str, _reqs.parse(v or [])))) for k, v in extras_require.items() | |
| ) | |
| def _finalize_license_expression(self) -> None: | |
| """ | |
| Normalize license and license_expression. | |
| >>> dist = Distribution({"license_expression": _static.Str("mit aNd gpl-3.0-OR-later")}) | |
| >>> _static.is_static(dist.metadata.license_expression) | |
| True | |
| >>> dist._finalize_license_expression() | |
| >>> _static.is_static(dist.metadata.license_expression) # preserve "static-ness" | |
| True | |
| >>> print(dist.metadata.license_expression) | |
| MIT AND GPL-3.0-or-later | |
| """ | |
| classifiers = self.metadata.get_classifiers() | |
| license_classifiers = [cl for cl in classifiers if cl.startswith("License :: ")] | |
| license_expr = self.metadata.license_expression | |
| if license_expr: | |
| str_ = _static.Str if _static.is_static(license_expr) else str | |
| normalized = str_(_canonicalize_license_expression(license_expr)) | |
| if license_expr != normalized: | |
| InformationOnly.emit(f"Normalizing '{license_expr}' to '{normalized}'") | |
| self.metadata.license_expression = normalized | |
| if license_classifiers: | |
| raise InvalidConfigError( | |
| "License classifiers have been superseded by license expressions " | |
| "(see https://peps.python.org/pep-0639/). Please remove:\n\n" | |
| + "\n".join(license_classifiers), | |
| ) | |
| elif license_classifiers: | |
| pypa_guides = "guides/writing-pyproject-toml/#license" | |
| SetuptoolsDeprecationWarning.emit( | |
| "License classifiers are deprecated.", | |
| "Please consider removing the following classifiers in favor of a " | |
| "SPDX license expression:\n\n" + "\n".join(license_classifiers), | |
| see_url=f"https://packaging.python.org/en/latest/{pypa_guides}", | |
| # Warning introduced on 2025-02-17 | |
| # TODO: Should we add a due date? It may affect old/unmaintained | |
| # packages in the ecosystem and cause problems... | |
| ) | |
| def _finalize_license_files(self) -> None: | |
| """Compute names of all license files which should be included.""" | |
| license_files: list[str] | None = self.metadata.license_files | |
| patterns = license_files or [] | |
| license_file: str | None = self.metadata.license_file | |
| if license_file and license_file not in patterns: | |
| patterns.append(license_file) | |
| if license_files is None and license_file is None: | |
| # 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*'] | |
| files = self._expand_patterns(patterns, enforce_match=False) | |
| else: # Patterns explicitly given by the user | |
| files = self._expand_patterns(patterns, enforce_match=True) | |
| self.metadata.license_files = list(unique_everseen(files)) | |
| def _expand_patterns( | |
| cls, patterns: list[str], enforce_match: bool = True | |
| ) -> Iterator[str]: | |
| """ | |
| >>> getfixture('sample_project_cwd') | |
| >>> list(Distribution._expand_patterns(['LICENSE.txt'])) | |
| ['LICENSE.txt'] | |
| >>> list(Distribution._expand_patterns(['pyproject.toml', 'LIC*'])) | |
| ['pyproject.toml', 'LICENSE.txt'] | |
| >>> list(Distribution._expand_patterns(['src/**/*.dat'])) | |
| ['src/sample/package_data.dat'] | |
| """ | |
| return ( | |
| path.replace(os.sep, "/") | |
| for pattern in patterns | |
| for path in sorted(cls._find_pattern(pattern, enforce_match)) | |
| if not path.endswith('~') and os.path.isfile(path) | |
| ) | |
| def _find_pattern(pattern: str, enforce_match: bool = True) -> list[str]: | |
| r""" | |
| >>> getfixture('sample_project_cwd') | |
| >>> Distribution._find_pattern("LICENSE.txt") | |
| ['LICENSE.txt'] | |
| >>> Distribution._find_pattern("/LICENSE.MIT") | |
| Traceback (most recent call last): | |
| ... | |
| setuptools.errors.InvalidConfigError: Pattern '/LICENSE.MIT' should be relative... | |
| >>> Distribution._find_pattern("../LICENSE.MIT") | |
| Traceback (most recent call last): | |
| ... | |
| setuptools.warnings.SetuptoolsDeprecationWarning: ...Pattern '../LICENSE.MIT' cannot contain '..'... | |
| >>> Distribution._find_pattern("LICEN{CSE*") | |
| Traceback (most recent call last): | |
| ... | |
| setuptools.warnings.SetuptoolsDeprecationWarning: ...Pattern 'LICEN{CSE*' contains invalid characters... | |
| """ | |
| pypa_guides = "specifications/glob-patterns/" | |
| if ".." in pattern: | |
| SetuptoolsDeprecationWarning.emit( | |
| f"Pattern {pattern!r} cannot contain '..'", | |
| """ | |
| Please ensure the files specified are contained by the root | |
| of the Python package (normally marked by `pyproject.toml`). | |
| """, | |
| see_url=f"https://packaging.python.org/en/latest/{pypa_guides}", | |
| due_date=(2026, 3, 20), # Introduced in 2025-03-20 | |
| # Replace with InvalidConfigError after deprecation | |
| ) | |
| if pattern.startswith((os.sep, "/")) or ":\\" in pattern: | |
| raise InvalidConfigError( | |
| f"Pattern {pattern!r} should be relative and must not start with '/'" | |
| ) | |
| if re.match(r'^[\w\-\.\/\*\?\[\]]+$', pattern) is None: | |
| SetuptoolsDeprecationWarning.emit( | |
| "Please provide a valid glob pattern.", | |
| "Pattern {pattern!r} contains invalid characters.", | |
| pattern=pattern, | |
| see_url=f"https://packaging.python.org/en/latest/{pypa_guides}", | |
| due_date=(2026, 3, 20), # Introduced in 2025-02-20 | |
| ) | |
| found = glob(pattern, recursive=True) | |
| if enforce_match and not found: | |
| SetuptoolsDeprecationWarning.emit( | |
| "Cannot find any files for the given pattern.", | |
| "Pattern {pattern!r} did not match any files.", | |
| pattern=pattern, | |
| due_date=(2026, 3, 20), # Introduced in 2025-02-20 | |
| # PEP 639 requires us to error, but as a transition period | |
| # we will only issue a warning to give people time to prepare. | |
| # After the transition, this should raise an InvalidConfigError. | |
| ) | |
| return found | |
| # FIXME: 'Distribution._parse_config_files' is too complex (14) | |
| def _parse_config_files(self, filenames=None): # noqa: C901 | |
| """ | |
| Adapted from distutils.dist.Distribution.parse_config_files, | |
| this method provides the same functionality in subtly-improved | |
| ways. | |
| """ | |
| from configparser import ConfigParser | |
| # Ignore install directory options if we have a venv | |
| ignore_options = ( | |
| [] | |
| if sys.prefix == sys.base_prefix | |
| else [ | |
| 'install-base', | |
| 'install-platbase', | |
| 'install-lib', | |
| 'install-platlib', | |
| 'install-purelib', | |
| 'install-headers', | |
| 'install-scripts', | |
| 'install-data', | |
| 'prefix', | |
| 'exec-prefix', | |
| 'home', | |
| 'user', | |
| 'root', | |
| ] | |
| ) | |
| ignore_options = frozenset(ignore_options) | |
| if filenames is None: | |
| filenames = self.find_config_files() | |
| if DEBUG: | |
| self.announce("Distribution.parse_config_files():") | |
| parser = ConfigParser() | |
| parser.optionxform = str | |
| for filename in filenames: | |
| with open(filename, encoding='utf-8') as reader: | |
| if DEBUG: | |
| self.announce(" reading {filename}".format(**locals())) | |
| parser.read_file(reader) | |
| for section in parser.sections(): | |
| options = parser.options(section) | |
| opt_dict = self.get_option_dict(section) | |
| for opt in options: | |
| if opt == '__name__' or opt in ignore_options: | |
| continue | |
| val = parser.get(section, opt) | |
| opt = self._enforce_underscore(opt, section) | |
| opt = self._enforce_option_lowercase(opt, section) | |
| opt_dict[opt] = (filename, val) | |
| # Make the ConfigParser forget everything (so we retain | |
| # the original filenames that options come from) | |
| parser.__init__() | |
| if 'global' not in self.command_options: | |
| return | |
| # If there was a "global" section in the config file, use it | |
| # to set Distribution options. | |
| for opt, (src, val) in self.command_options['global'].items(): | |
| alias = self.negative_opt.get(opt) | |
| if alias: | |
| val = not strtobool(val) | |
| elif opt in ('verbose', 'dry_run'): # ugh! | |
| val = strtobool(val) | |
| try: | |
| setattr(self, alias or opt, val) | |
| except ValueError as e: | |
| raise DistutilsOptionError(e) from e | |
| def _enforce_underscore(self, opt: str, section: str) -> str: | |
| if "-" not in opt or self._skip_setupcfg_normalization(section): | |
| return opt | |
| underscore_opt = opt.replace('-', '_') | |
| affected = f"(Affected: {self.metadata.name})." if self.metadata.name else "" | |
| SetuptoolsDeprecationWarning.emit( | |
| f"Invalid dash-separated key {opt!r} in {section!r} (setup.cfg), " | |
| f"please use the underscore name {underscore_opt!r} instead.", | |
| f""" | |
| Usage of dash-separated {opt!r} will not be supported in future | |
| versions. Please use the underscore name {underscore_opt!r} instead. | |
| {affected} | |
| """, | |
| see_docs="userguide/declarative_config.html", | |
| due_date=(2026, 3, 3), | |
| # Warning initially introduced in 3 Mar 2021 | |
| ) | |
| return underscore_opt | |
| def _enforce_option_lowercase(self, opt: str, section: str) -> str: | |
| if opt.islower() or self._skip_setupcfg_normalization(section): | |
| return opt | |
| lowercase_opt = opt.lower() | |
| affected = f"(Affected: {self.metadata.name})." if self.metadata.name else "" | |
| SetuptoolsDeprecationWarning.emit( | |
| f"Invalid uppercase key {opt!r} in {section!r} (setup.cfg), " | |
| f"please use lowercase {lowercase_opt!r} instead.", | |
| f""" | |
| Usage of uppercase key {opt!r} in {section!r} will not be supported in | |
| future versions. Please use lowercase {lowercase_opt!r} instead. | |
| {affected} | |
| """, | |
| see_docs="userguide/declarative_config.html", | |
| due_date=(2026, 3, 3), | |
| # Warning initially introduced in 6 Mar 2021 | |
| ) | |
| return lowercase_opt | |
| def _skip_setupcfg_normalization(self, section: str) -> bool: | |
| skip = ( | |
| 'options.extras_require', | |
| 'options.data_files', | |
| 'options.entry_points', | |
| 'options.package_data', | |
| 'options.exclude_package_data', | |
| ) | |
| return section in skip or not self._is_setuptools_section(section) | |
| def _is_setuptools_section(self, section: str) -> bool: | |
| return ( | |
| section == "metadata" | |
| or section.startswith("options") | |
| or section in _setuptools_commands() | |
| ) | |
| # FIXME: 'Distribution._set_command_options' is too complex (14) | |
| def _set_command_options(self, command_obj, option_dict=None): # noqa: C901 | |
| """ | |
| Set the options for 'command_obj' from 'option_dict'. Basically | |
| this means copying elements of a dictionary ('option_dict') to | |
| attributes of an instance ('command'). | |
| 'command_obj' must be a Command instance. If 'option_dict' is not | |
| supplied, uses the standard option dictionary for this command | |
| (from 'self.command_options'). | |
| (Adopted from distutils.dist.Distribution._set_command_options) | |
| """ | |
| command_name = command_obj.get_command_name() | |
| if option_dict is None: | |
| option_dict = self.get_option_dict(command_name) | |
| if DEBUG: | |
| self.announce(f" setting options for '{command_name}' command:") | |
| for option, (source, value) in option_dict.items(): | |
| if DEBUG: | |
| self.announce(f" {option} = {value} (from {source})") | |
| try: | |
| bool_opts = [translate_longopt(o) for o in command_obj.boolean_options] | |
| except AttributeError: | |
| bool_opts = [] | |
| try: | |
| neg_opt = command_obj.negative_opt | |
| except AttributeError: | |
| neg_opt = {} | |
| try: | |
| is_string = isinstance(value, str) | |
| if option in neg_opt and is_string: | |
| setattr(command_obj, neg_opt[option], not strtobool(value)) | |
| elif option in bool_opts and is_string: | |
| setattr(command_obj, option, strtobool(value)) | |
| elif hasattr(command_obj, option): | |
| setattr(command_obj, option, value) | |
| else: | |
| raise DistutilsOptionError( | |
| f"error in {source}: command '{command_name}' has no such option '{option}'" | |
| ) | |
| except ValueError as e: | |
| raise DistutilsOptionError(e) from e | |
| def _get_project_config_files(self, filenames: Iterable[StrPath] | None): | |
| """Add default file and split between INI and TOML""" | |
| tomlfiles = [] | |
| standard_project_metadata = Path(self.src_root or os.curdir, "pyproject.toml") | |
| if filenames is not None: | |
| parts = partition(lambda f: Path(f).suffix == ".toml", filenames) | |
| filenames = list(parts[0]) # 1st element => predicate is False | |
| tomlfiles = list(parts[1]) # 2nd element => predicate is True | |
| elif standard_project_metadata.exists(): | |
| tomlfiles = [standard_project_metadata] | |
| return filenames, tomlfiles | |
| 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. | |
| """ | |
| inifiles, tomlfiles = self._get_project_config_files(filenames) | |
| self._parse_config_files(filenames=inifiles) | |
| setupcfg.parse_configuration( | |
| self, self.command_options, ignore_option_errors=ignore_option_errors | |
| ) | |
| for filename in tomlfiles: | |
| pyprojecttoml.apply_configuration(self, filename, ignore_option_errors) | |
| self._finalize_requires() | |
| self._finalize_license_expression() | |
| self._finalize_license_files() | |
| def fetch_build_eggs(self, requires: _StrOrIter) -> list[metadata.Distribution]: | |
| """Resolve pre-setup requirements""" | |
| from .installer import _fetch_build_eggs | |
| return _fetch_build_eggs(self, requires) | |
| def finalize_options(self) -> None: | |
| """ | |
| Allow plugins to apply arbitrary operations to the | |
| distribution. Each hook may optionally define a 'order' | |
| to influence the order of execution. Smaller numbers | |
| go first and the default is 0. | |
| """ | |
| group = 'setuptools.finalize_distribution_options' | |
| def by_order(hook): | |
| return getattr(hook, 'order', 0) | |
| defined = metadata.entry_points(group=group) | |
| filtered = itertools.filterfalse(self._removed, defined) | |
| loaded = map(lambda e: e.load(), filtered) | |
| for ep in sorted(loaded, key=by_order): | |
| ep(self) | |
| def _removed(ep): | |
| """ | |
| When removing an entry point, if metadata is loaded | |
| from an older version of Setuptools, that removed | |
| entry point will attempt to be loaded and will fail. | |
| See #2765 for more details. | |
| """ | |
| removed = { | |
| # removed 2021-09-05 | |
| '2to3_doctests', | |
| } | |
| return ep.name in removed | |
| def _finalize_setup_keywords(self): | |
| for ep in metadata.entry_points(group='distutils.setup_keywords'): | |
| value = getattr(self, ep.name, None) | |
| if value is not None: | |
| ep.load()(self, ep.name, value) | |
| def get_egg_cache_dir(self): | |
| from . import windows_support | |
| egg_cache_dir = os.path.join(os.curdir, '.eggs') | |
| if not os.path.exists(egg_cache_dir): | |
| os.mkdir(egg_cache_dir) | |
| windows_support.hide_file(egg_cache_dir) | |
| readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt') | |
| with open(readme_txt_filename, 'w', encoding="utf-8") as f: | |
| f.write( | |
| 'This directory contains eggs that were downloaded ' | |
| 'by setuptools to build, test, and run plug-ins.\n\n' | |
| ) | |
| f.write( | |
| 'This directory caches those eggs to prevent ' | |
| 'repeated downloads.\n\n' | |
| ) | |
| f.write('However, it is safe to delete this directory.\n\n') | |
| return egg_cache_dir | |
| def fetch_build_egg(self, req): | |
| """Fetch an egg needed for building""" | |
| from .installer import fetch_build_egg | |
| return fetch_build_egg(self, req) | |
| 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] | |
| # Special case bdist_wheel so it's never loaded from "wheel" | |
| if command == 'bdist_wheel': | |
| from .command.bdist_wheel import bdist_wheel | |
| return bdist_wheel | |
| eps = metadata.entry_points(group='distutils.commands', name=command) | |
| for ep in eps: | |
| self.cmdclass[command] = cmdclass = ep.load() | |
| return cmdclass | |
| else: | |
| return _Distribution.get_command_class(self, command) | |
| def print_commands(self): | |
| for ep in metadata.entry_points(group='distutils.commands'): | |
| if ep.name not in self.cmdclass: | |
| cmdclass = ep.load() | |
| self.cmdclass[ep.name] = cmdclass | |
| return _Distribution.print_commands(self) | |
| def get_command_list(self): | |
| for ep in metadata.entry_points(group='distutils.commands'): | |
| if ep.name not in self.cmdclass: | |
| cmdclass = ep.load() | |
| self.cmdclass[ep.name] = cmdclass | |
| return _Distribution.get_command_list(self) | |
| def include(self, **attrs) -> None: | |
| """Add items to distribution that are named in keyword arguments | |
| For example, 'dist.include(py_modules=["x"])' would add 'x' to | |
| the distribution's 'py_modules' attribute, if it was not already | |
| there. | |
| Currently, this method only supports inclusion for attributes that are | |
| lists or tuples. If you need to add support for adding to other | |
| attributes in this or a subclass, you can add an '_include_X' method, | |
| where 'X' is the name of the attribute. The method will be called with | |
| the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})' | |
| will try to call 'dist._include_foo({"bar":"baz"})', which can then | |
| handle whatever special inclusion logic is needed. | |
| """ | |
| for k, v in attrs.items(): | |
| include = getattr(self, '_include_' + k, None) | |
| if include: | |
| include(v) | |
| else: | |
| self._include_misc(k, v) | |
| def exclude_package(self, package: str) -> None: | |
| """Remove packages, modules, and extensions in named package""" | |
| pfx = package + '.' | |
| if self.packages: | |
| self.packages = [ | |
| p for p in self.packages if p != package and not p.startswith(pfx) | |
| ] | |
| if self.py_modules: | |
| self.py_modules = [ | |
| p for p in self.py_modules if p != package and not p.startswith(pfx) | |
| ] | |
| if self.ext_modules: | |
| self.ext_modules = [ | |
| p | |
| for p in self.ext_modules | |
| if p.name != package and not p.name.startswith(pfx) | |
| ] | |
| def has_contents_for(self, package: str) -> bool: | |
| """Return true if 'exclude_package(package)' would do something""" | |
| pfx = package + '.' | |
| for p in self.iter_distribution_names(): | |
| if p == package or p.startswith(pfx): | |
| return True | |
| return False | |
| def _exclude_misc(self, name: str, value: _Sequence) -> None: | |
| """Handle 'exclude()' for list/tuple attrs without a special handler""" | |
| if not isinstance(value, _sequence): | |
| raise DistutilsSetupError( | |
| f"{name}: setting must be of type <{_sequence_type_repr}> (got {value!r})" | |
| ) | |
| try: | |
| old = getattr(self, name) | |
| except AttributeError as e: | |
| raise DistutilsSetupError(f"{name}: No such distribution setting") from e | |
| if old is not None and not isinstance(old, _sequence): | |
| raise DistutilsSetupError( | |
| name + ": this setting cannot be changed via include/exclude" | |
| ) | |
| elif old: | |
| setattr(self, name, [item for item in old if item not in value]) | |
| def _include_misc(self, name: str, value: _Sequence) -> None: | |
| """Handle 'include()' for list/tuple attrs without a special handler""" | |
| if not isinstance(value, _sequence): | |
| raise DistutilsSetupError( | |
| f"{name}: setting must be of type <{_sequence_type_repr}> (got {value!r})" | |
| ) | |
| try: | |
| old = getattr(self, name) | |
| except AttributeError as e: | |
| raise DistutilsSetupError(f"{name}: No such distribution setting") from e | |
| if old is None: | |
| setattr(self, name, value) | |
| elif not isinstance(old, _sequence): | |
| raise DistutilsSetupError( | |
| name + ": this setting cannot be changed via include/exclude" | |
| ) | |
| else: | |
| new = [item for item in value if item not in old] | |
| setattr(self, name, list(old) + new) | |
| def exclude(self, **attrs) -> None: | |
| """Remove items from distribution that are named in keyword arguments | |
| For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from | |
| the distribution's 'py_modules' attribute. Excluding packages uses | |
| the 'exclude_package()' method, so all of the package's contained | |
| packages, modules, and extensions are also excluded. | |
| Currently, this method only supports exclusion from attributes that are | |
| lists or tuples. If you need to add support for excluding from other | |
| attributes in this or a subclass, you can add an '_exclude_X' method, | |
| where 'X' is the name of the attribute. The method will be called with | |
| the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})' | |
| will try to call 'dist._exclude_foo({"bar":"baz"})', which can then | |
| handle whatever special exclusion logic is needed. | |
| """ | |
| for k, v in attrs.items(): | |
| exclude = getattr(self, '_exclude_' + k, None) | |
| if exclude: | |
| exclude(v) | |
| else: | |
| self._exclude_misc(k, v) | |
| def _exclude_packages(self, packages: _Sequence) -> None: | |
| if not isinstance(packages, _sequence): | |
| raise DistutilsSetupError( | |
| f"packages: setting must be of type <{_sequence_type_repr}> (got {packages!r})" | |
| ) | |
| list(map(self.exclude_package, packages)) | |
| def _parse_command_opts(self, parser, args): | |
| # Remove --with-X/--without-X options when processing command args | |
| self.global_options = self.__class__.global_options | |
| self.negative_opt = self.__class__.negative_opt | |
| # First, expand any aliases | |
| command = args[0] | |
| aliases = self.get_option_dict('aliases') | |
| while command in aliases: | |
| _src, alias = aliases[command] | |
| del aliases[command] # ensure each alias can expand only once! | |
| import shlex | |
| args[:1] = shlex.split(alias, True) | |
| command = args[0] | |
| nargs = _Distribution._parse_command_opts(self, parser, args) | |
| # Handle commands that want to consume all remaining arguments | |
| cmd_class = self.get_command_class(command) | |
| if getattr(cmd_class, 'command_consumes_arguments', None): | |
| self.get_option_dict(command)['args'] = ("command line", nargs) | |
| if nargs is not None: | |
| return [] | |
| return nargs | |
| def get_cmdline_options(self) -> dict[str, dict[str, str | None]]: | |
| """Return a '{cmd: {opt:val}}' map of all command-line options | |
| Option names are all long, but do not include the leading '--', and | |
| contain dashes rather than underscores. If the option doesn't take | |
| an argument (e.g. '--quiet'), the 'val' is 'None'. | |
| Note that options provided by config files are intentionally excluded. | |
| """ | |
| d: dict[str, dict[str, str | None]] = {} | |
| for cmd, opts in self.command_options.items(): | |
| val: str | None | |
| for opt, (src, val) in opts.items(): | |
| if src != "command line": | |
| continue | |
| opt = opt.replace('_', '-') | |
| if val == 0: | |
| cmdobj = self.get_command_obj(cmd) | |
| neg_opt = self.negative_opt.copy() | |
| neg_opt.update(getattr(cmdobj, 'negative_opt', {})) | |
| for neg, pos in neg_opt.items(): | |
| if pos == opt: | |
| opt = neg | |
| val = None | |
| break | |
| else: | |
| raise AssertionError("Shouldn't be able to get here") | |
| elif val == 1: | |
| val = None | |
| d.setdefault(cmd, {})[opt] = val | |
| return d | |
| def iter_distribution_names(self): | |
| """Yield all packages, modules, and extension names in distribution""" | |
| yield from self.packages or () | |
| yield from self.py_modules or () | |
| for ext in self.ext_modules or (): | |
| if isinstance(ext, tuple): | |
| name, _buildinfo = ext | |
| else: | |
| name = ext.name | |
| if name.endswith('module'): | |
| name = name[:-6] | |
| yield name | |
| def handle_display_options(self, option_order): | |
| """If there were any non-global "display-only" options | |
| (--help-commands or the metadata display options) on the command | |
| line, display the requested info and return true; else return | |
| false. | |
| """ | |
| import sys | |
| if self.help_commands: | |
| return _Distribution.handle_display_options(self, option_order) | |
| # Stdout may be StringIO (e.g. in tests) | |
| if not isinstance(sys.stdout, io.TextIOWrapper): | |
| return _Distribution.handle_display_options(self, option_order) | |
| # Don't wrap stdout if utf-8 is already the encoding. Provides | |
| # workaround for #334. | |
| if sys.stdout.encoding.lower() in ('utf-8', 'utf8'): | |
| return _Distribution.handle_display_options(self, option_order) | |
| # Print metadata in UTF-8 no matter the platform | |
| encoding = sys.stdout.encoding | |
| sys.stdout.reconfigure(encoding='utf-8') | |
| try: | |
| return _Distribution.handle_display_options(self, option_order) | |
| finally: | |
| sys.stdout.reconfigure(encoding=encoding) | |
| def run_command(self, command) -> None: | |
| self.set_defaults() | |
| # Postpone defaults until all explicit configuration is considered | |
| # (setup() args, config files, command line and plugins) | |
| super().run_command(command) | |
| def _setuptools_commands() -> set[str]: | |
| try: | |
| # Use older API for importlib.metadata compatibility | |
| entry_points = metadata.distribution('setuptools').entry_points | |
| eps: Iterable[str] = (ep.name for ep in entry_points) | |
| except metadata.PackageNotFoundError: | |
| # during bootstrapping, distribution doesn't exist | |
| eps = [] | |
| return {*distutils.command.__all__, *eps} | |
| class DistDeprecationWarning(SetuptoolsDeprecationWarning): | |
| """Class for warning about deprecations in dist in | |
| setuptools. Not ignored by default, unlike DeprecationWarning.""" | |
Xet Storage Details
- Size:
- 44.9 kB
- Xet hash:
- e18fda510443ace6373b020d1fff875576e947bd11fd22ec256d0cf9fc313fef
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.