diff --git a/Doc/library/packaging.database.rst b/Doc/library/packaging.database.rst --- a/Doc/library/packaging.database.rst +++ b/Doc/library/packaging.database.rst @@ -15,6 +15,12 @@ Installed Python distributions are repre Most functions also provide an extra argument ``use_egg_info`` to take legacy distributions into account. +For the purpose of this module, "installed" means that the distribution's +:file:`.dist-info`, :file:`.egg-info` or :file:`egg` directory or file is found +on :data:`sys.path`. If the parent directory of the :file:`dist-info` directory +of an installed project is for example added to :envvar:`PYTHONPATH`, then it +will be available in the database. + Classes representing installed distributions -------------------------------------------- @@ -128,12 +134,21 @@ Functions to work with the database for the first installed distribution matching *name*. Egg distributions are considered only if *use_egg_info* is true; if both a dist-info and an egg file are found, the dist-info prevails. The directories to be searched are - given in *paths*, which defaults to :data:`sys.path`. Return ``None`` if no + given in *paths*, which defaults to :data:`sys.path`. Returns ``None`` if no matching distribution is found. .. FIXME param should be named use_egg +.. function:: get_metadata(name, use_egg_info=False, paths=None) + + Return an instance of :class:`packaging.metadata.Metadata`. This function is + a shortcut for calling :func:`get_distribution` and getting the ``metadata`` + attribute of the result; all arguments have the same meaning as + :func:`get_distribution`. Returns ``None`` if no matching distribution is + found. + + .. function:: get_distributions(use_egg_info=False, paths=None) Return an iterator of :class:`Distribution` instances for all installed @@ -200,20 +215,23 @@ functions: Examples -------- -Print all information about a distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Printing all information about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Given a path to a ``.dist-info`` distribution, we shall print out all +Given the name of an installed distribution, we shall print out all information that can be obtained using functions provided in this module:: import sys import packaging.database - path = input() + try: + name = sys.argv[1] + except ValueError: + sys.exit('Not enough arguments') + # first create the Distribution instance - try: - dist = packaging.database.Distribution(path) - except IOError: + dist = packaging.database.get_distribution(name, use_egg_info=True) + if name is None: sys.exit('No such distribution') print('Information about %r' % dist.name) @@ -244,7 +262,7 @@ information from a :file:`.dist-info` di .. code-block:: sh - $ echo /tmp/choxie/choxie-2.0.0.9.dist-info | python3 print_info.py + python print_info.py choxie we get the following output: @@ -299,11 +317,27 @@ we get the following output: * It was installed as a dependency -Find out obsoleted distributions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Getting metadata about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Now, we take tackle a different problem, we are interested in finding out -which distributions have been obsoleted. This can be easily done as follows:: +If you're not interested about the packaging information contained in a full +:class:`Distribution` object but just want to do something with its metadata, +you can use the shortcut function :func:`get_metadata`:: + + from packaging.database import get_metadata + + info = get_metadata('chocolate') + if info is None: + print("'chocolate' not found") + else: + print("keywords for 'chocolate':", info['Keywords']) + + +Finding out obsoleted distributions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, we tackle a different problem, we are interested in finding out which +distributions have been obsoleted. This can be easily done as follows:: import packaging.database diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -16,9 +16,10 @@ from packaging.metadata import Metadata __all__ = [ 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', - 'get_distributions', 'get_distribution', 'get_file_users', - 'provides_distribution', 'obsoletes_distribution', + 'get_distributions', 'get_distribution', 'get_metadata', + 'get_file_users', 'provides_distribution', 'obsoletes_distribution', 'enable_cache', 'disable_cache', 'clear_cache', + # XXX these functions' names look like get_file_users but are not related 'get_file_path', 'get_file'] @@ -538,6 +539,17 @@ def get_distribution(name, use_egg_info= return None +def get_metadata(name, use_egg_info=False, paths=None): + """Return a metadata object for the dist called *name*. + + If no matching distribution is found, returns None. See + get_distribution for the meaning of *use_egg_info* and *paths*. + """ + dist = get_distribution(name, use_egg_info, paths) + if dist is not None: + return dist.metadata + + def obsoletes_distribution(name, version=None, use_egg_info=False): """ Iterates over all distributions to find which distributions obsolete diff --git a/Lib/packaging/tests/test_database.py b/Lib/packaging/tests/test_database.py --- a/Lib/packaging/tests/test_database.py +++ b/Lib/packaging/tests/test_database.py @@ -16,6 +16,7 @@ from packaging.metadata import Metadata from packaging.tests import unittest, support from packaging.database import ( Distribution, EggInfoDistribution, get_distribution, get_distributions, + get_metadata, provides_distribution, obsoletes_distribution, get_file_users, enable_cache, disable_cache, distinfo_dirname, _yield_distributions, get_file, get_file_path) @@ -383,6 +384,32 @@ class TestDatabase(support.LoggingCatche self.assertIsInstance(dist, EggInfoDistribution) self.assertEqual(dist.name, 'strawberry') + # TODO add tests for distribution names with spaces and other + # characters that get escaped by distinfo_dirname + + @requires_zlib + def test_get_metadata(self): + name = 'towel-stuff' + metadata = get_metadata(name) + self.assertIsInstance(metadata, Metadata) + self.assertEqual(metadata['Name'], name) + + eggdists = ('bacon', 'banana', 'cheese', 'strawberry') + + # default behavior does not consider legacy egg formats + for name in eggdists: + self.assertIsNone(get_metadata(name)) + + # with use_egg_info set to true, egg and egg-info files and + # directories are found + for name in eggdists: + metadata = get_metadata(name, use_egg_info=True) + self.assertIsInstance(metadata, Metadata) + self.assertEqual(metadata['Name'], name) + + # test that '' or '.' does not work in a dir with dist-info + # built and/or setup.cfg + def test_get_file_users(self): # Test the iteration of distributions that use a file. name = 'towel_stuff-0.1'