]> granicus.if.org Git - python/commitdiff
Issue #25802: Add an examples section to importlib.
authorBrett Cannon <brett@python.org>
Fri, 8 Jan 2016 22:33:09 +0000 (14:33 -0800)
committerBrett Cannon <brett@python.org>
Fri, 8 Jan 2016 22:33:09 +0000 (14:33 -0800)
Thanks to Berker Peksag for the patch review.

Doc/library/imp.rst
Doc/library/importlib.rst

index 68a6b681ef54ad0fe6ca703242641a949ca8ea58..420031ab48f5e0b836d0a515ec96216c834e2d21 100644 (file)
@@ -81,7 +81,9 @@ This module provides an interface to the mechanisms used to implement the
    .. deprecated:: 3.3
       Use :func:`importlib.util.find_spec` instead unless Python 3.3
       compatibility is required, in which case use
-      :func:`importlib.find_loader`.
+      :func:`importlib.find_loader`. For example usage of the former case,
+      see the :ref:`importlib-examples` section of the :mod:`importlib`
+      documentation.
 
 
 .. function:: load_module(name, file, pathname, description)
@@ -108,9 +110,12 @@ This module provides an interface to the mechanisms used to implement the
       If previously used in conjunction with :func:`imp.find_module` then
       consider using :func:`importlib.import_module`, otherwise use the loader
       returned by the replacement you chose for :func:`imp.find_module`. If you
-      called :func:`imp.load_module` and related functions directly then use the
-      classes in :mod:`importlib.machinery`, e.g.
-      ``importlib.machinery.SourceFileLoader(name, path).load_module()``.
+      called :func:`imp.load_module` and related functions directly with file
+      path arguments then use a combination of
+      :func:`importlib.util.spec_from_file_location` and
+      :func:`importlib.util.module_from_spec`. See the :ref:`importlib-examples`
+      section of the :mod:`importlib` documentation for details of the various
+      approaches.
 
 
 .. function:: new_module(name)
@@ -119,7 +124,7 @@ This module provides an interface to the mechanisms used to implement the
    in ``sys.modules``.
 
    .. deprecated:: 3.4
-      Use :class:`types.ModuleType` instead.
+      Use :func:`importlib.util.module_from_spec` instead.
 
 
 .. function:: reload(module)
index d800835e75be66f0a3d5694d520a5a215b45609a..45766a7b3f5f6d51bc47f362d72d44a4de621689 100644 (file)
@@ -256,7 +256,7 @@ ABC hierarchy::
       module and *path* will be the value of :attr:`__path__` from the
       parent package. If a spec cannot be found, ``None`` is returned.
       When passed in, ``target`` is a module object that the finder may
-      use to make a more educated about what spec to return.
+      use to make a more educated guess about what spec to return.
 
       .. versionadded:: 3.4
 
@@ -306,7 +306,7 @@ ABC hierarchy::
       within the :term:`path entry` to which it is assigned.  If a spec
       cannot be found, ``None`` is returned.  When passed in, ``target``
       is a module object that the finder may use to make a more educated
-      about what spec to return.
+      guess about what spec to return.
 
       .. versionadded:: 3.4
 
@@ -1307,3 +1307,90 @@ an :term:`importer`.
         loader = importlib.machinery.SourceFileLoader
         lazy_loader = importlib.util.LazyLoader.factory(loader)
         finder = importlib.machinery.FileFinder(path, [(lazy_loader, suffixes)])
+
+.. _importlib-examples:
+
+Examples
+--------
+
+To programmatically import a module, use :func:`importlib.import_module`.
+::
+
+  import importlib
+
+  itertools = importlib.import_module('itertools')
+
+If you need to find out if a module can be imported without actually doing the
+import, then you should use :func:`importlib.util.find_spec`.
+::
+
+  import importlib.util
+  import sys
+
+  # For illustrative purposes.
+  name = 'itertools'
+
+  spec = importlib.util.find_spec(name)
+  if spec is None:
+      print("can't find the itertools module")
+  else:
+      # If you chose to perform the actual import.
+      module = importlib.util.module_from_spec(spec)
+      spec.loader.exec_module(module)
+      # Adding the module to sys.modules is optional.
+      sys.modules[name] = module
+
+To import a Python source file directly, use the following recipe
+(Python 3.4 and newer only)::
+
+  import importlib.util
+  import sys
+
+  # For illustrative purposes.
+  import tokenize
+  file_path = tokenize.__file__
+  module_name = tokenize.__name__
+
+  spec = importlib.util.spec_from_file_location(module_name, file_path)
+  module = importlib.util.module_from_spec(spec)
+  spec.loader.exec_module(module)
+  # Optional; only necessary if you want to be able to import the module
+  # by name later.
+  sys.modules[module_name] = module
+
+Import itself is implemented in Python code, making it possible to
+expose most of the import machinery through importlib. The following
+helps illustrate the various APIs that importlib exposes by providing an
+approximate implementation of
+:func:`importlib.import_module` (Python 3.4 and newer for importlib usage,
+Python 3.6 and newer for other parts of the code).
+::
+
+  import importlib.util
+  import sys
+
+  def import_module(name, package=None):
+      """An approximate implementation of import."""
+      absolute_name = importlib.util.resolve_name(name, package)
+      try:
+          return sys.modules[absolute_name]
+      except KeyError:
+          pass
+
+      path = None
+      if '.' in absolute_name:
+          parent_name, _, child_name = absolute_name.rpartition('.')
+          parent_module = import_module(parent_name)
+          path = parent_module.spec.submodule_search_locations
+      for finder in sys.meta_path:
+          spec = finder.find_spec(absolute_name, path)
+          if spec is not None:
+              break
+      else:
+          raise ImportError(f'No module named {absolute_name!r}')
+      module = spec.loader.create_module(spec)
+      spec.loader.exec_module(module)
+      sys.modules[absolute_name] = module
+      if path is not None:
+          setattr(parent_module, child_name, module)
+      return module