[Python-checkins] r53283 - sandbox/trunk/import_in_py/importer.py

brett.cannon python-checkins at python.org
Sat Jan 6 00:54:44 CET 2007


Author: brett.cannon
Date: Sat Jan  6 00:54:43 2007
New Revision: 53283

Modified:
   sandbox/trunk/import_in_py/importer.py
Log:
Clean up docstrings.


Modified: sandbox/trunk/import_in_py/importer.py
==============================================================================
--- sandbox/trunk/import_in_py/importer.py	(original)
+++ sandbox/trunk/import_in_py/importer.py	Sat Jan  6 00:54:43 2007
@@ -1,4 +1,33 @@
-"""Re-implementation of import machinery in Python source code.
+"""Implementation of Python's import machinery in Python source code.
+
+The Import class implements the semantics of import.  This means that an
+instance of this class can be called to properly check sys.modules,
+sys.meta_path, sys.path, etc. to import the requested module.
+
+The importing of built-in, frozen, extension, .py, and .pyc files are all
+handled by implementing importers and loaders as specified by PEP 302.  This
+leads to the ability to easily control imports based on the type of module.
+There is also a clear distinction between how the module is stored and how it
+is formatted (e.g., a Python source file does not require it be stored as a
+file on a filesystem).
+
+To help with the distinction between how a module is stored compared to its
+format the idea of handlers is introduced.  A handler implements a specific
+interface while specifying the type of module it handles (usually by the what
+one would expect as a file extension if the module was on a filesystem).  This
+allows a PEP 302 importer/loader to represent how a module is stored while the
+handler deals with how the module is formatted.
+
+A handler is expected to implement the handle_code method only.  The handler
+for Python source and bytecode modules goes farther and defines an extensive
+interface that is designed so that alternatives on module formatting can be
+supported easily without needing to write a new importer/loader.  The Python
+source and bytecode handler also expects loaders to define a more extensive
+interface to allow for different backend stores (e.g., databases) to use the
+handler without modification.  All of this helps with code reuse and possible
+errors from the complicated relationship between Python source and bytecode
+modules.
+
 
 ====================
 References on import
@@ -132,12 +161,8 @@
 
     @classmethod
     def find_module(cls, fullname, path=None):
-        """See if import is for a built-in or frozen module.
-
-        Since built-in and frozen modules should never have a path,
-        short-circuit if one is specified.
-
-        """
+        """See if a built-in or frozen module can be imported based on the
+        specified name."""
         if cls._find(fullname):
             return cls
         else:
@@ -166,7 +191,7 @@
     """sys.meta_path class for importing built-in modules.
     
     XXX Possible optimization is to bail out in find_module() if 'path' is set
-    to a value.  Also can then raise an error in load_module() if 'path' is set.
+    to a value.
     
     """
 
@@ -184,11 +209,17 @@
 
 class FileSystemFactory(object):
 
-    """Factory object for sys.path_hooks for directory entries on sys.path.
+    """Factory function for sys.path_hooks for directory entries on sys.path.
     
     The path to be handled, if it is a filesystem directory, is used to
-    initialize a new FileSystemImporter for that path entry.  The handlers are
-    also passed on to the importer.
+    initialize a new FileSystemImporter for that path entry.  An instantiated
+    object stores various handlers that are to be used to decide if the path
+    entry contains the module to be imported.
+
+    XXX Possible optimization would be to get the directory's contents and make
+    sure that only handlers for the files in the directory are given to the
+    returned importer.  This would kill the ability to add a new module into
+    the directory during run-time that is a new type of file, though.
     
     """
 
@@ -221,6 +252,11 @@
     """Importer for the filesystem using the passed-in handlers."""
 
     def __init__(self, path_entry, *handlers):
+        """Store the path this importer handles and the handlers to use.
+
+        The order of the handlers determines precedence of file types.
+
+        """
         self.path_entry = path_entry
         self.handlers = handlers
         self.loader = FileSystemLoader
@@ -232,7 +268,7 @@
        
         If the module's name is dotted then only search for the trailing
         module's name on the path entry.  An importer is already created
-        for each directory in __path__ for a package.
+        for each directory in the __path__ attribute for a package.
         
         """
         tail_module = fullname.rsplit('.', 1)[-1]
@@ -273,7 +309,9 @@
     """
 
     def __init__(self, file_path, handler, package=None):
-        """Store arguments on to the instance."""
+        """Store the path to the file to use for the import and the handler to
+        use along with whether this is a package (this does not include modules
+        within a package)."""
         self.file_path = file_path
         self.handler = handler
         self.package = package
@@ -297,12 +335,21 @@
             return module
         
     def mod_time(self, path):
-        """Return the modification time for the specified path as an integer."""
+        """Return the modification time for the specified path as an integer.
+        
+        This method is required as part of the interface needed for
+        PyPycHandler.
+        
+        """
         return int(os.stat(path).st_mtime)
         
     def split_path(self, path):
         """Split the specified path into a base path and the type of the
-        path."""
+        path.
+        
+        This method is required for PyPycHandler.
+        
+        """
         return os.path.splitext(path)
         
     def create_path(self, base_path, type_, must_exist=False):
@@ -310,6 +357,8 @@
         
         If must_exist is True, the path must already exist in order to return a
         path instead of None.
+
+        This method is required for PyPycHandler.
         
         """
         path = base_path + type_
@@ -319,7 +368,11 @@
         
     def read_data(self, path, binary=False):
         """Open the path and return the data read from it in the specified
-        format."""
+        format.
+        
+        This method is required for PyPycHandler.
+        
+        """
         with open(path, 'rb' if binary else 'U') as data_file:
             data = data_file.read()
         return data
@@ -328,6 +381,8 @@
         """Write data to a specified path as either binary or textual data.
        
         If the path cannot be accessed, then exit silently.
+
+        This method is required for PyPycHandler.
         
         """
         try:
@@ -350,11 +405,11 @@
     """
     
     def __init__(self, source_handles=None, bytecode_handles=None):
-        """Specify the handles for source and bytecode to be handled by this
-        handler and set 'handles' appropriately.
-        
-        If either source code or bytecode are not to be used, pass in a false
-        value for the appropriate argument.
+        """Specify the file types for source and bytecode to be handled by this
+        handler and set 'handles' appropriately as tuples (empty tuples are
+        acceptable).
+
+        Not specifying handles will lead to reasonable defaults being used.
         
         """
         if source_handles is None:
@@ -376,7 +431,8 @@
         return data[:4], _r_long(data[4:8]), data[8:]
 
     def check_magic(self, magic):
-        """Check whether the magic number is valid or not."""
+        """Check whether the magic number is correct or not for the current
+        running interpreter."""
         return imp.get_magic() == magic
         
     def code_from_bytecode(self, bytecode):
@@ -393,7 +449,7 @@
         return compile(source, str(path), 'exec')
         
     def create_pyc(self, bytecode, timestamp):
-        """Create data for a .pyc file."""
+        """Create data to be written out for a .pyc file."""
         data = imp.get_magic()
         data += _w_long(timestamp)
         data += marshal.dumps(bytecode)
@@ -408,7 +464,7 @@
         to be able to load needed data.  A key point with some of these methods
         is the idea of opaque code objects which are not directly touched by
         the handler but are passed back to the loader so as to allow for a way
-        to keep state for the loader:
+        to keep state:
         
         * split_path(path)
             Take in an opaque path object and split it into a base path and a
@@ -535,7 +591,7 @@
 
 class Import(object):
 
-    """Class that re-implements __import__.
+    """Class that implements the __import__ interface.
     
     Backwards compatibility is maintained  by extending sys.meta_path
     interally (for handling built-in and frozen modules) and providing a
@@ -573,7 +629,8 @@
             raise ImportError("No module named %s" % name)
 
     def _sys_path_importer(self, path_entry):
-        """Return the importer for the specified path.
+        """Return the importer for the specified path, from
+        sys.path_importer_cache if possible.
         
         If None is stored in sys.path_importer_cache then use the default path
         hook.
@@ -775,11 +832,10 @@
         The 'name' argument is the name of the module to be imported (e.g.,
         'foo' in ``import foo`` or ``from foo import ...``).
 
-        'globals' and
-        'locals' are the global and local namespace dictionaries of the module
-        where the import statement appears.  'globals' is used to introspect
-        the __path__ and __name__ attributes of the module making the call.
-        'local's is ignored.
+        'globals' and 'locals' are the global and local namespace dictionaries
+        of the module where the import statement appears.  'globals' is used to
+        introspect the __path__ and __name__ attributes of the module making
+        the call.  'local's is ignored.
         
         'fromlist' lists any specific objects that are to eventually be put
         into the namespace (e.g., ``from for.bar import baz`` would have 'baz'
@@ -789,10 +845,8 @@
         attributes on the module, attempting a module import relative to 'name'
         to set that attribute.
         
-        When 'name' is a dotted name,
-        there are two
-        different situations to consider for the return value.  One is when
-        the fromlist is empty.
+        When 'name' is a dotted name, there are two different situations to
+        consider for the return value.  One is when the fromlist is empty.
         In this situation the import statement imports and returns the name up
         to the first dot.  All subsequent names are imported but set as
         attributes as needed on parent modules.  When fromlist is not empty


More information about the Python-checkins mailing list