[3.8] bpo-41855: Fix duplicate results in FastPath.zip_children() (#22404)
* bpo-41855: Backport fixes from importlib_metadata 1.5.2. * Add blurb. * Add anchor for finders and loaders
This commit is contained in:
parent
aeb66c1abb
commit
967fddae2f
|
@ -1,8 +1,8 @@
|
||||||
.. _using:
|
.. _using:
|
||||||
|
|
||||||
==========================
|
=================================
|
||||||
Using importlib.metadata
|
Using :mod:`!importlib.metadata`
|
||||||
==========================
|
=================================
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This functionality is provisional and may deviate from the usual
|
This functionality is provisional and may deviate from the usual
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
package metadata. Built in part on Python's import system, this library
|
package metadata. Built in part on Python's import system, this library
|
||||||
intends to replace similar functionality in the `entry point
|
intends to replace similar functionality in the `entry point
|
||||||
API`_ and `metadata API`_ of ``pkg_resources``. Along with
|
API`_ and `metadata API`_ of ``pkg_resources``. Along with
|
||||||
``importlib.resources`` in `Python 3.7
|
:mod:`importlib.resources` in Python 3.7
|
||||||
and newer`_ (backported as `importlib_resources`_ for older versions of
|
and newer (backported as `importlib_resources`_ for older versions of
|
||||||
Python), this can eliminate the need to use the older and less efficient
|
Python), this can eliminate the need to use the older and less efficient
|
||||||
``pkg_resources`` package.
|
``pkg_resources`` package.
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ By "installed package" we generally mean a third-party package installed into
|
||||||
Python's ``site-packages`` directory via tools such as `pip
|
Python's ``site-packages`` directory via tools such as `pip
|
||||||
<https://pypi.org/project/pip/>`_. Specifically,
|
<https://pypi.org/project/pip/>`_. Specifically,
|
||||||
it means a package with either a discoverable ``dist-info`` or ``egg-info``
|
it means a package with either a discoverable ``dist-info`` or ``egg-info``
|
||||||
directory, and metadata defined by `PEP 566`_ or its older specifications.
|
directory, and metadata defined by :pep:`566` or its older specifications.
|
||||||
By default, package metadata can live on the file system or in zip archives on
|
By default, package metadata can live on the file system or in zip archives on
|
||||||
``sys.path``. Through an extension mechanism, the metadata can live almost
|
:data:`sys.path`. Through an extension mechanism, the metadata can live almost
|
||||||
anywhere.
|
anywhere.
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ Distribution files
|
||||||
You can also get the full set of files contained within a distribution. The
|
You can also get the full set of files contained within a distribution. The
|
||||||
``files()`` function takes a distribution package name and returns all of the
|
``files()`` function takes a distribution package name and returns all of the
|
||||||
files installed by this distribution. Each file object returned is a
|
files installed by this distribution. Each file object returned is a
|
||||||
``PackagePath``, a `pathlib.Path`_ derived object with additional ``dist``,
|
``PackagePath``, a :class:`pathlib.Path` derived object with additional ``dist``,
|
||||||
``size``, and ``hash`` properties as indicated by the metadata. For example::
|
``size``, and ``hash`` properties as indicated by the metadata. For example::
|
||||||
|
|
||||||
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
|
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
|
||||||
|
@ -203,18 +203,18 @@ instance::
|
||||||
>>> d.metadata['License'] # doctest: +SKIP
|
>>> d.metadata['License'] # doctest: +SKIP
|
||||||
'MIT'
|
'MIT'
|
||||||
|
|
||||||
The full set of available metadata is not described here. See `PEP 566
|
The full set of available metadata is not described here. See :pep:`566`
|
||||||
<https://www.python.org/dev/peps/pep-0566/>`_ for additional details.
|
for additional details.
|
||||||
|
|
||||||
|
|
||||||
Extending the search algorithm
|
Extending the search algorithm
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
Because package metadata is not available through ``sys.path`` searches, or
|
Because package metadata is not available through :data:`sys.path` searches, or
|
||||||
package loaders directly, the metadata for a package is found through import
|
package loaders directly, the metadata for a package is found through import
|
||||||
system `finders`_. To find a distribution package's metadata,
|
system :ref:`finders <finders-and-loaders>`. To find a distribution package's metadata,
|
||||||
``importlib.metadata`` queries the list of `meta path finders`_ on
|
``importlib.metadata`` queries the list of :term:`meta path finders <meta path finder>` on
|
||||||
`sys.meta_path`_.
|
:data:`sys.meta_path`.
|
||||||
|
|
||||||
The default ``PathFinder`` for Python includes a hook that calls into
|
The default ``PathFinder`` for Python includes a hook that calls into
|
||||||
``importlib.metadata.MetadataPathFinder`` for finding distributions
|
``importlib.metadata.MetadataPathFinder`` for finding distributions
|
||||||
|
@ -224,7 +224,7 @@ The abstract class :py:class:`importlib.abc.MetaPathFinder` defines the
|
||||||
interface expected of finders by Python's import system.
|
interface expected of finders by Python's import system.
|
||||||
``importlib.metadata`` extends this protocol by looking for an optional
|
``importlib.metadata`` extends this protocol by looking for an optional
|
||||||
``find_distributions`` callable on the finders from
|
``find_distributions`` callable on the finders from
|
||||||
``sys.meta_path`` and presents this extended interface as the
|
:data:`sys.meta_path` and presents this extended interface as the
|
||||||
``DistributionFinder`` abstract base class, which defines this abstract
|
``DistributionFinder`` abstract base class, which defines this abstract
|
||||||
method::
|
method::
|
||||||
|
|
||||||
|
@ -247,20 +247,13 @@ a custom finder, return instances of this derived ``Distribution`` in the
|
||||||
|
|
||||||
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
|
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
|
||||||
.. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api
|
.. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api
|
||||||
.. _`Python 3.7 and newer`: https://docs.python.org/3/library/importlib.html#module-importlib.resources
|
|
||||||
.. _`importlib_resources`: https://importlib-resources.readthedocs.io/en/latest/index.html
|
.. _`importlib_resources`: https://importlib-resources.readthedocs.io/en/latest/index.html
|
||||||
.. _`PEP 566`: https://www.python.org/dev/peps/pep-0566/
|
|
||||||
.. _`finders`: https://docs.python.org/3/reference/import.html#finders-and-loaders
|
|
||||||
.. _`meta path finders`: https://docs.python.org/3/glossary.html#term-meta-path-finder
|
|
||||||
.. _`sys.meta_path`: https://docs.python.org/3/library/sys.html#sys.meta_path
|
|
||||||
.. _`pathlib.Path`: https://docs.python.org/3/library/pathlib.html#pathlib.Path
|
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
.. rubric:: Footnotes
|
||||||
|
|
||||||
.. [#f1] Technically, the returned distribution metadata object is an
|
.. [#f1] Technically, the returned distribution metadata object is an
|
||||||
`email.message.Message
|
:class:`email.message.EmailMessage`
|
||||||
<https://docs.python.org/3/library/email.message.html#email.message.EmailMessage>`_
|
|
||||||
instance, but this is an implementation detail, and not part of the
|
instance, but this is an implementation detail, and not part of the
|
||||||
stable API. You should only use dictionary-like methods and syntax
|
stable API. You should only use dictionary-like methods and syntax
|
||||||
to access the metadata contents.
|
to access the metadata contents.
|
||||||
|
|
|
@ -202,6 +202,8 @@ named module, the two module objects will *not* be the same. By contrast,
|
||||||
reinitialise the module contents by rerunning the module's code.
|
reinitialise the module contents by rerunning the module's code.
|
||||||
|
|
||||||
|
|
||||||
|
.. _finders-and-loaders:
|
||||||
|
|
||||||
Finders and loaders
|
Finders and loaders
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
|
@ -408,8 +408,8 @@ class FastPath:
|
||||||
names = zip_path.root.namelist()
|
names = zip_path.root.namelist()
|
||||||
self.joinpath = zip_path.joinpath
|
self.joinpath = zip_path.joinpath
|
||||||
|
|
||||||
return (
|
return dict.fromkeys(
|
||||||
posixpath.split(child)[0]
|
child.split(posixpath.sep, 1)[0]
|
||||||
for child in names
|
for child in names
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -475,7 +475,6 @@ class MetadataPathFinder(DistributionFinder):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PathDistribution(Distribution):
|
class PathDistribution(Distribution):
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
"""Construct a distribution from a path to the metadata directory.
|
"""Construct a distribution from a path to the metadata directory.
|
||||||
|
|
|
@ -3,11 +3,15 @@ import unittest
|
||||||
|
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
from importlib.metadata import (
|
from importlib.metadata import (
|
||||||
distribution, entry_points, files, PackageNotFoundError, version,
|
distribution, entry_points, files, PackageNotFoundError,
|
||||||
|
version, distributions,
|
||||||
)
|
)
|
||||||
from importlib.resources import path
|
from importlib.resources import path
|
||||||
|
|
||||||
|
from test.support import requires_zlib
|
||||||
|
|
||||||
|
|
||||||
|
@requires_zlib
|
||||||
class TestZip(unittest.TestCase):
|
class TestZip(unittest.TestCase):
|
||||||
root = 'test.test_importlib.data'
|
root = 'test.test_importlib.data'
|
||||||
|
|
||||||
|
@ -46,7 +50,12 @@ class TestZip(unittest.TestCase):
|
||||||
path = str(file.dist.locate_file(file))
|
path = str(file.dist.locate_file(file))
|
||||||
assert '.whl/' in path, path
|
assert '.whl/' in path, path
|
||||||
|
|
||||||
|
def test_one_distribution(self):
|
||||||
|
dists = list(distributions(path=sys.path[:1]))
|
||||||
|
assert len(dists) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@requires_zlib
|
||||||
class TestEgg(TestZip):
|
class TestEgg(TestZip):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Find the path to the example-*.egg so we can add it to the front of
|
# Find the path to the example-*.egg so we can add it to the front of
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
In ``importlib.metadata``, fix issue where multiple children can be returned
|
||||||
|
from ``FastPath.zip_children()``. Backport of
|
||||||
|
`python-devs/importlib_metadata#117
|
||||||
|
<https://gitlab.com/python-devs/importlib_metadata/-/issues/117>`_.
|
Loading…
Reference in New Issue