diff options
author | Brett Cannon <bcannon@gmail.com> | 2009-03-21 03:11:16 (GMT) |
---|---|---|
committer | Brett Cannon <bcannon@gmail.com> | 2009-03-21 03:11:16 (GMT) |
commit | e43b060b05e3d99f83bc900e5efc5cdb34298888 (patch) | |
tree | 750d9fdf871efccd124512002e46ba584e92739f | |
parent | b487e632826a45bb81925d1577856637c3fcafa0 (diff) | |
download | cpython-e43b060b05e3d99f83bc900e5efc5cdb34298888.zip cpython-e43b060b05e3d99f83bc900e5efc5cdb34298888.tar.gz cpython-e43b060b05e3d99f83bc900e5efc5cdb34298888.tar.bz2 |
Document import's semantics for the language reference. This includes filling
in missing details for the sys module.
-rw-r--r-- | Doc/glossary.rst | 6 | ||||
-rw-r--r-- | Doc/library/sys.rst | 37 | ||||
-rw-r--r-- | Doc/reference/simple_stmts.rst | 181 | ||||
-rw-r--r-- | Lib/importlib/NOTES | 7 |
4 files changed, 169 insertions, 62 deletions
diff --git a/Doc/glossary.rst b/Doc/glossary.rst index c9808fe..c4b6358 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -182,7 +182,8 @@ Glossary finder An object that tries to find the :term:`loader` for a module. It must implement a method named :meth:`find_module`. See :pep:`302` for - details. + details and :class:`importlib.abc.Finder` for an + :term:`abstract base class`. floor division Mathematical division discarding any remainder. The floor division @@ -363,7 +364,8 @@ Glossary loader An object that loads a module. It must define a method named :meth:`load_module`. A loader is typically returned by a - :term:`finder`. See :pep:`302` for details. + :term:`finder`. See :pep:`302` for details and + :class:`importlib.abc.Loader` for an :term:`abstract base class`. mapping A container object (such as :class:`dict`) which supports arbitrary key diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 632e550..c29e7fe 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -478,6 +478,22 @@ always available. characters are stored as UCS-2 or UCS-4. +.. data:: meta_path + + A list of :term:`finder` objects that have their :meth:`find_module` + methods called to see if one of the objects can find the module to be + imported. The :meth:`find_module` method is called at least with the + absolute name of the module being imported. If the module to be imported is + contained in package then the parent package's :attr:`__path__` attribute + is passed in as a second argument. The method returns :keyword:`None` if + the module cannot be found, else returns a :term:`loader`. + + :data:`sys.meta_path` is searched before any implicit default finders or + :data:`sys.path`. + + See :pep:`302` for the original specification. + + .. data:: modules This is a dictionary that maps module names to modules which have already been @@ -508,6 +524,27 @@ always available. :data:`sys.path`. +.. data:: path_hooks + + A list of callables that take a path argument to try to create a + :term:`finder` for the path. If a finder can be created, it is to be + returned by the callable, else raise :exc:`ImportError`. + + Originally specified in :pep:`302`. + + +.. data:: path_importer_cache + + A dictionary acting as a cache for :term:`finder` objects. The keys are + paths that have been passed to :data:`sys.path_hooks` and the values are + the finders that are found. If a path is a valid file system path but no + explicit finder is found on :data:`sys.path_hooks` then :keyword:`None` is + stored to represent the implicit default finder should be used. If the path + is not an existing path then :class:`imp.NullImporter` is set. + + Originally specified in :pep:`302`. + + .. data:: platform This string contains a platform identifier that can be used to append diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index d1e89e5..e6fa6cd 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -642,48 +642,125 @@ The :keyword:`import` statement Import statements are executed in two steps: (1) find a module, and initialize it if necessary; (2) define a name or names in the local namespace (of the scope -where the :keyword:`import` statement occurs). The first form (without -:keyword:`from`) repeats these steps for each identifier in the list. The form -with :keyword:`from` performs step (1) once, and then performs step (2) -repeatedly. +where the :keyword:`import` statement occurs). The statement comes in two +forms differing on whether it uses the :keyword:`from` keyword. The first form +(without :keyword:`from`) repeats these steps for each identifier in the list. +The form with :keyword:`from` performs step (1) once, and then performs step +(2) repeatedly. For a reference implementation of step (1), see the +:mod:`importlib` module. -In this context, to "initialize" a built-in or extension module means to call an -initialization function that the module must provide for the purpose (in the -reference implementation, the function's name is obtained by prepending string -"init" to the module's name); to "initialize" a Python-coded module means to -execute the module's body. +.. index:: + single: package + +To understand how step (1) occurs, one must first understand how Python handles +hierarchical naming of modules. To help organize modules and provide a +hierarchy in naming, Python has a concept of packages. A package can contain +other packages and modules while modules cannot contain other modules or +packages. From a file system perspective, packages are directories and modules +are files. The original `specification for packages +<http://www.python.org/doc/essays/packages.html>`_ is still available to read, +although minor details have changed since the writing of that document. .. index:: - single: modules (in module sys) - single: sys.modules - pair: module; name - pair: built-in; module - pair: user-defined; module - pair: filename; extension - triple: module; search; path - module: sys - -The system maintains a table of modules that have been or are being initialized, -indexed by module name. This table is accessible as ``sys.modules``. When a -module name is found in this table, step (1) is finished. If not, a search for -a module definition is started. When a module is found, it is loaded. Details -of the module searching and loading process are implementation and platform -specific. It generally involves searching for a "built-in" module with the -given name and then searching a list of locations given as ``sys.path``. + single: sys.modules + +Once the name of the module is known (unless otherwise specified, the term +"module" will refer to both packages and modules), searching +for the module or package can begin. The first place checked is +:data:`sys.modules`, the cache of all modules that have been imported +previously. If the module is found there then it is used in step (2) of import. .. index:: - pair: module; initialization - exception: ImportError - single: code block - exception: SyntaxError + single: sys.meta_path + single: finder + pair: finder; find_module + single: __path__ + +If the module is not found in the cache, then :data:`sys.meta_path` is searched +(the specification for :data:`sys.meta_path` can be found in :pep:`302`). +The object is a list of :term:`finder` objects which are queried in order as to +whether they know how to load the module by calling their :meth:`find_module` +method with the name of the module. If the module happens to be contained +within a package (as denoted by the existence of a dot in the name), then a +second argument to :meth:`find_module` is given as the value of the +:attr:`__path__` attribute from the parent package (everything up to the last +dot in the name of the module being imported). If a finder can find the module +it returns a :term:`loader` (discussed later) or returns :keyword:`None`. + +.. index:: + single: sys.path_hooks + single: sys.path_importer_cache + single: sys.path + +If none of the finders on :data:`sys.meta_path` are able to find the module +then some implicitly defined finders are queried. Implementations of Python +vary in what implicit meta path finders are defined. The one they all do +define, though, is one that handles :data:`sys.path_hooks`, +:data:`sys.path_importer_cache`, and :data:`sys.path`. + +The implicit finder searches for the requested module in the "paths" specified +in one of two places ("paths" do not have to be file system paths). If the +module being imported is supposed to be contained within a package then the +second argument passed to :meth:`find_module`, :attr:`__path__` on the parent +package, is used as the source of paths. If the module is not contained in a +package then :data:`sys.path` is used as the source of paths. + +Once the source of paths is chosen it is iterated over to find a finder that +can handle that path. The dict at :data:`sys.path_importer_cache` caches +finders for paths and is checked for a finder. If the path does not have a +finder cached then :data:`sys.path_hooks` is searched by calling each object in +the list with a single argument of the path, returning a finder or raises +:exc:`ImportError`. If a finder is returned then it is cached in +:data:`sys.path_importer_cache` and then used for that path entry. If no finder +can be found but the path exists then a value of :keyword:`None` is +stored in :data:`sys.path_importer_cache` to signify that an implicit, +file-based finder that handles modules stored as individual files should be +used for that path. If the path does not exist then a finder which always +returns :keyword:`None` is placed in the cache for the path. + +.. index:: + single: loader + pair: loader; load_module + exception: ImportError + +If no finder can find the module then :exc:`ImportError` is raised. Otherwise +some finder returned a loader whose :meth:`load_module` method is called with +the name of the module to load (see :pep:`302` for the original definition of +loaders). A loader has several responsibilities to perform on a module it +loads. First, if the module already exists in :data:`sys.modules` (a +possibility if the loader is called outside of the import machinery) then it +is to use that module for initialization and not a new module. But if the +module does not exist in :data:`sys.modules` then it is to be added to that +dict before initialization begins. If an error occurs during loading of the +module and it was added to :data:`sys.modules` it is to be removed from the +dict. If an error occurs but the module was already in :data:`sys.modules` it +is left in the dict. + +.. index:: + single: __name__ + single: __file__ + single: __path__ + single: __package__ + single: __loader__ + +The loader must set several attributes on the module. :data:`__name__` is to be +set to the name of the module. :data:`__file__` is to be the "path" to the file +unless the module is built-in (and thus listed in +:data:`sys.builtin_module_names`) in which case the attribute is not set. +If what is being imported is a package then :data:`__path__` is to be set to a +list of paths to be searched when looking for modules and packages contained +within the package being imported. :data:`__package__` is optional but should +be set to the name of package that contains the module or package (the empty +string is used for module not contained in a package). :data:`__loader__` is +also optional but should be set to the loader object that is loading the +module. -If a built-in module is found, its built-in initialization code is executed and -step (1) is finished. If no matching file is found, :exc:`ImportError` is -raised. If a file is found, it is parsed, yielding an executable code block. If -a syntax error occurs, :exc:`SyntaxError` is raised. Otherwise, an empty module -of the given name is created and inserted in the module table, and then the code -block is executed in the context of this module. Exceptions during this -execution terminate step (1). +.. index:: + exception: ImportError + +If an error occurs during loading then the loader raises :exc:`ImportError` if +some other exception is not already being propagated. Otherwise the loader +returns the module that was loaded and initialized. When step (1) finishes without raising an exception, step (2) can begin. @@ -723,23 +800,21 @@ function contains or is a nested block with free variables, the compiler will raise a :exc:`SyntaxError`. .. index:: - keyword: from - statement: from - triple: hierarchical; module; names - single: packages - single: __init__.py - -**Hierarchical module names:** when the module names contains one or more dots, -the module search path is carried out differently. The sequence of identifiers -up to the last dot is used to find a "package"; the final identifier is then -searched inside the package. A package is generally a subdirectory of a -directory on ``sys.path`` that has a file :file:`__init__.py`. - -.. - [XXX Can't be - bothered to spell this out right now; see the URL - http://www.python.org/doc/essays/packages.html for more details, also about how - the module search works from inside a package.] + single: relative; import + +When specifying what module to import you do not have to specify the absolute +name of the module. When a module or package is contained within another +package it is possible to make a relative import within the same top package +without having to mention the package name. By using leading dots in the +specified module or package after :keyword:`from` you can specify how high to +traverse up the current package hierarchy without specifying exact names. One +leading dot means the current package where the module making the import +exists. Two dots means up one package level. Three dots is up two levels, etc. +So if you execute ``from . import mod`` from a module in the ``pkg`` package +then you will end up importing ``pkg.mod``. If you execute ``from ..subpkg2 +imprt mod`` from within ``pkg.subpkg1`` you will import ``pkg.subpkg2.mod``. +The specification for relative imports is contained within :pep:`328`. + .. index:: builtin: __import__ diff --git a/Lib/importlib/NOTES b/Lib/importlib/NOTES deleted file mode 100644 index b472fad..0000000 --- a/Lib/importlib/NOTES +++ /dev/null @@ -1,7 +0,0 @@ -to do -///// - -* Make sure that there is documentation *somewhere* fully explaining the -semantics of import that can be referenced from the package's documentation -(even if it is in the package documentation itself, although it might be best -in the language specification). |