home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Lib / ni1.py < prev    next >
Text File  |  1997-09-29  |  14KB  |  435 lines

  1. """New import scheme with package support.
  2.  
  3. Quick Reference
  4. ---------------
  5.  
  6. - To enable package support, execute "import ni" before importing any
  7.   packages.  Importing this module automatically installs the relevant
  8.   import hooks.
  9.  
  10. - To create a package named spam containing sub-modules ham, bacon and
  11.   eggs, create a directory spam somewhere on Python's module search
  12.   path (i.e. spam's parent directory must be one of the directories in
  13.   sys.path or $PYTHONPATH); then create files ham.py, bacon.py and
  14.   eggs.py inside spam.
  15.  
  16. - To import module ham from package spam and use function hamneggs()
  17.   from that module, you can either do
  18.  
  19.     import spam.ham        # *not* "import spam" !!!
  20.     spam.ham.hamneggs()
  21.  
  22.   or
  23.  
  24.     from spam import ham
  25.     ham.hamneggs()
  26.  
  27.   or
  28.  
  29.     from spam.ham import hamneggs
  30.     hamneggs()
  31.  
  32. - Importing just "spam" does not do what you expect: it creates an
  33.   empty package named spam if one does not already exist, but it does
  34.   not import spam's submodules.  The only submodule that is guaranteed
  35.   to be imported is spam.__init__, if it exists.  Note that
  36.   spam.__init__ is a submodule of package spam.  It can reference to
  37.   spam's namespace via the '__.' prefix, for instance
  38.  
  39.     __.spam_inited = 1        # Set a package-level variable
  40.  
  41.  
  42.  
  43. Theory of Operation
  44. -------------------
  45.  
  46. A Package is a module that can contain other modules.  Packages can be
  47. nested.  Package introduce dotted names for modules, like P.Q.M, which
  48. could correspond to a file P/Q/M.py found somewhere on sys.path.  It
  49. is possible to import a package itself, though this makes little sense
  50. unless the package contains a module called __init__.
  51.  
  52. A package has two variables that control the namespace used for
  53. packages and modules, both initialized to sensible defaults the first
  54. time the package is referenced.
  55.  
  56. (1) A package's *module search path*, contained in the per-package
  57. variable __path__, defines a list of *directories* where submodules or
  58. subpackages of the package are searched.  It is initialized to the
  59. directory containing the package.  Setting this variable to None makes
  60. the module search path default to sys.path (this is not quite the same
  61. as setting it to sys.path, since the latter won't track later
  62. assignments to sys.path).
  63.  
  64. (2) A package's *import domain*, contained in the per-package variable
  65. __domain__, defines a list of *packages* that are searched (using
  66. their respective module search paths) to satisfy imports.  It is
  67. initialized to the list cosisting of the package itself, its parent
  68. package, its parent's parent, and so on, ending with the root package
  69. (the nameless package containing all top-level packages and modules,
  70. whose module search path is None, implying sys.path).
  71.  
  72. The default domain implements a search algorithm called "expanding
  73. search".  An alternative search algorithm called "explicit search"
  74. fixes the import search path to contain only the root package,
  75. requiring the modules in the package to name all imported modules by
  76. their full name.  The convention of using '__' to refer to the current
  77. package (both as a per-module variable and in module names) can be
  78. used by packages using explicit search to refer to modules in the same
  79. package; this combination is known as "explicit-relative search".
  80.  
  81. The PackageImporter and PackageLoader classes together implement the
  82. following policies:
  83.  
  84. - There is a root package, whose name is ''.  It cannot be imported
  85.   directly but may be referenced, e.g. by using '__' from a top-level
  86.   module.
  87.  
  88. - In each module or package, the variable '__' contains a reference to
  89.   the parent package; in the root package, '__' points to itself.
  90.  
  91. - In the name for imported modules (e.g. M in "import M" or "from M
  92.   import ..."), a leading '__' refers to the current package (i.e.
  93.   the package containing the current module); leading '__.__' and so
  94.   on refer to the current package's parent, and so on.  The use of
  95.   '__' elsewhere in the module name is not supported.
  96.  
  97. - Modules are searched using the "expanding search" algorithm by
  98.   virtue of the default value for __domain__.
  99.  
  100. - If A.B.C is imported, A is searched using __domain__; then
  101.   subpackage B is searched in A using its __path__, and so on.
  102.  
  103. - Built-in modules have priority: even if a file sys.py exists in a
  104.   package, "import sys" imports the built-in sys module.
  105.  
  106. - The same holds for frozen modules, for better or for worse.
  107.  
  108. - Submodules and subpackages are not automatically loaded when their
  109.   parent packages is loaded.
  110.  
  111. - The construct "from package import *" is illegal.  (It can still be
  112.   used to import names from a module.)
  113.  
  114. - When "from package import module1, module2, ..." is used, those
  115.     modules are explicitly loaded.
  116.  
  117. - When a package is loaded, if it has a submodule __init__, that
  118.   module is loaded.  This is the place where required submodules can
  119.   be loaded, the __path__ variable extended, etc.  The __init__ module
  120.   is loaded even if the package was loaded only in order to create a
  121.   stub for a sub-package: if "import P.Q.R" is the first reference to
  122.   P, and P has a submodule __init__, P.__init__ is loaded before P.Q
  123.   is even searched.
  124.  
  125. Caveats:
  126.  
  127. - It is possible to import a package that has no __init__ submodule;
  128.   this is not particularly useful but there may be useful applications
  129.   for it (e.g. to manipulate its search paths from the outside!).
  130.  
  131. - There are no special provisions for os.chdir().  If you plan to use
  132.   os.chdir() before you have imported all your modules, it is better
  133.   not to have relative pathnames in sys.path.  (This could actually be
  134.   fixed by changing the implementation of path_join() in the hook to
  135.   absolutize paths.)
  136.  
  137. - Packages and modules are introduced in sys.modules as soon as their
  138.   loading is started.  When the loading is terminated by an exception,
  139.   the sys.modules entries remain around.
  140.  
  141. - There are no special measures to support mutually recursive modules,
  142.   but it will work under the same conditions where it works in the
  143.   flat module space system.
  144.  
  145. - Sometimes dummy entries (whose value is None) are entered in
  146.   sys.modules, to indicate that a particular module does not exist --
  147.   this is done to speed up the expanding search algorithm when a
  148.   module residing at a higher level is repeatedly imported (Python
  149.   promises that importing a previously imported module is cheap!)
  150.  
  151. - Although dynamically loaded extensions are allowed inside packages,
  152.   the current implementation (hardcoded in the interpreter) of their
  153.   initialization may cause problems if an extension invokes the
  154.   interpreter during its initialization.
  155.  
  156. - reload() may find another version of the module only if it occurs on
  157.   the package search path.  Thus, it keeps the connection to the
  158.   package to which the module belongs, but may find a different file.
  159.  
  160. XXX Need to have an explicit name for '', e.g. '__root__'.
  161.  
  162. """
  163.  
  164.  
  165. import imp
  166. import string
  167. import sys
  168. import __builtin__
  169.  
  170. import ihooks
  171. from ihooks import ModuleLoader, ModuleImporter
  172.  
  173.  
  174. class PackageLoader(ModuleLoader):
  175.  
  176.     """A subclass of ModuleLoader with package support.
  177.  
  178.     find_module_in_dir() will succeed if there's a subdirectory with
  179.     the given name; load_module() will create a stub for a package and
  180.     load its __init__ module if it exists.
  181.  
  182.     """
  183.  
  184.     def find_module_in_dir(self, name, dir):
  185.     if dir is not None:
  186.         dirname = self.hooks.path_join(dir, name)
  187.         if self.hooks.path_isdir(dirname):
  188.         return None, dirname, ('', '', 'PACKAGE')
  189.     return ModuleLoader.find_module_in_dir(self, name, dir)
  190.  
  191.     def load_module(self, name, stuff):
  192.     file, filename, info = stuff
  193.     suff, mode, type = info
  194.     if type == 'PACKAGE':
  195.         return self.load_package(name, stuff)
  196.     if sys.modules.has_key(name):
  197.         m = sys.modules[name]
  198.     else:
  199.         sys.modules[name] = m = imp.new_module(name)
  200.     self.set_parent(m)
  201.     if type == imp.C_EXTENSION and '.' in name:
  202.         return self.load_dynamic(name, stuff)
  203.     else:
  204.         return ModuleLoader.load_module(self, name, stuff)
  205.  
  206.     def load_dynamic(self, name, stuff):
  207.     file, filename, (suff, mode, type) = stuff
  208.     # Hack around restriction in imp.load_dynamic()
  209.     i = string.rfind(name, '.')
  210.     tail = name[i+1:]
  211.     if sys.modules.has_key(tail):
  212.         save = sys.modules[tail]
  213.     else:
  214.         save = None
  215.     sys.modules[tail] = imp.new_module(name)
  216.     try:
  217.         m = imp.load_dynamic(tail, filename, file)
  218.     finally:
  219.         if save:
  220.         sys.modules[tail] = save
  221.         else:
  222.         del sys.modules[tail]
  223.     sys.modules[name] = m
  224.     return m
  225.  
  226.     def load_package(self, name, stuff):
  227.     file, filename, info = stuff
  228.     if sys.modules.has_key(name):
  229.         package = sys.modules[name]
  230.     else:
  231.         sys.modules[name] = package = imp.new_module(name)
  232.     package.__path__ = [filename]
  233.     self.init_package(package)
  234.     return package
  235.  
  236.     def init_package(self, package):
  237.     self.set_parent(package)
  238.     self.set_domain(package)
  239.     self.call_init_module(package)
  240.  
  241.     def set_parent(self, m):
  242.     name = m.__name__
  243.     if '.' in name:
  244.         name = name[:string.rfind(name, '.')]
  245.     else:
  246.         name = ''
  247.     m.__ = sys.modules[name]
  248.  
  249.     def set_domain(self, package):
  250.     name = package.__name__
  251.     package.__domain__ = domain = [name]
  252.     while '.' in name:
  253.         name = name[:string.rfind(name, '.')]
  254.         domain.append(name)
  255.     if name:
  256.         domain.append('')
  257.  
  258.     def call_init_module(self, package):
  259.     stuff = self.find_module('__init__', package.__path__)
  260.     if stuff:
  261.         m = self.load_module(package.__name__ + '.__init__', stuff)
  262.         package.__init__ = m
  263.  
  264.  
  265. class PackageImporter(ModuleImporter):
  266.  
  267.     """Importer that understands packages and '__'."""
  268.  
  269.     def __init__(self, loader = None, verbose = 0):
  270.     ModuleImporter.__init__(self,
  271.     loader or PackageLoader(None, verbose), verbose)
  272.  
  273.     def import_module(self, name, globals={}, locals={}, fromlist=[]):
  274.     if globals.has_key('__'):
  275.         package = globals['__']
  276.     else:
  277.         # No calling context, assume in root package
  278.         package = sys.modules['']
  279.     if name[:3] in ('__.', '__'):
  280.         p = package
  281.         name = name[3:]
  282.         while name[:3] in ('__.', '__'):
  283.         p = p.__
  284.         name = name[3:]
  285.         if not name:
  286.         return self.finish(package, p, '', fromlist)
  287.         if '.' in name:
  288.         i = string.find(name, '.')
  289.         name, tail = name[:i], name[i:]
  290.         else:
  291.         tail = ''
  292.         mname = p.__name__ and p.__name__+'.'+name or name
  293.         m = self.get1(mname)
  294.         return self.finish(package, m, tail, fromlist)
  295.     if '.' in name:
  296.         i = string.find(name, '.')
  297.         name, tail = name[:i], name[i:]
  298.     else:
  299.         tail = ''
  300.     for pname in package.__domain__:
  301.         mname = pname and pname+'.'+name or name
  302.         m = self.get0(mname)
  303.         if m: break
  304.     else:
  305.         raise ImportError, "No such module %s" % name
  306.     return self.finish(m, m, tail, fromlist)
  307.  
  308.     def finish(self, module, m, tail, fromlist):
  309.     # Got ....A; now get ....A.B.C.D
  310.     yname = m.__name__
  311.     if tail and sys.modules.has_key(yname + tail): # Fast path
  312.         yname, tail = yname + tail, ''
  313.         m = self.get1(yname)
  314.     while tail:
  315.         i = string.find(tail, '.', 1)
  316.         if i > 0:
  317.         head, tail = tail[:i], tail[i:]
  318.         else:
  319.         head, tail = tail, ''
  320.         yname = yname + head
  321.         m = self.get1(yname)
  322.  
  323.     # Got ....A.B.C.D; now finalize things depending on fromlist
  324.     if not fromlist:
  325.         return module
  326.     if '__' in fromlist:
  327.         raise ImportError, "Can't import __ from anywhere"
  328.     if not hasattr(m, '__path__'): return m
  329.     if '*' in fromlist:
  330.         raise ImportError, "Can't import * from a package"
  331.     for f in fromlist:
  332.         if hasattr(m, f): continue
  333.         fname = yname + '.' + f
  334.         self.get1(fname)
  335.     return m
  336.  
  337.     def get1(self, name):
  338.     m = self.get(name)
  339.     if not m:
  340.         raise ImportError, "No module named %s" % name
  341.     return m
  342.  
  343.     def get0(self, name):
  344.     m = self.get(name)
  345.     if not m:
  346.         sys.modules[name] = None
  347.     return m
  348.  
  349.     def get(self, name):
  350.     # Internal routine to get or load a module when its parent exists
  351.     if sys.modules.has_key(name):
  352.         return sys.modules[name]
  353.     if '.' in name:
  354.         i = string.rfind(name, '.')
  355.         head, tail = name[:i], name[i+1:]
  356.     else:
  357.         head, tail = '', name
  358.     path = sys.modules[head].__path__
  359.     stuff = self.loader.find_module(tail, path)
  360.     if not stuff:
  361.         return None
  362.     sys.modules[name] = m = self.loader.load_module(name, stuff)
  363.     if head:
  364.         setattr(sys.modules[head], tail, m)
  365.     return m
  366.  
  367.     def reload(self, module):
  368.     name = module.__name__
  369.     if '.' in name:
  370.         i = string.rfind(name, '.')
  371.         head, tail = name[:i], name[i+1:]
  372.         path = sys.modules[head].__path__
  373.     else:
  374.         tail = name
  375.         path = sys.modules[''].__path__
  376.     stuff = self.loader.find_module(tail, path)
  377.     if not stuff:
  378.         raise ImportError, "No module named %s" % name
  379.     return self.loader.load_module(name, stuff)
  380.  
  381.     def unload(self, module):
  382.     if hasattr(module, '__path__'):
  383.         raise ImportError, "don't know how to unload packages yet"
  384.     PackageImporter.unload(self, module)
  385.  
  386.     def install(self):
  387.     if not sys.modules.has_key(''):
  388.         sys.modules[''] = package = imp.new_module('')
  389.         package.__path__ = None
  390.         self.loader.init_package(package)
  391.         for m in sys.modules.values():
  392.         if not m: continue
  393.         if not hasattr(m, '__'):
  394.             self.loader.set_parent(m)
  395.     ModuleImporter.install(self)
  396.  
  397.  
  398. def install(v = 0):
  399.     ihooks.install(PackageImporter(None, v))
  400.  
  401. def uninstall():
  402.     ihooks.uninstall()
  403.  
  404. def ni(v = 0):
  405.     install(v)
  406.  
  407. def no():
  408.     uninstall()
  409.  
  410. def test():
  411.     import pdb
  412.     try:
  413.     testproper()
  414.     except:
  415.     sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info()
  416.     print
  417.     print sys.last_type, ':', sys.last_value
  418.     print
  419.     pdb.pm()
  420.  
  421. def testproper():
  422.     install(1)
  423.     try:
  424.     import mactest
  425.     print dir(mactest)
  426.     raw_input('OK?')
  427.     finally:
  428.     uninstall()
  429.  
  430.  
  431. if __name__ == '__main__':
  432.     test()
  433. else:
  434.     install()
  435.