@@ -397,6 +397,70 @@ metadata in locations other than the file system, subclass
397
397
a custom finder, return instances of this derived ``Distribution `` in the
398
398
``find_distributions() `` method.
399
399
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
+
400
464
401
465
.. _`entry point API` : https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
402
466
.. _`metadata API` : https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api
0 commit comments