blob: 36759789e5ea8a18da357bbaf2040b86499c8597 [file] [log] [blame]
Guido van Rossume7e578f1995-08-04 04:00:20 +00001"""Import hook support.
2
3Consistent use of this module will make it possible to change the
4different mechanisms involved in loading modules independently.
5
6While the built-in module imp exports interfaces to the built-in
7module searching and loading algorithm, and it is possible to replace
8the built-in function __import__ in order to change the semantics of
9the import statement, until now it has been difficult to combine the
10effect of different __import__ hacks, like loading modules from URLs
11(rimport.py), implementing a hierarchical module namespace (newimp.py)
12or restricted execution (rexec.py).
13
14This module defines three new concepts:
15
16(1) A "file system hooks" class provides an interface to a filesystem.
17
18One hooks class is defined (Hooks), which uses the interface provided
19by standard modules os and os.path. It should be used as the base
20class for other hooks classes.
21
22(2) A "module loader" class provides an interface to to search for a
23module in a search path and to load it. It defines a method which
24searches for a module in a single directory; by overriding this method
25one can redefine the details of the search. If the directory is None,
26built-in and frozen modules are searched instead.
27
28Two module loader class are defined, both implementing the search
29strategy used by the built-in __import__ function: ModuleLoader uses
30the imp module's find_module interface, while HookableModuleLoader
31uses a file system hooks class to interact with the file system. Both
32use the imp module's load_* interfaces to actually load the module.
33
34(3) A "module importer" class provides an interface to import a
35module, as well as interfaces to reload and unload a module. It also
36provides interfaces to install and uninstall itself instead of the
37default __import__ and reload (and unload) functions.
38
39One module importer class is defined (ModuleImporter), which uses a
40module loader instance passed in (by default HookableModuleLoader is
41instantiated).
42
43The classes defined here should be used as base classes for extended
44functionality along those lines.
45
46If a module mporter class supports dotted names, its import_module()
47must return a different value depending on whether it is called on
48behalf of a "from ... import ..." statement or not. (This is caused
49by the way the __import__ hook is used by the Python interpreter.) It
50would also do wise to install a different version of reload().
51
52XXX Should the imp.load_* functions also be called via the hooks
53instance?
54
55"""
56
57
58import __builtin__
59import imp
60import os
61import sys
62
63
64from imp import C_EXTENSION, PY_SOURCE, PY_COMPILED
65BUILTIN_MODULE = 32
66FROZEN_MODULE = 33
67
68
69class _Verbose:
70
71 def __init__(self, verbose = 0):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000072 self.verbose = verbose
Guido van Rossume7e578f1995-08-04 04:00:20 +000073
74 def get_verbose(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000075 return self.verbose
Guido van Rossume7e578f1995-08-04 04:00:20 +000076
77 def set_verbose(self, verbose):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000078 self.verbose = verbose
Guido van Rossume7e578f1995-08-04 04:00:20 +000079
80 # XXX The following is an experimental interface
81
82 def note(self, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000083 if self.verbose:
84 apply(self.message, args)
Guido van Rossume7e578f1995-08-04 04:00:20 +000085
86 def message(self, format, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000087 print format%args
Guido van Rossume7e578f1995-08-04 04:00:20 +000088
89
90class BasicModuleLoader(_Verbose):
91
92 """Basic module loader.
93
94 This provides the same functionality as built-in import. It
95 doesn't deal with checking sys.modules -- all it provides is
96 find_module() and a load_module(), as well as find_module_in_dir()
97 which searches just one directory, and can be overridden by a
98 derived class to change the module search algorithm when the basic
99 dependency on sys.path is unchanged.
100
101 The interface is a little more convenient than imp's:
102 find_module(name, [path]) returns None or 'stuff', and
103 load_module(name, stuff) loads the module.
104
105 """
106
107 def find_module(self, name, path = None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000108 if path is None:
109 path = [None] + self.default_path()
110 for dir in path:
111 stuff = self.find_module_in_dir(name, dir)
112 if stuff: return stuff
113 return None
Guido van Rossume7e578f1995-08-04 04:00:20 +0000114
115 def default_path(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000116 return sys.path
Guido van Rossume7e578f1995-08-04 04:00:20 +0000117
118 def find_module_in_dir(self, name, dir):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000119 if dir is None:
120 return self.find_builtin_module(name)
121 else:
122 try:
123 return imp.find_module(name, [dir])
124 except ImportError:
125 return None
Guido van Rossume7e578f1995-08-04 04:00:20 +0000126
127 def find_builtin_module(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000128 if imp.is_builtin(name):
129 return None, '', ('', '', BUILTIN_MODULE)
130 if imp.is_frozen(name):
131 return None, '', ('', '', FROZEN_MODULE)
132 return None
Guido van Rossume7e578f1995-08-04 04:00:20 +0000133
134 def load_module(self, name, stuff):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000135 file, filename, (suff, mode, type) = stuff
136 try:
137 if type == BUILTIN_MODULE:
138 return imp.init_builtin(name)
139 if type == FROZEN_MODULE:
140 return imp.init_frozen(name)
141 if type == C_EXTENSION:
142 return imp.load_dynamic(name, filename, file)
143 if type == PY_SOURCE:
144 return imp.load_source(name, filename, file)
145 if type == PY_COMPILED:
146 return imp.load_compiled(name, filename, file)
147 finally:
148 if file: file.close()
149 raise ImportError, "Unrecognized module type (%s) for %s" % \
150 (`type`, name)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000151
152
153class Hooks(_Verbose):
154
155 """Hooks into the filesystem and interpreter.
156
157 By deriving a subclass you can redefine your filesystem interface,
158 e.g. to merge it with the URL space.
159
160 This base class behaves just like the native filesystem.
161
162 """
163
164 # imp interface
165 def get_suffixes(self): return imp.get_suffixes()
166 def new_module(self, name): return imp.new_module(name)
167 def is_builtin(self, name): return imp.is_builtin(name)
168 def init_builtin(self, name): return imp.init_builtin(name)
169 def is_frozen(self, name): return imp.is_frozen(name)
170 def init_frozen(self, name): return imp.init_frozen(name)
171 def get_frozen_object(self, name): return imp.get_frozen_object(name)
172 def load_source(self, name, filename, file=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000173 return imp.load_source(name, filename, file)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000174 def load_compiled(self, name, filename, file=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000175 return imp.load_compiled(name, filename, file)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000176 def load_dynamic(self, name, filename, file=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000177 return imp.load_dynamic(name, filename, file)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000178
179 def add_module(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000180 d = self.modules_dict()
181 if d.has_key(name): return d[name]
182 d[name] = m = self.new_module(name)
183 return m
Guido van Rossume7e578f1995-08-04 04:00:20 +0000184
185 # sys interface
186 def modules_dict(self): return sys.modules
187 def default_path(self): return sys.path
188
189 def path_split(self, x): return os.path.split(x)
190 def path_join(self, x, y): return os.path.join(x, y)
191 def path_isabs(self, x): return os.path.isabs(x)
192 # etc.
193
194 def path_exists(self, x): return os.path.exists(x)
195 def path_isdir(self, x): return os.path.isdir(x)
196 def path_isfile(self, x): return os.path.isfile(x)
197 def path_islink(self, x): return os.path.islink(x)
198 # etc.
199
200 def openfile(self, *x): return apply(open, x)
201 openfile_error = IOError
202 def listdir(self, x): return os.listdir(x)
203 listdir_error = os.error
204 # etc.
205
206
207class ModuleLoader(BasicModuleLoader):
208
209 """Default module loader; uses file system hooks.
210
211 By defining suitable hooks, you might be able to load modules from
212 other sources than the file system, e.g. from compressed or
213 encrypted files, tar files or (if you're brave!) URLs.
214
215 """
216
217 def __init__(self, hooks = None, verbose = 0):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000218 BasicModuleLoader.__init__(self, verbose)
219 self.hooks = hooks or Hooks(verbose)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000220
221 def default_path(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000222 return self.hooks.default_path()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000223
224 def modules_dict(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000225 return self.hooks.modules_dict()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000226
227 def get_hooks(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000228 return self.hooks
Guido van Rossume7e578f1995-08-04 04:00:20 +0000229
230 def set_hooks(self, hooks):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000231 self.hooks = hooks
Guido van Rossume7e578f1995-08-04 04:00:20 +0000232
233 def find_builtin_module(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 if self.hooks.is_builtin(name):
235 return None, '', ('', '', BUILTIN_MODULE)
236 if self.hooks.is_frozen(name):
237 return None, '', ('', '', FROZEN_MODULE)
238 return None
Guido van Rossume7e578f1995-08-04 04:00:20 +0000239
240 def find_module_in_dir(self, name, dir):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000241 if dir is None:
242 return self.find_builtin_module(name)
243 for info in self.hooks.get_suffixes():
244 suff, mode, type = info
245 fullname = self.hooks.path_join(dir, name+suff)
246 try:
247 fp = self.hooks.openfile(fullname, mode)
248 return fp, fullname, info
249 except self.hooks.openfile_error:
250 pass
251 return None
Guido van Rossume7e578f1995-08-04 04:00:20 +0000252
253 def load_module(self, name, stuff):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000254 file, filename, (suff, mode, type) = stuff
255 try:
256 if type == BUILTIN_MODULE:
257 return self.hooks.init_builtin(name)
258 if type == FROZEN_MODULE:
259 return self.hooks.init_frozen(name)
260 if type == C_EXTENSION:
261 m = self.hooks.load_dynamic(name, filename, file)
262 elif type == PY_SOURCE:
263 m = self.hooks.load_source(name, filename, file)
264 elif type == PY_COMPILED:
265 m = self.hooks.load_compiled(name, filename, file)
266 else:
267 raise ImportError, "Unrecognized module type (%s) for %s" % \
268 (`type`, name)
269 finally:
270 if file: file.close()
271 m.__file__ = filename
272 return m
Guido van Rossume7e578f1995-08-04 04:00:20 +0000273
274
275class FancyModuleLoader(ModuleLoader):
276
277 """Fancy module loader -- parses and execs the code itself."""
278
279 def load_module(self, name, stuff):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000280 file, filename, (suff, mode, type) = stuff
281 if type == FROZEN_MODULE:
282 code = self.hooks.get_frozen_object(name)
283 elif type == PY_COMPILED:
284 import marshal
285 file.seek(8)
286 code = marshal.load(file)
287 elif type == PY_SOURCE:
288 data = file.read()
289 code = compile(data, filename, 'exec')
290 else:
291 return ModuleLoader.load_module(self, name, stuff)
292 m = self.hooks.add_module(name)
293 m.__file__ = filename
294 exec code in m.__dict__
295 return m
Guido van Rossume7e578f1995-08-04 04:00:20 +0000296
297
298class ModuleImporter(_Verbose):
299
300 """Default module importer; uses module loader.
301
302 This provides the same functionality as built-in import, when
303 combined with ModuleLoader.
304
305 """
306
307 def __init__(self, loader = None, verbose = 0):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000308 _Verbose.__init__(self, verbose)
309 self.loader = loader or ModuleLoader(None, verbose)
310 self.modules = self.loader.modules_dict()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000311
312 def get_loader(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000313 return self.loader
Guido van Rossume7e578f1995-08-04 04:00:20 +0000314
315 def set_loader(self, loader):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000316 self.loader = loader
Guido van Rossume7e578f1995-08-04 04:00:20 +0000317
318 def get_hooks(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000319 return self.loader.get_hooks()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000320
321 def set_hooks(self, hooks):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000322 return self.loader.set_hooks(hooks)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000323
324 def import_module(self, name, globals={}, locals={}, fromlist=[]):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000325 if self.modules.has_key(name):
326 return self.modules[name] # Fast path
327 stuff = self.loader.find_module(name)
328 if not stuff:
329 raise ImportError, "No module named %s" % name
330 return self.loader.load_module(name, stuff)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000331
332 def reload(self, module, path = None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000333 name = module.__name__
334 stuff = self.loader.find_module(name, path)
335 if not stuff:
336 raise ImportError, "Module %s not found for reload" % name
337 return self.loader.load_module(name, stuff)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000338
339 def unload(self, module):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000340 del self.modules[module.__name__]
341 # XXX Should this try to clear the module's namespace?
Guido van Rossume7e578f1995-08-04 04:00:20 +0000342
343 def install(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000344 self.save_import_module = __builtin__.__import__
345 self.save_reload = __builtin__.reload
346 if not hasattr(__builtin__, 'unload'):
347 __builtin__.unload = None
348 self.save_unload = __builtin__.unload
349 __builtin__.__import__ = self.import_module
350 __builtin__.reload = self.reload
351 __builtin__.unload = self.unload
Guido van Rossume7e578f1995-08-04 04:00:20 +0000352
353 def uninstall(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000354 __builtin__.__import__ = self.save_import_module
355 __builtin__.reload = self.save_reload
356 __builtin__.unload = self.save_unload
357 if not __builtin__.unload:
358 del __builtin__.unload
Guido van Rossume7e578f1995-08-04 04:00:20 +0000359
360
Guido van Rossume7e578f1995-08-04 04:00:20 +0000361default_importer = None
362current_importer = None
363
364def install(importer = None):
365 global current_importer
366 current_importer = importer or default_importer or ModuleImporter()
367 current_importer.install()
368
369def uninstall():
370 global current_importer
371 current_importer.uninstall()