8000 Expand the 'Extending' docs to provide a minimal example. Closes pyth… · python/cpython@5d15068 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5d15068

Browse files
committed
Expand the 'Extending' docs to provide a minimal example. Closes python/importlib_metadata#427.
1 parent e365c94 commit 5d15068

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

Doc/library/importlib.metadata.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,70 @@ metadata in locations other than the file system, subclass
397397
a custom finder, return instances of this derived ``Distribution`` in the
398398
``find_distributions()`` method.
399399

400+
Example
401+
-------
402+
403+
Consider for example a custom finder that loads Python
404+
modules from a database::
405+
406+
class DatabaseImporter(importlib.abc.MetaPathFinder):
407+
def __init__(self, db):
408+
self.db = db
409+
410+
def find_spec(self, fullname, target=None) -> ModuleSpec:
411+
return self.db.spec_from_name(fullname)
412+
413+
sys.meta_path.append(DatabaseImporter(connect_db(...)))
414+
415+
That importer now presumably provides importable modules from a
416+
database, but it provides no metadata or entry points. For this
417+
custom importer to provide metadata, it would also need to implement
418+
``DistributionFinder``::
419+
420+
from importlib.metadata import DistributionFinder
421+
422+
class DatabaseImporter(DistributionFinder):
423+
...
424+
425+
def find_distributions(self, context=DistributionFinder.Context()):
426+
query = dict(name=context.name) if context.name else {}
427+
for dist_record in self.db.query_distributions(query):
428+
yield DatabaseDistribution(dist_record)
429+
430+
431+
In this way, ``query_distributions`` would return records for
432+
each distribution served by the database matching the query. For
433+
example, if ``requests-1.0`` is in the database, ``find_distributions``
434+
would yield a ``DatabaseDistribution`` for ``Context(name='requests')``
435+
or ``Context(name=None)``.
436+
437+
``DatabaseDistribution``, then, would look something like::
438+
439+
class DatabaseDistribution(importlib.metadata.Distributon):
440+
def __init__(self, record):
441+
self.record = record
442+
443+
def read_text(self, filename):
444+
"""
445+
Read a file like "METADATA" for the current distribution.
446+
"""
447+
if filename == "METADATA":
448+
return f"""Name: {self.record.name}
449+
Version: {self.record.version}
450+
"""
451+
if filename == "entry_points.txt":
452+
return "\n".join(
453+
f"""[{ep.group}]\n{ep.name}={ep.value}"""
454+
for ep in self.record.entry_points)
455+
456+
def locate_file(self, path):
457+
raise RuntimeError("This distribution has no file system")
458+
459+
This basic implementation should provide metadata and entry points for
460+
packages served by the ``DatabaseImporter``, assuming that the
461+
``record`` supplies suitable ``.name``, ``.version``, and
462+
``.entry_points`` attributes.
463+
400464

401465
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
402466
.. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api

0 commit comments

Comments
 (0)
0