blob: 34c074d7fafd4b636360be2f1c0ef3407050c6dd [file] [log] [blame]
Greg Stein281b8d81999-11-07 12:54:45 +00001#
2# imputil.py
3#
4# Written by Greg Stein. Public Domain.
5# No Copyright, no Rights Reserved, and no Warranties.
6#
7# Utilities to help out with custom import mechanisms.
8#
9# Additional modifications were contribed by Marc-Andre Lemburg and
10# Gordon McMillan.
11#
Greg Steind4c64ba1999-11-07 13:14:58 +000012# This module is maintained by Greg and is available at:
Greg Steind4f1d202000-02-18 12:03:40 +000013# http://www.lyra.org/greg/python/
Greg Steind4c64ba1999-11-07 13:14:58 +000014#
15# Since this isn't in the Python distribution yet, we'll use the CVS ID
16# for tracking:
17# $Id$
18#
Greg Stein281b8d81999-11-07 12:54:45 +000019
Greg Stein281b8d81999-11-07 12:54:45 +000020# note: avoid importing non-builtin modules
Greg Stein3bb578c2000-02-18 13:04:10 +000021import imp ### not available in JPython?
Greg Stein281b8d81999-11-07 12:54:45 +000022import sys
23import strop
Greg Stein7ec28d21999-11-20 12:31:07 +000024import __builtin__
Greg Stein281b8d81999-11-07 12:54:45 +000025
26# for the DirectoryImporter
27import struct
28import marshal
29
Greg Steinf23aa1e2000-01-03 02:38:29 +000030_StringType = type('')
Greg Steind4f1d202000-02-18 12:03:40 +000031_ModuleType = type(sys) ### doesn't work in JPython...
Greg Steinf23aa1e2000-01-03 02:38:29 +000032
33class ImportManager:
34 "Manage the import process."
Greg Stein281b8d81999-11-07 12:54:45 +000035
Greg Steind4f1d202000-02-18 12:03:40 +000036 def install(self, namespace=vars(__builtin__)):
37 "Install this ImportManager into the specified namespace."
38
39 if isinstance(namespace, _ModuleType):
40 namespace = vars(namespace)
41
42 ### Note that we have no notion of "uninstall" or "chaining"
Greg Stein3bb578c2000-02-18 13:04:10 +000043
Greg Steind4f1d202000-02-18 12:03:40 +000044 namespace['__import__'] = self._import_hook
Greg Steinf23aa1e2000-01-03 02:38:29 +000045 ### fix this
Greg Steind4f1d202000-02-18 12:03:40 +000046 #namespace['reload'] = self._reload_hook
Greg Steinf23aa1e2000-01-03 02:38:29 +000047
Greg Stein3bb578c2000-02-18 13:04:10 +000048 def add_suffix(self, suffix, importFunc):
49 assert callable(importFunc)
50 self.fs_imp.add_suffix(suffix, importFunc)
Greg Stein281b8d81999-11-07 12:54:45 +000051
52 ######################################################################
53 #
54 # PRIVATE METHODS
55 #
Greg Stein3bb578c2000-02-18 13:04:10 +000056
57 clsFilesystemImporter = None
58
59 def __init__(self, fs_imp=None):
Greg Steinf23aa1e2000-01-03 02:38:29 +000060 # we're definitely going to be importing something in the future,
61 # so let's just load the OS-related facilities.
62 if not _os_stat:
63 _os_bootstrap()
Greg Stein281b8d81999-11-07 12:54:45 +000064
Greg Stein3bb578c2000-02-18 13:04:10 +000065 # This is the Importer that we use for grabbing stuff from the
66 # filesystem. It defines one more method (import_from_dir) for our use.
67 if not fs_imp:
68 cls = self.clsFilesystemImporter or _FilesystemImporter
69 fs_imp = cls()
70 self.fs_imp = fs_imp
71
Greg Steinf23aa1e2000-01-03 02:38:29 +000072 # Initialize the set of suffixes that we recognize and import.
73 # The default will import dynamic-load modules first, followed by
74 # .py files (or a .py file's cached bytecode)
Greg Steinf23aa1e2000-01-03 02:38:29 +000075 for desc in imp.get_suffixes():
76 if desc[2] == imp.C_EXTENSION:
Greg Stein3bb578c2000-02-18 13:04:10 +000077 self.add_suffix(desc[0], DynLoadSuffixImporter(desc).import_file)
78 self.add_suffix('.py', py_suffix_importer)
Greg Stein281b8d81999-11-07 12:54:45 +000079
Greg Steinf23aa1e2000-01-03 02:38:29 +000080 def _import_hook(self, fqname, globals=None, locals=None, fromlist=None):
81 """Python calls this hook to locate and import a module."""
82
83 parts = strop.split(fqname, '.')
Greg Stein63faa011999-11-20 11:22:37 +000084
Greg Stein281b8d81999-11-07 12:54:45 +000085 # determine the context of this import
86 parent = self._determine_import_context(globals)
87
Greg Steinf23aa1e2000-01-03 02:38:29 +000088 # if there is a parent, then its importer should manage this import
89 if parent:
90 module = parent.__importer__._do_import(parent, parts, fromlist)
91 if module:
92 return module
Greg Stein281b8d81999-11-07 12:54:45 +000093
Greg Steinf23aa1e2000-01-03 02:38:29 +000094 # has the top module already been imported?
95 try:
96 top_module = sys.modules[parts[0]]
97 except KeyError:
Greg Stein281b8d81999-11-07 12:54:45 +000098
Greg Steinf23aa1e2000-01-03 02:38:29 +000099 # look for the topmost module
100 top_module = self._import_top_module(parts[0])
101 if not top_module:
102 # the topmost module wasn't found at all.
103 raise ImportError, 'No module named ' + fqname
Greg Steinf23aa1e2000-01-03 02:38:29 +0000104
105 # fast-path simple imports
106 if len(parts) == 1:
107 if not fromlist:
108 return top_module
109
110 if not top_module.__dict__.get('__ispkg__'):
111 # __ispkg__ isn't defined (the module was not imported by us), or
112 # it is zero.
113 #
114 # In the former case, there is no way that we could import
115 # sub-modules that occur in the fromlist (but we can't raise an
116 # error because it may just be names) because we don't know how
117 # to deal with packages that were imported by other systems.
118 #
119 # In the latter case (__ispkg__ == 0), there can't be any sub-
120 # modules present, so we can just return.
121 #
122 # In both cases, since len(parts) == 1, the top_module is also
123 # the "bottom" which is the defined return when a fromlist exists.
124 return top_module
125
126 importer = top_module.__dict__.get('__importer__')
127 if importer:
128 return importer._finish_import(top_module, parts[1:], fromlist)
129
130 # If the importer does not exist, then we have to bail. A missing importer
131 # means that something else imported the module, and we have no knowledge
132 # of how to get sub-modules out of the thing.
133 raise ImportError, 'No module named ' + fqname
Greg Steinf23aa1e2000-01-03 02:38:29 +0000134
135 def _determine_import_context(self, globals):
136 """Returns the context in which a module should be imported.
137
138 The context could be a loaded (package) module and the imported module
139 will be looked for within that package. The context could also be None,
140 meaning there is no context -- the module should be looked for as a
141 "top-level" module.
142 """
143
144 if not globals or not globals.get('__importer__'):
145 # globals does not refer to one of our modules or packages. That
146 # implies there is no relative import context (as far as we are
147 # concerned), and it should just pick it off the standard path.
148 return None
149
150 # The globals refer to a module or package of ours. It will define
151 # the context of the new import. Get the module/package fqname.
152 parent_fqname = globals['__name__']
153
154 # if a package is performing the import, then return itself (imports
155 # refer to pkg contents)
156 if globals['__ispkg__']:
157 parent = sys.modules[parent_fqname]
158 assert globals is parent.__dict__
159 return parent
160
161 i = strop.rfind(parent_fqname, '.')
162
163 # a module outside of a package has no particular import context
164 if i == -1:
165 return None
166
167 # if a module in a package is performing the import, then return the
168 # package (imports refer to siblings)
169 parent_fqname = parent_fqname[:i]
170 parent = sys.modules[parent_fqname]
171 assert parent.__name__ == parent_fqname
172 return parent
173
174 def _import_top_module(self, name):
175 # scan sys.path looking for a location in the filesystem that contains
176 # the module, or an Importer object that can import the module.
177 for item in sys.path:
Greg Steind4f1d202000-02-18 12:03:40 +0000178 if isinstance(item, _StringType):
Greg Steinf23aa1e2000-01-03 02:38:29 +0000179 module = self.fs_imp.import_from_dir(item, name)
180 else:
181 module = item.import_top(name)
182 if module:
183 return module
184 return None
185
186 def _reload_hook(self, module):
187 "Python calls this hook to reload a module."
188
189 # reloading of a module may or may not be possible (depending on the
190 # importer), but at least we can validate that it's ours to reload
191 importer = module.__dict__.get('__importer__')
192 if not importer:
Greg Steind4f1d202000-02-18 12:03:40 +0000193 ### oops. now what...
194 pass
Greg Steinf23aa1e2000-01-03 02:38:29 +0000195
196 # okay. it is using the imputil system, and we must delegate it, but
197 # we don't know what to do (yet)
198 ### we should blast the module dict and do another get_code(). need to
199 ### flesh this out and add proper docco...
200 raise SystemError, "reload not yet implemented"
201
202
203class Importer:
204 "Base class for replacing standard import functions."
205
Greg Steinf23aa1e2000-01-03 02:38:29 +0000206 def import_top(self, name):
207 "Import a top-level module."
208 return self._import_one(None, name, name)
209
210 ######################################################################
211 #
212 # PRIVATE METHODS
213 #
214 def _finish_import(self, top, parts, fromlist):
Greg Stein281b8d81999-11-07 12:54:45 +0000215 # if "a.b.c" was provided, then load the ".b.c" portion down from
216 # below the top-level module.
Greg Steinf23aa1e2000-01-03 02:38:29 +0000217 bottom = self._load_tail(top, parts)
Greg Stein281b8d81999-11-07 12:54:45 +0000218
219 # if the form is "import a.b.c", then return "a"
220 if not fromlist:
221 # no fromlist: return the top of the import tree
222 return top
223
Greg Steinf23aa1e2000-01-03 02:38:29 +0000224 # the top module was imported by self.
Greg Stein281b8d81999-11-07 12:54:45 +0000225 #
Greg Steinf23aa1e2000-01-03 02:38:29 +0000226 # this means that the bottom module was also imported by self (just
227 # now, or in the past and we fetched it from sys.modules).
Greg Stein281b8d81999-11-07 12:54:45 +0000228 #
229 # since we imported/handled the bottom module, this means that we can
Greg Steinf23aa1e2000-01-03 02:38:29 +0000230 # also handle its fromlist (and reliably use __ispkg__).
Greg Stein281b8d81999-11-07 12:54:45 +0000231
232 # if the bottom node is a package, then (potentially) import some modules.
233 #
234 # note: if it is not a package, then "fromlist" refers to names in
235 # the bottom module rather than modules.
236 # note: for a mix of names and modules in the fromlist, we will
237 # import all modules and insert those into the namespace of
238 # the package module. Python will pick up all fromlist names
239 # from the bottom (package) module; some will be modules that
240 # we imported and stored in the namespace, others are expected
241 # to be present already.
Greg Steinf23aa1e2000-01-03 02:38:29 +0000242 if bottom.__ispkg__:
Greg Stein281b8d81999-11-07 12:54:45 +0000243 self._import_fromlist(bottom, fromlist)
244
245 # if the form is "from a.b import c, d" then return "b"
246 return bottom
247
Greg Stein281b8d81999-11-07 12:54:45 +0000248 def _import_one(self, parent, modname, fqname):
249 "Import a single module."
250
251 # has the module already been imported?
252 try:
253 return sys.modules[fqname]
254 except KeyError:
255 pass
256
257 # load the module's code, or fetch the module itself
258 result = self.get_code(parent, modname, fqname)
259 if result is None:
260 return None
261
Greg Steinf23aa1e2000-01-03 02:38:29 +0000262 module = self._process_result(result, fqname)
Greg Stein281b8d81999-11-07 12:54:45 +0000263
264 # insert the module into its parent
265 if parent:
266 setattr(parent, modname, module)
267 return module
268
Greg Steinf23aa1e2000-01-03 02:38:29 +0000269 def _process_result(self, (ispkg, code, values), fqname):
270 # did get_code() return an actual module? (rather than a code object)
Greg Steind4f1d202000-02-18 12:03:40 +0000271 is_module = isinstance(code, _ModuleType)
Greg Steinf23aa1e2000-01-03 02:38:29 +0000272
273 # use the returned module, or create a new one to exec code into
274 if is_module:
275 module = code
276 else:
277 module = imp.new_module(fqname)
278
279 ### record packages a bit differently??
280 module.__importer__ = self
281 module.__ispkg__ = ispkg
282
283 # insert additional values into the module (before executing the code)
284 module.__dict__.update(values)
285
286 # the module is almost ready... make it visible
287 sys.modules[fqname] = module
288
289 # execute the code within the module's namespace
290 if not is_module:
291 exec code in module.__dict__
292
293 return module
294
295 def _load_tail(self, m, parts):
Greg Stein281b8d81999-11-07 12:54:45 +0000296 """Import the rest of the modules, down from the top-level module.
297
298 Returns the last module in the dotted list of modules.
299 """
Greg Steinf23aa1e2000-01-03 02:38:29 +0000300 for part in parts:
301 fqname = "%s.%s" % (m.__name__, part)
302 m = self._import_one(m, part, fqname)
303 if not m:
304 raise ImportError, "No module named " + fqname
Greg Stein281b8d81999-11-07 12:54:45 +0000305 return m
306
307 def _import_fromlist(self, package, fromlist):
308 'Import any sub-modules in the "from" list.'
309
310 # if '*' is present in the fromlist, then look for the '__all__' variable
311 # to find additional items (modules) to import.
312 if '*' in fromlist:
313 fromlist = list(fromlist) + list(package.__dict__.get('__all__', []))
314
315 for sub in fromlist:
316 # if the name is already present, then don't try to import it (it
317 # might not be a module!).
318 if sub != '*' and not hasattr(package, sub):
319 subname = "%s.%s" % (package.__name__, sub)
320 submod = self._import_one(package, sub, subname)
321 if not submod:
322 raise ImportError, "cannot import name " + subname
323
Greg Steinf23aa1e2000-01-03 02:38:29 +0000324 def _do_import(self, parent, parts, fromlist):
325 """Attempt to import the module relative to parent.
Greg Stein281b8d81999-11-07 12:54:45 +0000326
Greg Steinf23aa1e2000-01-03 02:38:29 +0000327 This method is used when the import context specifies that <self>
328 imported the parent module.
Greg Stein281b8d81999-11-07 12:54:45 +0000329 """
Greg Steinf23aa1e2000-01-03 02:38:29 +0000330 top_name = parts[0]
331 top_fqname = parent.__name__ + '.' + top_name
332 top_module = self._import_one(parent, top_name, top_fqname)
333 if not top_module:
334 # this importer and parent could not find the module (relatively)
335 return None
336
337 return self._finish_import(top_module, parts[1:], fromlist)
Greg Stein281b8d81999-11-07 12:54:45 +0000338
339 ######################################################################
340 #
341 # METHODS TO OVERRIDE
342 #
343 def get_code(self, parent, modname, fqname):
344 """Find and retrieve the code for the given module.
345
346 parent specifies a parent module to define a context for importing. It
347 may be None, indicating no particular context for the search.
348
349 modname specifies a single module (not dotted) within the parent.
350
351 fqname specifies the fully-qualified module name. This is a (potentially)
352 dotted name from the "root" of the module namespace down to the modname.
353 If there is no parent, then modname==fqname.
354
Greg Steinf23aa1e2000-01-03 02:38:29 +0000355 This method should return None, or a 3-tuple.
Greg Stein281b8d81999-11-07 12:54:45 +0000356
357 * If the module was not found, then None should be returned.
358
359 * The first item of the 2- or 3-tuple should be the integer 0 or 1,
360 specifying whether the module that was found is a package or not.
361
362 * The second item is the code object for the module (it will be
363 executed within the new module's namespace). This item can also
364 be a fully-loaded module object (e.g. loaded from a shared lib).
365
Greg Steinf23aa1e2000-01-03 02:38:29 +0000366 * The third item is a dictionary of name/value pairs that will be
367 inserted into new module before the code object is executed. This
368 is provided in case the module's code expects certain values (such
Greg Stein281b8d81999-11-07 12:54:45 +0000369 as where the module was found). When the second item is a module
370 object, then these names/values will be inserted *after* the module
371 has been loaded/initialized.
372 """
373 raise RuntimeError, "get_code not implemented"
374
375
376######################################################################
377#
Greg Stein63faa011999-11-20 11:22:37 +0000378# Some handy stuff for the Importers
379#
380
Greg Steind4f1d202000-02-18 12:03:40 +0000381# byte-compiled file suffix character
Greg Stein63faa011999-11-20 11:22:37 +0000382_suffix_char = __debug__ and 'c' or 'o'
383
384# byte-compiled file suffix
385_suffix = '.py' + _suffix_char
386
Greg Stein63faa011999-11-20 11:22:37 +0000387def _compile(pathname, timestamp):
388 """Compile (and cache) a Python source file.
389
390 The file specified by <pathname> is compiled to a code object and
391 returned.
392
393 Presuming the appropriate privileges exist, the bytecodes will be
394 saved back to the filesystem for future imports. The source file's
395 modification timestamp must be provided as a Long value.
396 """
397 codestring = open(pathname, 'r').read()
398 if codestring and codestring[-1] != '\n':
399 codestring = codestring + '\n'
400 code = __builtin__.compile(codestring, pathname, 'exec')
401
402 # try to cache the compiled code
403 try:
404 f = open(pathname + _suffix_char, 'wb')
405 except IOError:
406 pass
407 else:
408 f.write('\0\0\0\0')
409 f.write(struct.pack('<I', timestamp))
410 marshal.dump(code, f)
411 f.flush()
412 f.seek(0, 0)
413 f.write(imp.get_magic())
414 f.close()
415
416 return code
417
418_os_stat = _os_path_join = None
419def _os_bootstrap():
420 "Set up 'os' module replacement functions for use during import bootstrap."
421
422 names = sys.builtin_module_names
423
424 join = None
425 if 'posix' in names:
426 sep = '/'
427 from posix import stat
428 elif 'nt' in names:
429 sep = '\\'
430 from nt import stat
431 elif 'dos' in names:
432 sep = '\\'
433 from dos import stat
434 elif 'os2' in names:
435 sep = '\\'
436 from os2 import stat
437 elif 'mac' in names:
438 from mac import stat
439 def join(a, b):
440 if a == '':
441 return b
442 path = s
443 if ':' not in a:
444 a = ':' + a
445 if a[-1:] <> ':':
446 a = a + ':'
447 return a + b
448 else:
449 raise ImportError, 'no os specific module found'
450
451 if join is None:
452 def join(a, b, sep=sep):
453 if a == '':
454 return b
455 lastchar = a[-1:]
456 if lastchar == '/' or lastchar == sep:
457 return a + b
458 return a + sep + b
459
460 global _os_stat
461 _os_stat = stat
462
463 global _os_path_join
464 _os_path_join = join
465
466def _os_path_isdir(pathname):
467 "Local replacement for os.path.isdir()."
468 try:
469 s = _os_stat(pathname)
470 except OSError:
471 return None
472 return (s[0] & 0170000) == 0040000
473
474def _timestamp(pathname):
475 "Return the file modification time as a Long."
476 try:
477 s = _os_stat(pathname)
478 except OSError:
479 return None
480 return long(s[8])
481
Greg Stein63faa011999-11-20 11:22:37 +0000482
483######################################################################
484#
485# Emulate the import mechanism for builtin and frozen modules
486#
487class BuiltinImporter(Importer):
488 def get_code(self, parent, modname, fqname):
489 if parent:
490 # these modules definitely do not occur within a package context
491 return None
492
493 # look for the module
494 if imp.is_builtin(modname):
495 type = imp.C_BUILTIN
496 elif imp.is_frozen(modname):
497 type = imp.PY_FROZEN
498 else:
499 # not found
500 return None
501
502 # got it. now load and return it.
503 module = imp.load_module(modname, None, modname, ('', '', type))
504 return 0, module, { }
505
506
507######################################################################
Greg Steinf23aa1e2000-01-03 02:38:29 +0000508#
509# Internal importer used for importing from the filesystem
510#
511class _FilesystemImporter(Importer):
Greg Stein3bb578c2000-02-18 13:04:10 +0000512 def __init__(self):
513 self.suffixes = [ ]
514
515 def add_suffix(self, suffix, importFunc):
516 assert callable(importFunc)
517 self.suffixes.append((suffix, importFunc))
Greg Steinf23aa1e2000-01-03 02:38:29 +0000518
519 def import_from_dir(self, dir, fqname):
520 result = self._import_pathname(_os_path_join(dir, fqname), fqname)
521 if result:
522 return self._process_result(result, fqname)
523 return None
524
525 def get_code(self, parent, modname, fqname):
526 # This importer is never used with an empty parent. Its existence is
527 # private to the ImportManager. The ImportManager uses the
528 # import_from_dir() method to import top-level modules/packages.
529 # This method is only used when we look for a module within a package.
530 assert parent
531
532 return self._import_pathname(_os_path_join(parent.__pkgdir__, modname),
533 fqname)
534
535 def _import_pathname(self, pathname, fqname):
536 if _os_path_isdir(pathname):
537 result = self._import_pathname(_os_path_join(pathname, '__init__'),
538 fqname)
539 if result:
540 values = result[2]
541 values['__pkgdir__'] = pathname
542 values['__path__'] = [ pathname ]
543 return 1, result[1], values
544 return None
545
Greg Stein3bb578c2000-02-18 13:04:10 +0000546 for suffix, importFunc in self.suffixes:
Greg Steinf23aa1e2000-01-03 02:38:29 +0000547 filename = pathname + suffix
548 try:
549 finfo = _os_stat(filename)
550 except OSError:
551 pass
552 else:
Greg Stein3bb578c2000-02-18 13:04:10 +0000553 return importFunc(filename, finfo, fqname)
Greg Steinf23aa1e2000-01-03 02:38:29 +0000554 return None
555
556######################################################################
557#
558# SUFFIX-BASED IMPORTERS
559#
560
Greg Stein3bb578c2000-02-18 13:04:10 +0000561def py_suffix_importer(filename, finfo, fqname):
562 file = filename[:-3] + _suffix
563 t_py = long(finfo[8])
564 t_pyc = _timestamp(file)
Greg Steinf23aa1e2000-01-03 02:38:29 +0000565
Greg Stein3bb578c2000-02-18 13:04:10 +0000566 code = None
567 if t_pyc is not None and t_pyc >= t_py:
568 f = open(file, 'rb')
569 if f.read(4) == imp.get_magic():
570 t = struct.unpack('<I', f.read(4))[0]
571 if t == t_py:
572 code = marshal.load(f)
573 f.close()
574 if code is None:
575 file = filename
576 code = _compile(file, t_py)
Greg Steinf23aa1e2000-01-03 02:38:29 +0000577
Greg Stein3bb578c2000-02-18 13:04:10 +0000578 return 0, code, { '__file__' : file }
Greg Steinf23aa1e2000-01-03 02:38:29 +0000579
Greg Stein3bb578c2000-02-18 13:04:10 +0000580class DynLoadSuffixImporter:
Greg Steinf23aa1e2000-01-03 02:38:29 +0000581 def __init__(self, desc):
582 self.desc = desc
583
584 def import_file(self, filename, finfo, fqname):
585 fp = open(filename, self.desc[1])
586 module = imp.load_module(fqname, fp, filename, self.desc)
587 module.__file__ = filename
588 return 0, module, { }
589
590
591######################################################################
Greg Stein63faa011999-11-20 11:22:37 +0000592
Greg Stein63faa011999-11-20 11:22:37 +0000593def _print_importers():
594 items = sys.modules.items()
595 items.sort()
596 for name, module in items:
597 if module:
598 print name, module.__dict__.get('__importer__', '-- no importer')
599 else:
600 print name, '-- non-existent module'
601
Greg Steinf23aa1e2000-01-03 02:38:29 +0000602def _test_revamp():
603 ImportManager().install()
604 sys.path.insert(0, BuiltinImporter())
605
Greg Stein281b8d81999-11-07 12:54:45 +0000606######################################################################