From 86352408cbee5f445b012cda81bab66d82a2f0d4 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 26 Dec 2023 11:46:00 -0500 Subject: [PATCH] Expand docstrings to elaborate on the purpose and details of the interfaces. --- importlib_metadata/__init__.py | 80 ++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index f399f1bd..bbd92a7d 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -360,7 +360,9 @@ class Distribution(DeprecatedNonAbstract): Custom providers may derive from this class and define the abstract methods to provide a concrete implementation - for their environment. + for their environment. Some providers may opt to override + the default implementation of some properties to bypass + the file-reading mechanism. """ @abc.abstractmethod @@ -374,11 +376,10 @@ def read_text(self, filename) -> Optional[str]: - METADATA: The distribution metadata including fields like Name and Version and Description. - - entry_points.txt: A series of entry points defined by - the Setuptools spec in an ini format with sections - representing the groups. - - RECORD: A record of files as installed by a typical - installer. + - entry_points.txt: A series of entry points as defined in + `this spec `_. + - RECORD: A record of files according to + `this spec `_. A package may provide any set of files, including those not listed here or none at all. @@ -454,7 +455,11 @@ def metadata(self) -> _meta.PackageMetadata: """Return the parsed metadata for this Distribution. The returned object will have keys that name the various bits of - metadata. See PEP 566 for details. + metadata per the + `Core metadata specifications `_. + + Custom providers may provide the METADATA file or override this + property. """ opt_text = ( self.read_text('METADATA') @@ -484,6 +489,12 @@ def version(self) -> str: @property def entry_points(self) -> EntryPoints: + """ + Return EntryPoints for this distribution. + + Custom providers may provide the ``entry_points.txt`` file + or override this property. + """ return EntryPoints._from_text_for(self.read_text('entry_points.txt'), self) @property @@ -496,6 +507,10 @@ def files(self) -> Optional[List[PackagePath]]: (i.e. RECORD for dist-info, or installed-files.txt or SOURCES.txt for egg-info) is missing. Result may be empty if the metadata exists but is empty. + + Custom providers are recommended to provide a "RECORD" file (in + ``read_text``) or override this property to allow for callers to be + able to resolve filenames provided by the package. """ def make_file(name, hash=None, size_str=None): @@ -523,7 +538,7 @@ def skip_missing_files(package_paths): def _read_files_distinfo(self): """ - Read the lines of RECORD + Read the lines of RECORD. """ text = self.read_text('RECORD') return text and text.splitlines() @@ -637,6 +652,9 @@ def _load_json(self, filename): class DistributionFinder(MetaPathFinder): """ A MetaPathFinder capable of discovering installed distributions. + + Custom providers should implement this interface in order to + supply metadata. """ class Context: @@ -684,11 +702,18 @@ def find_distributions(self, context=Context()) -> Iterable[Distribution]: class FastPath: """ - Micro-optimized class for searching a path for - children. + Micro-optimized class for searching a root for children. + + Root is a path on the file system that may contain metadata + directories either as natural directories or within a zip file. >>> FastPath('').children() ['...'] + + FastPath objects are cached and recycled for any given root. + + >>> FastPath('foobar') is FastPath('foobar') + True """ @functools.lru_cache() # type: ignore @@ -730,7 +755,18 @@ def lookup(self, mtime): class Lookup: + """ + A micro-optimized class for searching a (fast) path for metadata. + """ def __init__(self, path: FastPath): + """ + Calculate all of the children representing metadata. + + From the children in the path, calculate early all of the + children that appear to represent metadata (infos) or legacy + metadata (eggs). + """ + base = os.path.basename(path.root).lower() base_is_egg = base.endswith(".egg") self.infos = FreezableDefaultDict(list) @@ -751,7 +787,10 @@ def __init__(self, path: FastPath): self.infos.freeze() self.eggs.freeze() - def search(self, prepared): + def search(self, prepared: Prepared): + """ + Yield all infos and eggs matching the Prepared query. + """ infos = ( self.infos[prepared.normalized] if prepared @@ -767,13 +806,28 @@ def search(self, prepared): class Prepared: """ - A prepared search for metadata on a possibly-named package. + A prepared search query for metadata on a possibly-named package. + + Pre-calculates the normalization to prevent repeated operations. + + >>> none = Prepared(None) + >>> none.normalized + >>> none.legacy_normalized + >>> bool(none) + False + >>> sample = Prepared('Sample__Pkg-name.foo') + >>> sample.normalized + 'sample_pkg_name_foo' + >>> sample.legacy_normalized + 'sample__pkg_name.foo' + >>> bool(sample) + True """ normalized = None legacy_normalized = None - def __init__(self, name): + def __init__(self, name: Optional[str]): self.name = name if name is None: return