Commits

Vinay Sajip committed d2b351b Draft

Merged Ryan Macy's changes.

Comments (0)

Files changed (10)

docs/database.rst

 
    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
+   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`. Returns ``None`` if no
    matching distribution is found.
 
    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*
+   :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) are replaced by one ``'-'``.
 

docs/depgraph.rst

 .. class:: DependencyGraph
 
    Represent a dependency graph between releases. The nodes are distribution
-   instances, the edge model dependencies. An edge from ``a`` to ``b`` means
+   instances, the edges model dependencies. An edge from ``a`` to ``b`` means
    that ``a`` depends on ``b``.
 
    .. method:: add_distribution(distribution)

docs/internals.rst

   with a specific directory, and no other package can be associated with that
   directory.
 * Support should be provided for access to data deployed in the file system or
-  in packages contained in .zip files and third parties should be able to
+  in packages contained in .zip files, and third parties should be able to
   extend the facilities to work with other storage formats which support import
   of Python packages.
 * It should be possible to access the contents of any resource through a
 accesses.
 
 We know that we need to support resource access in the file system as well as
-.zip files and to support other sources of storage which might be used to
+.zip files, and to support other sources of storage which might be used to
 import Python packages. Since import and loading of Python packages happens
 through :pep:`302` importers and loaders, we can deduce that the mechanism used
 to find resources in a package will be closely tied to the loader for that
     r2 = find_resource(pkg, 'bar')
 
 However, we'll often have situations where we will want to get multiple
-resources from a package and in certain applications we might want to
+resources from a package, and in certain applications we might want to
 implement caching or other processing of resources before returning them.
 The above API doesn't facilitate this, so let's consider delegating the finding
 of resources in a package to a *finder* for that package. Once we get a finder,
 object for a package and returns a finder.
 
 Let's consider in more detail what finders look like and how they interact with
-the ``Resource`` class. We'll keep the Resource class minimal, API users never
+the ``Resource`` class. We'll keep the Resource class minimal; API users never
 instantiate ``Resource`` directly, but call a finder's ``find`` method to
 return a ``Resource`` instance. A finder could return an instance of a
 ``Resource`` subclass if really needed, though it shouldn't be necessary in
 
   where ``<rootdir>`` is the user's home directory. On Windows, if the
   environment specifies a variable named ``LOCALAPPDATA``, its value
-  will be used as ``<rootdir>``, otherwise, the user's home directory
+  will be used as ``<rootdir>`` -- otherwise, the user's home directory
   will be used.
 
 * A :meth:`get` method which takes a ``Resource`` and returns a file system
   and returns a (``prefix``, ``subpath``) tuple.
 
   The default implementation will use :func:`os.splitdrive` to see if there's
-  a Windows drive and convert its ``':'`` to ``'---'``. The rest of the
-  prefix will be converted by replacing ``'/'`` by ``'--'``, and appending
-  ``'.cache'`` to the result.
+  a Windows drive, if present, and convert its ``':'`` to ``'---'``. The rest
+  of the prefix will be converted by replacing ``'/'`` by ``'--'``, and
+  appending ``'.cache'`` to the result.
 
 The cache will be activated when the ``file_path`` property of a ``Resource``
 is accessed. This will be a cached property, and will call the cache's

docs/metadata.rst

 
    This class can read and write metadata files complying with any of the
    defined versions: 1.0 (:PEP:`241`), 1.1 (:PEP:`314`) and 1.2 (:PEP:`345`).
-   It implements methods to parse Metadata files and write them and a mapping
-   interface to its contents.
+   It implements methods to parse Metadata files and write them and provide a
+   mapping interface to its contents.
 
    The :PEP:`345` implementation supports the micro-language for the environment
    markers and displays warnings when versions that are supposed to be

docs/migration.rst

 ~~~~~~~~~~~~~~~~~~
 
 You can provide an ``XXXResourceFinder`` class which finds resources in custom
-storage containers and works like ``ResourceFinder``. Although it shouldn't
+storage containers, and works like ``ResourceFinder``. Although it shouldn't
 be necessary, you could also return a subclass of :class:`Resource` from your
 finders, to deal with custom requirements which aren't catered for.
 

docs/overview.rst

 While some very good work was done in defining PEPs to codify some of the
 best practices, ``packaging`` suffered from some drawbacks, too:
 
-* Not all the PEPs may have been functionality complete, because some important
+* Not all the PEPs may have been functionally complete, because some important
   use cases were not considered -- for example, built (binary) distributions for
   Windows.
 
 * There were a lot of rough edges in the ``packaging`` implementation, both
   in terms of bugs and in terms of incompletely implemented features. This
   can be seen (with the benefit of hindsight) as due to the goals being set too
-  ambitiously, the project developers bit off more than they could chew.
+  ambitiously; the project developers bit off more than they could chew.
 
 How Distlib can help
 --------------------

docs/reference.rst

       unchanged from the values in the ``RECORD`` file, written when the
       distribution was installed. It returns a list of mismatches. If the files
       in the distribution haven't been corrupted , an empty list will be
-      returned, otherwise, a list of mismatches will be returned.
+      returned; otherwise, a list of mismatches will be returned.
 
       :returns: A list which, if non-empty, will contain tuples with the
                 following elements:
 .. class:: DependencyGraph
 
    This class represents a dependency graph between releases. The nodes are
-   distribution instances; the edge model dependencies. An edge from ``a``
+   distribution instances; the edges model dependencies. An edge from ``a``
    to ``b`` means that ``a`` depends on ``b``.
 
    .. method:: add_distribution(distribution)
    This convenience function returns the latest version of a potentially
    downloadable distribution which matches a requirement (name and version
    constraints). If a potentially downloadable distribution (i.e. one with
-   a download URL) is not found, ``None`` is returned, otherwise, an
+   a download URL) is not found, ``None`` is returned -- otherwise, an
    instance of :class:`~distlib.database.Distribution` is returned. The
    returned instance will have, at a minimum, ``name``, ``version`` and
    ``download_url``.

docs/tutorial.rst

 ------------
 
 .. note:: Since ``distlib`` has not received its first release yet, you can't
-  currently install it from PyPI - the documentation below is a little
-  premature. Instead, you need to clone the Mercurial repository at
+   currently install it from PyPI - the documentation below is a little
+   premature. Instead, you need to clone the Mercurial repository at
 
-  https://bitbucket.org/vinay.sajip/distlib/
+   https://bitbucket.org/vinay.sajip/distlib/
 
-  or
+   or
 
-  http://hg.python.org/distlib/
+   http://hg.python.org/distlib/
 
-  followed by doing a ``python setup.py install`` invocation, ideally in a
-  virtual environment (like venv).
+   followed by doing a ``python setup.py install`` invocation, ideally in a
+   virtual environment (venv).
 
 Distlib is a pure-Python library. You should be able to install it using::
 
 
 .. currentmodule:: distlib.database
 
-   You can use the ``distlib.database`` package to access information about
-   installed distributions. This information is available through the
-   following classes:
+You can use the ``distlib.database`` package to access information about
+installed distributions. This information is available through the
+following classes:
 
-   * :class:`DistributionPath`, which represents a set of distributions installed
-     on a path.
-   * :class:`Distribution`, which represents an individual distribution,
-     conforming to recent packaging PEPs (:pep:`386`, :pep:`376`, :pep:`345`,
-     :pep:`314` and :pep:`241`).
-   * :class:`EggInfoDistribution`, which represents a legacy distribution in
-     egg format.
+* :class:`DistributionPath`, which represents a set of distributions installed
+  on a path.
+
+* :class:`Distribution`, which represents an individual distribution,
+  conforming to recent packaging PEPs (:pep:`386`, :pep:`376`, :pep:`345`,
+  :pep:`314` and :pep:`241`).
+* :class:`EggInfoDistribution`, which represents a legacy distribution in
+  egg format.
 
 Distribution paths
 ~~~~~~~~~~~~~~~~~~
 variety of sources, message text to be internationalised. Babel itself provides
 functionality to extract messages from e.g. Python and JavaScript source code,
 but helpfully offers a mechanism whereby providers of other sources of
-message text can offer their own extractors. It does this by providing a
+message text can provide their own extractors. It does this by providing a
 category ``'babel.extractors'``, under which other software can register
 extractors for their sources. The `Jinja2 <http://jinja2.pocoo.org/>`_ template
 engine, for example, makes use of this to provide a message extractor for
 
 .. currentmodule:: distlib.scripts
 
-   You can use the ``distlib.scripts`` API to install scripts. Installing scripts
-   is slightly more involved than just copying files:
+You can use the ``distlib.scripts`` API to install scripts. Installing scripts
+is slightly more involved than just copying files:
 
-    * You may need to adjust shebang lines in scripts to point to the interpreter
-      that will be used to run scripts. This is important in virtual environments
-      (venvs), and also in other situations where you may have multiple Python
-      installations on a single computer.
-    * On Windows or on systems where the :pep:`397` launcher isn't installed, it is
-      not easy to ensure that the correct Python interpreter is used for a script.
-      You may wish to install native Windows executable launchers which run the
-      correct interpreter, based on a shebang line in the script.
+* You may need to adjust shebang lines in scripts to point to the interpreter
+  to be used to run scripts. This is important in virtual environments (venvs),
+  and also in other situations where you may have multiple Python installations
+  on a single computer.
 
-   Specifying scripts to install
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* On Windows, on systems where the :pep:`397` launcher isn't installed, it is not
+  easy to ensure that the correct Python interpreter is used for a script. You
+  may wish to install native Windows executable launchers which run the correct
+  interpreter, based on a shebang line in the script.
 
-   To install scripts, create a :class:`ScriptMaker` instance,
-   giving it the source and target directories for scripts::
+Specifying scripts to install
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-      >>> from distlib.scripts import ScriptMaker
-      >>> maker = ScriptMaker(source_dir, target_dir)
-      >>>
+To install scripts, create a :class:`ScriptMaker` instance,
+giving it
+the source and target directories for scripts::
 
-   You can then install a script ``foo.py`` like this::
+    >>> from distlib.scripts import ScriptMaker
+    >>> maker = ScriptMaker(source_dir, target_dir)
 
-      >>> maker.make('foo.py')
-      >>>
+You can then install a script ``foo.py`` like this:
 
-   The string passed to make can take one of the following forms:
+    >>> maker.make('foo.py')
 
-   * A filename, relative to the source directory for scripts, such as ``foo.py``
-     or ``subdir/bar.py``.
-   * A reference to a callable, given in the form::
+The string passed to make can take one of the following forms:
 
-    name = some_package.some_module:some_callable [flags]
+* A filename, relative to the source directory for scripts, such as ``foo.py``
+  or ``subdir/bar.py``.
+* A reference to a callable, given in the form::
 
-   where the *flags* part is optional. The only flag currently in use is
-   ``'gui'``, which indicates on Windows that a Windows executable launcher
-   (rather than a launcher which is a console application) should be used.
-   (this only applies if ``add_launchers`` is true)
+      name = some_package.some_module:some_callable [flags]
 
-   For more information about flags, see :ref:`flag-formats`.
+  where the *flags* part is optional. The only flag currently in use is
+  ``'gui'``, which indicates on Windows that a Windows executable launcher
+  (rather than a launcher which is a console application) should be used.
+  (This only applies if ``add_launchers`` is true.)
 
-   Note that this format is exactly the same as for export entries in a
-   distribution (see :ref:`dist-exports`).
+  For more information about flags, see :ref:`flag-formats`.
 
-   When this form is passed to the :meth:`ScriptMaker.make`
-   method, a Python stub script is created with the appropriate shebang line
-   and with code to load and call the specified callable with no arguments,
-   returning its value as the return code from the script.
+  Note that this format is exactly the same as for export entries in a
+  distribution (see :ref:`dist-exports`).
 
-   Wrapping callables with scripts
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  When this form is passed to the :meth:`ScriptMaker.make`
+  method, a Python stub script is created with the appropriate shebang line
+  and with code to load and call the specified callable with no arguments,
+  returning its value as the return code from the script.
 
-   Let's see how wrapping a callable works. Consider the following file::
+Wrapping callables with scripts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's see how wrapping a callable works. Consider the following file::
 
     $ cat scripts/foo.py
       def main():
 
 .. currentmodule:: distlib.version
 
-   Overview
-   ~~~~~~~~
+Overview
+~~~~~~~~
 
-   The :class:`NormalizedVersion` class implements a :pep:`386` compatible
-   version::
+The :class:`NormalizedVersion` class implements a :pep:`386` compatible
+version::
 
       >>> from distlib.version import NormalizedVersion
       >>> v1 = NormalizedVersion('1.0')
       >>> v5 = NormalizedVersion('1.0.post1')
       >>>
 
-   These sort in the expected order::
+These sort in the expected order::
 
       >>> v2 < v3 < v4 < v1 < v5
       True
       >>>
 
-   You can't pass any old thing as a version number::
+You can't pass any old thing as a version number::
 
       >>> NormalizedVersion('foo')
       Traceback (most recent call last):
       distlib.version.UnsupportedVersionError: foo
       >>>
 
-   Matching versions against constraints
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Matching versions against constraints
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-   The :class:`NormalizedMatcher` is used to match version constraints against
-   versions::
+The :class:`NormalizedMatcher` is used to match version constraints against
+versions::
 
       >>> from distlib.version import NormalizedMatcher
       >>> m = NormalizedMatcher('foo (1.0b1)')
       [False, False, True, False, False]
       >>>
 
-   Specifying ``'foo (1.0b1)'`` is equivalent to specifying ``'foo (==1.0b1)'``,
-   i.e. only the exact version is matched. You can also specify inequality
-   constraints::
+Specifying ``'foo (1.0b1)'`` is equivalent to specifying ``'foo (==1.0b1)'``,
+i.e. only the exact version is matched. You can also specify inequality
+constraints::
 
       >>> m = NormalizedMatcher('foo (<1.0c1)')
       >>> [m.match(v) for v in v1, v2, v3, v4, v5]
       [False, True, True, False, False]
       >>>
 
-   and multiple constraints::
+and multiple constraints::
 
       >>> m = NormalizedMatcher('foo (>= 1.0b1, <1.0.post1)')
       >>> [m.match(v) for v in v1, v2, v3, v4, v5]
       [True, False, True, True, False]
       >>>
 
-   You can do exactly the same thing as above with ``setuptools``/
-   ``distribute`` version numbering (use ``LegacyVersion`` and ``LegacyMatcher``)
-   or with semantic versioning (use ``SemanticVersion`` and ``SemanticMatcher``).
-   However, you can't mix and match versions of different types::
+You can do exactly the same thing as above with ``setuptools``/
+``distribute`` version numbering (use ``LegacyVersion`` and ``LegacyMatcher``)
+or with semantic versioning (use ``SemanticVersion`` and ``SemanticMatcher``).
+However, you can't mix and match versions of different types::
 
       >>> from distlib.version import SemanticVersion, LegacyVersion
       >>> nv = NormalizedVersion('1.0.0')
 
 .. currentmodule:: distlib.locators
 
-   Overview
-   ~~~~~~~~
+Overview
+~~~~~~~~
 
-   To locate a distribution in an index, we can use the :func:`locate` function.
-   This returns a potentially downloadable distribution (in the sense that it
-   has a download URL - of course, there are no guarantees that there will
-   actually be a downloadable resource at that URL). The return value is an
-   instance of :class:`distlib.database.Distribution` which can be queried for
-   any distributions it requires, so that they can be located if desired.
-   Here is a basic example::
+To locate a distribution in an index, we can use the :func:`locate` function.
+This returns a potentially downloadable distribution (in the sense that it
+has a download URL - of course, there are no guarantees that there will
+actually be a downloadable resource at that URL). The return value is an
+instance of :class:`distlib.database.Distribution` which can be queried for
+any distributions it requires, so that they can also be located if desired.
+Here is a basic example::
 
       >>> from distlib.locators import locate
       >>> flask = locate('flask')
       <Distribution Jinja2 (2.6) [http://pypi.python.org/packages/source/J/Jinja2/Jinja2-2.6.tar.gz]>]
       >>>
 
-   The values returned by :meth:`get_requirements` are just strings. Here's another
-   example, showing a little more detail::
+The values returned by :meth:`get_requirements` are just strings. Here's another example,
+showing a little more detail::
 
       >>> authy = locate('authy')
       >>> authy.get_requirements('install')
       <Distribution simplejson (2.6.2) [http://pypi.python.org/packages/source/s/simplejson/simplejson-2.6.2.tar.gz]>]
       >>>
 
-   Note that the constraints on the dependencies were honoured by :func:`locate`.
+Note that the constraints on the dependencies were honoured by :func:`locate`.
 
-   Under the hood
-   ~~~~~~~~~~~~~~
 
-   Under the hood, :func:`locate` uses *locators*. Locators are a mechanism for
-   finding distributions from a range of sources. Although the ``pypi`` subpackage
-   has been copied from ``distutils2`` to ``distlib``, there may be benefits in a
-   higher-level API, and so the ``distlib.locators`` package has been created as
-   an experiment. Locators are objects which locate distributions. A locators
-   instance's :meth:`get_project` method is called, passing in a project name: The
-   method returns a dictionary containing information about distribution releases
-   found for that project. The keys of the returned dictionary are versions, and
-   the values are instances of :class:`distlib.database.Distribution`.
+Under the hood
+~~~~~~~~~~~~~~
 
-   The following locators are provided:
+Under the hood, :func:`locate` uses *locators*. Locators are a mechanism for
+finding distributions from a range of sources. Although the ``pypi`` subpackage
+has been copied from ``distutils2`` to ``distlib``, there may be benefits in a
+higher-level API, and so the ``distlib.locators`` package has been created as
+an experiment. Locators are objects which locate distributions. A locator
+instance's :meth:`get_project` method is called, passing in a project name: The
+method returns a dictionary containing information about distribution releases
+found for that project. The keys of the returned dictionary are versions, and
+the values are instances of :class:`distlib.database.Distribution`.
 
-   * :class:`DirectoryLocator` -- this is instantiated with a base directory and
-     will look for archives in the file system tree under that directory. Name
-     and version information is inferred from the filenames of archives and the
-     amount of information returned about the download is minimal.
-   * :class:`PyPIRPCLocator`. -- This takes a base URL for the RPC service and
-     will locate packages using PyPI's XML-RPC API. This locator is a little slow
-     (the scraping interface seems to work faster) and case-sensitive. For
-     example, searching for ``'flask'`` will throw up no results, but you get the
-     expected results when searching for ``'Flask'``. This appears to be a
-     limitation of the underlying XML-RPC API. Note that 20 versions of a
-     project necessitate 41 network calls (one to get the versions and
-     two more for each version -- one to get the metadata, and another to get the
-     downloads information).
-   * :class:`PyPIJSONLocator`. -- This takes a base URL for the JSON service and
-     will locate packages using PyPI's JSON API. This locator is case-sensitive. For
-     example, searching for ``'flask'`` will throw up no results, but you get the
-     expected results when searching for ``'Flask'``. This appears to be a
-     limitation of the underlying JSON API. Note that unlike the XML-RPC service,
-     only non-hidden releases will be returned.
-   * :class:`SimpleScrapingLocator` -- this takes a base URL for the site to
-     scrape, and locates packages using a similar approach to the
-     ``PackageFinder`` class in ``pip``, or as documented in ``setuptools``
-     as the approach used by ``easy_install``.
-   * :class:`DistPathLocator` -- this takes a :class:`DistributionPath` instance
-     and locates installed distributions. This can be used with
-     :class:`AggregatingLocator` to satisfy requirements from installed
-     distributions before looking elsewhere for them.
-   * :class:`AggregatingLocator` -- this takes a list of other aggregators and
-     delegates finding projects to them. It can either return the first result
-     found (i.e. from the first aggregator in the list provided which returns a
-     non-empty result) or a merged result from all the aggregators in the list.
+The following locators are provided:
 
-   There is a default locator, available at :attr:`distlib.locators.default_locator`.
+* :class:`DirectoryLocator` -- this is instantiated with a base directory and
+  will look for archives in the file system tree under that directory. Name
+  and version information is inferred from the filenames of archives, and the
+  amount of information returned about the download is minimal.
 
-   An example of usage of locator instances is given below::
+* :class:`PyPIRPCLocator`. -- This takes a base URL for the RPC service and
+  will locate packages using PyPI's XML-RPC API. This locator is a little slow
+  (the scraping interface seems to work faster) and case-sensitive. For
+  example, searching for ``'flask'`` will throw up no results, but you get the
+  expected results when searching from ``'Flask'``. This appears to be a
+  limitation of the underlying XML-RPC API. Note that 20 versions of a
+  project necessitate 41 network calls (one to get the versions, and
+  two more for each version -- one to get the metadata, and another to get the
+  downloads information).
 
-      >>> from distlib.locators import SimpleScrapingLocator
-      >>> from pprint import pprint
-      >>> locator = SimpleScrapingLocator('http://pypi.python.org/simple/')
-      >>> result = locator.get_project('python-gnupg')
-      >>> pprint(result)
-      {u'0.2.3': <Distribution python-gnupg (0.2.3) [http://python-gnupg.googlecode.com/files/python-gnupg-0.2.3.tar.gz]>,
-       u'0.2.4': <Distribution python-gnupg (0.2.4) [http://python-gnupg.googlecode.com/files/python-gnupg-0.2.4.tar.gz]>,
-       u'0.2.9': <Distribution python-gnupg (0.2.9) [http://python-gnupg.googlecode.com/files/python-gnupg-0.2.9.tar.gz]>,
-       u'0.3.0': <Distribution python-gnupg (0.3.0) [http://python-gnupg.googlecode.com/files/python-gnupg-0.3.0.tar.gz]>,
-       u'0.3.1': <Distribution python-gnupg (0.3.1) [http://python-gnupg.googlecode.com/files/python-gnupg-0.3.1.tar.gz]>}
-      >>>
+* :class:`PyPIJSONLocator`. -- This takes a base URL for the JSON service and
+  will locate packages using PyPI's JSON API. This locator is case-sensitive. For
+  example, searching for ``'flask'`` will throw up no results, but you get the
+  expected results when searching from ``'Flask'``. This appears to be a
+  limitation of the underlying JSON API. Note that unlike the XML-RPC service,
+  only non-hidden releases will be returned.
 
-   Now the same project, using the XML-RPC API::
+* :class:`SimpleScrapingLocator` -- this takes a base URL for the site to
+  scrape, and locates packages using a similar approach to the
+  ``PackageFinder`` class in ``pip``, or as documented in the ``setuptools``
+  documentation as the approach used by ``easy_install``.
 
-      >>> from distlib.locators import PyPIRPCLocator
-      >>> locator = PyPIRPCLocator('http://python.org/pypi')
-      >>> result = locator.get_project('python-gnupg')
-      >>> pprint(result)
-      {'0.2.3': <Distribution python-gnupg (0.2.3) [http://python-gnupg.googlecode.com/files/python-gnupg-0.2.3.tar.gz]>,
-       '0.2.4': <Distribution python-gnupg (0.2.4) [http://python-gnupg.googlecode.com/files/python-gnupg-0.2.4.tar.gz]>,
-       '0.2.6': <Distribution python-gnupg (0.2.6) [UNKNOWN]>,
-       '0.2.7': <Distribution python-gnupg (0.2.7) [UNKNOWN]>,
-       '0.2.8': <Distribution python-gnupg (0.2.8) [UNKNOWN]>,
-       '0.2.9': <Distribution python-gnupg (0.2.9) [http://python-gnupg.googlecode.com/files/python-gnupg-0.2.9.tar.gz]>,
-       '0.3.0': <Distribution python-gnupg (0.3.0) [http://python-gnupg.googlecode.com/files/python-gnupg-0.3.0.tar.gz]>,
-       '0.3.1': <Distribution python-gnupg (0.3.1) [http://python-gnupg.googlecode.com/files/python-gnupg-0.3.1.tar.gz]>}
-      >>>
+* :class:`DistPathLocator` -- this takes a :class:`DistributionPath` instance
+  and locates installed distributions. This can be used with
+  :class:`AggregatingLocator` to satisfy requirements from installed
+  distributions before looking elsewhere for them.
 
-   .. note::
-      The reason why some of the download URLs come up as UNKNOWN is that some of
-      the PyPI metadata is incomplete.
+* :class:`AggregatingLocator` -- this takes a list of other aggregators and
+  delegates finding projects to them. It can either return the first result
+  found (i.e. from the first aggregator in the list provided which returns a
+  non-empty result), or a merged result from all the aggregators in the list.
 
-   Locators also have a method, :meth:`get_distribution_names`, which returns a
-   set of all the distribution names known to that locator instance. Note that
-   the base :class:`Locator` and :class:`JSONLocator` classes don't implement this
-   method, so they will raise a :class:`NotImplementedError`.
+There is a default locator, available at :attr:`distlib.locators.default_locator`.
 
-   The ``locators`` package also contains a function,
-   :func:`get_all_distribution_names`, which retrieves the names of all
-   distributions registered on PyPI::
+The ``locators`` package also contains a function,
+:func:`get_all_distribution_names`, which retrieves the names of all
+distributions registered on PyPI::
 
       >>> from distlib.locators import get_all_distribution_names
       >>> names = get_all_package_names()
       24801
       >>>
 
-   This is implemented using the XML-RPC API.
+This is implemented using the XML-RPC API.
 
    The Locator API is very bare-bones at the moment, but additional features will
    be added in due course. A very bare-bones command-line script which exercises
 =========================================================
 
 .. module:: packaging.util
-  :synopsis: Miscellaneous utility functions.
+   :synopsis: Miscellaneous utility functions.
 
 
 This module contains various helpers for the other modules.
 
 .. XXX a number of functions are missing, but the module may be split first
-  (it's ginormous right now, some things could go to compat for example)
+   (it's ginormous right now, some things could go to compat for example)
 
 .. function:: get_platform()
 
    or to the same directory when using the distutils2 backport on Python
    versions older than 3.2.
 
-   *py_files* is a list of files to compile, any files that don't end in
+   *py_files* is a list of files to compile; any files that don't end in
    :file:`.py` are silently skipped. *optimize* must be one of the following:
 
    * ``0`` - don't optimize (generate :file:`.pyc`)
    * ``2`` - extra optimization (like ``python -OO``)
 
    This function is independent from the running Python's :option:`-O` or
-   :option:`-B` options, it is fully controlled by the parameters passed in.
+   :option:`-B` options; it is fully controlled by the parameters passed in.
 
    If *force* is true, all files are recompiled regardless of timestamps.
 
    The source filename encoded in each :term:`bytecode` file defaults to the
-   filenames listed in *py_files*, you can modify these with *prefix* and
+   filenames listed in *py_files*; you can modify these with *prefix* and
    *basedir*. *prefix* is a string that will be stripped off of each source
    filename, and *base_dir* is a directory name that will be prepended (after
    *prefix* is stripped). You can supply either or both (or neither) of
    :class:`NormalizedVersion`::
 
       >>> NormalizedVersion("irrational_version_number")
+      ...
       IrrationalVersionError: irrational_version_number
       >>>
 
 
       >>> print(suggest_normalized_version('not a version'))
       None
-      >>
+      >>>
 
 Version predicates
 ------------------
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.