Skip to content

Commit

Permalink
Merge branch 'docs' into 'master'
Browse files Browse the repository at this point in the history
Add documentation and clean up docstrings

Closes #11

See merge request python-devs/importlib_metadata!8
  • Loading branch information
warsaw committed Sep 12, 2018
2 parents d688448 + 5e6c27c commit 23ac29a
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 49 deletions.
25 changes: 23 additions & 2 deletions importlib_metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,37 @@


def distribution(package):
"""Get the ``Distribution`` instance for the given package.
:param package: The module object for the package or the name of the
package as a string.
:return: A ``Distribution`` instance (or subclass thereof).
"""
if isinstance(package, ModuleType):
return Distribution.from_module(package)
else:
return Distribution.from_name(package)


def version(name):
return distribution(name).version
def version(package):
"""Get the version string for the named package.
:param package: The module object for the package or the name of the
package as a string.
:return: The version string for the package as defined in the package's
"Version" metadata key.
"""
return distribution(package).version


def resolve(entry_point):
"""Resolve an entry point string into the named callable.
:param entry_point: An entry point string of the form
`path.to.module:callable`.
:return: The actual callable object `path.to.module.callable`
:raises ValueError: When `entry_point` doesn't have the proper format.
"""
path, colon, name = entry_point.rpartition(':')
if colon != ':':
raise ValueError('Not an entry point: {}'.format(entry_point))
Expand All @@ -38,6 +58,7 @@ def resolve(entry_point):


def _install(): # pragma: nocover
"""Install the appropriate sys.meta_path finder for the Python version."""
if sys.version_info < (3, ):
from ._py2 import MetadataPathFinder
sys.meta_path.append(MetadataPathFinder)
Expand Down
27 changes: 15 additions & 12 deletions importlib_metadata/_py2.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@


class MetadataPathFinder:
"""
A degenerate finder, supplying only a find_distribution
method for versions of Python that do not have a
PathFinder find_distribution.
"""A degenerate finder for distribution packages.
This finder supplies only a find_distribution() method for versions
of Python that do not have a PathFinder find_distribution().
"""
@staticmethod
def find_module(*args, **kwargs):
Expand All @@ -31,9 +31,6 @@ def find_distribution(cls, name):

@classmethod
def _search_paths(cls, name):
"""
Find metadata directories in sys.path heuristically.
"""
return itertools.chain.from_iterable(
cls._search_path(path, name)
for path in map(Path, sys.path)
Expand All @@ -53,14 +50,14 @@ def _search_path(cls, root, name):

class PathDistribution(Distribution):
def __init__(self, path):
"""
Construct a distribution from a path to the metadata dir.
"""
"""Construct a distribution from a path to the metadata directory."""
self.path = path

def load_metadata(self, name):
"""
Attempt to load metadata given by the name. Return None if not found.
"""Attempt to load metadata given by the name.
:param name: The name of the distribution package.
:return: The metadata string if found, otherwise None.
"""
filename = os.path.join(str(self.path), name)
try:
Expand All @@ -73,6 +70,12 @@ def load_metadata(self, name):


def entry_points(name):
"""Return the entry points for the named distribution package.
:param name: The name of the distribution package to query.
:return: A ConfigParser instance where the sections and keys are taken
from the entry_points.txt ini-style contents.
"""
# Avoid circular imports.
from importlib_metadata import distribution
as_string = distribution(name).load_metadata('entry_points.txt')
Expand Down
24 changes: 15 additions & 9 deletions importlib_metadata/_py3.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@


class MetadataPathFinder:
"""
A degenerate finder, supplying only a find_distribution
method for versions of Python that do not have a
PathFinder find_distribution.
"""A degenerate finder for distribution packages.
This finder supplies only a find_distribution() method for versions
of Python that do not have a PathFinder find_distribution().
"""
@staticmethod
def find_spec(*args, **kwargs):
Expand Down Expand Up @@ -50,14 +50,14 @@ def _search_path(cls, root, name):

class PathDistribution(Distribution):
def __init__(self, path):
"""
Construct a distribution from a path to the metadata dir.
"""
"""Construct a distribution from a path to the metadata directory."""
self.path = path

def load_metadata(self, name):
"""
Attempt to load metadata given by the name. Return None if not found.
"""Attempt to load metadata given by the name.
:param name: The name of the distribution package.
:return: The metadata string if found, otherwise None.
"""
filename = os.path.join(self.path, name)
with contextlib.suppress(FileNotFoundError):
Expand All @@ -66,6 +66,12 @@ def load_metadata(self, name):


def entry_points(name):
"""Return the entry points for the named distribution package.
:param name: The name of the distribution package to query.
:return: A ConfigParser instance where the sections and keys are taken
from the entry_points.txt ini-style contents.
"""
# Avoid circular imports.
from importlib_metadata import distribution
as_string = distribution(name).load_metadata('entry_points.txt')
Expand Down
50 changes: 25 additions & 25 deletions importlib_metadata/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,29 @@


class PackageNotFound(Exception):
"""Package Not Found"""
"""The package was not found."""


class Distribution:
"""
A Python Distribution package.
"""
"""A Python distribution package."""

@abc.abstractmethod
def load_metadata(self, name):
"""
Attempt to load metadata given by the name. Return None if not found.
"""Attempt to load metadata given by the name.
:param name: The name of the distribution package.
:return: The metadata string if found, otherwise None.
"""

@classmethod
def from_name(cls, name):
"""
Given the name of a distribution (the name of the package as
installed), return a Distribution.
"""Return the Distribution for the given package name.
:param name: The name of the distribution package to search for.
:return: The Distribution instance (or subclass thereof) for the named
package, if found.
:raises PackageNotFound: When the named package's distribution
metadata cannot be found.
"""
for resolver in cls._discover_resolvers():
resolved = resolver(name)
Expand All @@ -34,43 +38,39 @@ def from_name(cls, name):

@staticmethod
def _discover_resolvers():
"""
Search the meta_path for resolvers.
"""
"""Search the meta_path for resolvers."""
declared = (
getattr(finder, 'find_distribution', None)
for finder in sys.meta_path
)
return filter(None, declared)

@classmethod
def from_module(cls, mod):
"""
Given a module, discover the Distribution package for that
module.
"""
return cls.from_name(cls.name_for_module(mod))
def from_module(cls, module):
"""Discover the Distribution package for a module."""
return cls.from_name(cls.name_for_module(module))

@classmethod
def from_named_module(cls, mod_name):
return cls.from_module(importlib.import_module(mod_name))

@staticmethod
def name_for_module(mod):
"""
Given an imported module, infer the distribution package name.
"""
return getattr(mod, '__dist_name__', mod.__name__)
def name_for_module(module):
"""Given an imported module, infer the distribution package name."""
return getattr(module, '__dist_name__', module.__name__)

@property
def metadata(self):
"""
Return metadata for this Distribution, parsed.
"""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.
"""
return email.message_from_string(
self.load_metadata('METADATA') or self.load_metadata('PKG-INFO')
)

@property
def version(self):
"""Return the 'Version' metadata for the distribution package."""
return self.metadata['Version']
1 change: 1 addition & 0 deletions importlib_metadata/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

0.3 (201X-XX-XX)
================
* Added usage documentation. Closes #8

0.2 (2018-09-11)
================
Expand Down
26 changes: 25 additions & 1 deletion importlib_metadata/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@
Welcome to importlib_metadata
===============================

``importlib_metadata`` does stuff.
``importlib_metadata`` is a library which provides an API for accessing an
installed package's `metadata`_, such as its entry points or its top-level
name. This functionality intends to replace most uses of ``pkg_resources``
`entry point API`_ and `metadata API`_. Along with ``importlib.resources`` in
`Python 3.7 and newer`_ (backported as `importlib_resources`_ for older
versions of Python), this can eliminate the need to use the older and less
efficient ``pkg_resources`` package.

``importlib_metadata`` is a backport of Python 3.8's standard library
`importlib.metadata`_ module for Python 2.7, and 3.4 through 3.7. Users of
Python 3.8 and beyond are encouraged to use the standard library module, and
in fact for these versions, ``importlib_metadata`` just shadows that module.
Developers looking for detailed API descriptions should refer to the Python
3.8 standard library documentation.

The documentation here includes a general :ref:`usage <using>` guide.


.. toctree::
:maxdepth: 2
:caption: Contents:

using.rst
changelog.rst


Expand All @@ -27,3 +43,11 @@ Indices and tables
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`


.. _`metadata`: https://www.python.org/dev/peps/pep-0566/
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
.. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api
.. _`Python 3.7 and newer`: https://docs.python.org/3/library/importlib.html#module-importlib.resources
.. _`importlib_resources`: https://importlib-resources.readthedocs.io/en/latest/index.html
.. _`importlib.metadata`: TBD
Loading

0 comments on commit 23ac29a

Please sign in to comment.