diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2022-03-13 14:01:16 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-13 14:01:16 -0400 |
commit | ba25a5f0287177f19574c577db370c684b51b415 (patch) | |
tree | 330dbaaf858eb83af7534241fd415855a9cd2c56 | |
parent | fc72349c9397f2f03e971d8ebc3e4928957180f1 (diff) | |
parent | e7b99faf0add4e9bbc1970a975c371657a125e70 (diff) | |
download | python-setuptools-git-ba25a5f0287177f19574c577db370c684b51b415.tar.gz |
Merge pull request #3170 from pypa/feature/nspektr
Vendor nspektr. Utilize it in Distribution._install_dependencies.
-rw-r--r-- | changelog.d/3170.change.rst | 1 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/INSTALLER | 1 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/LICENSE | 19 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/METADATA | 57 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/RECORD | 11 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/REQUESTED | 0 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/WHEEL | 5 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr-0.3.0.dist-info/top_level.txt | 1 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr/__init__.py | 145 | ||||
-rw-r--r-- | setuptools/_vendor/nspektr/_compat.py | 21 | ||||
-rw-r--r-- | setuptools/_vendor/vendored.txt | 1 | ||||
-rw-r--r-- | setuptools/dist.py | 22 | ||||
-rw-r--r-- | setuptools/extern/__init__.py | 2 | ||||
-rw-r--r-- | tools/vendored.py | 11 |
14 files changed, 278 insertions, 19 deletions
diff --git a/changelog.d/3170.change.rst b/changelog.d/3170.change.rst new file mode 100644 index 00000000..8e356ca3 --- /dev/null +++ b/changelog.d/3170.change.rst @@ -0,0 +1 @@ +Adopt nspektr (vendored) to implement Distribution._install_dependencies. diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/INSTALLER b/setuptools/_vendor/nspektr-0.3.0.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/LICENSE b/setuptools/_vendor/nspektr-0.3.0.dist-info/LICENSE new file mode 100644 index 00000000..353924be --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright Jason R. Coombs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/METADATA b/setuptools/_vendor/nspektr-0.3.0.dist-info/METADATA new file mode 100644 index 00000000..aadc3749 --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/METADATA @@ -0,0 +1,57 @@ +Metadata-Version: 2.1 +Name: nspektr +Version: 0.3.0 +Summary: package inspector +Home-page: https://github.com/jaraco/nspektr +Author: Jason R. Coombs +Author-email: jaraco@jaraco.com +License: UNKNOWN +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Requires-Python: >=3.7 +License-File: LICENSE +Requires-Dist: jaraco.context +Requires-Dist: jaraco.functools +Requires-Dist: more-itertools +Requires-Dist: packaging +Requires-Dist: importlib-metadata (>=3.6) ; python_version < "3.10" +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: jaraco.packaging (>=9) ; extra == 'docs' +Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' +Provides-Extra: testing +Requires-Dist: pytest (>=6) ; extra == 'testing' +Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing' +Requires-Dist: pytest-flake8 ; extra == 'testing' +Requires-Dist: pytest-cov ; extra == 'testing' +Requires-Dist: pytest-enabler (>=1.0.1) ; extra == 'testing' +Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-mypy (>=0.9.1) ; (platform_python_implementation != "PyPy") and extra == 'testing' + +.. image:: https://img.shields.io/pypi/v/nspektr.svg + :target: `PyPI link`_ + +.. image:: https://img.shields.io/pypi/pyversions/nspektr.svg + :target: `PyPI link`_ + +.. _PyPI link: https://pypi.org/project/nspektr + +.. image:: https://github.com/jaraco/nspektr/workflows/tests/badge.svg + :target: https://github.com/jaraco/nspektr/actions?query=workflow%3A%22tests%22 + :alt: tests + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: Black + +.. .. image:: https://readthedocs.org/projects/skeleton/badge/?version=latest +.. :target: https://skeleton.readthedocs.io/en/latest/?badge=latest + +.. image:: https://img.shields.io/badge/skeleton-2022-informational + :target: https://blog.jaraco.com/skeleton + + diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/RECORD b/setuptools/_vendor/nspektr-0.3.0.dist-info/RECORD new file mode 100644 index 00000000..5e5de5eb --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/RECORD @@ -0,0 +1,11 @@ +nspektr-0.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+nspektr-0.3.0.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050
+nspektr-0.3.0.dist-info/METADATA,sha256=X0stV4vwFBDBxvzhBl4kAHVdGWPIjEitqAuTJItcQH0,2162
+nspektr-0.3.0.dist-info/RECORD,,
+nspektr-0.3.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+nspektr-0.3.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
+nspektr-0.3.0.dist-info/top_level.txt,sha256=uEA20Ixo04XS3wOIt5-Jk5ZuMkBrtlleFipRr8Y1SjQ,8
+nspektr/__init__.py,sha256=d6-d-ZlGAQQP-MEi_NZMiyn2vLbq8Hw3HxICgm3X0Q8,3949
+nspektr/__pycache__/__init__.cpython-310.pyc,,
+nspektr/__pycache__/_compat.cpython-310.pyc,,
+nspektr/_compat.py,sha256=2QoozYhuhgow_NMUATmhoM-yppBV3jiZYQgdiP-ww0s,582
diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/REQUESTED b/setuptools/_vendor/nspektr-0.3.0.dist-info/REQUESTED new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/REQUESTED diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/WHEEL b/setuptools/_vendor/nspektr-0.3.0.dist-info/WHEEL new file mode 100644 index 00000000..becc9a66 --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/setuptools/_vendor/nspektr-0.3.0.dist-info/top_level.txt b/setuptools/_vendor/nspektr-0.3.0.dist-info/top_level.txt new file mode 100644 index 00000000..b10ef50a --- /dev/null +++ b/setuptools/_vendor/nspektr-0.3.0.dist-info/top_level.txt @@ -0,0 +1 @@ +nspektr diff --git a/setuptools/_vendor/nspektr/__init__.py b/setuptools/_vendor/nspektr/__init__.py new file mode 100644 index 00000000..938bbdb9 --- /dev/null +++ b/setuptools/_vendor/nspektr/__init__.py @@ -0,0 +1,145 @@ +import itertools +import functools +import contextlib + +from setuptools.extern.packaging.requirements import Requirement +from setuptools.extern.packaging.version import Version +from setuptools.extern.more_itertools import always_iterable +from setuptools.extern.jaraco.context import suppress +from setuptools.extern.jaraco.functools import apply + +from ._compat import metadata, repair_extras + + +def resolve(req: Requirement) -> metadata.Distribution: + """ + Resolve the requirement to its distribution. + + Ignore exception detail for Python 3.9 compatibility. + + >>> resolve(Requirement('pytest<3')) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + importlib.metadata.PackageNotFoundError: No package metadata was found for pytest<3 + """ + dist = metadata.distribution(req.name) + if not req.specifier.contains(Version(dist.version), prereleases=True): + raise metadata.PackageNotFoundError(str(req)) + dist.extras = req.extras # type: ignore + return dist + + +@apply(bool) +@suppress(metadata.PackageNotFoundError) +def is_satisfied(req: Requirement): + return resolve(req) + + +unsatisfied = functools.partial(itertools.filterfalse, is_satisfied) + + +class NullMarker: + @classmethod + def wrap(cls, req: Requirement): + return req.marker or cls() + + def evaluate(self, *args, **kwargs): + return True + + +def find_direct_dependencies(dist, extras=None): + """ + Find direct, declared dependencies for dist. + """ + simple = ( + req + for req in map(Requirement, always_iterable(dist.requires)) + if NullMarker.wrap(req).evaluate(dict(extra=None)) + ) + extra_deps = ( + req + for req in map(Requirement, always_iterable(dist.requires)) + for extra in always_iterable(getattr(dist, 'extras', extras)) + if NullMarker.wrap(req).evaluate(dict(extra=extra)) + ) + return itertools.chain(simple, extra_deps) + + +def traverse(items, visit): + """ + Given an iterable of items, traverse the items. + + For each item, visit is called to return any additional items + to include in the traversal. + """ + while True: + try: + item = next(items) + except StopIteration: + return + yield item + items = itertools.chain(items, visit(item)) + + +def find_req_dependencies(req): + with contextlib.suppress(metadata.PackageNotFoundError): + dist = resolve(req) + yield from find_direct_dependencies(dist) + + +def find_dependencies(dist, extras=None): + """ + Find all reachable dependencies for dist. + + dist is an importlib.metadata.Distribution (or similar). + TODO: create a suitable protocol for type hint. + + >>> deps = find_dependencies(resolve(Requirement('nspektr'))) + >>> all(isinstance(dep, Requirement) for dep in deps) + True + >>> not any('pytest' in str(dep) for dep in deps) + True + >>> test_deps = find_dependencies(resolve(Requirement('nspektr[testing]'))) + >>> any('pytest' in str(dep) for dep in test_deps) + True + """ + + def visit(req, seen=set()): + if req in seen: + return () + seen.add(req) + return find_req_dependencies(req) + + return traverse(find_direct_dependencies(dist, extras), visit) + + +class Unresolved(Exception): + def __iter__(self): + return iter(self.args[0]) + + +def missing(ep): + """ + Generate the unresolved dependencies (if any) of ep. + """ + return unsatisfied(find_dependencies(ep.dist, repair_extras(ep.extras))) + + +def check(ep): + """ + >>> ep, = metadata.entry_points(group='console_scripts', name='pip') + >>> check(ep) + >>> dist = metadata.distribution('nspektr') + + Since 'docs' extras are not installed, requesting them should fail. + + >>> ep = metadata.EntryPoint( + ... group=None, name=None, value='nspektr [docs]')._for(dist) + >>> check(ep) + Traceback (most recent call last): + ... + nspektr.Unresolved: [...] + """ + missed = list(missing(ep)) + if missed: + raise Unresolved(missed) diff --git a/setuptools/_vendor/nspektr/_compat.py b/setuptools/_vendor/nspektr/_compat.py new file mode 100644 index 00000000..3278379a --- /dev/null +++ b/setuptools/_vendor/nspektr/_compat.py @@ -0,0 +1,21 @@ +import contextlib +import sys + + +if sys.version_info >= (3, 10): + import importlib.metadata as metadata +else: + import setuptools.extern.importlib_metadata as metadata # type: ignore # noqa: F401 + + +def repair_extras(extras): + """ + Repair extras that appear as match objects. + + python/importlib_metadata#369 revealed a flaw in the EntryPoint + implementation. This function wraps the extras to ensure + they are proper strings even on older implementations. + """ + with contextlib.suppress(AttributeError): + return list(item.group(0) for item in extras) + return extras diff --git a/setuptools/_vendor/vendored.txt b/setuptools/_vendor/vendored.txt index db24b402..4320b352 100644 --- a/setuptools/_vendor/vendored.txt +++ b/setuptools/_vendor/vendored.txt @@ -5,6 +5,7 @@ more_itertools==8.8.0 jaraco.text==3.7.0 importlib_resources==5.4.0 importlib_metadata==4.11.1 +nspektr==0.3.0 # required for importlib_metadata on older Pythons typing_extensions==4.0.1 # required for importlib_resources and _metadata on older Pythons diff --git a/setuptools/dist.py b/setuptools/dist.py index e825785e..b55996f0 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -28,7 +28,8 @@ from distutils.util import rfc822_escape from setuptools.extern import packaging from setuptools.extern import ordered_set -from setuptools.extern.more_itertools import unique_everseen, always_iterable +from setuptools.extern.more_itertools import unique_everseen +from setuptools.extern import nspektr from ._importlib import metadata @@ -40,7 +41,7 @@ from setuptools import windows_support from setuptools.monkey import get_unpatched from setuptools.config import parse_configuration import pkg_resources -from setuptools.extern.packaging import version, requirements +from setuptools.extern.packaging import version from . import _reqs from . import _entry_points @@ -876,25 +877,10 @@ class Distribution(_Distribution): Given an entry point, ensure that any declared extras for its distribution are installed. """ - reqs = { - req - for req in map(requirements.Requirement, always_iterable(ep.dist.requires)) - for extra in ep.extras - if extra in req.extras - } - missing = itertools.filterfalse(self._is_installed, reqs) - for req in missing: + for req in nspektr.missing(ep): # fetch_build_egg expects pkg_resources.Requirement self.fetch_build_egg(pkg_resources.Requirement(str(req))) - def _is_installed(self, req): - try: - dist = metadata.distribution(req.name) - except metadata.PackageNotFoundError: - return False - found_ver = packaging.version.Version(dist.version()) - return found_ver in req.specifier - def get_egg_cache_dir(self): egg_cache_dir = os.path.join(os.curdir, '.eggs') if not os.path.exists(egg_cache_dir): diff --git a/setuptools/extern/__init__.py b/setuptools/extern/__init__.py index 98235a4b..7907fafc 100644 --- a/setuptools/extern/__init__.py +++ b/setuptools/extern/__init__.py @@ -71,6 +71,6 @@ class VendorImporter: names = ( 'packaging', 'pyparsing', 'ordered_set', 'more_itertools', 'importlib_metadata', - 'zipp', 'importlib_resources', 'jaraco', 'typing_extensions', + 'zipp', 'importlib_resources', 'jaraco', 'typing_extensions', 'nspektr', ) VendorImporter(__name__, names, 'setuptools._vendor').install() diff --git a/tools/vendored.py b/tools/vendored.py index 8a122ad7..cd15adbf 100644 --- a/tools/vendored.py +++ b/tools/vendored.py @@ -89,6 +89,16 @@ def rewrite_more_itertools(pkg_files: Path): more_file.write_text(text) +def rewrite_nspektr(pkg_files: Path, new_root): + for file in pkg_files.glob('*.py'): + text = file.read_text() + text = re.sub(r' (more_itertools)', rf' {new_root}.\1', text) + text = re.sub(r' (jaraco\.\w+)', rf' {new_root}.\1', text) + text = re.sub(r' (packaging)', rf' {new_root}.\1', text) + text = re.sub(r' (importlib_metadata)', rf' {new_root}.\1', text) + file.write_text(text) + + def clean(vendor): """ Remove all files out of the vendor directory except the meta @@ -133,6 +143,7 @@ def update_setuptools(): rewrite_importlib_resources(vendor / 'importlib_resources', 'setuptools.extern') rewrite_importlib_metadata(vendor / 'importlib_metadata', 'setuptools.extern') rewrite_more_itertools(vendor / "more_itertools") + rewrite_nspektr(vendor / "nspektr", 'setuptools.extern') __name__ == '__main__' and update_vendored() |