1 """Import hook support.
3 Consistent use of this module will make it possible to change the
4 different mechanisms involved in loading modules independently.
6 While the built-in module imp exports interfaces to the built-in
7 module searching and loading algorithm, and it is possible to replace
8 the built-in function __import__ in order to change the semantics of
9 the import statement, until now it has been difficult to combine the
10 effect of different __import__ hacks, like loading modules from URLs
11 by rimport.py, or restricted execution by rexec.py.
13 This module defines three new concepts:
15 1) A "file system hooks" class provides an interface to a filesystem.
17 One hooks class is defined (Hooks), which uses the interface provided
18 by standard modules os and os.path. It should be used as the base
19 class for other hooks classes.
21 2) A "module loader" class provides an interface to to search for a
22 module in a search path and to load it. It defines a method which
23 searches for a module in a single directory; by overriding this method
24 one can redefine the details of the search. If the directory is None,
25 built-in and frozen modules are searched instead.
27 Two module loader class are defined, both implementing the search
28 strategy used by the built-in __import__ function: ModuleLoader uses
29 the imp module's find_module interface, while HookableModuleLoader
30 uses a file system hooks class to interact with the file system. Both
31 use the imp module's load_* interfaces to actually load the module.
33 3) A "module importer" class provides an interface to import a
34 module, as well as interfaces to reload and unload a module. It also
35 provides interfaces to install and uninstall itself instead of the
36 default __import__ and reload (and unload) functions.
38 One module importer class is defined (ModuleImporter), which uses a
39 module loader instance passed in (by default HookableModuleLoader is
42 The classes defined here should be used as base classes for extended
43 functionality along those lines.
45 If a module importer class supports dotted names, its import_module()
46 must return a different value depending on whether it is called on
47 behalf of a "from ... import ..." statement or not. (This is caused
48 by the way the __import__ hook is used by the Python interpreter.) It
49 would also do wise to install a different version of reload().
59 __all__ = [
"BasicModuleLoader",
"Hooks",
"ModuleLoader",
"FancyModuleLoader",
60 "BasicModuleImporter",
"ModuleImporter",
"install",
"uninstall"]
65 from imp
import C_EXTENSION, PY_SOURCE, PY_COMPILED
66 from imp
import C_BUILTIN, PY_FROZEN, PKG_DIRECTORY
67 BUILTIN_MODULE = C_BUILTIN
68 FROZEN_MODULE = PY_FROZEN
97 """Basic module loader.
99 This provides the same functionality as built-in import. It
100 doesn't deal with checking sys.modules -- all it provides is
101 find_module() and a load_module(), as well as find_module_in_dir()
102 which searches just one directory, and can be overridden by a
103 derived class to change the module search algorithm when the basic
104 dependency on sys.path is unchanged.
106 The interface is a little more convenient than imp's:
107 find_module(name, [path]) returns None or 'stuff', and
108 load_module(name, stuff) loads the module.
117 if stuff:
return stuff
128 return imp.find_module(name, [dir])
134 if imp.is_builtin(name):
135 return None,
'', (
'',
'', BUILTIN_MODULE)
136 if imp.is_frozen(name):
137 return None,
'', (
'',
'', FROZEN_MODULE)
141 file, filename, info = stuff
143 return imp.load_module(name, file, filename, info)
145 if file: file.close()
150 """Hooks into the filesystem and interpreter.
152 By deriving a subclass you can redefine your filesystem interface,
153 e.g. to merge it with the URL space.
155 This base class behaves just like the native filesystem.
168 return imp.load_source(name, filename, file)
170 return imp.load_compiled(name, filename, file)
172 return imp.load_dynamic(name, filename, file)
174 return imp.load_module(name, file, filename, (
"",
"", PKG_DIRECTORY))
178 if d.has_key(name):
return d[name]
198 openfile_error = IOError
200 listdir_error = os.error
206 """Default module loader; uses file system hooks.
208 By defining suitable hooks, you might be able to load modules from
209 other sources than the file system, e.g. from compressed or
210 encrypted files, tar files or (if you're brave!) URLs.
214 def __init__(self, hooks = None, verbose = VERBOSE):
215 BasicModuleLoader.__init__(self, verbose)
219 return self.hooks.default_path()
222 return self.hooks.modules_dict()
232 if self.hooks.is_builtin(name):
233 return None,
'', (
'',
'', BUILTIN_MODULE)
234 if self.hooks.is_frozen(name):
235 return None,
'', (
'',
'', FROZEN_MODULE)
242 fullname = self.hooks.path_join(dir, name)
243 if self.hooks.path_isdir(fullname):
247 if file: file.close()
248 return None, fullname, (
'',
'', PKG_DIRECTORY)
249 for info
in self.hooks.get_suffixes():
250 suff, mode, type = info
251 fullname = self.hooks.path_join(dir, name+suff)
253 fp = self.hooks.openfile(fullname, mode)
254 return fp, fullname, info
255 except self.hooks.openfile_error:
260 file, filename, info = stuff
261 (suff, mode, type) = info
263 if type == BUILTIN_MODULE:
264 return self.hooks.init_builtin(name)
265 if type == FROZEN_MODULE:
266 return self.hooks.init_frozen(name)
267 if type == C_EXTENSION:
268 m = self.hooks.load_dynamic(name, filename, file)
269 elif type == PY_SOURCE:
270 m = self.hooks.load_source(name, filename, file)
271 elif type == PY_COMPILED:
272 m = self.hooks.load_compiled(name, filename, file)
273 elif type == PKG_DIRECTORY:
274 m = self.hooks.load_package(name, filename, file)
276 raise ImportError,
"Unrecognized module type (%s) for %s" % \
279 if file: file.close()
280 m.__file__ = filename
286 """Fancy module loader -- parses and execs the code itself."""
289 file, filename, (suff, mode, type) = stuff
290 realfilename = filename
293 if type == PKG_DIRECTORY:
296 raise ImportError,
"No __init__ module in package %s" % name
297 initfile, initfilename, initinfo = initstuff
298 initsuff, initmode, inittype = initinfo
299 if inittype
not in (PY_COMPILED, PY_SOURCE):
300 if initfile: initfile.close()
302 "Bad type (%s) for __init__ module in package %s" % (
306 realfilename = initfilename
309 if type == FROZEN_MODULE:
310 code = self.hooks.get_frozen_object(name)
311 elif type == PY_COMPILED:
314 code = marshal.load(file)
315 elif type == PY_SOURCE:
317 code =
compile(data, realfilename,
'exec')
319 return ModuleLoader.load_module(self, name, stuff)
321 m = self.hooks.add_module(name)
324 m.__file__ = filename
325 exec code
in m.__dict__
331 """Basic module importer; uses module loader.
333 This provides basic import facilities but no package imports.
337 def __init__(self, loader = None, verbose = VERBOSE):
338 _Verbose.__init__(self, verbose)
349 return self.loader.get_hooks()
352 return self.loader.set_hooks(hooks)
355 if self.modules.has_key(name):
357 stuff = self.loader.find_module(name)
359 raise ImportError,
"No module named %s" % name
360 return self.loader.load_module(name, stuff)
363 name = module.__name__
364 stuff = self.loader.find_module(name, path)
366 raise ImportError,
"Module %s not found for reload" % name
367 return self.loader.load_module(name, stuff)
370 del self.
modules[module.__name__]
376 if not hasattr(__builtin__,
'unload'):
377 __builtin__.unload =
None
380 __builtin__.reload = self.
reload
381 __builtin__.unload = self.
unload
387 if not __builtin__.unload:
388 del __builtin__.unload
393 """A module importer that supports packages."""
401 if hasattr(m,
"__path__"):
406 if not globals
or not globals.has_key(
"__name__"):
408 pname = globals[
'__name__']
409 if globals.has_key(
"__path__"):
411 assert globals
is parent.__dict__
417 assert parent.__name__ == pname
430 qname =
"%s.%s" % (parent.__name__, head)
440 raise ImportError,
"No module named " + qname
446 if i < 0: i = len(tail)
447 head, tail = tail[:i], tail[i+1:]
448 mname =
"%s.%s" % (m.__name__, head)
451 raise ImportError,
"No module named " + mname
460 except AttributeError:
465 if sub !=
"*" and not hasattr(m, sub):
466 subname =
"%s.%s" % (m.__name__, sub)
469 raise ImportError,
"No module named " + subname
471 def import_it(self, partname, fqname, parent, force_load=0):
473 raise ValueError,
"Empty module name"
480 path = parent
and parent.__path__
481 except AttributeError:
483 stuff = self.loader.find_module(partname, path)
486 m = self.loader.load_module(fqname, stuff)
488 setattr(parent, partname, m)
492 name = module.__name__
494 return self.
import_it(name, name,
None, force_load=1)
498 return self.
import_it(name[i+1:], name, parent, force_load=1)
501 default_importer =
None
502 current_importer =
None
505 global current_importer
506 current_importer = importer
or default_importer
or ModuleImporter()
507 current_importer.install()
510 global current_importer
511 current_importer.uninstall()