Skip to content

Commit

Permalink
Fix #185: Update documentation to correct links.
Browse files Browse the repository at this point in the history
  • Loading branch information
vsajip committed Sep 2, 2022
1 parent 2b33be1 commit 98b9b89
Show file tree
Hide file tree
Showing 8 changed files with 542 additions and 324 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ Released: 2013-04-30

- metadata

- Added missing condition in :meth:`todict`.
- Added missing condition in :meth:`~distlib.metadata.Metadata.todict`.

- scripts

Expand Down
5 changes: 3 additions & 2 deletions distlib/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@
_PYTHON_VERSION = sys.version_info[:2]

class Manifest(object):
"""A list of files built by on exploring the filesystem and filtered by
applying various patterns to what we find there.
"""
A list of files built by exploring the filesystem and filtered by applying various
patterns to what we find there.
"""

def __init__(self, base=None):
Expand Down
2 changes: 1 addition & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXBUILD = sphinx-build -n
PAPER =
BUILDDIR = _build

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@


# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}

def skip_module_docstring(app, what, name, obj, options, lines):
if (what, name) == ('module', 'distlib'):
Expand Down
149 changes: 76 additions & 73 deletions docs/internals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,24 @@ Locating distributions
~~~~~~~~~~~~~~~~~~~~~~

It seems that the simplest API to locate a distribution would look like
``locate(requirement)``, where ``requirement`` is a string giving the
distribution name and optional version constraints. Given that we know that
distributions can be found in different places, it's best to consider a
:class:`Locator` class which has a :meth:`locate` method with a corresponding
``locate(requirement)``, where ``requirement`` is a string giving the distribution
name and optional version constraints. Given that we know that distributions can be
found in different places, it's best to consider a :class:`~distlib.locators.Locator`
class which has a :meth:`~distlib.locators.Locator.locate` method with a corresponding
signature, with subclasses for each of the different types of location that
distributions inhabit. It's also reasonable to provide a default locator in
a module attribute :attr:`default_locator`, and a module-level :func:`locate`
function which calls the :meth:`locate` method on the default locator.

Since we'll often need to locate all the versions of a project before picking
one, we can imagine that a locator would need a :meth:`get_project` method for
fetching all versions of a project; and since we will be likely to want to use
caching, we can assume there will be a :meth:`_get_project` method to do the
actual work of fetching the version data, which the higher-level
:meth:`get_project` will call (and probably cache). So our locator base class
will look something like this::
distributions inhabit. It's also reasonable to provide a default locator in a module
attribute :attr:`~distlib.locators.default_locator`, and a module-level
:func:`~distlib.locators.locate` function which calls the
:meth:`~distlib.locators.Locator.locate` method on the default locator.

Since we'll often need to locate all the versions of a project before picking one, we
can imagine that a locator would need a :meth:`~distlib.locators.Locator.get_project`
method for fetching all versions of a project; and since we will be likely to want to
use caching, we can assume there will be a
:meth:`~distlib.locators.Locator._get_project` method to do the actual work of
fetching the version data, which the higher-level
:meth:`~distlib.locators.Locator.get_project` will call (and probably cache). So our
locator base class will look something like this::

class Locator(object):
"""
Expand Down Expand Up @@ -114,20 +116,20 @@ will look something like this::
instance, or an empty dictionary if nothing was found.
"""

When attempting to :meth:`locate`, it would be useful to pass requirement
information to :meth:`get_project` / :meth:`_get_project`. This can be done in
a :attr:`matcher` attribute which is normally ``None`` but set to a
:class:`distlib.version.Matcher` instance when a :meth:`locate` call is in
progress.
When attempting to :meth:`~distlib.locators.Locator.locate`, it would be useful to
pass requirement information to :meth:`~distlib.locators.Locator.get_project` /
:meth:`~distlib.locators.Locator._get_project`. This can be done in a :attr:`~distlib.locators.Locator.matcher`
attribute which is normally ``None`` but set to a :class:`~distlib.version.Matcher`
instance when a :meth:`~distlib.locators.Locator.locate` call is in progress.

Note that in order to work with legacy version numbers (those not complying with PEP
440), you need to pass ``scheme='legacy'`` to the initializer for a locator.

Finding dependencies
~~~~~~~~~~~~~~~~~~~~

A dependency finder will depend on a locator to locate dependencies. A simple
approach will be to consider a :class:`DependencyFinder` class which takes a
A dependency finder will depend on a locator to locate dependencies. A simple approach
will be to consider a :class:`~distlib.locators.DependencyFinder` class which takes a
locator as a constructor argument. It might look something like this::

class DependencyFinder(object):
Expand Down Expand Up @@ -195,17 +197,19 @@ A minimal solution
^^^^^^^^^^^^^^^^^^

The distutils approach was to have several separate command classes called
``register``, ``upload`` and ``upload_doc``, where really all that was needed
was some methods. That's the approach ``distlib`` takes, by implementing a
:class:`PackageIndex` class with :meth:`register`, :meth:`upload_file` and
:meth:`upload_documentation` methods. The :class:`PackageIndex` class contains
no user interface code whatsoever: that's assumed to be the domain of the
packaging tool. The packaging tool is expected to get the required information
from a user using whatever means the developers of that tool deem to be the
most appropriate; the required attributes are then set on the
:class:`PackageIndex` instance. (Examples of this kind of information: user
name, password, whether the user wants to save a default configuration, where
the signing program and its keys live.)
``register``, ``upload`` and ``upload_doc``, where really all that was needed was some
methods. That's the approach ``distlib`` takes, by implementing a
:class:`~distlib.index.PackageIndex` class with
:meth:`~distlib.index.PackageIndex.register`,
:meth:`~distlib.index.PackageIndex.upload_file` and
:meth:`~distlib.index.PackageIndex.upload_documentation` methods. The
:class:`~distlib.index.PackageIndex` class contains no user interface code whatsoever:
that's assumed to be the domain of the packaging tool. The packaging tool is expected
to get the required information from a user using whatever means the developers of
that tool deem to be the most appropriate; the required attributes are then set on the
:class:`~distlib.index.PackageIndex` instance. (Examples of this kind of information:
user name, password, whether the user wants to save a default configuration, where the
signing program and its keys live.)

The minimal interface to provide the required functionality thus looks like
this::
Expand Down Expand Up @@ -245,8 +249,8 @@ this::
archiving the directory contents into a .zip file.
"""

The following additional attributes can be identified on :class:`PackageIndex`
instances:
The following additional attributes can be identified on
:class:`~distlib.index.PackageIndex` instances:

* ``username`` - the username to use for authentication.
* ``password`` - the password to use for authentication.
Expand Down Expand Up @@ -465,7 +469,7 @@ available via a file on the file system, we'll assume a simple caching
solution that saves any such resources to a local file system cache, and
returns the filename of the resource in the cache. We need to divide the
work between the finder and the cache. We'll deliver the cache function
through a :class:`Cache` class, which will have the following methods:
through a :class:`~distlib.util.Cache` class, which will have the following methods:

* A constructor which takes an optional base directory for the cache. If
none is provided, we'll construct a base directory of the form::
Expand All @@ -477,36 +481,36 @@ through a :class:`Cache` class, which will have the following methods:
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
filename, such that the contents of that named file will be the contents
of the resource.

* An :meth:`is_stale` method which takes a ``Resource`` and its corresponding
file system filename, and returns whether the file system file is stale
when compared with the resource. Knowing that cache invalidation is hard,
the default implementation just returns ``True``.

* A :meth:`prefix_to_dir` method which converts a prefix to a directory name.
We'll assume that for the cache, a resource path can be divided into two
parts: the *prefix* and the *subpath*. For resources in a .zip file, the
prefix would be the pathname of the archive, while the subpath would be the
path inside the archive. For a file system resource, since it is already in
the file system, the prefix would be ``None`` and the subpath would be the
absolute path name of the resource. The :meth:`prefix_to_dir` method's job
is to convert a prefix (if not ``None``) to a subdirectory in the cache
that holds the cached files for all resources with that prefix. We'll
delegate the determination of a resource's prefix and subpath to its finder,
using a :meth:`get_cache_info` method on finders, which takes a ``Resource``
and returns a (``prefix``, ``subpath``) tuple.

The default implementation will use :func:`os.splitdrive` to see if there's
* A :meth:`~distlib.resources.ResourceCache.get` method which takes a ``Resource`` and
returns a file system filename, such that the contents of that named file will be
the contents of the resource.

* An :meth:`~distlib.resources.ResourceCache.is_stale` method which takes a
``Resource`` and its corresponding file system filename, and returns whether the
file system file is stale when compared with the resource. Knowing that cache
invalidation is hard, the default implementation just returns ``True``.

* A :meth:`~distlib.util.Cache.prefix_to_dir` method which converts a
prefix to a directory name. We'll assume that for the cache, a resource path can be
divided into two parts: the *prefix* and the *subpath*. For resources in a .zip
file, the prefix would be the pathname of the archive, while the subpath would be
the path inside the archive. For a file system resource, since it is already in the
file system, the prefix would be ``None`` and the subpath would be the absolute path
name of the resource. The :meth:`~distlib.util.Cache.prefix_to_dir` method's job is
to convert a prefix (if not ``None``) to a subdirectory in the cache that holds the
cached files for all resources with that prefix. We'll delegate the determination of
a resource's prefix and subpath to its finder, using a
:meth:`~distlib.resources.ResourceFinder.get_cache_info` method on finders, which
takes a ``Resource`` and returns a (``prefix``, ``subpath``) tuple.

The default implementation will use :func:`os.path.splitdrive` to see if there's
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
:meth:`get` method to obtain the file system path.
:meth:`~distlib.resources.ResourceCache.get` method to obtain the file system path.

The ``scripts`` API
-------------------
Expand Down Expand Up @@ -602,9 +606,9 @@ In addition, other methods suggest themselves for :class:`ScriptMaker`:
analysis tool, over all the installed files.

* The details of the callable specification can be encapsulated in a utility
function, :func:`~distlib.util.get_exports_entry`. This would take a
specification and return ``None``, if the specification didn't match the
callable format, or an instance of :class:`ExportEntry` if it did match.
function, :func:`~distlib.util.get_export_entry`. This would take a specification
and return ``None``, if the specification didn't match the callable format, or an
instance of :class:`~distlib.util.ExportEntry` if it did match.

In addition, the following attributes on a ``ScriptMaker`` could be further used
to refine its behaviour:
Expand Down Expand Up @@ -863,11 +867,10 @@ each scheme are bundled into a simple :class:`VersionScheme` class::
Of course, the version class is also available through the matcher's
``version_class`` attribute.

:class:`VersionScheme` makes it easier to work with alternative version schemes.
For example, say we decide to experiment with an "adaptive" version scheme,
which is based on the PEP 386 scheme, but when handed a non-conforming version,
automatically tries to convert it to a normalized version using
:func:`suggest_normalized_version`. Then, code which has to deal with version
:class:`VersionScheme` makes it easier to work with alternative version schemes. For
example, say we decide to experiment with an "adaptive" version scheme, which is based
on the PEP 386 scheme, but when handed a non-conforming version, automatically tries
to convert it to a normalized version. Then, code which has to deal with version
schemes just has to pick the appropriate scheme by name.

Creating the adaptive scheme is easy::
Expand Down Expand Up @@ -927,10 +930,10 @@ There are basically two operations which need to be performed on wheels:
A minimal solution
^^^^^^^^^^^^^^^^^^

Since we're talking about wheels, it seems likely that a :class:`Wheel` class
would be part of the design. This allows for extensibility over a purely
function-based API. The :class:`Wheel` would be expected to have methods that
support the required operations::
Since we're talking about wheels, it seems likely that a :class:`~distlib.wheel.Wheel`
class would be part of the design. This allows for extensibility over a purely
function-based API. The :class:`~distlib.wheel.Wheel` would be expected to have
methods that support the required operations::

class Wheel(object):
def __init__(self, spec):
Expand Down Expand Up @@ -985,7 +988,7 @@ support the required operations::
"""

In addition to the above, the following attributes can be identified for a
:class:`Wheel` instance:
:class:`~distlib.wheel.Wheel` instance:

* ``name`` -- the name of the distribution
* ``version`` -- the version of the distribution
Expand Down
48 changes: 25 additions & 23 deletions docs/migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ Resource extraction

resources.cache = resources.Cache(extraction_path)

before accessing the ``file_path`` property of any :class:`Resource`.
Note that if you have accessed the ``file_path`` property for a resource
*before* doing this, the cache may already have extracted files.
before accessing the ``file_path`` property of any
:class:`~distlib.resources.Resource`. Note that if you have accessed the
``file_path`` property for a resource *before* doing this, the cache may already
have extracted files.

``cleanup_resources(force=False)``
This is not actually implemented in ``pkg_resources`` -- it's a no-op.
Expand All @@ -55,9 +56,9 @@ Resource extraction
Provider interface
~~~~~~~~~~~~~~~~~~

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

``get_cache_path(archive_name, names=())``
Expand All @@ -66,17 +67,18 @@ finders, to deal with custom requirements which aren't catered for.
API, please give feedback with more information about your use cases.

``extraction_error()``
There's no analogue for this. The :meth:`Cache.get` method, which writes
a resource's bytes to a file in the cache, will raise any exception caused
by underlying I/O. If you need to handle this in the cache layer, you can
subclass :class:`Cache` and override :meth:`get`. If that doesn't work for
you, please give feedback with more information about your use cases.
There's no analogue for this. The :meth:`~distlib.resources.ResourceCache.get`
method, which writes a resource's bytes to a file in the cache, will raise any
exception caused by underlying I/O. If you need to handle this in the cache layer,
you can subclass :class:`~distlib.resources.ResourceCache` and override
:meth:`~distlib.resources.ResourceCache.get`. If that doesn't work for you, please
give feedback with more information about your use cases.

``postprocess(tempname, filename)``
There's no analogue for this. The :meth:`Cache.get` method, which writes
a resource's bytes to a file in the cache, can be overridden to perform any
custom post-processing. If that doesn't work for you, please give feedback
with more information about your use cases.
There's no analogue for this. The :meth:`~distlib.resources.ResourceCache.get`
method, which writes a resource's bytes to a file in the cache, can be overridden
to perform any custom post-processing. If that doesn't work for you, please give
feedback with more information about your use cases.

The ``pkg_resources`` entry point API
-------------------------------------
Expand All @@ -89,15 +91,15 @@ term is a little ambiguous. In Eclipse, for example, they are called *extension
point IDs*, which is a little closer to the intended usage, but a bit of a
mouthful. In ``distlib``, we'll use the term ``category`` or ``export category``.

In ``distlib``, the implementation of exports is slightly different from
entry points of ``pkg_resources``. A :class:`Distribution` instance has an
``exports`` attribute, which is a dictionary keyed by category and whose values
are dictionaries that map names to :class:`ExportEntry` instances.
In ``distlib``, the implementation of exports is slightly different from entry points
of ``pkg_resources``. A :class:`~distlib.database.Distribution` instance has an
``exports`` attribute, which is a dictionary keyed by category and whose values are
dictionaries that map names to :class:`~distlib.util.ExportEntry` instances.

Below are the ``pkg_resources`` functions and how to achieve the equivalent
in ``distlib``. In cases where the ``pkg_resources`` functions take distribution
names, in ``distlib`` you get the corresponding :class:`Distribution` instance,
using::
Below are the ``pkg_resources`` functions and how to achieve the equivalent in
``distlib``. In cases where the ``pkg_resources`` functions take distribution names,
in ``distlib`` you get the corresponding :class:`~distlib.database.Distribution`
instance, using::

dist = dist_path.get_distribution(distname)

Expand Down

0 comments on commit 98b9b89

Please sign in to comment.