CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-importlib-metadata

Read metadata from Python packages, providing third-party access to importlib.metadata functionality

Pending
Overview
Eval results
Files

distribution-classes.mddocs/

Distribution Classes

Distribution classes provide object-oriented access to package metadata, including abstract base classes and concrete implementations for different package formats. The Distribution system forms the core of importlib_metadata's architecture.

Capabilities

Abstract Distribution Base Class

The base Distribution class defines the interface for accessing package metadata and provides common functionality.

class Distribution(metaclass=abc.ABCMeta):
    """
    An abstract Python distribution package.
    
    Custom providers may derive from this class and define the abstract methods 
    to provide a concrete implementation for their environment.
    """
    
    @abc.abstractmethod
    def read_text(self, filename) -> str | None:
        """
        Attempt to load metadata file given by the name.
        
        Parameters:
        - filename: The name of the file in the distribution info
        
        Returns:
        str | None: The text if found, otherwise None
        """
    
    @abc.abstractmethod
    def locate_file(self, path: str | os.PathLike[str]) -> SimplePath:
        """
        Given a path to a file in this distribution, return a SimplePath to it.
        
        Parameters:
        - path: Path to a file in this distribution
        
        Returns:
        SimplePath: Path object for the file
        
        Raises:
        NotImplementedError: If provider doesn't support file location
        """
    
    @classmethod
    def from_name(cls, name: str) -> Distribution:
        """
        Return the Distribution for the given package name.
        
        Parameters:
        - name: The name of the distribution package to search for
        
        Returns:
        Distribution: The Distribution instance for the named package
        
        Raises:
        PackageNotFoundError: When the named package's distribution metadata cannot be found
        ValueError: When an invalid value is supplied for name
        """
    
    @classmethod
    def discover(cls, *, context: DistributionFinder.Context | None = None, **kwargs) -> Iterable[Distribution]:
        """
        Return an iterable of Distribution objects for all packages.
        
        Pass a context or pass keyword arguments for constructing a context.
        
        Parameters:
        - context: A DistributionFinder.Context object (optional)
        - **kwargs: Keyword arguments for constructing a context
        
        Returns:
        Iterable[Distribution]: Iterable of Distribution objects for packages matching the context
        
        Raises:
        ValueError: If both context and kwargs are provided
        """
    
    @staticmethod
    def at(path: str | os.PathLike[str]) -> Distribution:
        """
        Return a Distribution for the indicated metadata path.
        
        Parameters:
        - path: A string or path-like object to the metadata directory
        
        Returns:
        Distribution: A concrete Distribution instance for the path
        """
    
    @staticmethod
    def _discover_resolvers():
        """
        Search the meta_path for resolvers (MetadataPathFinders).
        
        Returns:
        Iterator: Iterator of find_distributions methods from MetaPathFinders
        """
    
    @staticmethod
    def _prefer_valid(dists: Iterable[Distribution]) -> Iterable[Distribution]:
        """
        Prefer (move to the front) distributions that have metadata.
        
        This optimization addresses cases where multiple distributions
        may be found but some lack proper metadata.
        
        Parameters:
        - dists: Iterable of Distribution instances
        
        Returns:
        Iterable[Distribution]: Distributions with valid metadata prioritized
        """

Distribution Properties

Access to distribution metadata through properties:

class Distribution:
    @property
    def metadata(self) -> PackageMetadata | None:
        """
        Return the parsed metadata for this Distribution.
        
        The returned object will have keys that name the various bits of metadata
        per the Core metadata specifications.
        """
    
    @property
    def name(self) -> str:
        """Return the 'Name' metadata for the distribution package."""
    
    @property
    def version(self) -> str:
        """Return the 'Version' metadata for the distribution package."""
    
    @property
    def entry_points(self) -> EntryPoints:
        """Return EntryPoints for this distribution."""
    
    @property
    def files(self) -> list[PackagePath] | None:
        """
        Files in this distribution.
        
        Returns:
        list[PackagePath] | None: List of PackagePath for this distribution or None 
                                  if the metadata file that enumerates files is missing
        """
    
    @property
    def requires(self) -> list[str] | None:
        """Generated requirements specified for this Distribution."""
    
    @property
    def origin(self):
        """
        Return the origin metadata from direct_url.json.
        
        This provides information about how the package was installed,
        including VCS information, local paths, or archive URLs.
        
        Returns:
        SimpleNamespace | None: Origin metadata object or None if not available
        """
    
    @property
    def _normalized_name(self):
        """
        Return a normalized version of the name.
        
        Used internally for consistent name comparisons and lookups.
        
        Returns:
        str: Normalized package name
        """

Usage Examples

import importlib_metadata

# Get distribution and access properties
dist = importlib_metadata.Distribution.from_name('requests')
print(f"Name: {dist.name}")
print(f"Version: {dist.version}")

# Access metadata
metadata = dist.metadata
if metadata:
    print(f"Summary: {metadata['Summary']}")
    print(f"Author: {metadata['Author']}")

# Get entry points for this distribution
eps = dist.entry_points
console_scripts = eps.select(group='console_scripts')
for ep in console_scripts:
    print(f"Script: {ep.name}")

# Get files
files = dist.files
if files:
    print(f"Distribution has {len(files)} files")

PathDistribution Implementation

Concrete implementation for filesystem-based distributions:

class PathDistribution(Distribution):
    """Concrete Distribution implementation for filesystem paths."""
    
    def __init__(self, path: SimplePath) -> None:
        """
        Construct a distribution.
        
        Parameters:
        - path: SimplePath indicating the metadata directory
        """
    
    def read_text(self, filename: str | os.PathLike[str]) -> str | None:
        """Read text from a file in the distribution metadata."""
    
    def locate_file(self, path: str | os.PathLike[str]) -> SimplePath:
        """Locate a file relative to the distribution."""

Usage Examples

import importlib_metadata
from pathlib import Path

# Create distribution from path
metadata_path = Path('/path/to/package-1.0.dist-info')
dist = importlib_metadata.PathDistribution(metadata_path)

# Use like any other distribution
print(f"Package: {dist.name}")
print(f"Version: {dist.version}")

Distribution Discovery

The DistributionFinder system enables pluggable package discovery:

class DistributionFinder(MetaPathFinder):
    """
    A MetaPathFinder capable of discovering installed distributions.
    
    Custom providers should implement this interface in order to supply metadata.
    """
    
    class Context:
        """
        Keyword arguments presented by the caller to distributions() or 
        Distribution.discover() to narrow the scope of a search for distributions.
        """
        
        name = None  # Specific name for which a distribution finder should match
        
        def __init__(self, **kwargs):
            """
            Initialize context with keyword arguments.
            
            Parameters:
            - **kwargs: Context parameters for filtering distributions
            """
        
        @property
        def path(self) -> list[str]:
            """
            The sequence of directory paths that a distribution finder should search.
            Typically refers to Python installed package paths such as "site-packages" 
            directories and defaults to sys.path.
            
            Returns:
            list[str]: List of directory paths to search
            """
    
    @abc.abstractmethod
    def find_distributions(self, context=Context()) -> Iterable[Distribution]:
        """
        Find distributions.
        
        Parameters:
        - context: DistributionFinder.Context instance for filtering
        
        Returns:
        Iterable[Distribution]: Iterable of all Distribution instances capable of 
                               loading the metadata for packages matching the context
        """

MetadataPathFinder Implementation

Concrete implementation of DistributionFinder for filesystem-based package discovery:

class MetadataPathFinder(DistributionFinder):
    """
    A degenerate finder for distribution packages on the file system.
    
    This finder supplies only a find_distributions() method for versions
    of Python that do not have a PathFinder find_distributions().
    """
    
    @classmethod
    def find_distributions(cls, context=DistributionFinder.Context()) -> Iterable[PathDistribution]:
        """
        Find distributions.
        
        Return an iterable of all Distribution instances capable of
        loading the metadata for packages matching context.name
        (or all names if None indicated) along the paths in the list
        of directories context.path.
        
        Parameters:
        - context: DistributionFinder.Context instance for filtering
        
        Returns:
        Iterable[PathDistribution]: PathDistribution instances for found packages
        """
    
    @classmethod
    def invalidate_caches(cls) -> None:
        """Invalidate internal caches used for distribution discovery."""

Usage Examples

import importlib_metadata

# Discover all distributions
all_dists = list(importlib_metadata.Distribution.discover())
print(f"Found {len(all_dists)} distributions")

# Discover with context
context = importlib_metadata.DistributionFinder.Context(name='requests')
matching_dists = list(importlib_metadata.Distribution.discover(context=context))

# Discover with kwargs
specific_dists = list(importlib_metadata.Distribution.discover(name='requests'))

Error Handling

Distribution classes raise specific exceptions for various error conditions:

import importlib_metadata

try:
    dist = importlib_metadata.Distribution.from_name('nonexistent')
except importlib_metadata.PackageNotFoundError:
    print("Package not found")

try:
    dist = importlib_metadata.Distribution.from_name('')
except ValueError:
    print("Invalid distribution name")

Install with Tessl CLI

npx tessl i tessl/pypi-importlib-metadata@8.7.2

docs

core-functions.md

distribution-classes.md

entry-points.md

index.md

path-file-management.md

tile.json