diff options
Diffstat (limited to 'docs/source/library/pkgutil.rst')
| -rw-r--r-- | docs/source/library/pkgutil.rst | 218 |
1 files changed, 172 insertions, 46 deletions
diff --git a/docs/source/library/pkgutil.rst b/docs/source/library/pkgutil.rst index d529508..43a9a2a 100644 --- a/docs/source/library/pkgutil.rst +++ b/docs/source/library/pkgutil.rst @@ -4,77 +4,204 @@ .. module:: pkgutil :synopsis: Utilities to support packages. -.. TODO Follow the reST conventions used in the stdlib - -This module provides functions to manipulate packages, as well as -the necessary functions to provide support for the "Importer Protocol" as -described in :PEP:`302` and for working with the database of installed Python -distributions which is specified in :PEP:`376`. In addition to the functions -required in :PEP:`376`, back support for older ``.egg`` and ``.egg-info`` -distributions is provided as well. These distributions are represented by the -class :class:`~distutils2._backport.pkgutil.EggInfoDistribution` and most -functions provide an extra argument ``use_egg_info`` which indicates if -they should consider these old styled distributions. This document details -first the functions and classes available and then presents several use cases. +This module provides utilities to manipulate packages: support for the +Importer protocol defined in :PEP:`302` and implementation of the API +described in :PEP:`376` to work with the database of installed Python +distributions. +Import system utilities +----------------------- .. function:: extend_path(path, name) - Extend the search path for the modules which comprise a package. Intended use is - to place the following code in a package's :file:`__init__.py`:: + Extend the search path for the modules which comprise a package. Intended + use is to place the following code in a package's :file:`__init__.py`:: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories on - ``sys.path`` named after the package. This is useful if one wants to distribute - different parts of a single logical package as multiple directories. + This will add to the package's ``__path__`` all subdirectories of directories + on :data:`sys.path` named after the package. This is useful if one wants to + distribute different parts of a single logical package as multiple + directories. - It also looks for :file:`\*.pkg` files beginning where ``*`` matches the *name* - argument. This feature is similar to :file:`\*.pth` files (see the :mod:`site` - module for more information), except that it doesn't special-case lines starting - with ``import``. A :file:`\*.pkg` file is trusted at face value: apart from - checking for duplicates, all entries found in a :file:`\*.pkg` file are added to - the path, regardless of whether they exist on the filesystem. (This is a - feature.) + It also looks for :file:`\*.pkg` files beginning where ``*`` matches the + *name* argument. This feature is similar to :file:`\*.pth` files (see the + :mod:`site` module for more information), except that it doesn't special-case + lines starting with ``import``. A :file:`\*.pkg` file is trusted at face + value: apart from checking for duplicates, all entries found in a + :file:`\*.pkg` file are added to the path, regardless of whether they exist + on the filesystem. (This is a feature.) If the input path is not a list (as is the case for frozen packages) it is returned unchanged. The input path is not modified; an extended copy is returned. Items are only appended to the copy at the end. - It is assumed that ``sys.path`` is a sequence. Items of ``sys.path`` that are - not strings referring to existing directories are ignored. Unicode items on - ``sys.path`` that cause errors when used as filenames may cause this function - to raise an exception (in line with :func:`os.path.isdir` behavior). + It is assumed that :data:`sys.path` is a sequence. Items of :data:`sys.path` + that are not strings referring to existing directories are ignored. Unicode + items on :data:`sys.path` that cause errors when used as filenames may cause + this function to raise an exception (in line with :func:`os.path.isdir` + behavior). + + +.. class:: ImpImporter(dirname=None) + + :pep:`302` Importer that wraps Python's "classic" import algorithm. + + If *dirname* is a string, a :pep:`302` importer is created that searches that + directory. If *dirname* is ``None``, a :pep:`302` importer is created that + searches the current :data:`sys.path`, plus any modules that are frozen or + built-in. + + Note that :class:`ImpImporter` does not currently support being used by + placement on :data:`sys.meta_path`. + + +.. class:: ImpLoader(fullname, file, filename, etc) + + :pep:`302` Loader that wraps Python's "classic" import algorithm. + + +.. function:: find_loader(fullname) + + Find a :pep:`302` "loader" object for *fullname*. + + If *fullname* contains dots, path must be the containing package's + ``__path__``. Returns ``None`` if the module cannot be found or imported. + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: get_importer(path_item) + + Retrieve a :pep:`302` importer for the given *path_item*. + + The returned importer is cached in :data:`sys.path_importer_cache` if it was + newly created by a path hook. + + If there is no importer, a wrapper around the basic import machinery is + returned. This wrapper is never inserted into the importer cache (None is + inserted instead). + + The cache (or part of it) can be cleared manually if a rescan of + :data:`sys.path_hooks` is necessary. + + +.. function:: get_loader(module_or_name) + + Get a :pep:`302` "loader" object for *module_or_name*. + + If the module or package is accessible via the normal import mechanism, a + wrapper around the relevant part of that machinery is returned. Returns + ``None`` if the module cannot be found or imported. If the named module is + not already imported, its containing package (if any) is imported, in order + to establish the package ``__path__``. + + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: iter_importers(fullname='') + + Yield :pep:`302` importers for the given module name. + + If fullname contains a '.', the importers will be for the package containing + fullname, otherwise they will be importers for :data:`sys.meta_path`, + :data:`sys.path`, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side effect + of invoking this function. + + Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard + import machinery to find files in alternative locations are partially + supported, but are searched *after* :data:`sys.path`. Normally, these + locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must be a module + or package name that is accessible via both :data:`sys.path` and one of the + non-:pep:`302` file system mechanisms. In this case, the emulation will find + the former version, while the builtin import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, + ``imp.PKG_DIRECTORY``. + + +.. function:: iter_modules(path=None, prefix='') + + Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if + path is ``None``, all top-level modules on :data:`sys.path`. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + +.. function:: walk_packages(path=None, prefix='', onerror=None) + + Yields ``(module_loader, name, ispkg)`` for all modules recursively on + *path*, or, if path is ``None``, all accessible modules. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + Note that this function must import all *packages* (*not* all modules!) on + the given *path*, in order to access the ``__path__`` attribute to find + submodules. + + *onerror* is a function which gets called with one argument (the name of the + package which was being imported) if any exception occurs while trying to + import a package. If no *onerror* function is supplied, :exc:`ImportError`\s + are caught and ignored, while all other exceptions are propagated, + terminating the search. + + Examples:: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__ + '.') + .. function:: get_data(package, resource) Get a resource from a package. - This is a wrapper for the :pep:`302` loader :func:`get_data` API. The package - argument should be the name of a package, in standard module format - (foo.bar). The resource argument should be in the form of a relative - filename, using ``/`` as the path separator. The parent directory name + This is a wrapper for the :pep:`302` loader :func:`get_data` API. The + *package* argument should be the name of a package, in standard module format + (``foo.bar``). The *resource* argument should be in the form of a relative + filename, using ``/`` as the path separator. The parent directory name ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). - The function returns a binary string that is the contents of the - specified resource. + The function returns a binary string that is the contents of the specified + resource. For packages located in the filesystem, which have already been imported, this is the rough equivalent of:: - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then None is returned. + which does not support :func:`get_data`, then ``None`` is returned. + +Installed distributions database +-------------------------------- -API Reference -============= +Installed Python distributions are represented by instances of +:class:`~distutils2._backport.pkgutil.Distribution`, or its subclass +:class:`~distutils2._backport.pkgutil.EggInfoDistribution` for legacy ``.egg`` +and ``.egg-info`` formats). Most functions also provide an extra argument +``use_egg_info`` to take legacy distributions into account. -.. automodule:: distutils2._backport.pkgutil - :members: +.. TODO write docs here, don't rely on automodule + classes: Distribution and descendents + functions: provides, obsoletes, replaces, etc. Caching +++++++ @@ -86,11 +213,10 @@ it using :func:`~distutils2._backport.pkgutil.enable_cache`, :func:`~distutils2._backport.pkgutil.clear_cache`. +Examples +-------- -Example Usage -============= - -Print All Information About a Distribution +Print all information about a distribution ++++++++++++++++++++++++++++++++++++++++++ Given a path to a ``.dist-info`` distribution, we shall print out all @@ -182,7 +308,7 @@ we get the following output: ===== * It was installed as a dependency -Find Out Obsoleted Distributions +Find out obsoleted distributions ++++++++++++++++++++++++++++++++ Now, we take tackle a different problem, we are interested in finding out |
