diff --git a/CHANGES.rst b/CHANGES.rst index 8942503..6352e74 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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 diff --git a/distlib/manifest.py b/distlib/manifest.py index ca0fe44..18beba3 100644 --- a/distlib/manifest.py +++ b/distlib/manifest.py @@ -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): diff --git a/docs/Makefile b/docs/Makefile index bbeb6cf..f526618 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -3,7 +3,7 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = sphinx-build +SPHINXBUILD = sphinx-build -n PAPER = BUILDDIR = _build diff --git a/docs/conf.py b/docs/conf.py index 042b52c..6937b5d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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'): diff --git a/docs/internals.rst b/docs/internals.rst index c66be1e..c3f3929 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -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): """ @@ -114,11 +116,11 @@ 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. @@ -126,8 +128,8 @@ Note that in order to work with legacy version numbers (those not complying with 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): @@ -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:: @@ -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. @@ -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:: @@ -477,36 +481,36 @@ through a :class:`Cache` class, which will have the following methods: will be used as ```` -- 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 ------------------- @@ -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: @@ -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:: @@ -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): @@ -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 diff --git a/docs/migration.rst b/docs/migration.rst index aa1ac3a..b87f165 100644 --- a/docs/migration.rst +++ b/docs/migration.rst @@ -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. @@ -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=())`` @@ -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 ------------------------------------- @@ -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) diff --git a/docs/reference.rst b/docs/reference.rst index 73c2304..d504c8b 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -6,9 +6,24 @@ API Reference This is the place where the functions and classes in ``distlib's`` public API are described. +The ``distlib`` package +----------------------- + +.. currentmodule:: distlib + +Classes +^^^^^^^ + +.. class:: DistlibException + + This is the base class for all exceptions raised by this packages, other than + lower-level standard Python exceptions. + The ``distlib.database`` package -------------------------------- +.. currentmodule:: distlib.database + Classes ^^^^^^^ @@ -26,7 +41,7 @@ Classes :param path: The path to use when looking for distributions. If ``None`` is specified, ``sys.path`` is used. - :type path: list of str + :type path: list[str] :param include_egg: If ``True``, legacy distributions (eggs) are included in the search; otherwise, they aren't. @@ -79,7 +94,7 @@ Classes entries in the category are returned. :type name: str :returns: An iterator which iterates over exported entries (instances of - :class:`ExportEntry`). + :class:`~distlib.util.ExportEntry`). .. class:: Distribution @@ -207,7 +222,7 @@ Classes directory is written. :param exports: A dictionary whose keys are categories and whose values - are dictionaries which contain :class:`ExportEntry` + are dictionaries which contain :class:`~distlib.util.ExportEntry` instances keyed on their name. :type exports: dict :param filename: The filename to read from, or ``None`` to read from the @@ -285,6 +300,24 @@ Classes Dictionary mapping distributions to a list of requirements that were not provided by any distribution. +Functions +^^^^^^^^^ + +.. function:: make_graph(dists, scheme='default') + + Return a dependency graph from the given distributions. + +.. function:: get_dependent_dists(dists, dist) + + Recursively generate a list of distributions from *dists* that are dependent on + *dist*. + +.. function:: get_required_dists(dists, dist) + + Recursively generate a list of distributions from *dists* that are required by + *dist*. + + The ``distlib.resources`` package --------------------------------- @@ -364,7 +397,7 @@ Classes This attribute is set by the resource's finder. It is a textual representation of the path, such that if a PEP 302 loader's - :meth:`get_data` method is called with the path, the resource's + ``get_data()`` method is called with the path, the resource's bytes are returned by the loader. This attribute is analogous to the ``resource_filename`` API in ``setuptools``. Note that for resources in zip files, the path will be a pointer to the resource @@ -381,7 +414,7 @@ Classes to a file in a cache in the file system, and the name of the cached file is returned. This is for use with APIs that need file names, or need to be able to access data through OS-level file handles. See - the :class:`~distlib.resources.Cache` documentation for more + the :class:`~distlib.resources.ResourceCache` documentation for more information about the cache. Methods: @@ -463,6 +496,16 @@ Classes :type resource: a :class:`Resource` instance :returns: The size of the resource in bytes. + .. method:: get_cache_info(resource) + + Return the cache information for the specified resource. This is a two-tuple + consisting of an optional prefix (currently used for zip-based resources only, + and is otherwise ``None``) and an absolute path. + + :param resource: The resource for which the cache info is wanted. + :type resource: a :class:`Resource` instance + :returns: tuple + .. class:: ZipResourceFinder @@ -484,7 +527,7 @@ Classes Ensures that the resource is available as a file in the file system, and returns the name of that file. This method calls the resource's - finder's :meth:`get_cache_info` method. + finder's :meth:`~distlib.resources.ResourceFinder.get_cache_info` method. .. method:: is_stale(resource, path) @@ -493,6 +536,7 @@ Classes implementation returns ``True``, causing the resource's data to be re-written to the file every time. +.. _scripts: The ``distlib.scripts`` package ------------------------------- @@ -527,6 +571,16 @@ Classes Whether to overwrite scripts even when timestamps show they're up to date. + .. attribute:: clobber + + Whether to overwrite existing scripts. The default is ``False``, which means that + existing scripts will not be overwritten. + + .. attribute:: executable + + Value to use for the executable to use when constructing a shebang. If specified, + it is used in place of any value determined algorithmically. + .. attribute:: set_mode Whether, on Posix, the scripts should have their execute mode set. @@ -682,7 +736,7 @@ Functions ``"/usr/bin/env /dir with spaces/bin/jython"`` .. versionchanged:: 0.3.1 - This was an internal function :func:`_enquote_executable` in earlier versions. + This was an internal function ``_enquote_executable`` in earlier versions. The ``distlib.locators`` package -------------------------------- @@ -696,6 +750,10 @@ Classes The base class for locators. Implements logic common to multiple locators. + .. attribute:: matcher + + A :class:~distlib.version.VersionMatcher` + .. method:: __init__(scheme='default') Initialise an instance of the locator. @@ -703,12 +761,17 @@ Classes :param scheme: The version scheme to use. :type scheme: str - .. method:: get_project(name) + .. method:: _get_project(name) This method should be implemented in subclasses. It returns a (potentially empty) dictionary whose keys are the versions located for the project named by ``name``, and whose values are instances of - :class:`distlib.util.Distribution`. + :class:`distlib.database.Distribution`. + + .. method:: get_project(name) + + This method calls :meth:`_get_project` to do the actual work, and provides a + caching layer on top. .. method:: convert_url_to_download_info(url, project_name) @@ -846,13 +909,13 @@ Classes .. class:: DistPathLocator - This locator uses a :class:`DistributionPath` instance to locate installed - distributions. + This locator uses a :class:`~distlib.database.DistributionPath` instance to locate + installed distributions. .. method:: __init__(url, distpath, **kwargs) :param distpath: The distribution path to use. - :type distpath: :class:`DistributionPath` + :type distpath: :class:`~distlib.database.DistributionPath` :param kwargs: Passed to base class constructor. .. class:: AggregatingLocator(Locator) @@ -865,13 +928,16 @@ Classes .. method:: __init__(*locators, **kwargs) :param locators: A list of aggregators to delegate finding projects to. - :type locators: sequence of locators + + :type locators: list[Locator] + :param merge: If this *kwarg* is ``True``, each aggregator in the list is asked to provide results, which are aggregated into a results dictionary. If ``False``, the first non-empty return value from the list of aggregators is returned. The locators are consulted in the order in which they're passed in. + :type merge: bool .. class:: DependencyFinder @@ -889,29 +955,29 @@ Classes Find all the distributions needed to fulfill ``requirement``. :param requirement: A string of the from ``name (version)`` where - version can include an inequality constraint, or an - instance of :class:`Distribution` (e.g. representing - a distribution on the local hard disk). + version can include an inequality constraint, or an instance + of :class:`~distlib.database.Distribution` (e.g. + representing a distribution on the local hard disk). :param meta_extras: A list of meta extras such as :test:, :build: and so on, to be included in the dependencies. :param prereleases: If ``True``, allow pre-release versions to be returned - otherwise, don't return prereleases unless they're all that's available. - :returns: A 2-tuple. The first element is a set of :class:`Distribution` - instances. The second element is a set of problems encountered - during dependency resolution. Currently, if this set is non- - empty, it will contain 2-tuples whose first element is the - string 'unsatisfied' and whose second element is a requirement - which couldn't be satisfied. + :returns: A 2-tuple. The first element is a set of + :class:`~distlib.database.Distribution` instances. The second element + is a set of problems encountered during dependency resolution. + Currently, if this set is non- empty, it will contain 2-tuples whose + first element is the string 'unsatisfied' and whose second element is + a requirement which couldn't be satisfied. - In the set of :class:`Distribution` instances returned, some - attributes will be set: + In the set of :class:`~distlib.database.Distribution` instances + returned, some attributes will be set: * The instance representing the passed-in ``requirement`` will - have the :attr:`requested` attribute set to ``True``. + have the ``requested`` attribute set to ``True``. * All requirements which are not installation requirements (in other words, are needed only for build and test) will have - the :attr:`build_time_dependency` attribute set to ``True``. + the ``build_time_dependency`` attribute set to ``True``. Functions @@ -1000,10 +1066,9 @@ Classes can see this in PyPI's Web UI when you click the "Package submission" link in the left-hand side menu. :returns: An ``urllib`` HTTP response returned by the index. If an error - occurs, an :class:`HTTPError` exception will be raised. + occurs, an :class:`~urllib.error.HTTPError` exception will be raised. - .. method:: upload_file(metadata, filename, signer=None, sign_password=None, - filetype='sdist', pyversion='source', keystore=None) + .. method:: upload_file(metadata, filename, signer=None, sign_password=None, filetype='sdist', pyversion='source', keystore=None) Upload a distribution to the index. @@ -1032,7 +1097,7 @@ Classes instance's ``gpg_home`` attribute is used instead. This parameter is not used unless a signer is specified. :returns: An ``urllib`` HTTP response returned by the index. If an error - occurs, an :class:`HTTPError` exception will be raised. + occurs, an :class:`~urllib.error.HTTPError` exception will be raised. .. versionchanged:: 0.1.9 The ``keystore`` argument was added. @@ -1050,10 +1115,9 @@ Classes documentation. This directory should be the one that contains ``index.html``. :returns: An ``urllib`` HTTP response returned by the index. If an error - occurs, an :class:`HTTPError` exception will be raised. + occurs, an :class:`~urllib.error.HTTPError` exception will be raised. - .. method:: verify_signature(self, signature_filename, data_filename, - keystore=None) + .. method:: verify_signature(self, signature_filename, data_filename, keystore=None) Verify a digital signature against a downloaded distribution. @@ -1071,6 +1135,15 @@ Classes .. versionchanged:: 0.1.9 The ``keystore`` argument was added. + .. method:: read_configuration() + + Read the PyPI access configuration. + + .. method:: save_configuration() + + Save the PyPI access configuration. You must have set ``username`` and + ``password`` attributes before calling this method. + .. method:: search(query, operation=None) Search the index for distributions matching a search query. @@ -1209,7 +1282,18 @@ Classes .. attribute:: dist The distribution which exports this entry. This is normally an - instance of :class:`InstalledDistribution`. + instance of :class:`~distlib.database.InstalledDistribution`. + +.. class:: HTTPSHandler + + A request handler inheriting from :class:`urllib.request.HTTPSHandler` which does + certificate validation. + +.. class:: HTTPSOnlyHandler + + A request handler inheriting from :class:`urllib.request.HTTPSHandler` which raises + an exception if an attempt is made to open an HTTP (as opposed to HTTPS) + connection. Functions ^^^^^^^^^ @@ -1240,13 +1324,13 @@ Functions * As a place to cache package resources which need to be in the file system, because they are used by APIs which either expect filesystem paths, or to be able to use OS-level file handles. An example of the - former is the :meth:`SSLContext.load_verify_locations` method in + former is the :meth:`~ssl.SSLContext.load_verify_locations` method in Python's ``ssl`` module. The subdirectory ``resource-cache`` is used for this purpose. * As a place to cache shared libraries which are extracted as a result - of calling the :meth:`~wheel.Wheel.mount` method of the - :class:`~wheel.Wheel` class. The subdirectory ``dylib-cache`` is used + of calling the :meth:`~distlib.wheel.Wheel.mount` method of the + :class:`~distlib.wheel.Wheel` class. The subdirectory ``dylib-cache`` is used for this purpose. The application using this cache functionality, whether through the @@ -1302,6 +1386,8 @@ Functions The ``distlib.wheel`` package ----------------------------- +.. currentmodule:: distlib.wheel + This package has functionality which allows you to work with wheels (see :pep:`427`). @@ -1376,10 +1462,10 @@ Classes the wheel is for a pure-Python distribution. :param maker: This should be set to a suitably configured instance of - :class:`ScriptMaker`. The ``source_dir`` and ``target_dir`` - arguments can be set to ``None`` when creating the - instance - these will be set to appropriate values inside - this method. + :class:`~distlib.scripts.ScriptMaker`. The ``source_dir`` and + ``target_dir`` arguments can be set to ``None`` when creating the + instance - these will be set to appropriate values inside this + method. :param warner: If specified, should be a callable that will be called with (software_wheel_ver, file_wheel_ver) if they differ. @@ -1415,11 +1501,11 @@ Classes for import. If the wheel tags indicate it is not compatible with the running Python, - a :class:`DistlibException` is raised. (The :meth:`is_compatible` + a :class:`~distlib.DistlibException` is raised. (The :meth:`is_compatible` method is used to determine compatibility.) If the wheel is indicated as not suitable for mounting, a - :class:`DistlibException` is raised. (The :meth:`is_mountable` + :class:`distlib.DistlibException` is raised. (The :meth:`is_mountable` method is used to determine mountability.) :param append: If ``True``, the wheel's pathname is added to the end of @@ -1427,7 +1513,7 @@ Classes .. note:: Wheels may state in their metadata that they are not intended to be mountable, in which case this method will raise a - :class:`DistlibException` with a suitable message. If C extensions + :class:`distlib.DistlibException` with a suitable message. If C extensions are extracted, the location for extraction will be under the directory ``dylib-cache`` in the directory returned by :func:`~distlib.util.get_cache_base`. @@ -1452,7 +1538,7 @@ Classes Verify sizes and hashes of the wheel's contents against the sizes and hashes declared in the wheel's RECORD. Raise a - :class:`DistlibException` if a size or digest mismatch is detected. + :class:`distlib.DistlibException` if a size or digest mismatch is detected. .. versionadded:: 0.1.8 @@ -1513,8 +1599,8 @@ Classes .. attribute:: metadata - The metadata for the distribution in the wheel, as a :class:`Metadata` - instance. + The metadata for the distribution in the wheel, as a + :class:`~distlib.metadata.Metadata` instance. .. attribute:: info @@ -1544,6 +1630,116 @@ Functions :return: ``True`` if compatible, else ``False``. +The ``distlib.versions`` package +-------------------------------- + +.. currentmodule:: distlib.version + +This package has functionality which allows you to work with standard versions (see +:pep:`440`) but also legacy versions and semantic versions. + +Classes +^^^^^^^ + +.. class:: Version + + This base class represents a version. + +.. class:: Matcher + + This base class represents a version matcher. It's used for parsing and comparing + versions. + +.. class:: VersionScheme + + This class represents a version scheme (e.g. legacy, semantic or standard). + +.. class:: NormalizedVersion + + This class represents :pep:`440`-compatible versions. + +.. class:: NormalizedMatcher + + This class represents a matcher for :pep:`440`-compatible versions. + + +Functions +^^^^^^^^^ + +.. function:: get_scheme(name) + + Return a :class:`VersionScheme` instance corresponding to the specified *name*. + +The ``distlib.manifest`` package +-------------------------------- + +.. currentmodule:: distlib.manifest + +This package has functionality which allows you to maintain a manifest, i.e. a list of +files which makes up a source distribution. + +Classes +^^^^^^^ + +.. class:: Manifest + + This base class represents a manifest. You can explore files under a directory, + add and remove files, and process directives to e.g. include or exclude files based + on patterns. + + .. attribute:: files + + The list of paths representing files included in the manifest. + + .. attribute:: allfiles + + The list of paths representing all files in the directory tree which the manifest + is based on. + + .. attribute:: base + + The base directory on which this manifest instance is based. + + .. method:: process_directive(directive) + + Process a *directive* which either adds some files from ``allfiles`` to + ``files``, or removes some files from ``files``. + +The ``distlib.metadata`` package +-------------------------------- + +.. currentmodule:: distlib.metadata + +This package has functionality which allows you to manage a distribution's metadata. + +Classes +^^^^^^^ + +.. class:: Metadata + + This class represents a distribution's metadata. + + .. method:: todict() + + Returns the metadata as a dictionary. + + +The ``distlib.markers`` package +-------------------------------- + +.. currentmodule:: distlib.markers + +This package has functionality for interpreting environment markers. + +Functions +^^^^^^^^^ + +.. function:: interpret(marker, execution_context=None) + + This function returns the result of interpreting an environment marker in aptional + execution context, which is used for name lookups. + + Next steps ---------- diff --git a/docs/tutorial.rst b/docs/tutorial.rst index f69a9da..d1f7ade 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -118,10 +118,10 @@ following classes: Distribution paths ~~~~~~~~~~~~~~~~~~ -The :class:`Distribution` and :class:`EggInfoDistribution` classes are normally -not instantiated directly; rather, they are returned by querying -:class:`DistributionPath` for distributions. To create a ``DistributionPath`` -instance, you can do :: +The :class:`Distribution` and :class:`EggInfoDistribution` classes are normally not +instantiated directly; rather, they are returned by querying +:class:`~distlib.database.DistributionPath` for distributions. To create a +``DistributionPath`` instance, you can do :: >>> from distlib.database import DistributionPath >>> dist_path = DistributionPath() @@ -131,7 +131,8 @@ Querying a path for distributions In this most basic form, ``dist_path`` will provide access to all non-legacy distributions on ``sys.path``. To get these distributions, you invoke the -:meth:`get_distributions` method, which returns an iterable. Let's try it:: +:meth:`~distlib.database.DistributionPath.get_distributions` method, which returns an +iterable. Let's try it:: >>> list(dist_path.get_distributions()) [] @@ -153,9 +154,9 @@ and then you'll get a less surprising result:: >>> len(list(dist_path.get_distributions())) 77 -The exact number returned will be different for you, of course. You can ask -for a particular distribution by name, using the :meth:`get_distribution` -method:: +The exact number returned will be different for you, of course. You can ask for a +particular distribution by name, using the +:meth:`~distlib.database.DistributionPath.get_distribution` method:: >>> dist_path.get_distribution('setuptools') @@ -257,8 +258,8 @@ callable, ``suffix`` is the path to the callable in the module, and flags can be used for any purpose determined by the distribution author (for example, the ``extras`` feature in ``distribute`` / ``setuptools``). -This entry format is used in the :mod:`distlib.scripts` package for installing -scripts based on Python callables. +This entry format is used in the :ref:`scripts` for installing scripts based on Python +callables. Distribution dependencies ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -267,16 +268,16 @@ You can use the ``distlib.locators`` package to locate the dependencies that a distribution has. The ``distlib.database`` package has code which allow you to analyse the relationships between a set of distributions: -* :func:`make_graph`, which generates a dependency graph from a list of - distributions. -* :func:`get_dependent_dists`, which takes a list of distributions and a - specific distribution in that list, and returns the distributions that +* :func:`~distlib.database.make_graph`, which generates a dependency graph from a list + of distributions. +* :func:`~distlib.database.get_dependent_dists`, which takes a list of distributions + and a specific distribution in that list, and returns the distributions that are dependent on that specific distribution. -* :func:`get_required_dists`, which takes a list of distributions and a - specific distribution in that list, and returns the distributions that +* :func:`~distlib.database.get_required_dists`, which takes a list of distributions and + a specific distribution in that list, and returns the distributions that are required by that specific distribution. -The graph returned by :func:`make_graph` is an instance of +The graph returned by :func:`~distlib.database.make_graph` is an instance of :class:`DependencyGraph`. Using the locators API @@ -330,14 +331,14 @@ 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 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 +Under the hood, :func:`~distlib.locators.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:`~distlib.locators.Locator.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`. The following locators are provided: @@ -360,30 +361,31 @@ The following locators are provided: 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 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. +* :class:`~distlib.locators.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. -* :class:`SimpleScrapingLocator` -- this takes a base URL for the site to - scrape, and locates packages using a similar approach to the +* :class:`~distlib.locators.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``. -* :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:`~distlib.locators.DistPathLocator` -- this takes a + :class:`~distlib.database.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:`JSONLocator` -- this uses an improved JSON metadata schema and - returns data on all versions of a distribution, including dependencies, - using a single network request. +.. + * :class:`~distlib.locators.JSONLocator` -- this uses an improved JSON metadata schema + and returns data on all versions of a distribution, including dependencies, + using a single network request. -* :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 +* :class:`~distlib.locators.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. There is a default locator, available at :attr:`distlib.locators.default_locator`. @@ -400,14 +402,18 @@ distributions registered on PyPI:: This is implemented using the XML-RPC API. -Apart from :class:`JSONLocator`, none of the locators currently returns enough -metadata to allow dependency resolution to be carried out, but that is a result -of the fact that metadata relating to dependencies are not indexed, and would -require not just downloading the distribution archives and inspection of -contained metadata files, but potentially also introspecting setup.py! This is -the downside of having vital information only available via keyword arguments -to the :func:`setup` call: hopefully, a move to fully declarative metadata will -facilitate indexing it and allowing the provision of improved features. +.. + + Apart from ``JSONLocator``, + +None of the locators currently returns enough metadata to allow dependency resolution +to be carried out, but that is a result of the fact that metadata relating to +dependencies are not indexed, and would require not just downloading the distribution +archives and inspection of contained metadata files, but potentially also +introspecting setup.py! This is the downside of having vital information only +available via keyword arguments to the ``setup()`` call: hopefully, a move to fully +declarative metadata will facilitate indexing it and allowing the provision of +improved features. The locators will skip binary distributions other than wheels. (``.egg`` files are currently treated as binary distributions). @@ -450,8 +456,8 @@ To use a local test server, you might do this:: Registering a project ~~~~~~~~~~~~~~~~~~~~~ -Registering a project can be done using a :class:`Metadata` instance which -holds the index metadata used for registering. A simple example:: +Registering a project can be done using a :class:`~distlib.metadata.Metadata` instance +which holds the index metadata used for registering. A simple example:: >>> from distlib.metadata import Metadata >>> metadata = Metadata() @@ -460,9 +466,9 @@ holds the index metadata used for registering. A simple example:: >>> # other fields omitted >>> response = index.register(metadata) -The :meth:`register` method returns an HTTP response, such as might be returned -by a call to ``urlopen``. If an error occurs, a :class:`HTTPError` will be -raised. Otherwise, the ``response.code`` should be 200. +The :meth:`~distlib.index.PackageIndex.register` method returns an HTTP response, such +as might be returned by a call to ``urlopen``. If an error occurs, a +:py:class:`~urllib.error.HTTPError` will be raised. Otherwise, the ``response.code`` should be 200. Uploading a source distribution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -472,8 +478,8 @@ To upload a source distribution, you need to do the following as a minimum:: >>> metadata = ... # get a populated Metadata instance >>> response = index.upload_file(metadata, archive_name) -The :meth:`upload_file` method returns an HTTP response or, in case of error, -raises an :class:`HTTPError`. +The :meth:`~distlib.index.PackageIndex.upload_file` method returns an HTTP response +or, in case of error, raises an :py:class:`~urllib.error.HTTPError`. Uploading binary distributions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -523,15 +529,15 @@ download distributions (and other files, such as signatures):: >>> index.download_file(url, destfile, digest=None, reporthook=None) -This is similar in function to :func:`urlretrieve` in the standard library. -Provide a ``digest`` if you want the call to check that the has digest of the -downloaded file matches a specific value: if not provided, no matching is done. -The value passed can just be a plain string in the case of an MD5 digest or, if -you want to specify the hashing algorithm to use, specify a tuple such as -``('sha1', '0123456789abcdef...')``. The hashing algorithm must be one that's -supported by the :mod:`hashlib` module. +This is similar in function to :py:func:`~urllib.request.urlretrieve` in the standard +library. Provide a ``digest`` if you want the call to check that the has digest of the +downloaded file matches a specific value: if not provided, no matching is done. The +value passed can just be a plain string in the case of an MD5 digest or, if you want +to specify the hashing algorithm to use, specify a tuple such as ``('sha1', +'0123456789abcdef...')``. The hashing algorithm must be one that's supported by the +:mod:`hashlib` module. -Benefits to using this method over plain :func:`urlretrieve` are: +Benefits to using this method over plain :func:`~urllib.request.urlretrieve` are: * It will use the ``ssl_verifier``, if set, to ensure that the download is coming from where you think it is (see :ref:`verify-https`). @@ -547,12 +553,13 @@ whichever ``url`` you supply -- whether it's a resource on the index or not. Verifying signatures ~~~~~~~~~~~~~~~~~~~~ -For any archive downloaded from an index, you can retrieve any signature by -just appending ``.asc`` to the path portion of the download URL for the -archive, and downloading that. The index class offers a -:meth:`verify_signature` method for validating a signature. If you have files -'good.bin', 'bad.bin' which are different from each other, and 'good.bin.asc' -has the signature for 'good.bin', then you can verify signatures like this:: +For any archive downloaded from an index, you can retrieve any signature by just +appending ``.asc`` to the path portion of the download URL for the archive, and +downloading that. The index class offers a +:meth:`~distlib.index.PackageIndex.verify_signature` method for validating a +signature. If you have files 'good.bin', 'bad.bin' which are different from each +other, and 'good.bin.asc' has the signature for 'good.bin', then you can verify +signatures like this:: >>> index.verify_signature('good.bin.asc', 'good.bin', '/path/to/keys') True @@ -604,9 +611,10 @@ build your documentation, this will be something like >>> response = index.upload_documentation(metadata, doc_dir) -The :meth:`upload_documentation` method returns an HTTP response or, in case of -error, raises an :class:`HTTPError`. The call will zip up the entire contents -of the passed directory ``doc_dir`` and upload the zip file to the index. +The :meth:`~distlib.index.PackageIndex.upload_documentation` method returns an HTTP +response or, in case of error, raises an :class:`~urllib.error.HTTPError`. The call +will zip up the entire contents of the passed directory ``doc_dir`` and upload the zip +file to the index. Authentication ~~~~~~~~~~~~~~ @@ -675,7 +683,7 @@ By default, the handler will attempt to match domains, including wildcard matching. This means that (for example) you access ``foo.org`` or ``www.foo.org`` which have a certificate for ``*.foo.org``, the domains will match. If the domains don't match, the handler raises a -:class:`CertificateError` (a subclass of :class:`ValueError`). +:class:`~ssl.CertificateError` (a subclass of :class:`ValueError`). Domain mismatches can, however, happen for valid reasons. Say a hosting server ``bar.com`` hosts ``www.foo.org``, which we are trying to access using SSL. If @@ -699,16 +707,16 @@ interaction with a server -- for example: * Deal with situations where an index page obtained via HTTPS contains links with a scheme of ``http`` rather than ``https``. -To do this, instead of using :class:`HTTPSHandler` as shown above, -use the :class:`HTTPSOnlyHandler` class instead, which disallows any -HTTP traffic. It's used in the same way as :class:`HTTPSHandler`:: +To do this, instead of using :py:class:`~urllib.request.HTTPSHandler` as shown above, +use the :class:`~distlib.util.HTTPSOnlyHandler` class instead, which disallows any +HTTP traffic. It's used in the same way as :py:class:`~urllib.request.HTTPSHandler`:: >>> from distlib.util import HTTPSOnlyHandler >>> verifier = HTTPSOnlyHandler('/path/to/root/certs.pem') >>> index.ssl_verifier = verifier Note that with this handler, you can't make *any* HTTP connections at all - -it will raise :class:`URLError` if you try. +it will raise :py:class:`~urllib.error.URLError` if you try. Getting hold of root certificates @@ -722,9 +730,9 @@ At the time of writing, you can find a file in the appropriate format on the Saving a default configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you don't have a ``.pypirc`` file but want to save one, you can do this by -setting the username and password and calling the :meth:`save_configuration` -method:: +If you don't have a ``.pypirc`` file but want to save one, you can do this by setting +the username and password and calling the +:meth:`~distlib.index.PackageIndex.save_configuration` method:: >>> index = PackageIndex() >>> index.username = 'fred' @@ -950,12 +958,12 @@ Using markers single: Markers; evaluating single: Environment markers; evaluating -Environment markers are implemented in the :mod:`distlib.markers` package -and accessed via a single function, :func:`interpret`. +Environment markers are implemented in the ``distlib.markers`` package and accessed +via a single function, :func:`~distlib.markers.interpret`. -See `PEP 508 `_ -for more information about environment markers. The :func:`interpret` function -takes a string argument which represents a Boolean expression, and returns +See `PEP 508 `_ for +more information about environment markers. The :func:`~distlib.markers.interpret` +function takes a string argument which represents a Boolean expression, and returns either ``True`` or ``False``:: >>> from distlib.markers import interpret @@ -973,8 +981,9 @@ environment:: False -You won't normally need to work with markers in this way -- they are dealt -with by the :class:`Metadata` and :class:`Distribution` logic when needed. +You won't normally need to work with markers in this way -- they are dealt with by the +:class:`~distlib.metadata.Metadata` and :class:`~distlib.database.Distribution` logic +when needed. Using the resource API @@ -1175,9 +1184,9 @@ The string passed to make can take one of the following forms: load and call the specified callable with no arguments, returning its value as the return code from the script. - You can pass an optional ``options`` dictionary to the :meth:`make` method. - This is meant to contain options which control script generation. There are - two options currently in use: + You can pass an optional ``options`` dictionary to the + :meth:`~distlib.scripts.ScriptMaker.make` method. This is meant to contain options + which control script generation. There are two options currently in use: ``gui``: This Boolean value, if ``True``, indicates on Windows that a Windows executable launcher (rather than a launcher which is a console application) @@ -1262,15 +1271,15 @@ Specifying a custom executable for shebangs single: Scripts; specifying custom executables You may need to specify a custom executable for shebang lines. To do this, set the -:attr:`executable` attribute of a :class:`ScriptMaker` instance to the absolute -Unicode path of the executable which you want to be written to the shebang lines of -scripts. If not specified, the executable running the :class:`ScriptMaker` code is -used. If the value has spaces, you should surround it with double quotes. You can use -the :func:`enquote_executable` function for this. +:attr:`~distlib.scripts.ScriptMaker.executable` attribute of a :class:`ScriptMaker` +instance to the absolute Unicode path of the executable which you want to be written +to the shebang lines of scripts. If not specified, the executable running the +:class:`ScriptMaker` code is used. If the value has spaces, you should surround it +with double quotes. You can use the :func:`enquote_executable` function for this. .. versionchanged:: 0.3.1 - The :func:`enquote_executable` function was an internal function - :func:`_enquote_executable` in earlier versions. + The :func:`~distlib.scripts.enquote_executable` function was an internal function + ``_enquote_executable`` in earlier versions. For relocatable .exe files under Windows, you can specify the location of the python executable relative to the script by putting ** as the beginning of the @@ -1321,9 +1330,9 @@ installation to fail, because the overwritten file may be different (and so have a different hash from what was computed during the 2.7 installation). To control overwriting of generated scripts this way, you can use the -:attr:`clobber` attribute of a :class:`ScriptMaker` instance. This is set to -``False`` by default, which prevents overwriting; to force overwriting, set it -to ``True``. +:attr:`~distlib.scripts.ScriptMaker.clobber` attribute of a +:class:`~distlib.scripts.ScriptMaker` instance. This is set to ``False`` by default, +which prevents overwriting; to force overwriting, set it to ``True``. Generating windowed scripts on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1331,14 +1340,15 @@ Generating windowed scripts on Windows .. index:: single: Scripts; windowed -The :meth:`make` and :meth:`make_multiple` methods take an optional second -``options`` argument, which can be used to control script generation. If -specified, this should be a dictionary of options. Currently, only the value -for the ``gui`` key in the dictionary is inspected: if ``True``, it generates -scripts with ``.pyw`` extensions (rather than ``.py``) and, if -``add_launchers`` is specified as ``True`` in the :class:`ScriptMaker` -instance, then (on Windows) a windowed native executable launcher is created -(otherwise, the native executable launcher will be a console application). +The :meth:`~distlib.scripts.ScriptMaker.make` and +:meth:`~distlib.scripts.ScriptMaker.make_multiple` methods take an optional second +``options`` argument, which can be used to control script generation. If specified, +this should be a dictionary of options. Currently, only the value for the ``gui`` key +in the dictionary is inspected: if ``True``, it generates scripts with ``.pyw`` +extensions (rather than ``.py``) and, if ``add_launchers`` is specified as ``True`` in +the :class:`~distlib.scripts.ScriptMaker` instance, then (on Windows) a windowed +native executable launcher is created (otherwise, the native executable launcher will +be a console application). Using the version API @@ -1505,8 +1515,8 @@ Customising tags during build .. index:: single: wheels; custom tags when building -By default, the :meth:`build` method will use default tags depending on whether -or not the build is a pure-Python build: +By default, the :meth:`~distlib.wheel.Wheel.build` method will use default tags +depending on whether or not the build is a pure-Python build: * For a pure-Python build, the ``pyver`` will be set to ``pyXY`` where ``XY`` is the version of the building Python. The ``abi`` tag will be ``none`` and @@ -1516,10 +1526,10 @@ or not the build is a pure-Python build: will be set to e.g. ``cpXY``, and the ``abi`` and ``arch`` tags will be set according to the building Python. -If you want to override these default tags, you can pass a ``tags`` parameter -to the :meth:`build` method which has the tags you want to declare. For -example, for a pure build where we know that the code in the wheel will be -compatible with the major version of the building Python:: +If you want to override these default tags, you can pass a ``tags`` parameter to the +:meth:`~distlib.wheel.Wheel.build` method which has the tags you want to declare. For +example, for a pure build where we know that the code in the wheel will be compatible +with the major version of the building Python:: from wheel import PYVER tags = { @@ -1536,7 +1546,7 @@ Specifying a wheel's version You can also specify a particular "Wheel-Version" to be written to the wheel metadata of a wheel you're building. Simply pass a (major, minor) tuple in -the ``wheel_version`` keyword argument to :meth:`~Wheel.build`. If not +the ``wheel_version`` keyword argument to :meth:`~distlib.wheel.Wheel.build`. If not specified, the most recent version supported is written. Installing from wheels @@ -1594,9 +1604,9 @@ Verifying wheels .. index:: pair: verifying; wheels -You can verify that a wheel's contents match the declared contents in the -wheel's ``RECORD`` entry, by calling the :meth:`~Wheel.verify` method. This will -raise a :class:`DistlibException` if a size or digest mismatch is found. +You can verify that a wheel's contents match the declared contents in the wheel's +``RECORD`` entry, by calling the :meth:`~distlib.wheel.Wheel.verify` method. This will +raise a :class:`~distlib.DistlibException` if a size or digest mismatch is found. Modifying wheels @@ -1618,14 +1628,14 @@ You can update existing wheels with ``distlib`` by calling the modified = wheel.update(modifier, dest_dir, **kwargs) -where the ``modifier`` is a callable which you specify, and ``kwargs`` are -options you want to pass to it (currently, the :meth:`update` method passes -``kwargs`` unchanged to the ``modifier``). The ``dest_dir`` argument indicates -where you want any new wheel to be written - it is optional and if not -specified, *the existing wheel will be overwritten*. +where the ``modifier`` is a callable which you specify, and ``kwargs`` are options you +want to pass to it (currently, the :meth:`~distlib.wheel.Wheel.update` method passes +``kwargs`` unchanged to the ``modifier``). The ``dest_dir`` argument indicates where +you want any new wheel to be written - it is optional and if not specified, *the +existing wheel will be overwritten*. -The :meth:`update` method extracts the entire contents of the wheel to -a temporary location, and then calls ``modifier`` as follows:: +The :meth:`~distlib.wheel.Wheel.update` method extracts the entire contents of the +wheel to a temporary location, and then calls ``modifier`` as follows:: modified = modifier(path_map, **kwargs) @@ -1672,32 +1682,33 @@ Mounting wheels .. index:: single: wheels; mounting -One of Python's perhaps under-used features is ``zipimport``, which gives the -ability to import Python source from ``.zip`` files. Since wheels are ``.zip`` -files, they can sometimes be used to provide functionality without needing to -be installed. Whereas ``.zip`` files contain no convention for indicating -compatibility with a particular Python, wheels *do* contain this compatibility -information. Thus, it is possible to check if a wheel can be directly imported -from, and the wheel support in ``distlib`` allows you to take advantage of this -using the :meth:`mount` and :meth:`unmount` methods. When you mount a wheel, -its absolute path name is added to ``sys.path``, allowing the Python code in it -to be imported. (A :class:`DistlibException` is raised if the wheel isn't -compatible with the Python which calls the :meth:`mount` method.) - -The :meth:`mount` method takes an optional keyword parameter ``append`` which -defaults to ``False``, meaning the a mounted wheel's pathname is added to the -beginning of ``sys.path``. If you pass ``True``, the pathname is appended to -``sys.path``. - -The :meth:`mount` method goes further than just enabling Python imports -- any -C extensions in the wheel are also made available for import. For this to be -possible, the wheel has to be built with additional metadata about extensions --- a JSON file called ``EXTENSIONS`` which serialises an extension mapping -dictionary. This maps extension module names to the names in the wheel of the -shared libraries which implement those modules. - -Running :meth:`unmount` on the wheel removes its absolute pathname from -``sys.path`` and makes its C extensions, if any, also unavailable for import. +One of Python's perhaps under-used features is ``zipimport``, which gives the ability +to import Python source from ``.zip`` files. Since wheels are ``.zip`` files, they can +sometimes be used to provide functionality without needing to be installed. Whereas +``.zip`` files contain no convention for indicating compatibility with a particular +Python, wheels *do* contain this compatibility information. Thus, it is possible to +check if a wheel can be directly imported from, and the wheel support in ``distlib`` +allows you to take advantage of this using the :meth:`~distlib.wheel.Wheel.mount` and +:meth:`~distlib.wheel.Wheel.unmount` methods. When you mount a wheel, its absolute +path name is added to ``sys.path``, allowing the Python code in it to be imported. (A +:class:`~distlib.DistlibException` is raised if the wheel isn't compatible with the +Python which calls the :meth:`~distlib.wheel.Wheel.mount` method.) + +The :meth:`~distlib.wheel.Wheel.mount` method takes an optional keyword parameter +``append`` which defaults to ``False``, meaning the a mounted wheel's pathname is +added to the beginning of ``sys.path``. If you pass ``True``, the pathname is appended +to ``sys.path``. + +The :meth:`~distlib.wheel.Wheel.mount` method goes further than just enabling Python +imports -- any C extensions in the wheel are also made available for import. For this +to be possible, the wheel has to be built with additional metadata about extensions -- +a JSON file called ``EXTENSIONS`` which serialises an extension mapping dictionary. +This maps extension module names to the names in the wheel of the shared libraries +which implement those modules. + +Running :meth:`~distlib.wheel.Wheel.unmount` on the wheel removes its absolute +pathname from ``sys.path`` and makes its C extensions, if any, also unavailable for +import. .. note:: The C extension mounting functionality may not work in all cases, though it should work in a useful subset of cases. Use with care. Note that @@ -2058,8 +2069,9 @@ of files rooted in a particular directory:: >>> from distlib.manifest import Manifest >>> manifest = Manifest('/path/to/my/sources') -This sets the :attr:`base` attribute to the passed in root directory. You can -add one or multiple files using names relative to the base directory:: +This sets the :attr:`~distlib.manifest.Manifest.base` attribute to the passed in root +directory. You can add one or multiple files using names relative to the base +directory:: >>> manifest.add('abc') >>> manifest.add_many(['def', 'ghi']) @@ -2073,20 +2085,22 @@ You can get all the files below the base directory of the manifest:: >>> manifest.findall() -This will populate the :attr:`allfiles` attribute of ``manifest`` with -a list of all files in the directory tree rooted at the base. However, -the manifest is still empty:: +This will populate the :attr:`~distlib.manifest.Manifest.allfiles` attribute of +``manifest`` with a list of all files in the directory tree rooted at the base. +However, the manifest is still empty:: >>> manifest.files >>> set() -You can populate the manifest -- the :attr:`files` attribute -- by running -a number of *directives*, using the :meth:`process_directive` method. Each -directive will either add files from :attr:`allfiles` to :attr:`files`, or -remove files from :attr:`allfiles` if they were added by a previous directive. -A directive is a string which must have a specific syntax: malformed lines will -result in a :class:`DistlibException` being raised. The following directives -are available: they are compatible with the syntax of ``MANIFEST.in`` files +You can populate the manifest -- the :attr:`~distlib.manifest.Manifest.files` +attribute -- by running a number of *directives*, using the +:meth:`~distlib.manifest.Manifest.process_directive` method. Each directive will +either add files from :attr:`~distlib.manifest.Manifest.allfiles` to +:attr:`~distlib.manifest.Manifest.files`, or remove files from +:attr:`~distlib.manifest.Manifest.allfiles` if they were added by a previous +directive. A directive is a string which must have a specific syntax: malformed lines +will result in a :class:`~distlib.DistlibException` being raised. The following +directives are available: they are compatible with the syntax of ``MANIFEST.in`` files processed by ``distutils``. Consider the following directory tree:: @@ -2113,10 +2127,11 @@ The ``include`` directive .. index:: single: Manifest; including files -This takes the form of the word ``include`` (case-sensitive) followed by a -number of file-name patterns (as used in ``MANIFEST.in`` in ``distutils``). All -files in :attr:`allfiles`` matching the patterns (considered relative to the -base directory) are added to :attr:`files`. For example:: +This takes the form of the word ``include`` (case-sensitive) followed by a number of +file-name patterns (as used in ``MANIFEST.in`` in ``distutils``). All files in +:attr:`~distlib.manifest.Manifest.allfiles` matching the patterns (considered relative +to the base directory) are added to :attr:`~distlib.manifest.Manifest.files`. For +example:: >>> manifest.process_directive('include R*.txt LIC* keep/*.txt') @@ -2130,10 +2145,11 @@ The ``exclude`` directive .. index:: single: Manifest; excluding files -This takes the form of the word ``exclude`` (case-sensitive) followed by a -number of file-name patterns (as used in ``MANIFEST.in`` in ``distutils``). All -files in :attr:`files`` matching the patterns (considered relative to the -base directory) are removed from :attr:`files`. For example:: +This takes the form of the word ``exclude`` (case-sensitive) followed by a number of +file-name patterns (as used in ``MANIFEST.in`` in ``distutils``). All files in +:attr:`~distlib.manifest.Manifest.files` matching the patterns (considered relative +to the base directory) are removed from :attr:`~distlib.manifest.Manifest.files`. For +example:: >>> manifest.process_directive('exclude LIC*') @@ -2205,7 +2221,7 @@ The ``graft`` directive single: Manifest; grafting directories This directive takes the name of a directory (relative to the base) and copies -all the names under it from :attr:`allfiles` to :attr:`files`. +all the names under it from :attr:`~distlib.manifest.Manifest.allfiles` to :attr:`~distlib.manifest.Manifest.files`. The ``prune`` directive @@ -2215,7 +2231,7 @@ The ``prune`` directive single: Manifest; pruning directories This directive takes the name of a directory (relative to the base) and removes -all the names under it from :attr:`files`. +all the names under it from :attr:`~distlib.manifest.Manifest.files`. Next steps