612 lines
25 KiB
Plaintext
612 lines
25 KiB
Plaintext
PEP: 451
|
||
Title: A ModuleSpec Type for the Import System
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Eric Snow <ericsnowcurrently@gmail.com>
|
||
Discussions-To: import-sig@python.org
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Content-Type: text/x-rst
|
||
Created: 8-Aug-2013
|
||
Python-Version: 3.4
|
||
Post-History: 8-Aug-2013
|
||
Resolution:
|
||
|
||
|
||
Abstract
|
||
========
|
||
|
||
This PEP proposes to add a new class to ``importlib.machinery`` called
|
||
``ModuleSpec``. It will contain all the import-related information
|
||
about a module without needing to load the module first. Finders will
|
||
now return a module's spec rather than a loader. The import system will
|
||
use the spec to load the module.
|
||
|
||
|
||
Motivation
|
||
==========
|
||
|
||
The import system has evolved over the lifetime of Python. In late 2002
|
||
PEP 302 introduced standardized import hooks via ``finders`` and
|
||
``loaders`` and ``sys.meta_path``. The ``importlib`` module, introduced
|
||
with Python 3.1, now exposes a pure Python implementation of the APIs
|
||
described by PEP 302, as well as of the full import system. It is now
|
||
much easier to understand and extend the import system. While a benefit
|
||
to the Python community, this greater accessibilty also presents a
|
||
challenge.
|
||
|
||
As more developers come to understand and customize the import system,
|
||
any weaknesses in the finder and loader APIs will be more impactful. So
|
||
the sooner we can address any such weaknesses the import system, the
|
||
better...and there are a couple we can take care of with this proposal.
|
||
|
||
Firstly, any time the import system needs to save information about a
|
||
module we end up with more attributes on module objects that are
|
||
generally only meaningful to the import system and occasionally to some
|
||
people. It would be nice to have a per-module namespace to put future
|
||
import-related information. Secondly, there's an API void between
|
||
finders and loaders that causes undue complexity when encountered.
|
||
|
||
Currently finders are strictly responsible for providing the loader
|
||
which the import system will use to load the module. The loader is then
|
||
responsible for doing some checks, creating the module object, setting
|
||
import-related attributes, "installing" the module to ``sys.modules``,
|
||
and loading the module, along with some cleanup. This all takes place
|
||
during the import system's call to ``Loader.load_module()``. Loaders
|
||
also provide some APIs for accessing data associated with a module.
|
||
|
||
Loaders are not required to provide any of the functionality of
|
||
``load_module()`` through other methods. Thus, though the import-
|
||
related information about a module is likely available without loading
|
||
the module, it is not otherwise exposed.
|
||
|
||
Furthermore, the requirements assocated with ``load_module()`` are
|
||
common to all loaders and mostly are implemented in exactly the same
|
||
way. This means every loader has to duplicate the same boilerplate
|
||
code. ``importlib.util`` provides some tools that help with this, but
|
||
it would be more helpful if the import system simply took charge of
|
||
these responsibilities. The trouble is that this would limit the degree
|
||
of customization that ``load_module()`` facilitates. This is a gap
|
||
between finders and loaders which this proposal aims to fill.
|
||
|
||
Finally, when the import system calls a finder's ``find_module()``, the
|
||
finder makes use of a variety of information about the module that is
|
||
useful outside the context of the method. Currently the options are
|
||
limited for persisting that per-module information past the method call,
|
||
since it only returns the loader. Popular options for this limitation
|
||
are to store the information in a module-to-info mapping somewhere on
|
||
the finder itself, or store it on the loader.
|
||
|
||
Unfortunately, loaders are not required to be module-specific. On top
|
||
of that, some of the useful information finders could provide is
|
||
common to all finders, so ideally the import system could take care of
|
||
that. This is the same gap as before between finders and loaders.
|
||
|
||
As an example of complexity attributable to this flaw, the
|
||
implementation of namespace packages in Python 3.3 (see PEP 420) added
|
||
``FileFinder.find_loader()`` because there was no good way for
|
||
``find_module()`` to provide the namespace path.
|
||
|
||
The answer to this gap is a ``ModuleSpec`` object that contains the
|
||
per-module information and takes care of the boilerplate functionality
|
||
of loading the module.
|
||
|
||
(The idea gained momentum during discussions related to another PEP.[1])
|
||
|
||
|
||
Specification
|
||
=============
|
||
|
||
The goal is to address the gap between finders and loaders while
|
||
changing as little of their semantics as possible. Though some
|
||
functionality and information is moved to the new ``ModuleSpec`` type,
|
||
their semantics should remain the same. However, for the sake of
|
||
clarity, those semantics will be explicitly identified.
|
||
|
||
ModuleSpec
|
||
----------
|
||
|
||
A new class which defines the import-related values to use when loading
|
||
the module. It closely corresponds to the import-related attributes of
|
||
module objects. ``ModuleSpec`` objects may also be used by finders and
|
||
loaders and other import-related APIs to hold extra import-related
|
||
state about the module. This greatly reduces the need to add any new
|
||
new import-related attributes to module objects, and loader ``__init__``
|
||
methods won't need to accommodate such per-module state.
|
||
|
||
Creating a ModuleSpec:
|
||
|
||
``ModuleSpec(name, loader, *, origin=None, filename=None, cached=None,
|
||
path=None)``
|
||
|
||
Passed in parameter values are assigned directly to the corresponding
|
||
attributes below. Other attributes not listed as parameters (such as
|
||
``package``) are read-only properties that are automatically derived
|
||
from these values.
|
||
|
||
The ``ModuleSpec.from_loader()`` class method allows a suitable
|
||
ModuleSpec instance to be easily created from a PEP 302 loader object.
|
||
|
||
ModuleSpec Attributes
|
||
---------------------
|
||
|
||
Each of the following names is an attribute on ``ModuleSpec`` objects.
|
||
A value of ``None`` indicates "not set". This contrasts with module
|
||
objects where the attribute simply doesn't exist.
|
||
|
||
While ``package`` and ``is_package`` are read-only properties, the
|
||
remaining attributes can be replaced after the module spec is created
|
||
and after import is complete. This allows for unusual cases where
|
||
modifying the spec is the best option. However, typical use should not
|
||
involve changing the state of a module's spec.
|
||
|
||
Most of the attributes correspond to the import-related attributes of
|
||
modules. Here is the mapping, followed by a description of the
|
||
attributes. The reverse of this mapping is used by
|
||
``init_module_attrs()``.
|
||
|
||
============= ===========
|
||
On ModuleSpec On Modules
|
||
============= ===========
|
||
name __name__
|
||
loader __loader__
|
||
package __package__
|
||
is_package -
|
||
origin -
|
||
filename __file__
|
||
cached __cached__
|
||
path __path__
|
||
============= ===========
|
||
|
||
``name``
|
||
|
||
The module's fully resolved and absolute name. It must be set.
|
||
|
||
``loader``
|
||
|
||
The loader to use during loading and for module data. These specific
|
||
functionalities do not change for loaders. Finders are still
|
||
responsible for creating the loader and this attribute is where it is
|
||
stored. The loader must be set.
|
||
|
||
``package``
|
||
|
||
The name of the module's parent. This is a dynamic attribute with a
|
||
value derived from ``name`` and ``is_package``. For packages it is the
|
||
value of ``name``. Otherwise it is equivalent to
|
||
``name.rpartition('.')[0]``. Consequently, a top-level module will have
|
||
the empty string for ``package``.
|
||
|
||
|
||
``is_package``
|
||
|
||
Whether or not the module is a package. This dynamic attribute is True
|
||
if ``path`` is not None (e.g. the empty list is a "true" value), else it
|
||
is false.
|
||
|
||
``origin``
|
||
|
||
A string for the location from which the module originates. If
|
||
``filename`` is set, ``origin`` should be set to the same value unless
|
||
some other value is more appropriate. ``origin`` is used in
|
||
``module_repr()`` if it does not match the value of ``filename``.
|
||
|
||
Using ``filename`` for this meaning would be inaccurate, since not all
|
||
modules have path-based locations. For instance, built-in modules do
|
||
not have ``__file__`` set. Yet it is useful to have a descriptive
|
||
string indicating that it originated from the interpreter as a built-in
|
||
module. So built-in modules will have ``origin`` set to ``"built-in"``.
|
||
|
||
Path-based attributes:
|
||
|
||
If any of these is set, it indicates that the module is path-based. For
|
||
reference, a path entry is a string for a location where the import
|
||
system will look for modules, e.g. the path entries in ``sys.path`` or a
|
||
package's ``__path__``).
|
||
|
||
``filename``
|
||
|
||
Like ``origin``, but limited to a path-based location. If ``filename``
|
||
is set, ``origin`` should be set to the same string, unless origin is
|
||
explicitly set to something else. ``filename`` is not necessarily an
|
||
actual file name, but could be any location string based on a path
|
||
entry. Regarding the attribute name, while it is potentially
|
||
inaccurate, it is both consistent with the equivalent module attribute
|
||
and generally accurate.
|
||
|
||
.. XXX Would a different name be better? ``path_location``?
|
||
|
||
``cached``
|
||
|
||
The path-based location where the compiled code for a module should be
|
||
stored. If ``filename`` is set to a source file, this should be set to
|
||
corresponding path that PEP 3147 specifies. The
|
||
``importlib.util.source_to_cache()`` function facilitates getting the
|
||
correct value.
|
||
|
||
``path``
|
||
|
||
The list of path entries in which to search for submodules if this
|
||
module is a package. Otherwise it is ``None``.
|
||
|
||
.. XXX add a path-based subclass?
|
||
|
||
ModuleSpec Methods
|
||
------------------
|
||
|
||
``from_loader(name, loader, *, is_package=None, origin=None, filename=None, cached=None, path=None)``
|
||
|
||
.. XXX use a different name?
|
||
|
||
A factory classmethod that returns a new ``ModuleSpec`` derived from the
|
||
arguments. ``is_package`` is used inside the method to indicate that
|
||
the module is a package. If not explicitly passed in, it is set to
|
||
``True`` if ``path`` is passed in. It falls back to using the result of
|
||
the loader's ``is_package()``, if available. Finally it defaults to
|
||
False. The remaining parameters have the same meaning as the
|
||
corresponding ``ModuleSpec`` attributes.
|
||
|
||
In contrast to ``ModuleSpec.__init__()``, which takes the arguments
|
||
as-is, ``from_loader()`` calculates missing values from the ones passed
|
||
in, as much as possible. This replaces the behavior that is currently
|
||
provided by several ``importlib.util`` functions as well as the optional
|
||
``init_module_attrs()`` method of loaders. Just to be clear, here is a
|
||
more detailed description of those calculations::
|
||
|
||
If not passed in, ``filename`` is to the result of calling the
|
||
loader's ``get_filename()``, if available. Otherwise it stays
|
||
unset (``None``).
|
||
|
||
If not passed in, ``path`` is set to an empty list if
|
||
``is_package`` is true. Then the directory from ``filename`` is
|
||
appended to it, if possible. If ``is_package`` is false, ``path``
|
||
stays unset.
|
||
|
||
If ``cached`` is not passed in and ``filename`` is passed in,
|
||
``cached`` is derived from it. For filenames with a source suffix,
|
||
it set to the result of calling
|
||
``importlib.util.cache_from_source()``. For bytecode suffixes (e.g.
|
||
``.pyc``), ``cached`` is set to the value of ``filename``. If
|
||
``filename`` is not passed in or ``cache_from_source()`` raises
|
||
``NotImplementedError``, ``cached`` stays unset.
|
||
|
||
If not passed in, ``origin`` is set to ``filename``. Thus if
|
||
``filename`` is unset, ``origin`` stays unset.
|
||
|
||
``module_repr()``
|
||
|
||
Returns a repr string for the module if ``origin`` is set and
|
||
``filename`` is not set. The string refers to the value of ``origin``.
|
||
Otherwise ``module_repr()`` returns None. This indicates to the module
|
||
type's ``__repr__()`` that it should fall back to the default repr.
|
||
|
||
We could also have ``module_repr()`` produce the repr for the case where
|
||
``filename`` is set or where ``origin`` is not set, mirroring the repr
|
||
that the module type produces directly. However, the repr string is
|
||
derived from the import-related module attributes, which might be out of
|
||
sync with the spec.
|
||
|
||
.. XXX Is using the spec close enough? Probably not.
|
||
|
||
The implementation of the module type's ``__repr__()`` will change to
|
||
accommodate this PEP. However, the current functionality will remain to
|
||
handle the case where a module does not have a ``__spec__`` attribute.
|
||
|
||
.. XXX Clarify the above justification.
|
||
|
||
``init_module_attrs(module)``
|
||
|
||
Sets the module's import-related attributes to the corresponding values
|
||
in the module spec. If a path-based attribute is not set on the spec,
|
||
it is not set on the module. For the rest, a ``None`` value on the spec
|
||
(aka "not set") means ``None`` will be set on the module. If any of the
|
||
attributes are already set on the module, the existing values are
|
||
replaced. The module's own ``__spec__`` is not consulted but does get
|
||
replaced with the spec on which ``init_module_attrs()`` was called.
|
||
The earlier mapping of ``ModuleSpec`` attributes to module attributes
|
||
indicates which attributes are involved on both sides.
|
||
|
||
``load(module=None, *, is_reload=False)``
|
||
|
||
This method captures the current functionality of and requirements on
|
||
``Loader.load_module()`` without any semantic changes, except one.
|
||
Reloading a module when ``exec_module()`` is available actually uses
|
||
``module`` rather than ignoring it in favor of the one in
|
||
``sys.modules``, as ``Loader.load_module()`` does.
|
||
|
||
``module`` is only allowed when ``is_reload`` is true. This means that
|
||
``is_reload`` could be dropped as a parameter. However, doing so would
|
||
mean we could not use ``None`` to indicate that the module should be
|
||
pulled from ``sys.modules``. Furthermore, ``is_reload`` makes the
|
||
intent of the call clear.
|
||
|
||
There are two parts to what happens in ``load()``. First, the module is
|
||
prepared, loaded, updated appropriately, and left available for the
|
||
second part. This is described in more detail shortly.
|
||
|
||
Second, in the case of error during a normal load (not reload) the
|
||
module is removed from ``sys.modules``. If no error happened, the
|
||
module is pulled from ``sys.modules``. This the module returned by
|
||
``load()``. Before it is returned, if it is a different object than the
|
||
one produced by the first part, attributes of the module from
|
||
``sys.modules`` are updated to reflect the spec.
|
||
|
||
Returning the module from ``sys.modules`` accommodates the ability of
|
||
the module to replace itself there while it is executing (during load).
|
||
|
||
As already noted, this is what already happens in the import system.
|
||
``load()`` is not meant to change any of this behavior.
|
||
|
||
Regarding the first part of ``load()``, the following describes what
|
||
happens. It depends on if ``is_reload`` is true and if the loader has
|
||
``exec_module()``.
|
||
|
||
For normal load with ``exec_module()`` available::
|
||
|
||
A new module is created, ``init_module_attrs()`` is called to set
|
||
its attributes, and it is set on sys.modules. At that point
|
||
the loader's ``exec_module()`` is called, after which the module
|
||
is ready for the second part of loading.
|
||
|
||
.. XXX What if the module already exists in sys.modules?
|
||
|
||
For normal load without ``exec_module()`` available::
|
||
|
||
The loader's ``load_module()`` is called and the attributes of the
|
||
module it returns are updated to match the spec.
|
||
|
||
For reload with ``exec_module()`` available::
|
||
|
||
If ``module`` is ``None``, it is pulled from ``sys.modules``. If
|
||
still ``None``, ImportError is raised. Otherwise ``exec_module()``
|
||
is called, passing in the module-to-be-reloaded.
|
||
|
||
For reload without ``exec_module()`` available::
|
||
|
||
The loader's ``load_module()`` is called and the attributes of the
|
||
module it returns are updated to match the spec.
|
||
|
||
There is some boilerplate involved when ``exec_module()`` is available,
|
||
but only the boilerplate that the import system uses currently.
|
||
|
||
If ``loader`` is not set (``None``), ``load()`` raises a ValueError. If
|
||
``module`` is passed in but ``is_reload`` is false, a ValueError is also
|
||
raises to indicate that ``load()`` was called incorrectly. There may be
|
||
use cases for calling ``load()`` in that way, but they are outside the
|
||
scope of this PEP
|
||
|
||
.. XXX add reload(module=None) and drop load()'s parameters entirely?
|
||
.. XXX add more of importlib.reload()'s boilerplate to load()/reload()?
|
||
|
||
Omitted Attributes and Methods
|
||
------------------------------
|
||
|
||
``ModuleSpec`` does not have a ``from_module()`` factory method since
|
||
all modules should already have a spec.
|
||
|
||
Additionally, there is no ``PathModuleSpec`` subclass of ``ModuleSpec``
|
||
that provides the ``filename``, ``cached``, and ``path`` functionality.
|
||
While that might make the separation cleaner, module objects don't have
|
||
that distinction. ``ModuleSpec`` will support both cases equally well.
|
||
|
||
Backward Compatibility
|
||
----------------------
|
||
|
||
Since ``Finder.find_module()`` methods would now return a module spec
|
||
instead of loader, specs must act like the loader that would have been
|
||
returned instead. This is relatively simple to solve since the loader
|
||
is available as an attribute of the spec. We will use ``__getattr__()``
|
||
to do it.
|
||
|
||
However, ``ModuleSpec.is_package`` (an attribute) conflicts with
|
||
``InspectLoader.is_package()`` (a method). Working around this requires
|
||
a more complicated solution but is not a large obstacle. Simply making
|
||
``ModuleSpec.is_package`` a method does not reflect that is a relatively
|
||
static piece of data. ``module_repr()`` also conflicts with the same
|
||
method on loaders, but that workaround is not complicated since both are
|
||
methods.
|
||
|
||
Unfortunately, the ability to proxy does not extend to ``id()``
|
||
comparisons and ``isinstance()`` tests. In the case of the return value
|
||
of ``find_module()``, we accept that break in backward compatibility.
|
||
However, we will mitigate the problem with ``isinstance()`` somewhat by
|
||
registering ``ModuleSpec`` on the loaders in ``importlib.abc``.
|
||
|
||
Subclassing
|
||
-----------
|
||
|
||
Subclasses of ModuleSpec are allowed, but should not be necessary.
|
||
Adding functionality to a custom finder or loader will likely be a
|
||
better fit and should be tried first. However, as long as a subclass
|
||
still fulfills the requirements of the import system, objects of that
|
||
type are completely fine as the return value of ``find_module()``.
|
||
|
||
Module Objects
|
||
--------------
|
||
|
||
Module objects will now have a ``__spec__`` attribute to which the
|
||
module's spec will be bound. None of the other import-related module
|
||
attributes will be changed or deprecated, though some of them could be;
|
||
any such deprecation can wait until Python 4.
|
||
|
||
``ModuleSpec`` objects will not be kept in sync with the corresponding
|
||
module object's import-related attributes. Though they may differ, in
|
||
practice they will typically be the same.
|
||
|
||
One notable exception is that case where a module is run as a script by
|
||
using the ``-m`` flag. In that case ``module.__spec__.name`` will
|
||
reflect the actual module name while ``module.__name__`` will be
|
||
``__main__``.
|
||
|
||
The ``__file__`` attribute will be set where applicable in the same way
|
||
it is now. For instance, zip imports will still have it set for
|
||
backward-compatibility reasons. However, the recommendation will be to
|
||
have ``__file__`` set only for actual filenames from now on.
|
||
|
||
Finders
|
||
-------
|
||
|
||
Finders will now return ModuleSpec objects when ``find_module()`` is
|
||
called rather than loaders. For backward compatility, ``Modulespec``
|
||
objects proxy the attributes of their ``loader`` attribute.
|
||
|
||
Adding another similar method to avoid backward-compatibility issues
|
||
is undersireable if avoidable. The import APIs have suffered enough,
|
||
especially considering ``PathEntryFinder.find_loader()`` was just
|
||
added in Python 3.3. The approach taken by this PEP should be
|
||
sufficient to address backward-compatibility issues for
|
||
``find_module()``.
|
||
|
||
The change to ``find_module()`` applies to both ``MetaPathFinder`` and
|
||
``PathEntryFinder``. ``PathEntryFinder.find_loader()`` will be
|
||
deprecated and, for backward compatibility, implicitly special-cased if
|
||
the method exists on a finder.
|
||
|
||
Finders are still responsible for creating the loader. That loader will
|
||
now be stored in the module spec returned by ``find_module()`` rather
|
||
than returned directly. As is currently the case without the PEP, if a
|
||
loader would be costly to create, that loader can be designed to defer
|
||
the cost until later.
|
||
|
||
Loaders
|
||
-------
|
||
|
||
Loaders will have a new method, ``exec_module(module)``. Its only job
|
||
is to "exec" the module and consequently populate the module's
|
||
namespace. It is not responsible for creating or preparing the module
|
||
object, nor for any cleanup afterward. It has no return value.
|
||
|
||
The ``load_module()`` of loaders will still work and be an active part
|
||
of the loader API. It is still useful for cases where the default
|
||
module creation/prepartion/cleanup is not appropriate for the loader.
|
||
|
||
For example, the C API for extension modules only supports the full
|
||
control of ``load_module()``. As such, ``ExtensionFileLoader`` will not
|
||
implement ``exec_module()``. In the future it may be appropriate to
|
||
produce a second C API that would support an ``exec_module()``
|
||
implementation for ``ExtensionFileLoader``. Such a change is outside
|
||
the scope of this PEP.
|
||
|
||
A loader must define either ``exec_module()`` or ``load_module()``. If
|
||
both exist on the loader, ``ModuleSpec.load()`` uses ``exec_module()``
|
||
and ignores ``load_module()``.
|
||
|
||
PEP 420 introduced the optional ``module_repr()`` loader method to limit
|
||
the amount of special-casing in the module type's ``__repr__()``. Since
|
||
this method is part of ``ModuleSpec``, it will be deprecated on loaders.
|
||
However, if it exists on a loader it will be used exclusively.
|
||
|
||
``Loader.init_module_attr()`` method, added prior to Python 3.4's
|
||
release , will be removed in favor of the same method on ``ModuleSpec``.
|
||
|
||
However, ``InspectLoader.is_package()`` will not be deprecated even
|
||
though the same information is found on ``ModuleSpec``. ``ModuleSpec``
|
||
can use it to populate its own ``is_package`` if that information is
|
||
not otherwise available. Still, it will be made optional.
|
||
|
||
The path-based loaders in ``importlib`` take arguments in their
|
||
``__init__()`` and have corresponding attributes. However, the need for
|
||
those values is eliminated. The only exception is
|
||
``FileLoader.get_filename()``, which uses ``self.path``. The signatures
|
||
for these loaders and the accompanying attributes will be deprecated.
|
||
|
||
In addition to executing a module during loading, loaders will still be
|
||
directly responsible for providing APIs concerning module-related data.
|
||
|
||
Other Changes
|
||
-------------
|
||
|
||
* The various finders and loaders provided by ``importlib`` will be
|
||
updated to comply with this proposal.
|
||
|
||
* The spec for the ``__main__`` module will reflect how the interpreter
|
||
was started. For instance, with ``-m`` the spec's name will be that
|
||
of the run module, while ``__main__.__name__`` will still be
|
||
"__main__".
|
||
|
||
* We add ``importlib.find_module()`` to mirror
|
||
``importlib.find_loader()`` (which becomes deprecated).
|
||
|
||
* Deprecations in ``importlib.util``: ``set_package()``,
|
||
``set_loader()``, and ``module_for_loader()``. ``module_to_load()``
|
||
(introduced prior to Python 3.4's release) can be removed.
|
||
|
||
* ``importlib.reload()`` is changed to use ``ModuleSpec.load()``.
|
||
|
||
* ``ModuleSpec.load()`` and ``importlib.reload()`` will now make use of
|
||
the per-module import lock, whereas ``Loader.load_module()`` did not.
|
||
|
||
Reference Implementation
|
||
------------------------
|
||
|
||
A reference implementation is available at <TBD>.
|
||
|
||
|
||
Open Questions
|
||
==============
|
||
|
||
* How to avoid having custom ModuleSpec attributes conflict with future
|
||
normal attributes?
|
||
|
||
This could be done with a sub-namespace bound to a single ModuleSpec
|
||
attribute. It could also be done by reserving names with a single
|
||
leading underscore for custom attributes. Or we could just not worry
|
||
about it.
|
||
|
||
* Get rid of the ``is_package`` property?
|
||
|
||
It duplicates information
|
||
both in the ``ModuleSpec()`` signature and in attributes. It is
|
||
technically unncessary in light of the path attribute and it conflicts
|
||
with ``InspectLoader.is_package()``, which makes the implementation more
|
||
complicated. However, it also provides an explicit indicator of
|
||
package-ness, which helps those less familiar with the import system.
|
||
|
||
* Deprecate the use of ``__file__`` for anything except actual files?
|
||
|
||
* Introduce a new extension module API that takes advantage of
|
||
``ModuleSpec``? I'd rather that be part of a separate proposal.
|
||
|
||
* Add ``create_module()`` to loaders?
|
||
|
||
It would take a ``ModuleSpec``
|
||
and return the module that should be passed to ``spec.exec()``. This
|
||
method would be helpful for new extension module import APIs.
|
||
|
||
* Have ``ModuleSpec.module_repr()`` replace more of the module type's
|
||
``__repr__()`` implementation?
|
||
|
||
A compliant module is required to have
|
||
``__spec__`` set so that should work. However, currently the repr uses
|
||
the module attributes. Using the spec attributes would give precedence
|
||
to the spec in the case that they differ, which would be
|
||
backward-incompatible.
|
||
|
||
* Factor the path-based attributes/functionality into a subclass--
|
||
something like ``PathModuleSpec``?
|
||
|
||
It looks like there just isn't enough benefit to doing so.
|
||
|
||
|
||
References
|
||
==========
|
||
|
||
[1] http://mail.python.org/pipermail/import-sig/2013-August/000658.html
|
||
|
||
|
||
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
|
||
coding: utf-8
|
||
End:
|
||
|