@@ -237,11 +237,12 @@ Distribution metadata
237237
238238.. class :: PackageMetadata
239239
240- A concrete implementation of the
241- `PackageMetadata protocol <https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata >`_.
240+ A protocol describing the interface distribution metadata presents. The
241+ :pypi: `importlib_metadata ` backport presents the same protocol; see
242+ :ref: `metadata-backport-caveats `.
242243
243- In addition to providing the defined protocol methods and attributes, subscripting
244- the instance is equivalent to calling the :meth: `!get ` method.
244+ In addition to the protocol methods and attributes, subscripting an
245+ instance is equivalent to calling the :meth: `!get ` method.
245246
246247Every `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package >`_
247248includes some metadata, which you can extract using the :func: `!metadata ` function::
@@ -332,6 +333,13 @@ Distribution files
332333 check if it ``exists() ``, to traverse using ``joinpath() `` and ``parent ``,
333334 and to retrieve data using ``read_text() `` and ``read_bytes() ``.
334335
336+ .. class :: IPackagePath
337+
338+ A protocol describing the interface a :class: `PackagePath ` presents. See
339+ :ref: `metadata-backport-caveats `.
340+
341+ .. versionadded :: 3.16
342+
335343The :func: `!files ` function takes a
336344`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package >`_
337345name and returns all of the files installed by this distribution. For example::
@@ -544,6 +552,17 @@ The same applies for :func:`entry_points` and :func:`files`.
544552
545553 A shortcut for ``distribution.locate_file(filename).read_text() ``.
546554
555+ .. class :: IDistribution
556+
557+ A protocol describing the interface a :class: `Distribution ` presents.
558+
559+ A consumer that targets this protocol, rather than a concrete class, works
560+ with distributions from either this module or the
561+ :pypi: `importlib_metadata ` backport, however they were supplied. See
562+ :ref: `metadata-backport-caveats `.
563+
564+ .. versionadded :: 3.16
565+
547566.. _distribution-discovery :
548567
549568Distribution Discovery
@@ -748,10 +767,15 @@ Caveats for backports
748767
749768The :pypi: `importlib_metadata ` package backports this module and supplies its
750769own :class: `!Distribution `, :class: `!PackagePath `, and metadata classes. Those
751- classes are separate from the ones in :mod: `!importlib.metadata `; neither set
752- derives from the other. Both libraries discover distributions by querying the
753- finders on :data: `sys.meta_path `, so one custom provider serves consumers of
754- both and has no say in which of the two a given consumer uses.
770+ classes are separate from the ones here; neither set derives from the other.
771+ Both libraries discover distributions by querying the finders on
772+ :data: `sys.meta_path `, so one custom provider serves consumers of both and has
773+ no say in which of the two a given consumer uses.
774+
775+ Both libraries present the same protocols, :class: `IDistribution `,
776+ :class: `IPackagePath `, and :class: `PackageMetadata `, and the classes of both
777+ satisfy them. Those protocols, rather than any concrete class, are the
778+ interface to write against.
755779
756780For consumers
757781-------------
@@ -765,24 +789,23 @@ substituting its own class for each object it recognizes, such as a
765789:class: `Distribution ` subclass from a custom provider, so it passes such an
766790object through unchanged.
767791
768- Rely on an object satisfying the interface rather than on its type, and do not
769- test it with :func: `isinstance ` against a concrete class. The backport
770- publishes ``IDistribution ``, ``IPackagePath ``, and ``PackageMetadata ``
771- protocols for this purpose, which the classes of both libraries satisfy.
772- Import them from the backport; this module does not present them yet.
792+ Annotate against the protocols, then, and do not test an object with
793+ :func: `isinstance ` against a concrete class. Code that needs the protocols on
794+ earlier Python versions can import them from the backport, which presents them
795+ there too.
773796
774797.. _metadata-backport-providers :
775798
776799For custom providers
777800--------------------
778801
779802A provider's objects reach consumers of both libraries, so supply objects that
780- present the whole interface , not part of it . Deriving from
803+ satisfy :class: ` IDistribution ` whole, not in part . Deriving from
781804:class: `Distribution `, as the example above does, achieves this: the base
782805class builds the rest of the interface on :meth: `~Distribution.read_text ` and
783- :meth: `~Distribution.locate_file `. Where a class omits a member the interface
806+ :meth: `~Distribution.locate_file `. Where a class omits a member the protocol
784807requires, the backport emits a :exc: `UserWarning ` naming what is missing; a
785- provider presenting the whole interface draws no warning.
808+ provider satisfying the protocol whole draws no warning.
786809
787810Deriving from whichever of the two libraries happens to be importable is not a
788811general answer. A provider cannot know whether a consumer will import the
0 commit comments