diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 833a3217..00000000 --- a/.coveragerc +++ /dev/null @@ -1,19 +0,0 @@ -[run] -omit = - # leading `*/` for pytest-dev/pytest-cov#456 - */.tox/* - */pep517-build-env-* - tests/* - prepare/* - */_itertools.py - exercises.py - */pip-run-* -disable_warnings = - couldnt-parse - -[report] -show_missing = True -exclude_also = - # jaraco/skeleton#97 - @overload - if TYPE_CHECKING: diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 304196f8..00000000 --- a/.editorconfig +++ /dev/null @@ -1,19 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_style = tab -indent_size = 4 -insert_final_newline = true -end_of_line = lf - -[*.py] -indent_style = space -max_line_length = 88 - -[*.{yml,yaml}] -indent_style = space -indent_size = 2 - -[*.rst] -indent_style = space diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 5cbfe040..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -tidelift: pypi/importlib-metadata diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 89ff3396..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,8 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "daily" - allow: - - dependency-type: "all" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index ac0ff69e..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: tests - -on: - merge_group: - push: - branches-ignore: - # temporary GH branches relating to merge queues (jaraco/skeleton#93) - - gh-readonly-queue/** - tags: - # required if branches-ignore is supplied (jaraco/skeleton#103) - - '**' - pull_request: - -permissions: - contents: read - -env: - # Environment variable to support color support (jaraco/skeleton#66) - FORCE_COLOR: 1 - - # Suppress noisy pip warnings - PIP_DISABLE_PIP_VERSION_CHECK: 'true' - PIP_NO_PYTHON_VERSION_WARNING: 'true' - PIP_NO_WARN_SCRIPT_LOCATION: 'true' - - # Ensure tests can sense settings about the environment - TOX_OVERRIDE: >- - testenv.pass_env+=GITHUB_*,FORCE_COLOR - - -jobs: - test: - strategy: - # https://blog.jaraco.com/efficient-use-of-ci-resources/ - matrix: - python: - - "3.8" - - "3.12" - platform: - - ubuntu-latest - - macos-latest - - windows-latest - include: - - python: "3.9" - platform: ubuntu-latest - - python: "3.10" - platform: ubuntu-latest - - python: "3.11" - platform: ubuntu-latest - - python: pypy3.10 - platform: ubuntu-latest - runs-on: ${{ matrix.platform }} - continue-on-error: ${{ matrix.python == '3.13' }} - steps: - - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - allow-prereleases: true - - name: Install tox - run: python -m pip install tox - - name: Run - run: tox - - collateral: - strategy: - fail-fast: false - matrix: - job: - - diffcov - - docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: 3.x - - name: Install tox - run: python -m pip install tox - - name: Eval ${{ matrix.job }} - run: tox -e ${{ matrix.job }} - - check: # This job does nothing and is only used for the branch protection - if: always() - - needs: - - test - - collateral - - runs-on: ubuntu-latest - - steps: - - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@release/v1 - with: - jobs: ${{ toJSON(needs) }} - - release: - permissions: - contents: write - needs: - - check - if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: 3.x - - name: Install tox - run: python -m pip install tox - - name: Run - run: tox -e release - env: - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ae864d61..00000000 --- a/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -build -/coverage.xml -/diffcov.html -htmlcov -importlib_metadata.egg-info -.mypy_cache -/.coverage -/.DS_Store -artifacts -.eggs -.doctrees -dist -pip-wheel-metadata diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 5a4a7e91..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -repos: -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.8 - hooks: - - id: ruff - - id: ruff-format diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index dc8516ac..00000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -python: - install: - - path: . - extra_requirements: - - doc - -# required boilerplate readthedocs/readthedocs.org#10401 -build: - os: ubuntu-lts-latest - tools: - python: latest - # post-checkout job to ensure the clone isn't shallow jaraco/skeleton#114 - jobs: - post_checkout: - - git fetch --unshallow || true diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d6456956..00000000 --- a/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/importlib_metadata/__init__.py b/Lib/importlib/metadata/__init__.py similarity index 98% rename from importlib_metadata/__init__.py rename to Lib/importlib/metadata/__init__.py index 2c71d33c..b59587e8 100644 --- a/importlib_metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -5,11 +5,11 @@ import abc import sys import json -import zipp import email import types import inspect import pathlib +import zipfile import operator import textwrap import functools @@ -18,12 +18,7 @@ import collections from . import _meta -from .compat import py39, py311 from ._collections import FreezableDefaultDict, Pair -from ._compat import ( - NullFinder, - install, -) from ._functools import method_cache, pass_none from ._itertools import always_iterable, bucket, unique_everseen from ._meta import PackageMetadata, SimplePath @@ -280,7 +275,7 @@ def select(self, **params) -> EntryPoints: Select entry points from self that match the given parameters (typically group and/or name). """ - return EntryPoints(ep for ep in self if py39.ep_matches(ep, **params)) + return EntryPoints(ep for ep in self if ep.matches(**params)) @property def names(self) -> Set[str]: @@ -560,7 +555,8 @@ def _read_files_egginfo_installed(self): return paths = ( - py311.relative_fix((subdir / name).resolve()) + (subdir / name) + .resolve() .relative_to(self.locate_file('').resolve(), walk_up=True) .as_posix() for name in text.splitlines() @@ -741,7 +737,7 @@ def children(self): return [] def zip_children(self): - zip_path = zipp.Path(self.root) + zip_path = zipfile.Path(self.root) names = zip_path.root.namelist() self.joinpath = zip_path.joinpath @@ -861,14 +857,7 @@ def __bool__(self): return bool(self.name) -@install -class MetadataPathFinder(NullFinder, DistributionFinder): - """A degenerate finder for distribution packages on the file system. - - This finder supplies only a find_distributions() method for versions - of Python that do not have a PathFinder find_distributions(). - """ - +class MetadataPathFinder(DistributionFinder): @classmethod def find_distributions( cls, context=DistributionFinder.Context() @@ -990,7 +979,7 @@ def version(distribution_name: str) -> str: _unique = functools.partial( unique_everseen, - key=py39.normalized_name, + key=operator.attrgetter('_normalized_name'), ) """ Wrapper for ``distributions`` to return unique distributions by name. diff --git a/importlib_metadata/_adapters.py b/Lib/importlib/metadata/_adapters.py similarity index 100% rename from importlib_metadata/_adapters.py rename to Lib/importlib/metadata/_adapters.py diff --git a/importlib_metadata/_collections.py b/Lib/importlib/metadata/_collections.py similarity index 100% rename from importlib_metadata/_collections.py rename to Lib/importlib/metadata/_collections.py diff --git a/importlib_metadata/_functools.py b/Lib/importlib/metadata/_functools.py similarity index 100% rename from importlib_metadata/_functools.py rename to Lib/importlib/metadata/_functools.py diff --git a/importlib_metadata/_itertools.py b/Lib/importlib/metadata/_itertools.py similarity index 100% rename from importlib_metadata/_itertools.py rename to Lib/importlib/metadata/_itertools.py diff --git a/importlib_metadata/_meta.py b/Lib/importlib/metadata/_meta.py similarity index 100% rename from importlib_metadata/_meta.py rename to Lib/importlib/metadata/_meta.py diff --git a/importlib_metadata/_text.py b/Lib/importlib/metadata/_text.py similarity index 100% rename from importlib_metadata/_text.py rename to Lib/importlib/metadata/_text.py diff --git a/importlib_metadata/diagnose.py b/Lib/importlib/metadata/diagnose.py similarity index 100% rename from importlib_metadata/diagnose.py rename to Lib/importlib/metadata/diagnose.py diff --git a/tests/_context.py b/Lib/test/test_importlib/metadata/_context.py similarity index 100% rename from tests/_context.py rename to Lib/test/test_importlib/metadata/_context.py diff --git a/tests/_path.py b/Lib/test/test_importlib/metadata/_path.py similarity index 100% rename from tests/_path.py rename to Lib/test/test_importlib/metadata/_path.py diff --git a/docs/__init__.py b/Lib/test/test_importlib/metadata/data/__init__.py similarity index 100% rename from docs/__init__.py rename to Lib/test/test_importlib/metadata/data/__init__.py diff --git a/tests/data/example-21.12-py3-none-any.whl b/Lib/test/test_importlib/metadata/data/example-21.12-py3-none-any.whl similarity index 100% rename from tests/data/example-21.12-py3-none-any.whl rename to Lib/test/test_importlib/metadata/data/example-21.12-py3-none-any.whl diff --git a/tests/data/example-21.12-py3.6.egg b/Lib/test/test_importlib/metadata/data/example-21.12-py3.6.egg similarity index 100% rename from tests/data/example-21.12-py3.6.egg rename to Lib/test/test_importlib/metadata/data/example-21.12-py3.6.egg diff --git a/tests/data/example2-1.0.0-py3-none-any.whl b/Lib/test/test_importlib/metadata/data/example2-1.0.0-py3-none-any.whl similarity index 100% rename from tests/data/example2-1.0.0-py3-none-any.whl rename to Lib/test/test_importlib/metadata/data/example2-1.0.0-py3-none-any.whl diff --git a/tests/data/sources/example/example/__init__.py b/Lib/test/test_importlib/metadata/data/sources/example/example/__init__.py similarity index 100% rename from tests/data/sources/example/example/__init__.py rename to Lib/test/test_importlib/metadata/data/sources/example/example/__init__.py diff --git a/tests/data/sources/example/setup.py b/Lib/test/test_importlib/metadata/data/sources/example/setup.py similarity index 100% rename from tests/data/sources/example/setup.py rename to Lib/test/test_importlib/metadata/data/sources/example/setup.py diff --git a/tests/data/sources/example2/example2/__init__.py b/Lib/test/test_importlib/metadata/data/sources/example2/example2/__init__.py similarity index 100% rename from tests/data/sources/example2/example2/__init__.py rename to Lib/test/test_importlib/metadata/data/sources/example2/example2/__init__.py diff --git a/tests/data/sources/example2/pyproject.toml b/Lib/test/test_importlib/metadata/data/sources/example2/pyproject.toml similarity index 100% rename from tests/data/sources/example2/pyproject.toml rename to Lib/test/test_importlib/metadata/data/sources/example2/pyproject.toml diff --git a/tests/fixtures.py b/Lib/test/test_importlib/metadata/fixtures.py similarity index 98% rename from tests/fixtures.py rename to Lib/test/test_importlib/metadata/fixtures.py index 187f1705..826b1b32 100644 --- a/tests/fixtures.py +++ b/Lib/test/test_importlib/metadata/fixtures.py @@ -7,8 +7,9 @@ import functools import contextlib -from .compat.py312 import import_helper -from .compat.py39 import os_helper +from test.support import import_helper +from test.support import os_helper +from test.support import requires_zlib from . import _path from ._path import FilesSpec @@ -362,8 +363,9 @@ def DALS(str): return textwrap.dedent(str).lstrip() +@requires_zlib() class ZipFixtures: - root = 'tests.data' + root = 'test.test_importlib.metadata.data' def _fixture_on_path(self, filename): pkg_file = resources.files(self.root).joinpath(filename) diff --git a/Lib/test/test_importlib/metadata/stubs.py b/Lib/test/test_importlib/metadata/stubs.py new file mode 100644 index 00000000..e5b011c3 --- /dev/null +++ b/Lib/test/test_importlib/metadata/stubs.py @@ -0,0 +1,10 @@ +import unittest + + +class fake_filesystem_unittest: + """ + Stubbed version of the pyfakefs module + """ + class TestCase(unittest.TestCase): + def setUpPyfakefs(self): + self.skipTest("pyfakefs not available") diff --git a/tests/test_api.py b/Lib/test/test_importlib/metadata/test_api.py similarity index 98% rename from tests/test_api.py rename to Lib/test/test_importlib/metadata/test_api.py index 7ce0cd64..813febf2 100644 --- a/tests/test_api.py +++ b/Lib/test/test_importlib/metadata/test_api.py @@ -4,7 +4,7 @@ import importlib from . import fixtures -from importlib_metadata import ( +from importlib.metadata import ( Distribution, PackageNotFoundError, distribution, @@ -144,10 +144,6 @@ def test_metadata_for_this_package(self): classifiers = md.get_all('Classifier') assert 'Topic :: Software Development :: Libraries' in classifiers - def test_importlib_metadata_version(self): - resolved = version('importlib-metadata') - assert re.match(self.version_pattern, resolved) - def test_missing_key(self): """ Requesting a missing key raises KeyError. diff --git a/tests/test_main.py b/Lib/test/test_importlib/metadata/test_main.py similarity index 97% rename from tests/test_main.py rename to Lib/test/test_importlib/metadata/test_main.py index dc248492..a0bc8222 100644 --- a/tests/test_main.py +++ b/Lib/test/test_importlib/metadata/test_main.py @@ -2,14 +2,17 @@ import pickle import unittest import importlib -import importlib_metadata -from .compat.py39 import os_helper +import importlib.metadata +from test.support import os_helper -import pyfakefs.fake_filesystem_unittest as ffs +try: + import pyfakefs.fake_filesystem_unittest as ffs +except ImportError: + from .stubs import fake_filesystem_unittest as ffs from . import fixtures from ._path import Symlink -from importlib_metadata import ( +from importlib.metadata import ( Distribution, EntryPoint, PackageNotFoundError, @@ -77,10 +80,10 @@ def test_entrypoint_with_colon_in_name(self): def test_resolve_without_attr(self): ep = EntryPoint( name='ep', - value='importlib_metadata', + value='importlib.metadata', group='grp', ) - assert ep.load() is importlib_metadata + assert ep.load() is importlib.metadata class NameNormalizationTests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase): @@ -258,7 +261,7 @@ def test_discovery(self): Discovering distributions should succeed even if there is an invalid path on sys.path. """ - importlib_metadata.distributions() + importlib.metadata.distributions() class InaccessibleSysPath(fixtures.OnSysPath, ffs.TestCase): @@ -274,13 +277,13 @@ def test_discovery(self): Discovering distributions should succeed even if there is an invalid path on sys.path. """ - list(importlib_metadata.distributions()) + list(importlib.metadata.distributions()) class TestEntryPoints(unittest.TestCase): def __init__(self, *args): super().__init__(*args) - self.ep = importlib_metadata.EntryPoint( + self.ep = importlib.metadata.EntryPoint( name='name', value='value', group='group' ) diff --git a/tests/test_zip.py b/Lib/test/test_importlib/metadata/test_zip.py similarity index 98% rename from tests/test_zip.py rename to Lib/test/test_importlib/metadata/test_zip.py index 01aba6df..276f6288 100644 --- a/tests/test_zip.py +++ b/Lib/test/test_importlib/metadata/test_zip.py @@ -2,7 +2,7 @@ import unittest from . import fixtures -from importlib_metadata import ( +from importlib.metadata import ( PackageNotFoundError, distribution, distributions, diff --git a/NEWS.rst b/NEWS.rst deleted file mode 100644 index 2e22a335..00000000 --- a/NEWS.rst +++ /dev/null @@ -1,971 +0,0 @@ -v8.2.0 -====== - -Features --------- - -- Add SimplePath to importlib_metadata.__all__. (#494) - - -v8.1.0 -====== - -Features --------- - -- Prioritize valid dists to invalid dists when retrieving by name. (#489) - - -v8.0.0 -====== - -Deprecations and Removals -------------------------- - -- Message.__getitem__ now raises a KeyError on missing keys. (#371) -- Removed deprecated support for Distribution subclasses not implementing abstract methods. - - -v7.2.1 -====== - -Bugfixes --------- - -- When reading installed files from an egg, use ``relative_to(walk_up=True)`` to honor files installed outside of the installation root. (#455) - - -v7.2.0 -====== - -Features --------- - -- Deferred select imports in for speedup (python/cpython#109829). -- Updated fixtures for python/cpython#120801. - - -v7.1.0 -====== - -Features --------- - -- Improve import time (python/cpython#114664). - - -Bugfixes --------- - -- Make MetadataPathFinder.find_distributions a classmethod for consistency with CPython. Closes #484. (#484) -- Allow ``MetadataPathFinder.invalidate_caches`` to be called as a classmethod. - - -v7.0.2 -====== - -No significant changes. - - -v7.0.1 -====== - -Bugfixes --------- - -- Corrected the interface for SimplePath to encompass the expectations of locate_file and PackagePath. -- Fixed type annotations to allow strings. - - -v7.0.0 -====== - -Deprecations and Removals -------------------------- - -- Removed EntryPoint access by numeric index (tuple behavior). - - -v6.11.0 -======= - -Features --------- - -- Added ``Distribution.origin`` supplying the ``direct_url.json`` in a ``SimpleNamespace``. (#404) - - -v6.10.0 -======= - -Features --------- - -- Added diagnose script. (#461) - - -v6.9.0 -====== - -Features --------- - -- Added EntryPoints.__repr__ (#473) - - -v6.8.0 -====== - -Features --------- - -- Require Python 3.8 or later. - - -v6.7.0 -====== - -* #453: When inferring top-level names that are importable for - distributions in ``package_distributions``, now symlinks to - other directories are honored. - -v6.6.0 -====== - -* #449: Expanded type annotations. - -v6.5.1 -====== - -* python/cpython#103661: Removed excess error suppression in - ``_read_files_egginfo_installed`` and fixed path handling - on Windows. - -v6.5.0 -====== - -* #422: Removed ABC metaclass from ``Distribution`` and instead - deprecated construction of ``Distribution`` objects without - concrete methods. - -v6.4.1 -====== - -* Updated docs with tweaks from upstream CPython. - -v6.4.0 -====== - -* Consolidated some behaviors in tests around ``_path``. -* Added type annotation for ``Distribution.read_text``. - -v6.3.0 -====== - -* #115: Support ``installed-files.txt`` for ``Distribution.files`` - when present. - -v6.2.1 -====== - -* #442: Fixed issue introduced in v6.1.0 where non-importable - names (metadata dirs) began appearing in - ``packages_distributions``. - -v6.2.0 -====== - -* #384: ``PackageMetadata`` now stipulates an additional ``get`` - method allowing for easy querying of metadata keys that may not - be present. - -v6.1.0 -====== - -* #428: ``packages_distributions`` now honors packages and modules - with Python modules that not ``.py`` sources (e.g. ``.pyc``, - ``.so``). - -v6.0.1 -====== - -* #434: Expand protocol for ``PackageMetadata.get_all`` to match - the upstream implementation of ``email.message.Message.get_all`` - in python/typeshed#9620. - -v6.0.0 -====== - -* #419: Declared ``Distribution`` as an abstract class, enforcing - definition of abstract methods in instantiated subclasses. It's no - longer possible to instantiate a ``Distribution`` or any subclasses - unless they define the abstract methods. - - Please comment in the issue if this change breaks any projects. - This change will likely be rolled back if it causes significant - disruption. - -v5.2.0 -====== - -* #371: Deprecated expectation that ``PackageMetadata.__getitem__`` - will return ``None`` for missing keys. In the future, it will raise a - ``KeyError``. - -v5.1.0 -====== - -* #415: Instrument ``SimplePath`` with generic support. - -v5.0.0 -====== - -* #97, #284, #300: Removed compatibility shims for deprecated entry - point interfaces. - -v4.13.0 -======= - -* #396: Added compatibility for ``PathDistributions`` originating - from Python 3.8 and 3.9. - -v4.12.0 -======= - -* py-93259: Now raise ``ValueError`` when ``None`` or an empty - string are passed to ``Distribution.from_name`` (and other - callers). - -v4.11.4 -======= - -* #379: In ``PathDistribution._name_from_stem``, avoid including - parts of the extension in the result. -* #381: In ``PathDistribution._normalized_name``, ensure names - loaded from the stem of the filename are also normalized, ensuring - duplicate entry points by packages varying only by non-normalized - name are hidden. - -Note (#459): This change had a backward-incompatible effect for -any installers that created metadata in the filesystem with dashes -in the package names (not replaced by underscores). - -v4.11.3 -======= - -* #372: Removed cast of path items in FastPath, not needed. - -v4.11.2 -======= - -* #369: Fixed bug where ``EntryPoint.extras`` was returning - match objects and not the extras strings. - -v4.11.1 -======= - -* #367: In ``Distribution.requires`` for egg-info, if ``requires.txt`` - is empty, return an empty list. - -v4.11.0 -======= - -* bpo-46246: Added ``__slots__`` to ``EntryPoints``. - -v4.10.2 -======= - -* #365 and bpo-46546: Avoid leaking ``method_name`` in - ``DeprecatedList``. - -v4.10.1 -======= - -v2.1.3 -======= - -* #361: Avoid potential REDoS in ``EntryPoint.pattern``. - -v4.10.0 -======= - -* #354: Removed ``Distribution._local`` factory. This - functionality was created as a demonstration of the - possible implementation. Now, the - `pep517 `_ package - provides this functionality directly through - `pep517.meta.load `_. - -v4.9.0 -====== - -* Require Python 3.7 or later. - -v4.8.3 -====== - -* #357: Fixed requirement generation from egg-info when a - URL requirement is given. - -v4.8.2 -====== - -v2.1.2 -====== - -* #353: Fixed discovery of distributions when path is empty. - -v4.8.1 -====== - -* #348: Restored support for ``EntryPoint`` access by item, - deprecating support in the process. Users are advised - to use direct member access instead of item-based access:: - - - ep[0] -> ep.name - - ep[1] -> ep.value - - ep[2] -> ep.group - - ep[:] -> ep.name, ep.value, ep.group - -v4.8.0 -====== - -* #337: Rewrote ``EntryPoint`` as a simple class, still - immutable and still with the attributes, but without any - expectation for ``namedtuple`` functionality such as - ``_asdict``. - -v4.7.1 -====== - -* #344: Fixed regression in ``packages_distributions`` when - neither top-level.txt nor a files manifest is present. - -v4.7.0 -====== - -* #330: In ``packages_distributions``, now infer top-level - names from ``.files()`` when a ``top-level.txt`` - (Setuptools-specific metadata) is not present. - -v4.6.4 -====== - -* #334: Correct ``SimplePath`` protocol to match ``pathlib`` - protocol for ``__truediv__``. - -v4.6.3 -====== - -* Moved workaround for #327 to ``_compat`` module. - -v4.6.2 -====== - -* bpo-44784: Avoid errors in test suite when - DeprecationWarnings are treated as errors. - -v4.6.1 -====== - -* #327: Deprecation warnings now honor call stack variance - on PyPy. - -v4.6.0 -====== - -* #326: Performance tests now rely on - `pytest-perf `_. - To disable these tests, which require network access - and a git checkout, pass ``-p no:perf`` to pytest. - -v4.5.0 -====== - -* #319: Remove ``SelectableGroups`` deprecation exception - for flake8. - -v4.4.0 -====== - -* #300: Restore compatibility in the result from - ``Distribution.entry_points`` (``EntryPoints``) to honor - expectations in older implementations and issuing - deprecation warnings for these cases: - - - ``EntryPoints`` objects are once again mutable, allowing - for ``sort()`` and other list-based mutation operations. - Avoid deprecation warnings by casting to a - mutable sequence (e.g. - ``list(dist.entry_points).sort()``). - - - ``EntryPoints`` results once again allow - for access by index. To avoid deprecation warnings, - cast the result to a Sequence first - (e.g. ``tuple(dist.entry_points)[0]``). - -v4.3.1 -====== - -* #320: Fix issue where normalized name for eggs was - incorrectly solicited, leading to metadata being - unavailable for eggs. - -v4.3.0 -====== - -* #317: De-duplication of distributions no longer requires - loading the full metadata for ``PathDistribution`` objects, - entry point loading performance by ~10x. - -v4.2.0 -====== - -* Prefer f-strings to ``.format`` calls. - -v4.1.0 -====== - -* #312: Add support for metadata 2.2 (``Dynamic`` field). - -* #315: Add ``SimplePath`` protocol for interface clarity - in ``PathDistribution``. - -v4.0.1 -====== - -* #306: Clearer guidance about compatibility in readme. - -v4.0.0 -====== - -* #304: ``PackageMetadata`` as returned by ``metadata()`` - and ``Distribution.metadata()`` now provides normalized - metadata honoring PEP 566: - - - If a long description is provided in the payload of the - RFC 822 value, it can be retrieved as the ``Description`` - field. - - Any multi-line values in the metadata will be returned as - such. - - For any multi-line values, line continuation characters - are removed. This backward-incompatible change means - that any projects relying on the RFC 822 line continuation - characters being present must be tolerant to them having - been removed. - - Add a ``json`` property that provides the metadata - converted to a JSON-compatible form per PEP 566. - - -v3.10.1 -======= - -* Minor tweaks from CPython. - -v3.10.0 -======= - -* #295: Internal refactoring to unify section parsing logic. - -v3.9.1 -====== - -* #296: Exclude 'prepare' package. -* #297: Fix ValueError when entry points contains comments. - -v3.9.0 -====== - -* Use of Mapping (dict) interfaces on ``SelectableGroups`` - is now flagged as deprecated. Instead, users are advised - to use the select interface for future compatibility. - - Suppress the warning with this filter: - ``ignore:SelectableGroups dict interface``. - - Or with this invocation in the Python environment: - ``warnings.filterwarnings('ignore', 'SelectableGroups dict interface')``. - - Preferably, switch to the ``select`` interface introduced - in 3.7.0. See the - `entry points documentation `_ and changelog for the 3.6 - release below for more detail. - - For some use-cases, especially those that rely on - ``importlib.metadata`` in Python 3.8 and 3.9 or - those relying on older ``importlib_metadata`` (especially - on Python 3.5 and earlier), - `backports.entry_points_selectable `_ - was created to ease the transition. Please have a look - at that project if simply relying on importlib_metadata 3.6+ - is not straightforward. Background in #298. - -* #283: Entry point parsing no longer relies on ConfigParser - and instead uses a custom, one-pass parser to load the - config, resulting in a ~20% performance improvement when - loading entry points. - -v3.8.2 -====== - -* #293: Re-enabled lazy evaluation of path lookup through - a FreezableDefaultDict. - -v3.8.1 -====== - -* #293: Workaround for error in distribution search. - -v3.8.0 -====== - -* #290: Add mtime-based caching for ``FastPath`` and its - lookups, dramatically increasing performance for repeated - distribution lookups. - -v3.7.3 -====== - -* Docs enhancements and cleanup following review in - `GH-24782 `_. - -v3.7.2 -====== - -* Cleaned up cruft in entry_points docstring. - -v3.7.1 -====== - -* Internal refactoring to facilitate ``entry_points() -> dict`` - deprecation. - -v3.7.0 -====== - -* #131: Added ``packages_distributions`` to conveniently - resolve a top-level package or module to its distribution(s). - -v3.6.0 -====== - -* #284: Introduces new ``EntryPoints`` object, a tuple of - ``EntryPoint`` objects but with convenience properties for - selecting and inspecting the results: - - - ``.select()`` accepts ``group`` or ``name`` keyword - parameters and returns a new ``EntryPoints`` tuple - with only those that match the selection. - - ``.groups`` property presents all of the group names. - - ``.names`` property presents the names of the entry points. - - Item access (e.g. ``eps[name]``) retrieves a single - entry point by name. - - ``entry_points`` now accepts "selection parameters", - same as ``EntryPoint.select()``. - - ``entry_points()`` now provides a future-compatible - ``SelectableGroups`` object that supplies the above interface - (except item access) but remains a dict for compatibility. - - In the future, ``entry_points()`` will return an - ``EntryPoints`` object for all entry points. - - If passing selection parameters to ``entry_points``, the - future behavior is invoked and an ``EntryPoints`` is the - result. - -* #284: Construction of entry points using - ``dict([EntryPoint, ...])`` is now deprecated and raises - an appropriate DeprecationWarning and will be removed in - a future version. - -* #300: ``Distribution.entry_points`` now presents as an - ``EntryPoints`` object and access by index is no longer - allowed. If access by index is required, cast to a sequence - first. - -v3.5.0 -====== - -* #280: ``entry_points`` now only returns entry points for - unique distributions (by name). - -v3.4.0 -====== - -* #10: Project now declares itself as being typed. -* #272: Additional performance enhancements to distribution - discovery. -* #111: For PyPA projects, add test ensuring that - ``MetadataPathFinder._search_paths`` honors the needed - interface. Method is still private. - -v3.3.0 -====== - -* #265: ``EntryPoint`` objects now expose a ``.dist`` object - referencing the ``Distribution`` when constructed from a - Distribution. - -v3.2.0 -====== - -* The object returned by ``metadata()`` now has a - formally-defined protocol called ``PackageMetadata`` - with declared support for the ``.get_all()`` method. - Fixes #126. - -v3.1.1 -====== - -v2.1.1 -====== - -* #261: Restored compatibility for package discovery for - metadata without version in the name and for legacy - eggs. - -v3.1.0 -====== - -* Merge with 2.1.0. - -v2.1.0 -====== - -* #253: When querying for package metadata, the lookup - now honors - `package normalization rules `_. - -v3.0.0 -====== - -* Require Python 3.6 or later. - -v2.0.0 -====== - -* ``importlib_metadata`` no longer presents a - ``__version__`` attribute. Consumers wishing to - resolve the version of the package should query it - directly with - ``importlib_metadata.version('importlib-metadata')``. - Closes #71. - -v1.7.0 -====== - -* ``PathNotFoundError`` now has a custom ``__str__`` - mentioning "package metadata" being missing to help - guide users to the cause when the package is installed - but no metadata is present. Closes #124. - -v1.6.1 -====== - -* Added ``Distribution._local()`` as a provisional - demonstration of how to load metadata for a local - package. Implicitly requires that - `pep517 `_ is - installed. Ref #42. -* Ensure inputs to FastPath are Unicode. Closes #121. -* Tests now rely on ``importlib.resources.files`` (and - backport) instead of the older ``path`` function. -* Support any iterable from ``find_distributions``. - Closes #122. - -v1.6.0 -====== - -* Added ``module`` and ``attr`` attributes to ``EntryPoint`` - -v1.5.2 -====== - -* Fix redundant entries from ``FastPath.zip_children``. - Closes #117. - -v1.5.1 -====== - -* Improve reliability and consistency of compatibility - imports for contextlib and pathlib when running tests. - Closes #116. - -v1.5.0 -====== - -* Additional performance optimizations in FastPath now - saves an additional 20% on a typical call. -* Correct for issue where PyOxidizer finder has no - ``__module__`` attribute. Closes #110. - -v1.4.0 -====== - -* Through careful optimization, ``distribution()`` is - 3-4x faster. Thanks to Antony Lee for the - contribution. Closes #95. - -* When searching through ``sys.path``, if any error - occurs attempting to list a path entry, that entry - is skipped, making the system much more lenient - to errors. Closes #94. - -v1.3.0 -====== - -* Improve custom finders documentation. Closes #105. - -v1.2.0 -====== - -* Once again, drop support for Python 3.4. Ref #104. - -v1.1.3 -====== - -* Restored support for Python 3.4 due to improper version - compatibility declarations in the v1.1.0 and v1.1.1 - releases. Closes #104. - -v1.1.2 -====== - -* Repaired project metadata to correctly declare the - ``python_requires`` directive. Closes #103. - -v1.1.1 -====== - -* Fixed ``repr(EntryPoint)`` on PyPy 3 also. Closes #102. - -v1.1.0 -====== - -* Dropped support for Python 3.4. -* EntryPoints are now pickleable. Closes #96. -* Fixed ``repr(EntryPoint)`` on PyPy 2. Closes #97. - -v1.0.0 -====== - -* Project adopts semver for versioning. - -* Removed compatibility shim introduced in 0.23. - -* For better compatibility with the stdlib implementation and to - avoid the same distributions being discovered by the stdlib and - backport implementations, the backport now disables the - stdlib DistributionFinder during initialization (import time). - Closes #91 and closes #100. - -0.23 -==== - -* Added a compatibility shim to prevent failures on beta releases - of Python before the signature changed to accept the - "context" parameter on find_distributions. This workaround - will have a limited lifespan, not to extend beyond release of - Python 3.8 final. - -0.22 -==== - -* Renamed ``package`` parameter to ``distribution_name`` - as `recommended `_ - in the following functions: ``distribution``, ``metadata``, - ``version``, ``files``, and ``requires``. This - backward-incompatible change is expected to have little impact - as these functions are assumed to be primarily used with - positional parameters. - -0.21 -==== - -* ``importlib.metadata`` now exposes the ``DistributionFinder`` - metaclass and references it in the docs for extending the - search algorithm. -* Add ``Distribution.at`` for constructing a Distribution object - from a known metadata directory on the file system. Closes #80. -* Distribution finders now receive a context object that - supplies ``.path`` and ``.name`` properties. This change - introduces a fundamental backward incompatibility for - any projects implementing a ``find_distributions`` method - on a ``MetaPathFinder``. This new layer of abstraction - allows this context to be supplied directly or constructed - on demand and opens the opportunity for a - ``find_distributions`` method to solicit additional - context from the caller. Closes #85. - -0.20 -==== - -* Clarify in the docs that calls to ``.files`` could return - ``None`` when the metadata is not present. Closes #69. -* Return all requirements and not just the first for dist-info - packages. Closes #67. - -0.19 -==== - -* Restrain over-eager egg metadata resolution. -* Add support for entry points with colons in the name. Closes #75. - -0.18 -==== - -* Parse entry points case sensitively. Closes #68 -* Add a version constraint on the backport configparser package. Closes #66 - -0.17 -==== - -* Fix a permission problem in the tests on Windows. - -0.16 -==== - -* Don't crash if there exists an EGG-INFO directory on sys.path. - -0.15 -==== - -* Fix documentation. - -0.14 -==== - -* Removed ``local_distribution`` function from the API. - **This backward-incompatible change removes this - behavior summarily**. Projects should remove their - reliance on this behavior. A replacement behavior is - under review in the `pep517 project - `_. Closes #42. - -0.13 -==== - -* Update docstrings to match PEP 8. Closes #63. -* Merged modules into one module. Closes #62. - -0.12 -==== - -* Add support for eggs. !65; Closes #19. - -0.11 -==== - -* Support generic zip files (not just wheels). Closes #59 -* Support zip files with multiple distributions in them. Closes #60 -* Fully expose the public API in ``importlib_metadata.__all__``. - -0.10 -==== - -* The ``Distribution`` ABC is now officially part of the public API. - Closes #37. -* Fixed support for older single file egg-info formats. Closes #43. -* Fixed a testing bug when ``$CWD`` has spaces in the path. Closes #50. -* Add Python 3.8 to the ``tox`` testing matrix. - -0.9 -=== - -* Fixed issue where entry points without an attribute would raise an - Exception. Closes #40. -* Removed unused ``name`` parameter from ``entry_points()``. Closes #44. -* ``DistributionFinder`` classes must now be instantiated before - being placed on ``sys.meta_path``. - -0.8 -=== - -* This library can now discover/enumerate all installed packages. **This - backward-incompatible change alters the protocol finders must - implement to support distribution package discovery.** Closes #24. -* The signature of ``find_distributions()`` on custom installer finders - should now accept two parameters, ``name`` and ``path`` and - these parameters must supply defaults. -* The ``entry_points()`` method no longer accepts a package name - but instead returns all entry points in a dictionary keyed by the - ``EntryPoint.group``. The ``resolve`` method has been removed. Instead, - call ``EntryPoint.load()``, which has the same semantics as - ``pkg_resources`` and ``entrypoints``. **This is a backward incompatible - change.** -* Metadata is now always returned as Unicode text regardless of - Python version. Closes #29. -* This library can now discover metadata for a 'local' package (found - in the current-working directory). Closes #27. -* Added ``files()`` function for resolving files from a distribution. -* Added a new ``requires()`` function, which returns the requirements - for a package suitable for parsing by - ``packaging.requirements.Requirement``. Closes #18. -* The top-level ``read_text()`` function has been removed. Use - ``PackagePath.read_text()`` on instances returned by the ``files()`` - function. **This is a backward incompatible change.** -* Release dates are now automatically injected into the changelog - based on SCM tags. - -0.7 -=== - -* Fixed issue where packages with dashes in their names would - not be discovered. Closes #21. -* Distribution lookup is now case-insensitive. Closes #20. -* Wheel distributions can no longer be discovered by their module - name. Like Path distributions, they must be indicated by their - distribution package name. - -0.6 -=== - -* Removed ``importlib_metadata.distribution`` function. Now - the public interface is primarily the utility functions exposed - in ``importlib_metadata.__all__``. Closes #14. -* Added two new utility functions ``read_text`` and - ``metadata``. - -0.5 -=== - -* Updated README and removed details about Distribution - class, now considered private. Closes #15. -* Added test suite support for Python 3.4+. -* Fixed SyntaxErrors on Python 3.4 and 3.5. !12 -* Fixed errors on Windows joining Path elements. !15 - -0.4 -=== - -* Housekeeping. - -0.3 -=== - -* Added usage documentation. Closes #8 -* Add support for getting metadata from wheels on ``sys.path``. Closes #9 - -0.2 -=== - -* Added ``importlib_metadata.entry_points()``. Closes #1 -* Added ``importlib_metadata.resolve()``. Closes #12 -* Add support for Python 2.7. Closes #4 - -0.1 -=== - -* Initial release. - - -.. - Local Variables: - mode: change-log-mode - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 78 - coding: utf-8 - End: diff --git a/README.rst b/README.rst deleted file mode 100644 index ffb63387..00000000 --- a/README.rst +++ /dev/null @@ -1,90 +0,0 @@ -.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg - :target: https://pypi.org/project/importlib_metadata - -.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg - -.. image:: https://github.com/python/importlib_metadata/actions/workflows/main.yml/badge.svg - :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22 - :alt: tests - -.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json - :target: https://github.com/astral-sh/ruff - :alt: Ruff - -.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest - :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest - -.. image:: https://img.shields.io/badge/skeleton-2024-informational - :target: https://blog.jaraco.com/skeleton - -.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata - :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme - -Library to access the metadata for a Python package. - -This package supplies third-party access to the functionality of -`importlib.metadata `_ -including improvements added to subsequent Python versions. - - -Compatibility -============= - -New features are introduced in this third-party library and later merged -into CPython. The following table indicates which versions of this library -were contributed to different versions in the standard library: - -.. list-table:: - :header-rows: 1 - - * - importlib_metadata - - stdlib - * - 7.0 - - 3.13 - * - 6.5 - - 3.12 - * - 4.13 - - 3.11 - * - 4.6 - - 3.10 - * - 1.4 - - 3.8 - - -Usage -===== - -See the `online documentation `_ -for usage details. - -`Finder authors -`_ can -also add support for custom package installers. See the above documentation -for details. - - -Caveats -======= - -This project primarily supports third-party packages installed by PyPA -tools (or other conforming packages). It does not support: - -- Packages in the stdlib. -- Packages installed without metadata. - -Project details -=============== - - * Project home: https://github.com/python/importlib_metadata - * Report bugs at: https://github.com/python/importlib_metadata/issues - * Code hosting: https://github.com/python/importlib_metadata - * Documentation: https://importlib-metadata.readthedocs.io/ - -For Enterprise -============== - -Available as part of the Tidelift Subscription. - -This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. - -`Learn more `_. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 54f99acb..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,3 +0,0 @@ -# Security Contact - -To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/conftest.py b/conftest.py deleted file mode 100644 index 779ac24b..00000000 --- a/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys - - -collect_ignore = [ - # this module fails mypy tests because 'setup.py' matches './setup.py' - 'tests/data/sources/example/setup.py', -] - - -def pytest_configure(): - remove_importlib_metadata() - - -def remove_importlib_metadata(): - """ - Because pytest imports importlib_metadata, the coverage - reports are broken (#322). So work around the issue by - undoing the changes made by pytest's import of - importlib_metadata (if any). - """ - if sys.meta_path[-1].__class__.__name__ == 'MetadataPathFinder': - del sys.meta_path[-1] - for mod in list(sys.modules): - if mod.startswith('importlib_metadata'): - del sys.modules[mod] diff --git a/docs/api.rst b/docs/api.rst deleted file mode 100644 index d22eecd5..00000000 --- a/docs/api.rst +++ /dev/null @@ -1,16 +0,0 @@ -============= -API Reference -============= - -``importlib_metadata`` module ------------------------------ - -.. automodule:: importlib_metadata - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: importlib_metadata._meta - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 2cd8fb0c..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,72 +0,0 @@ -extensions = [ - 'sphinx.ext.autodoc', - 'jaraco.packaging.sphinx', -] - -master_doc = "index" -html_theme = "furo" - -# Link dates and other references in the changelog -extensions += ['rst.linker'] -link_files = { - '../NEWS.rst': dict( - using=dict(GH='https://github.com'), - replace=[ - dict( - pattern=r'(Issue #|\B#)(?P\d+)', - url='{package_url}/issues/{issue}', - ), - dict( - pattern=r'(?m:^((?Pv?\d+(\.\d+){1,2}))\n[-=]+\n)', - with_scm='{text}\n{rev[timestamp]:%d %b %Y}\n', - ), - dict( - pattern=r'PEP[- ](?P\d+)', - url='https://peps.python.org/pep-{pep_number:0>4}/', - ), - dict( - pattern=r'(python/cpython#|Python #|py-)(?P\d+)', - url='https://github.com/python/cpython/issues/{python}', - ), - ], - ) -} - -# Be strict about any broken references -nitpicky = True - -# Include Python intersphinx mapping to prevent failures -# jaraco/skeleton#51 -extensions += ['sphinx.ext.intersphinx'] -intersphinx_mapping = { - 'python': ('https://docs.python.org/3', None), -} - -# Preserve authored syntax for defaults -autodoc_preserve_defaults = True - -extensions += ['jaraco.tidelift'] - -intersphinx_mapping.update( - importlib_resources=( - 'https://importlib-resources.readthedocs.io/en/latest/', - None, - ), -) - -intersphinx_mapping.update( - packaging=( - 'https://packaging.python.org/en/latest/', - None, - ), -) - -nitpick_ignore = [ - # Workaround for #316 - ('py:class', 'importlib_metadata.EntryPoints'), - ('py:class', 'importlib_metadata.PackagePath'), - ('py:class', 'importlib_metadata.SelectableGroups'), - ('py:class', 'importlib_metadata._meta._T'), - # Workaround for #435 - ('py:class', '_T'), -] diff --git a/docs/history.rst b/docs/history.rst deleted file mode 100644 index 5bdc2320..00000000 --- a/docs/history.rst +++ /dev/null @@ -1,8 +0,0 @@ -:tocdepth: 2 - -.. _changes: - -History -******* - -.. include:: ../NEWS (links).rst diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 66755216..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,41 +0,0 @@ -Welcome to |project| documentation! -=================================== - -.. sidebar-links:: - :home: - :pypi: - -``importlib_metadata`` supplies a backport of :mod:`importlib.metadata`, -enabling early access to features of future Python versions and making -functionality available for older Python versions. Users are encouraged to -use the Python standard library where suitable and fall back to -this library for future compatibility. For general usage guidance, start -with :mod:`importlib.metadata` but substitute ``importlib_metadata`` -for ``importlib.metadata``. - - -.. toctree:: - :maxdepth: 1 - - api - migration - history - -.. tidelift-referral-banner:: - - -Project details -=============== - - * Project home: https://github.com/python/importlib_metadata - * Report bugs at: https://github.com/python/importlib_metadata/issues - * Code hosting: https://github.com/python/importlib_metadata - * Documentation: https://importlib-metadata.readthedocs.io/ - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/migration.rst b/docs/migration.rst deleted file mode 100644 index 3c700778..00000000 --- a/docs/migration.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. _migration: - -================= - Migration guide -================= - -The following guide will help you migrate common ``pkg_resources`` -APIs to ``importlib_metadata``. ``importlib_metadata`` aims to -replace the following ``pkg_resources`` APIs: - -* ``pkg_resources.iter_entry_points()`` -* ``pkg_resources.require()`` -* convenience functions -* ``pkg_resources.find_distributions()`` -* ``pkg_resources.get_distribution()`` - -Other functionality from ``pkg_resources`` is replaced by other -packages such as -`importlib_resources `_ -and `packaging `_. - - -pkg_resources.iter_entry_points() -================================= - -``importlib_metadata`` provides :ref:`entry-points`. - -Compatibility note: entry points provided by importlib_metadata -do not have the following implicit behaviors found in those -from ``pkg_resources``: - -- Each EntryPoint is not automatically validated to match. To - ensure each one is validated, invoke any property on the - object (e.g. ``ep.name``). - -- When invoking ``EntryPoint.load()``, no checks are performed - to ensure the declared extras are installed. If this behavior - is desired/required, it is left to the user to perform the - check and install any dependencies. See - `importlib_metadata#368 `_ - for more details. - -pkg_resources.require() -======================= - -``importlib_metadata`` does not provide support for dynamically -discovering or requiring distributions nor does it provide any -support for managing the "working set". Furthermore, -``importlib_metadata`` assumes that only one version of a given -distribution is discoverable at any time (no support for multi-version -installs). Any projects that require the above behavior needs to -provide that behavior independently. - -``importlib_metadata`` does aim to resolve metadata concerns late -such that any dynamic changes to package availability should be -reflected immediately. - -Convenience functions -===================== - -In addition to the support for direct access to ``Distribution`` -objects (below), ``importlib_metadata`` presents some top-level -functions for easy access to the most common metadata: - -- :ref:`metadata` queries the metadata fields from the distribution. -- :ref:`version` provides quick access to the distribution version. -- :ref:`requirements` presents the requirements of the distribution. -- :ref:`files` provides file-like access to the data blobs backing - the metadata. - -pkg_resources.find_distributions() -================================== - -``importlib_metadata`` provides functionality -similar to ``find_distributions()``. Both ``distributions(...)`` and -``Distribution.discover(...)`` return an iterable of :ref:`distributions` -matching the indicated parameters. - -pkg_resources.get_distribution() -================================= - -Similar to ``distributions``, the ``distribution()`` function provides -access to a single distribution by name. - diff --git a/exercises.py b/exercises.py deleted file mode 100644 index c88fa983..00000000 --- a/exercises.py +++ /dev/null @@ -1,45 +0,0 @@ -from pytest_perf.deco import extras - - -@extras('perf') -def discovery_perf(): - "discovery" - import importlib_metadata # end warmup - - importlib_metadata.distribution('ipython') - - -def entry_points_perf(): - "entry_points()" - import importlib_metadata # end warmup - - importlib_metadata.entry_points() - - -@extras('perf') -def cached_distribution_perf(): - "cached distribution" - import importlib_metadata - - importlib_metadata.distribution('ipython') # end warmup - importlib_metadata.distribution('ipython') - - -@extras('perf') -def uncached_distribution_perf(): - "uncached distribution" - import importlib - import importlib_metadata - - # end warmup - importlib.invalidate_caches() - importlib_metadata.distribution('ipython') - - -def entrypoint_regexp_perf(): - import importlib_metadata - import re - - input = '0' + ' ' * 2**10 + '0' # end warmup - - re.match(importlib_metadata.EntryPoint.pattern, input) diff --git a/importlib_metadata/_compat.py b/importlib_metadata/_compat.py deleted file mode 100644 index df312b1c..00000000 --- a/importlib_metadata/_compat.py +++ /dev/null @@ -1,57 +0,0 @@ -import sys -import platform - - -__all__ = ['install', 'NullFinder'] - - -def install(cls): - """ - Class decorator for installation on sys.meta_path. - - Adds the backport DistributionFinder to sys.meta_path and - attempts to disable the finder functionality of the stdlib - DistributionFinder. - """ - sys.meta_path.append(cls()) - disable_stdlib_finder() - return cls - - -def disable_stdlib_finder(): - """ - Give the backport primacy for discovering path-based distributions - by monkey-patching the stdlib O_O. - - See #91 for more background for rationale on this sketchy - behavior. - """ - - def matches(finder): - return getattr( - finder, '__module__', None - ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions') - - for finder in filter(matches, sys.meta_path): # pragma: nocover - del finder.find_distributions - - -class NullFinder: - """ - A "Finder" (aka "MetaPathFinder") that never finds any modules, - but may find distributions. - """ - - @staticmethod - def find_spec(*args, **kwargs): - return None - - -def pypy_partial(val): - """ - Adjust for variable stacklevel on partial under PyPy. - - Workaround for #327. - """ - is_pypy = platform.python_implementation() == 'PyPy' - return val + is_pypy diff --git a/importlib_metadata/compat/__init__.py b/importlib_metadata/compat/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/importlib_metadata/compat/py311.py b/importlib_metadata/compat/py311.py deleted file mode 100644 index 3a532743..00000000 --- a/importlib_metadata/compat/py311.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import pathlib -import sys -import types - - -def wrap(path): # pragma: no cover - """ - Workaround for https://github.com/python/cpython/issues/84538 - to add backward compatibility for walk_up=True. - An example affected package is dask-labextension, which uses - jupyter-packaging to install JupyterLab javascript files outside - of site-packages. - """ - - def relative_to(root, *, walk_up=False): - return pathlib.Path(os.path.relpath(path, root)) - - return types.SimpleNamespace(relative_to=relative_to) - - -relative_fix = wrap if sys.version_info < (3, 12) else lambda x: x diff --git a/importlib_metadata/compat/py39.py b/importlib_metadata/compat/py39.py deleted file mode 100644 index 1f15bd97..00000000 --- a/importlib_metadata/compat/py39.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Compatibility layer with Python 3.8/3.9 -""" - -from typing import TYPE_CHECKING, Any, Optional - -if TYPE_CHECKING: # pragma: no cover - # Prevent circular imports on runtime. - from .. import Distribution, EntryPoint -else: - Distribution = EntryPoint = Any - - -def normalized_name(dist: Distribution) -> Optional[str]: - """ - Honor name normalization for distributions that don't provide ``_normalized_name``. - """ - try: - return dist._normalized_name - except AttributeError: - from .. import Prepared # -> delay to prevent circular imports. - - return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name']) - - -def ep_matches(ep: EntryPoint, **params) -> bool: - """ - Workaround for ``EntryPoint`` objects without the ``matches`` method. - """ - try: - return ep.matches(**params) - except AttributeError: - from .. import EntryPoint # -> delay to prevent circular imports. - - # Reconstruct the EntryPoint object to make sure it is compatible. - return EntryPoint(ep.name, ep.value, ep.group).matches(**params) diff --git a/importlib_metadata/py.typed b/importlib_metadata/py.typed deleted file mode 100644 index e69de29b..00000000 diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index b6f97276..00000000 --- a/mypy.ini +++ /dev/null @@ -1,5 +0,0 @@ -[mypy] -ignore_missing_imports = True -# required to support namespace packages -# https://github.com/python/mypy/issues/14057 -explicit_package_bases = True diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 24ce25e3..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,62 +0,0 @@ -[build-system] -requires = ["setuptools>=61.2", "setuptools_scm[toml]>=3.4.1"] -build-backend = "setuptools.build_meta" - -[project] -name = "importlib_metadata" -authors = [ - { name = "Jason R. Coombs", email = "jaraco@jaraco.com" }, -] -description = "Read metadata from Python packages" -readme = "README.rst" -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", -] -requires-python = ">=3.8" -dependencies = [ - "zipp>=0.5", - 'typing-extensions>=3.6.4; python_version < "3.8"', -] -dynamic = ["version"] - -[project.urls] -Source = "https://github.com/python/importlib_metadata" - -[project.optional-dependencies] -test = [ - # upstream - "pytest >= 6, != 8.1.*", - "pytest-checkdocs >= 2.4", - "pytest-cov", - "pytest-mypy", - "pytest-enabler >= 2.2", - "pytest-ruff >= 0.2.1; sys_platform != 'cygwin'", - - # local - 'importlib_resources>=1.3; python_version < "3.9"', - "packaging", - "pyfakefs", - "flufl.flake8", - "pytest-perf >= 0.9.2", - "jaraco.test >= 5.4", -] -doc = [ - # upstream - "sphinx >= 3.5", - "jaraco.packaging >= 9.3", - "rst.linker >= 1.9", - "furo", - "sphinx-lint", - - # tidelift - "jaraco.tidelift >= 1.4", - - # local -] -perf = ["ipython"] - -[tool.setuptools_scm] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 9a0f3bce..00000000 --- a/pytest.ini +++ /dev/null @@ -1,25 +0,0 @@ -[pytest] -norecursedirs=dist build .tox .eggs -addopts= - --doctest-modules - --import-mode importlib -consider_namespace_packages=true -filterwarnings= - ## upstream - - # Ensure ResourceWarnings are emitted - default::ResourceWarning - - # realpython/pytest-mypy#152 - ignore:'encoding' argument not specified::pytest_mypy - - # python/cpython#100750 - ignore:'encoding' argument not specified::platform - - # pypa/build#615 - ignore:'encoding' argument not specified::build.env - - # dateutil/dateutil#1284 - ignore:datetime.datetime.utcfromtimestamp:DeprecationWarning:dateutil.tz.tz - - ## end upstream diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 922aa1f1..00000000 --- a/ruff.toml +++ /dev/null @@ -1,30 +0,0 @@ -[lint] -extend-select = [ - "C901", - "PERF401", - "W", -] -ignore = [ - # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules - "W191", - "E111", - "E114", - "E117", - "D206", - "D300", - "Q000", - "Q001", - "Q002", - "Q003", - "COM812", - "COM819", - "ISC001", - "ISC002", -] - -[format] -# Enable preview to get hugged parenthesis unwrapping and other nice surprises -# See https://github.com/jaraco/skeleton/pull/133#issuecomment-2239538373 -preview = true -# https://docs.astral.sh/ruff/settings/#format_quote-style -quote-style = "preserve" diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/compat/__init__.py b/tests/compat/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/compat/py312.py b/tests/compat/py312.py deleted file mode 100644 index ea9a58ba..00000000 --- a/tests/compat/py312.py +++ /dev/null @@ -1,18 +0,0 @@ -import contextlib - -from .py39 import import_helper - - -@contextlib.contextmanager -def isolated_modules(): - """ - Save modules on entry and cleanup on exit. - """ - (saved,) = import_helper.modules_setup() - try: - yield - finally: - import_helper.modules_cleanup(saved) - - -vars(import_helper).setdefault('isolated_modules', isolated_modules) diff --git a/tests/compat/py39.py b/tests/compat/py39.py deleted file mode 100644 index 9476eb35..00000000 --- a/tests/compat/py39.py +++ /dev/null @@ -1,9 +0,0 @@ -from jaraco.test.cpython import from_test_support, try_import - - -os_helper = try_import('os_helper') or from_test_support( - 'FS_NONASCII', 'skip_unless_symlink', 'temp_dir' -) -import_helper = try_import('import_helper') or from_test_support( - 'modules_setup', 'modules_cleanup' -) diff --git a/tests/compat/test_py39_compat.py b/tests/compat/test_py39_compat.py deleted file mode 100644 index 549e518a..00000000 --- a/tests/compat/test_py39_compat.py +++ /dev/null @@ -1,73 +0,0 @@ -import sys -import pathlib -import unittest - -from .. import fixtures -from importlib_metadata import ( - distribution, - distributions, - entry_points, - metadata, - version, -) - - -class OldStdlibFinderTests(fixtures.DistInfoPkgOffPath, unittest.TestCase): - def setUp(self): - if sys.version_info >= (3, 10): - self.skipTest("Tests specific for Python 3.8/3.9") - super().setUp() - - def _meta_path_finder(self): - from importlib.metadata import ( - Distribution, - DistributionFinder, - PathDistribution, - ) - from importlib.util import spec_from_file_location - - path = pathlib.Path(self.site_dir) - - class CustomDistribution(Distribution): - def __init__(self, name, path): - self.name = name - self._path_distribution = PathDistribution(path) - - def read_text(self, filename): - return self._path_distribution.read_text(filename) - - def locate_file(self, path): - return self._path_distribution.locate_file(path) - - class CustomFinder: - @classmethod - def find_spec(cls, fullname, _path=None, _target=None): - candidate = pathlib.Path(path, *fullname.split(".")).with_suffix(".py") - if candidate.exists(): - return spec_from_file_location(fullname, candidate) - - @classmethod - def find_distributions(self, context=DistributionFinder.Context()): - for dist_info in path.glob("*.dist-info"): - yield PathDistribution(dist_info) - name, _, _ = str(dist_info).partition("-") - yield CustomDistribution(name + "_custom", dist_info) - - return CustomFinder - - def test_compatibility_with_old_stdlib_path_distribution(self): - """ - Given a custom finder that uses Python 3.8/3.9 importlib.metadata is installed, - when importlib_metadata functions are called, there should be no exceptions. - Ref python/importlib_metadata#396. - """ - self.fixtures.enter_context(fixtures.install_finder(self._meta_path_finder())) - - assert list(distributions()) - assert distribution("distinfo_pkg") - assert distribution("distinfo_pkg_custom") - assert version("distinfo_pkg") > "0" - assert version("distinfo_pkg_custom") > "0" - assert list(metadata("distinfo_pkg")) - assert list(metadata("distinfo_pkg_custom")) - assert list(entry_points(group="entries")) diff --git a/tests/data/__init__.py b/tests/data/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/test_integration.py b/tests/test_integration.py deleted file mode 100644 index f7af67f3..00000000 --- a/tests/test_integration.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Test behaviors specific to importlib_metadata. - -These tests are excluded downstream in CPython as they -test functionality only in importlib_metadata or require -behaviors ('packaging') that aren't available in the -stdlib. -""" - -import unittest -import packaging.requirements -import packaging.version - -from . import fixtures -from importlib_metadata import ( - _compat, - version, -) - - -class IntegrationTests(fixtures.DistInfoPkg, unittest.TestCase): - def test_package_spec_installed(self): - """ - Illustrate the recommended procedure to determine if - a specified version of a package is installed. - """ - - def is_installed(package_spec): - req = packaging.requirements.Requirement(package_spec) - return version(req.name) in req.specifier - - assert is_installed('distinfo-pkg==1.0') - assert is_installed('distinfo-pkg>=1.0,<2.0') - assert not is_installed('distinfo-pkg<1.0') - - -class FinderTests(fixtures.Fixtures, unittest.TestCase): - def test_finder_without_module(self): - class ModuleFreeFinder: - """ - A finder without an __module__ attribute - """ - - def find_module(self, name): - pass - - def __getattribute__(self, name): - if name == '__module__': - raise AttributeError(name) - return super().__getattribute__(name) - - self.fixtures.enter_context(fixtures.install_finder(ModuleFreeFinder())) - _compat.disable_stdlib_finder() diff --git a/towncrier.toml b/towncrier.toml deleted file mode 100644 index 6fa480e4..00000000 --- a/towncrier.toml +++ /dev/null @@ -1,2 +0,0 @@ -[tool.towncrier] -title_format = "{version}" diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 71fd05f6..00000000 --- a/tox.ini +++ /dev/null @@ -1,63 +0,0 @@ -[testenv] -description = perform primary checks (tests, style, types, coverage) -deps = -setenv = - PYTHONWARNDEFAULTENCODING = 1 -commands = - pytest {posargs} -passenv = - HOME -usedevelop = True -extras = - test - -[testenv:diffcov] -description = run tests and check that diff from main is covered -deps = - {[testenv]deps} - diff-cover -commands = - pytest {posargs} --cov-report xml - diff-cover coverage.xml --compare-branch=origin/main --html-report diffcov.html - diff-cover coverage.xml --compare-branch=origin/main --fail-under=100 - -[testenv:docs] -description = build the documentation -extras = - doc - test -changedir = docs -commands = - python -m sphinx -W --keep-going . {toxinidir}/build/html - python -m sphinxlint \ - # workaround for sphinx-contrib/sphinx-lint#83 - --jobs 1 - -[testenv:finalize] -description = assemble changelog and tag a release -skip_install = True -deps = - towncrier - jaraco.develop >= 7.23 -pass_env = * -commands = - python -m jaraco.develop.finalize - - -[testenv:release] -description = publish the package to PyPI and GitHub -skip_install = True -deps = - build - twine>=3 - jaraco.develop>=7.1 -pass_env = - TWINE_PASSWORD - GITHUB_TOKEN -setenv = - TWINE_USERNAME = {env:TWINE_USERNAME:__token__} -commands = - python -c "import shutil; shutil.rmtree('dist', ignore_errors=True)" - python -m build - python -m twine upload dist/* - python -m jaraco.develop.create-github-release pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy