| :mod:`packaging.database` --- Database of installed distributions |
| ================================================================= |
| |
| .. module:: packaging.database |
| :synopsis: Functions to query and manipulate installed distributions. |
| |
| |
| This module provides an implementation of :PEP:`376`. It was originally |
| intended to land in :mod:`pkgutil`, but with the inclusion of Packaging in the |
| standard library, it was thought best to include it in a submodule of |
| :mod:`packaging`, leaving :mod:`pkgutil` to deal with imports. |
| |
| Installed Python distributions are represented by instances of |
| :class:`Distribution`, or :class:`EggInfoDistribution` for legacy egg formats. |
| Most functions also provide an extra argument ``use_egg_info`` to take legacy |
| distributions into account. |
| |
| |
| Classes representing installed distributions |
| -------------------------------------------- |
| |
| .. class:: Distribution(path) |
| |
| Class representing an installed distribution. It is different from |
| :class:`packaging.dist.Distribution` which holds the list of files, the |
| metadata and options during the run of a Packaging command. |
| |
| Instantiate with the *path* to a ``.dist-info`` directory. Instances can be |
| compared and sorted. Other available methods are: |
| |
| .. XXX describe how comparison works |
| |
| .. method:: get_distinfo_file(path, binary=False) |
| |
| Return a read-only file object for a file located at |
| :file:`{project}-{version}.dist-info/{path}`. *path* should be a |
| ``'/'``-separated path relative to the ``.dist-info`` directory or an |
| absolute path; if it is an absolute path and doesn't start with the path |
| to the :file:`.dist-info` directory, a :class:`PackagingError` is raised. |
| |
| If *binary* is ``True``, the file is opened in binary mode. |
| |
| .. method:: get_resource_path(relative_path) |
| |
| .. TODO |
| |
| .. method:: list_distinfo_files(local=False) |
| |
| Return an iterator over all files located in the :file:`.dist-info` |
| directory. If *local* is ``True``, each returned path is transformed into |
| a local absolute path, otherwise the raw value found in the :file:`RECORD` |
| file is returned. |
| |
| .. method:: list_installed_files(local=False) |
| |
| Iterate over the files installed with the distribution and registered in |
| the :file:`RECORD` file and yield a tuple ``(path, md5, size)`` for each |
| line. If *local* is ``True``, the returned path is transformed into a |
| local absolute path, otherwise the raw value is returned. |
| |
| A local absolute path is an absolute path in which occurrences of ``'/'`` |
| have been replaced by :data:`os.sep`. |
| |
| .. method:: uses(path) |
| |
| Check whether *path* was installed by this distribution (i.e. if the path |
| is present in the :file:`RECORD` file). *path* can be a local absolute |
| path or a relative ``'/'``-separated path. Returns a boolean. |
| |
| Available attributes: |
| |
| .. attribute:: metadata |
| |
| Instance of :class:`packaging.metadata.Metadata` filled with the contents |
| of the :file:`{project}-{version}.dist-info/METADATA` file. |
| |
| .. attribute:: name |
| |
| Shortcut for ``metadata['Name']``. |
| |
| .. attribute:: version |
| |
| Shortcut for ``metadata['Version']``. |
| |
| .. attribute:: requested |
| |
| Boolean indicating whether this distribution was requested by the user of |
| automatically installed as a dependency. |
| |
| |
| .. class:: EggInfoDistribution(path) |
| |
| Class representing a legacy distribution. It is compatible with distutils' |
| and setuptools' :file:`.egg-info` and :file:`.egg` files and directories. |
| |
| .. FIXME should be named EggDistribution |
| |
| Instantiate with the *path* to an egg file or directory. Instances can be |
| compared and sorted. Other available methods are: |
| |
| .. method:: list_installed_files(local=False) |
| |
| .. method:: uses(path) |
| |
| Available attributes: |
| |
| .. attribute:: metadata |
| |
| Instance of :class:`packaging.metadata.Metadata` filled with the contents |
| of the :file:`{project-version}.egg-info/PKG-INFO` or |
| :file:`{project-version}.egg` file. |
| |
| .. attribute:: name |
| |
| Shortcut for ``metadata['Name']``. |
| |
| .. attribute:: version |
| |
| Shortcut for ``metadata['Version']``. |
| |
| |
| Functions to work with the database |
| ----------------------------------- |
| |
| .. function:: get_distribution(name, use_egg_info=False, paths=None) |
| |
| Return an instance of :class:`Distribution` or :class:`EggInfoDistribution` |
| 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 |
| matching distribution is found. |
| |
| .. FIXME param should be named use_egg |
| |
| |
| .. function:: get_distributions(use_egg_info=False, paths=None) |
| |
| Return an iterator of :class:`Distribution` instances for all installed |
| distributions found in *paths* (defaults to :data:`sys.path`). If |
| *use_egg_info* is true, also return instances of :class:`EggInfoDistribution` |
| for legacy distributions found. |
| |
| |
| .. function:: get_file_users(path) |
| |
| Return an iterator over all distributions using *path*, a local absolute path |
| or a relative ``'/'``-separated path. |
| |
| .. XXX does this work with prefixes or full file path only? |
| |
| |
| .. function:: obsoletes_distribution(name, version=None, use_egg_info=False) |
| |
| Return an iterator over all distributions that declare they obsolete *name*. |
| *version* is an optional argument to match only specific releases (see |
| :mod:`packaging.version`). If *use_egg_info* is true, legacy egg |
| distributions will be considered as well. |
| |
| |
| .. function:: provides_distribution(name, version=None, use_egg_info=False) |
| |
| Return an iterator over all distributions that declare they provide *name*. |
| *version* is an optional argument to match only specific releases (see |
| :mod:`packaging.version`). If *use_egg_info* is true, legacy egg |
| distributions will be considered as well. |
| |
| |
| Utility functions |
| ----------------- |
| |
| .. function:: distinfo_dirname(name, version) |
| |
| Escape *name* and *version* into a filename-safe form and return the |
| directory name built from them, for example |
| :file:`{safename}-{safeversion}.dist-info.` In *name*, runs of |
| non-alphanumeric characters are replaced with one ``'_'``; in *version*, |
| spaces become dots, and runs of other non-alphanumeric characters (except |
| dots) a replaced by one ``'-'``. |
| |
| .. XXX wth spaces in version numbers? |
| |
| For performance purposes, the list of distributions is being internally |
| cached. Caching is enabled by default, but you can control it with these |
| functions: |
| |
| .. function:: clear_cache() |
| |
| Clear the cache. |
| |
| .. function:: disable_cache() |
| |
| Disable the cache, without clearing it. |
| |
| .. function:: enable_cache() |
| |
| Enable the internal cache, without clearing it. |
| |
| |
| Examples |
| -------- |
| |
| Print all information about a distribution |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| Given a path to a ``.dist-info`` distribution, we shall print out all |
| information that can be obtained using functions provided in this module:: |
| |
| import sys |
| import packaging.database |
| |
| path = input() |
| # first create the Distribution instance |
| try: |
| dist = packaging.database.Distribution(path) |
| except FileNotFoundError: |
| sys.exit('No such distribution') |
| |
| print('Information about %r' % dist.name) |
| print() |
| |
| print('Files') |
| print('=====') |
| for path, md5, size in dist.list_installed_files(): |
| print('* Path: %s' % path) |
| print(' Hash %s, Size: %s bytes' % (md5, size)) |
| print() |
| |
| print('Metadata') |
| print('========') |
| for key, value in dist.metadata.items(): |
| print('%20s: %s' % (key, value)) |
| print() |
| |
| print('Extra') |
| print('=====') |
| if dist.requested: |
| print('* It was installed by user request') |
| else: |
| print('* It was installed as a dependency') |
| |
| If we save the script above as ``print_info.py``, we can use it to extract |
| information from a :file:`.dist-info` directory. By typing in the console: |
| |
| .. code-block:: sh |
| |
| $ echo /tmp/choxie/choxie-2.0.0.9.dist-info | python3 print_info.py |
| |
| we get the following output: |
| |
| .. code-block:: none |
| |
| Information about 'choxie' |
| |
| Files |
| ===== |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9/truffles.py |
| Hash 5e052db6a478d06bad9ae033e6bc08af, Size: 111 bytes |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py |
| Hash ac56bf496d8d1d26f866235b95f31030, Size: 214 bytes |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py |
| Hash 416aab08dfa846f473129e89a7625bbc, Size: 25 bytes |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER |
| Hash d41d8cd98f00b204e9800998ecf8427e, Size: 0 bytes |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA |
| Hash 696a209967fef3c8b8f5a7bb10386385, Size: 225 bytes |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED |
| Hash d41d8cd98f00b204e9800998ecf8427e, Size: 0 bytes |
| * Path: ../tmp/distutils2/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD |
| Hash None, Size: None bytes |
| |
| Metadata |
| ======== |
| Metadata-Version: 1.2 |
| Name: choxie |
| Version: 2.0.0.9 |
| Platform: [] |
| Supported-Platform: UNKNOWN |
| Summary: Chocolate with a kick! |
| Description: UNKNOWN |
| Keywords: [] |
| Home-page: UNKNOWN |
| Author: UNKNOWN |
| Author-email: UNKNOWN |
| Maintainer: UNKNOWN |
| Maintainer-email: UNKNOWN |
| License: UNKNOWN |
| Classifier: [] |
| Download-URL: UNKNOWN |
| Obsoletes-Dist: ['truffles (<=0.8,>=0.5)', 'truffles (<=0.9,>=0.6)'] |
| Project-URL: [] |
| Provides-Dist: ['truffles (1.0)'] |
| Requires-Dist: ['towel-stuff (0.1)'] |
| Requires-Python: UNKNOWN |
| Requires-External: [] |
| |
| Extra |
| ===== |
| * It was installed as a dependency |
| |
| |
| Find out obsoleted distributions |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| 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:: |
| |
| import packaging.database |
| |
| # iterate over all distributions in the system |
| for dist in packaging.database.get_distributions(): |
| name, version = dist.name, dist.version |
| # find out which distributions obsolete this name/version combination |
| replacements = packaging.database.obsoletes_distribution(name, version) |
| if replacements: |
| print('%r %s is obsoleted by' % (name, version), |
| ', '.join(repr(r.name) for r in replacements)) |
| |
| This is how the output might look like: |
| |
| .. code-block:: none |
| |
| 'strawberry' 0.6 is obsoleted by 'choxie' |
| 'grammar' 1.0a4 is obsoleted by 'towel-stuff' |