703 lines
24 KiB
Plaintext
703 lines
24 KiB
Plaintext
PEP: 459
|
|
Title: Standard Metadata Extensions for Python Software Packages
|
|
Version: $Revision$
|
|
Last-Modified: $Date$
|
|
Author: Nick Coghlan <ncoghlan@gmail.com>
|
|
BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com>
|
|
Discussions-To: Distutils SIG <distutils-sig@python.org>
|
|
Status: Draft
|
|
Type: Standards Track
|
|
Content-Type: text/x-rst
|
|
Requires: 426
|
|
Created: 11 Nov 2013
|
|
Post-History: 21 Dec 2013
|
|
|
|
|
|
Abstract
|
|
========
|
|
|
|
This PEP describes several standard extensions to the Python metadata.
|
|
|
|
Like all metadata extensions, each standard extension format is
|
|
independently versioned. Changing any of the formats requires an update
|
|
to this PEP, but does not require an update to the core packaging metadata.
|
|
|
|
.. note::
|
|
|
|
These extensions may eventually be separated out into their own PEPs,
|
|
but we're already suffering from PEP overload in the packaging
|
|
metadata space.
|
|
|
|
This PEP was initially created by slicing out large sections of earlier
|
|
drafts of PEP 426 and making them extensions, so some of the specifics
|
|
may still be rough in the new context.
|
|
|
|
|
|
Standard Extension Namespace
|
|
============================
|
|
|
|
The ``python`` project on the Python Package Index refers to the CPython
|
|
reference interpreter. This namespace is used as the namespace for the
|
|
standard metadata extensions.
|
|
|
|
The currently defined standard extensions are:
|
|
|
|
* ``python.details``
|
|
* ``python.project``
|
|
* ``python.integrator``
|
|
* ``python.commands``
|
|
* ``python.exports``
|
|
* ``python.metadata_hooks``
|
|
|
|
All standard extensions are currently at version ``1.0``, and thus the
|
|
``extension_metadata`` field may be omitted without losing access to any
|
|
functionality.
|
|
|
|
|
|
The ``details`` extension
|
|
=========================
|
|
|
|
The ``details`` extension allows for more information to be provided
|
|
regarding the software distribution.
|
|
|
|
The ``details`` extension contains three subfields:
|
|
|
|
* ``license``: the copyright license for the distribution
|
|
* ``keywords``: package index keywords for the distribution
|
|
* ``classifiers``: package index Trove classifiers for the distribution
|
|
* ``document_names``: the names of additional metadata files
|
|
|
|
All of these fields are optional. Automated tools MUST operate correctly if
|
|
a distribution does not provide them, including failing cleanly when an
|
|
operation depending on one of these fields is requested.
|
|
|
|
|
|
License
|
|
-------
|
|
|
|
A short string summarising the license used for this distribution.
|
|
|
|
Note that distributions that provide this field should still specify any
|
|
applicable license Trove classifiers in the `Classifiers`_ field. Even
|
|
when an appropriate Trove classifier is available, the license summary can
|
|
be a good way to specify a particular version of that license, or to
|
|
indicate any variations or exception to the license.
|
|
|
|
This field SHOULD contain fewer than 512 characters and MUST contain fewer
|
|
than 2048.
|
|
|
|
This field SHOULD NOT contain any line breaks.
|
|
|
|
The full license text SHOULD be included as a separate file in the source
|
|
archive for the distribution. See `Document names`_ for details.
|
|
|
|
Example::
|
|
|
|
"license": "GPL version 3, excluding DRM provisions"
|
|
|
|
|
|
Keywords
|
|
--------
|
|
|
|
A list of additional keywords to be used to assist searching for the
|
|
distribution in a larger catalog.
|
|
|
|
Example::
|
|
|
|
"keywords": ["comfy", "chair", "cushions", "too silly", "monty python"]
|
|
|
|
|
|
Classifiers
|
|
-----------
|
|
|
|
A list of strings, with each giving a single classification value
|
|
for the distribution. Classifiers are described in PEP 301 [2].
|
|
|
|
Example::
|
|
|
|
"classifiers": [
|
|
"Development Status :: 4 - Beta",
|
|
"Environment :: Console (Text Based)",
|
|
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)"
|
|
]
|
|
|
|
|
|
Document names
|
|
--------------
|
|
|
|
Filenames for supporting documents included in the distribution's
|
|
``dist-info`` metadata directory.
|
|
|
|
The following supporting documents can be named:
|
|
|
|
* ``description``: a file containing a long description of the distribution
|
|
* ``license``: a file with the full text of the distribution's license
|
|
* ``changelog``: a file describing changes made to the distribution
|
|
|
|
Supporting documents MUST be included directly in the ``dist-info``
|
|
directory. Directory separators are NOT permitted in document names.
|
|
|
|
The markup format (if any) for the file is indicated by the file extension.
|
|
This allows index servers and other automated tools to render included
|
|
text documents correctly and provide feedback on rendering errors, rather
|
|
than having to guess the intended format.
|
|
|
|
If the filename has no extension, or the extension is not recognised, the
|
|
default rendering format MUST be plain text.
|
|
|
|
The following markup renderers SHOULD be used for the specified file
|
|
extensions:
|
|
|
|
* Plain text: ``.txt``, no extension, unknown extension
|
|
* reStructured Text: ``.rst``
|
|
* Markdown: ``.md``
|
|
* AsciiDoc: ``.adoc``, ``.asc``, ``.asciidoc``
|
|
* HTML: ``.html``, ``.htm``
|
|
|
|
Automated tools MAY render one or more of the specified formats as plain
|
|
text and MAY render other markup formats beyond those listed.
|
|
|
|
Automated tools SHOULD NOT make any assumptions regarding the maximum length
|
|
of supporting document content, except as necessary to protect the
|
|
integrity of a service.
|
|
|
|
Example::
|
|
|
|
"document_names": {
|
|
"description": "README.rst",
|
|
"license": "LICENSE.rst",
|
|
"changelog": "NEWS"
|
|
}
|
|
|
|
|
|
The ``project`` extension
|
|
=========================
|
|
|
|
The ``project`` extension allows for more information to be provided
|
|
regarding the creation and maintenance of the distribution.
|
|
|
|
The ``project`` extension contains three subfields:
|
|
|
|
* ``contacts``: key contact points for the distribution
|
|
* ``contributors``: other contributors to the distribution
|
|
* ``project_urls``: relevant URLs for the distribution
|
|
|
|
|
|
Contact information
|
|
-------------------
|
|
|
|
Details on individuals and organisations are recorded as mappings with
|
|
the following subfields:
|
|
|
|
* ``name``: the name of an individual or group
|
|
* ``email``: an email address (this may be a mailing list)
|
|
* ``url``: a URL (such as a profile page on a source code hosting service)
|
|
* ``role``: one of ``"author"``, ``"maintainer"`` or ``"contributor"``
|
|
|
|
The ``name`` subfield is required, the other subfields are optional.
|
|
|
|
If no specific role is stated, the default is ``contributor``.
|
|
|
|
Email addresses must be in the form ``local-part@domain`` where the
|
|
local-part may be up to 64 characters long and the entire email address
|
|
contains no more than 254 characters. The formal specification of the
|
|
format is in RFC 5322 (sections 3.2.3 and 3.4.1) and RFC 5321, with a more
|
|
readable form given in the informational RFC 3696 and the associated errata.
|
|
|
|
The defined contributor roles are as follows:
|
|
|
|
* ``author``: the original creator of a distribution
|
|
* ``maintainer``: the current lead contributor for a distribution, when
|
|
they are not the original creator
|
|
* ``contributor``: any other individuals or organizations involved in the
|
|
creation of the distribution
|
|
|
|
Contact and contributor metadata is optional. Automated tools MUST operate
|
|
correctly if a distribution does not provide it, including failing cleanly
|
|
when an operation depending on one of these fields is requested.
|
|
|
|
|
|
Contacts
|
|
--------
|
|
|
|
A list of contributor entries giving the recommended contact points for
|
|
getting more information about the project.
|
|
|
|
The example below would be suitable for a project that was in the process
|
|
of handing over from the original author to a new lead maintainer, while
|
|
operating as part of a larger development group.
|
|
|
|
Example::
|
|
|
|
"contacts": [
|
|
{
|
|
"name": "Python Packaging Authority/Distutils-SIG",
|
|
"email": "distutils-sig@python.org",
|
|
"url": "https://bitbucket.org/pypa/"
|
|
},
|
|
{
|
|
"name": "Samantha C.",
|
|
"role": "maintainer",
|
|
"email": "dontblameme@example.org"
|
|
},
|
|
{
|
|
"name": "Charlotte C.",
|
|
"role": "author",
|
|
"email": "iambecomingasketchcomedian@example.com"
|
|
}
|
|
]
|
|
|
|
|
|
Contributors
|
|
------------
|
|
|
|
A list of contributor entries for other contributors not already listed as
|
|
current project points of contact. The subfields within the list elements
|
|
are the same as those for the main contact field.
|
|
|
|
Example::
|
|
|
|
"contributors": [
|
|
{"name": "John C."},
|
|
{"name": "Erik I."},
|
|
{"name": "Terry G."},
|
|
{"name": "Mike P."},
|
|
{"name": "Graeme C."},
|
|
{"name": "Terry J."}
|
|
]
|
|
|
|
|
|
Project URLs
|
|
------------
|
|
|
|
A mapping of arbitrary text labels to additional URLs relevant to the
|
|
project.
|
|
|
|
While projects are free to choose their own labels and specific URLs,
|
|
it is RECOMMENDED that home page, source control, issue tracker and
|
|
documentation links be provided using the labels in the example below.
|
|
|
|
URL labels MUST be treated as case insensitive by automated tools, but they
|
|
are not required to be valid Python identifiers. Any legal JSON string is
|
|
permitted as a URL label.
|
|
|
|
Example::
|
|
|
|
"project_urls": {
|
|
"Documentation": "https://distlib.readthedocs.org",
|
|
"Home": "https://bitbucket.org/pypa/distlib",
|
|
"Repository": "https://bitbucket.org/pypa/distlib/src",
|
|
"Tracker": "https://bitbucket.org/pypa/distlib/issues"
|
|
}
|
|
|
|
|
|
The ``integrator`` extension
|
|
============================
|
|
|
|
Structurally, this extension is identical to the ``project`` extension.
|
|
|
|
However, where the ``project`` metadata refers to the upstream creators
|
|
of the software, the ``integrator`` metadata refers to the downstream
|
|
redistributor of a modified version.
|
|
|
|
If the software is being redistributed unmodified, then typically this
|
|
extension will not be used. However, if the software has been patched (for
|
|
example, backporting compatible fixes from a later version, or addressing
|
|
a platform compatibility issue), then this extension SHOULD be used, and
|
|
an integrator suffix added to the package version number.
|
|
|
|
If there are multiple redistributors in the chain, each one just overwrites
|
|
this extension with their particular metadata.
|
|
|
|
|
|
The ``exports`` extension
|
|
=========================
|
|
|
|
Most Python distributions expose packages and modules for import through
|
|
the Python module namespace. Distributions may also expose other
|
|
interfaces when installed.
|
|
|
|
The ``exports`` extension contains three subfields:
|
|
|
|
* ``modules``: modules exported by the distribution
|
|
* ``namespaces``: namespace packages that the distribution contributes to
|
|
* ``exports``: other Python interfaces exported by the distribution
|
|
|
|
|
|
Export specifiers
|
|
-----------------
|
|
|
|
An export specifier is a string consisting of a fully qualified name, as
|
|
well as an optional extra name enclosed in square brackets. This gives the
|
|
following four possible forms for an export specifier::
|
|
|
|
module
|
|
module:name
|
|
module[requires_extra]
|
|
module:name[requires_extra]
|
|
|
|
.. note::
|
|
|
|
The jsonschema file currently restricts qualified names using the
|
|
Python 2 ASCII identifier rules. This may need to be reconsidered
|
|
given the more relaxed identifier rules in Python 3.
|
|
|
|
The meaning of the subfields is as follows:
|
|
|
|
* ``module``: the module providing the export
|
|
* ``name``: if applicable, the qualified name of the export within the module
|
|
* ``requires_extra``: indicates the export will only work correctly if the
|
|
additional dependencies named in the given extra are available in the
|
|
installed environment
|
|
|
|
.. note::
|
|
|
|
I tried this as a mapping with subfields, and it made the examples below
|
|
unreadable. While this PEP is mostly for tool use, readability still
|
|
matters to some degree for debugging purposes, and because I expect
|
|
snippets of the format to be reused elsewhere.
|
|
|
|
|
|
Modules
|
|
-------
|
|
|
|
A list of qualified names of modules and packages that the distribution
|
|
provides for import.
|
|
|
|
.. note::
|
|
|
|
The jsonschema file currently restricts qualified names using the
|
|
Python 2 ASCII identifier rules. This may need to be reconsidered
|
|
given the more relaxed identifier rules in Python 3.
|
|
|
|
For names that contain dots, the portion of the name before the final dot
|
|
MUST appear either in the installed module list or in the namespace package
|
|
list.
|
|
|
|
To help avoid name conflicts, it is RECOMMENDED that distributions provide
|
|
a single top level module or package that matches the distribution name
|
|
(or a lower case equivalent). This requires that the distribution name also
|
|
meet the requirements of a Python identifier, which are stricter than
|
|
those for distribution names). This practice will also make it easier to
|
|
find authoritative sources for modules.
|
|
|
|
Index servers SHOULD allow multiple distributions to publish the same
|
|
modules, but MAY notify distribution authors of potential conflicts.
|
|
|
|
Installation tools SHOULD report an error when asked to install a
|
|
distribution that provides a module that is also provided by a different,
|
|
previously installed, distribution.
|
|
|
|
Note that attempting to import some declared modules may result in an
|
|
exception if the appropriate extras are not installed.
|
|
|
|
Example::
|
|
|
|
"modules": ["chair", "chair.cushions", "python_sketches.nobody_expects"]
|
|
|
|
.. note::
|
|
|
|
Making this a list of export specifiers instead would allow a distribution
|
|
to declare when a particular module requires a particular extra in order
|
|
to run correctly. On the other hand, there's an argument to be made that
|
|
that is the point where it starts to become worthwhile to split out a
|
|
separate distribution rather than using extras.
|
|
|
|
|
|
Namespaces
|
|
----------
|
|
|
|
A list of qualified names of namespace packages that the distribution
|
|
contributes modules to.
|
|
|
|
.. note::
|
|
|
|
The jsonschema file currently restricts qualified names using the
|
|
Python 2 ASCII identifier rules. This may need to be reconsidered
|
|
given the more relaxed identifier rules in Python 3.
|
|
|
|
On versions of Python prior to Python 3.3 (which provides native namespace
|
|
package support), installation tools SHOULD emit a suitable ``__init__.py``
|
|
file to properly initialise the namespace rather than using a distribution
|
|
provided file.
|
|
|
|
Installation tools SHOULD emit a warning and MAY emit an error if a
|
|
distribution declares a namespace package that conflicts with the name of
|
|
an already installed module or vice-versa.
|
|
|
|
Example::
|
|
|
|
"namespaces": ["python_sketches"]
|
|
|
|
|
|
Exports
|
|
-------
|
|
|
|
The ``exports`` field is a mapping containing prefixed names as keys. Each
|
|
key identifies an export group containing one or more exports published by
|
|
the distribution.
|
|
|
|
Export group names are defined by distributions that will then make use of
|
|
the published export information in some way. The primary use case is for
|
|
distributions that support a plugin model: defining an export group allows
|
|
other distributions to indicate which plugins they provide, how they
|
|
can be imported and accessed, and which additional dependencies (if any)
|
|
are needed for the plugin to work correctly.
|
|
|
|
To reduce the chance of name conflicts, export group names SHOULD use a
|
|
prefix that corresponds to a module name in the distribution that defines
|
|
the meaning of the export group. This practice will also make it easier to
|
|
find authoritative documentation for export groups.
|
|
|
|
Each individual export group is then a mapping of arbitrary non-empty string
|
|
keys to export specifiers. The meaning of export names within an export
|
|
group is up to the distribution that defines the export group. Creating an
|
|
appropriate definition for the export name format can allow the importing
|
|
distribution to determine whether or not an export is relevant without
|
|
needing to import every exporting module.
|
|
|
|
Example::
|
|
|
|
"exports": {
|
|
"nose.plugins.0.10": {
|
|
"chairtest": "chair:NosePlugin"
|
|
}
|
|
}
|
|
|
|
|
|
The ``commands`` extension
|
|
==========================
|
|
|
|
The ``commands`` extension contains three subfields:
|
|
|
|
* ``wrap_console``: console wrapper scripts to be generated by the installer
|
|
* ``wrap_gui``: GUI wrapper scripts to be generated by the installer
|
|
* ``prebuilt``: scripts created by the distribution's build process and
|
|
installed directly to the configured scripts directory
|
|
|
|
``wrap_console`` and ``wrap_gui`` are both mappings of script names to
|
|
export specifiers. The script names must follow the same naming rules as
|
|
distribution names.
|
|
|
|
The export specifiers for wrapper scripts must refer to either a package
|
|
with a __main__ submodule (if no ``name`` subfield is given in the export
|
|
specifier) or else to a callable inside the named module.
|
|
|
|
Installation tools should generate appropriate wrappers as part of the
|
|
installation process.
|
|
|
|
.. note::
|
|
|
|
Still needs more detail on what "appropriate wrappers" means. For now,
|
|
refer to what setuptools and zc.buildout generate as wrapper scripts.
|
|
|
|
``prebuilt`` is a list of script paths, relative to the scripts directory in
|
|
a wheel file or following installation. They are provided for informational
|
|
purpose only - installing them is handled through the normal processes for
|
|
files created when building a distribution.
|
|
|
|
Index servers SHOULD allow multiple distributions to publish the same
|
|
commands, but MAY notify distribution authors of potential conflicts.
|
|
|
|
Installation tools SHOULD report an error when asked to install a
|
|
distribution that provides a command that is also provided by a different,
|
|
previously installed, distribution.
|
|
|
|
Example::
|
|
|
|
"commands": {
|
|
"wrap_console": [{"chair": "chair:run_cli"}],
|
|
"wrap_gui": [{"chair-gui": "chair:run_gui"}],
|
|
"prebuilt": ["reduniforms"]
|
|
}
|
|
|
|
|
|
|
|
The ``metadata_hooks`` extension
|
|
================================
|
|
|
|
The ``metadata_hooks`` extension is used to define operations to be
|
|
invoked on the distribution in the following situations:
|
|
|
|
* a relevant distribution has been installed or changed on the system
|
|
* a relevant distribution has been completely uninstalled from the system
|
|
|
|
The following subfields determine when hooks are triggered:
|
|
|
|
* ``export_groups``: trigger based on named export groups
|
|
* ``extensions``: trigger based on named extensions
|
|
|
|
Note that distributions *do* trigger their own install hooks, but do
|
|
*not* trigger their own uninstall hooks.
|
|
|
|
|
|
Hook signatures
|
|
---------------
|
|
|
|
The currently defined metadata hooks are:
|
|
|
|
* ``postinstall``: run after a relevant distribution has been installed,
|
|
upgraded or downgraded on the current system. May also be run as part
|
|
of a system state resync operation. If the hook is not defined, it
|
|
indicates no distribution specific actions are needed following
|
|
installation.
|
|
* ``postuninstall``: run after a relevant distribution has been completely
|
|
removed from the current system. If the hook is not defined, it indicates
|
|
no distribution specific actions are needed following uninstallation.
|
|
|
|
The required signatures of these hooks are as follows::
|
|
|
|
def postinstall(current_meta, previous_meta=None):
|
|
"""Run following installation or upgrade of a relevant distribution
|
|
|
|
*current_meta* is the distribution metadata for the version now
|
|
installed on the current system
|
|
*previous_meta* is either omitted or ``None`` (indicating a fresh
|
|
install) or else the distribution metadata for the version that
|
|
was previously installed (indicating an upgrade, downgrade or
|
|
resynchronisation of the system state).
|
|
"""
|
|
|
|
def postuninstall(previous_meta):
|
|
"""Run after complete uninstallation of a relevant distribution
|
|
|
|
*previous_meta* is the distribution metadata for the version that
|
|
was previously installed on the current system
|
|
"""
|
|
|
|
Export group hooks
|
|
------------------
|
|
|
|
Export group hooks are named after the export group of interest::
|
|
|
|
"export_groups": {
|
|
"ComfyChair.plugins": {
|
|
"postinstall": "ComfyChair.plugins:install_hook",
|
|
"postuininstall": "ComfyChair.plugins:uninstall_hook"
|
|
}
|
|
}
|
|
|
|
The nominated hooks will then be invoked appropriately for any distribution
|
|
that publishes that export group as part of their ``python.exports``
|
|
extension metadata.
|
|
|
|
A trailing ".*" may be used to request prefix matching rather than
|
|
requiring an exact match on the export group name.
|
|
|
|
|
|
Extension hooks
|
|
---------------
|
|
|
|
Extension hooks are named after the metadata extension of interest::
|
|
|
|
"extensions": {
|
|
"python.exports": {
|
|
"postinstall": "pip.export_group_hooks:run_install_hooks",
|
|
"postuininstall": "pip.export_group_hooks:run_uninstall_hooks"
|
|
}
|
|
"python.commands": {
|
|
"postinstall": "pip.command_hook:install_wrapper_scripts",
|
|
}
|
|
}
|
|
|
|
(Note: this is just an example, but the intent is that pip *could* implement
|
|
that functionality that way if it wanted to).
|
|
|
|
A trailing ".*" may be used to request prefix matching rather than
|
|
requiring an exact match on the extension name.
|
|
|
|
|
|
Guidelines for metadata hook invocation
|
|
---------------------------------------
|
|
|
|
.. note::
|
|
|
|
Metadata hooks are likely to run with elevated privileges, this needs
|
|
to be considered carefully (e.g. by *requiring* that metadata hook
|
|
installation be opt in when using the standard tools and running with
|
|
elevated privileges).
|
|
|
|
The given parameter names are considered part of the hook signature.
|
|
Installation tools MUST call metadata hooks solely with keyword arguments.
|
|
|
|
When metadata hooks are defined, it is assumed that they MUST be executed
|
|
to obtain a properly working installation of the distribution, and to
|
|
properly remove the distribution from a system.
|
|
|
|
Installation tools MUST ensure the new or updated distribution is fully
|
|
installed, and available through the import system and installation database
|
|
when invoking install hooks.
|
|
|
|
Installation tools MUST ensure the removed distribution is fully uninstalled,
|
|
and no longer available through the import system and installation database
|
|
when invoking uninstall hooks.
|
|
|
|
Installation tools MUST call metadata hooks with full metadata (including
|
|
all extensions), rather than only the core metadata.
|
|
|
|
Installation tools SHOULD invoke metadata hooks automatically after
|
|
installing a distribution from a binary archive.
|
|
|
|
When installing from an sdist, source archive or VCS checkout, installation
|
|
tools SHOULD create a binary archive using ``setup.py bdist_wheel`` and
|
|
then install the binary archive normally (including invocation of any
|
|
metadata hooks). Installation tools SHOULD NOT invoke ``setup.py install``
|
|
directly.
|
|
|
|
Installation tools SHOULD treat an exception thrown by a metadata install
|
|
hook as a failure of the installation and revert any other changes made
|
|
to the system. The installed distribution responsible for the hook that
|
|
failed should be clearly indicated to the user.
|
|
|
|
Installation tools SHOULD provide a warning to the user for any exception
|
|
thrown by a metadata uninstall hook, again clearly indicating to the user
|
|
the installed distribution that triggered the warning.
|
|
|
|
Installation tools MUST NOT silently ignore metadata hooks, as failing
|
|
to call these hooks may result in a misconfigured installation that fails
|
|
unexpectedly at runtime. Installation tools MAY refuse to install
|
|
distributions that define metadata hooks, or require that users
|
|
explicitly opt in to permitting the installation of packages that
|
|
define such hooks.
|
|
|
|
|
|
Guidelines for metadata hook implementations
|
|
--------------------------------------------
|
|
|
|
The given parameter names are considered part of the hook signature.
|
|
Metadata hook implementations MUST use the given parameter names.
|
|
|
|
Metadata hooks SHOULD NOT be used to provide functionality that is
|
|
expected to be provided by installation tools (such as rewriting of
|
|
shebang lines and generation of executable wrappers for Windows).
|
|
|
|
Metadata hook implementations MUST NOT make any assumptions regarding the
|
|
current working directory when they are invoked, and MUST NOT make
|
|
persistent alterations to the working directory or any other process global
|
|
state (other than potentially importing additional modules, or other
|
|
expected side effects of running the distribution).
|
|
|
|
Metadata install hooks have access to the full metadata for the release being
|
|
installed, that of the previous/next release (as appropriate), as well as
|
|
to all the normal runtime information (such as available imports). Hook
|
|
implementations can use this information to perform additional platform
|
|
specific installation steps. To check for the presence or absence of
|
|
"extras", hook implementations should use the same runtime checks that
|
|
would be used during normal operation (such as checking for the availability
|
|
of the relevant dependencies).
|
|
|
|
|
|
Copyright
|
|
=========
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
..
|
|
Local Variables:
|
|
mode: indented-text
|
|
indent-tabs-mode: nil
|
|
sentence-end-double-space: t
|
|
fill-column: 70
|
|
End:
|