blob: 3417ea646b4bbea885236566e2ce6a16e06d271a [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:
13# http://www.lyra.org/greg/python/imputil.py
14#
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
21import imp
22import 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('')
31_ModuleType = type(sys)
32
33class ImportManager:
34 "Manage the import process."
Greg Stein281b8d81999-11-07 12:54:45 +000035
36 def install(self):
Greg Steinf23aa1e2000-01-03 02:38:29 +000037 ### warning: Python 1.6 will have a different hook mechanism; this
38 ### code will need to change.
Greg Stein281b8d81999-11-07 12:54:45 +000039 self.__chain_import = __builtin__.__import__
40 self.__chain_reload = __builtin__.reload
41 __builtin__.__import__ = self._import_hook
Greg Steinf23aa1e2000-01-03 02:38:29 +000042 ### fix this
43 #__builtin__.reload = None
44 #__builtin__.reload = self._reload_hook
45
46 def add_suffix(self, suffix, importer):
47 assert isinstance(importer, SuffixImporter)
48 self.suffixes.append((suffix, importer))
Greg Stein281b8d81999-11-07 12:54:45 +000049
50 ######################################################################
51 #
52 # PRIVATE METHODS
53 #
Greg Steinf23aa1e2000-01-03 02:38:29 +000054 def __init__(self):
55 # we're definitely going to be importing something in the future,
56 # so let's just load the OS-related facilities.
57 if not _os_stat:
58 _os_bootstrap()
Greg Stein281b8d81999-11-07 12:54:45 +000059
Greg Steinf23aa1e2000-01-03 02:38:29 +000060 # Initialize the set of suffixes that we recognize and import.
61 # The default will import dynamic-load modules first, followed by
62 # .py files (or a .py file's cached bytecode)
63 self.suffixes = [ ]
64 for desc in imp.get_suffixes():
65 if desc[2] == imp.C_EXTENSION:
66 self.suffixes.append((desc[0], DynLoadSuffixImporter(desc)))
67 self.suffixes.append(('.py', PySuffixImporter()))
Greg Stein281b8d81999-11-07 12:54:45 +000068
Greg Steinf23aa1e2000-01-03 02:38:29 +000069 # This is the importer that we use for grabbing stuff from the
70 # filesystem. It defines one more method (import_from_dir) for our use.
71 self.fs_imp = _FilesystemImporter(self.suffixes)
Greg Stein281b8d81999-11-07 12:54:45 +000072
Greg Steinf23aa1e2000-01-03 02:38:29 +000073 def _import_hook(self, fqname, globals=None, locals=None, fromlist=None):
74 """Python calls this hook to locate and import a module."""
75
76 parts = strop.split(fqname, '.')
Greg Stein63faa011999-11-20 11:22:37 +000077
Greg Stein281b8d81999-11-07 12:54:45 +000078 # determine the context of this import
79 parent = self._determine_import_context(globals)
80
Greg Steinf23aa1e2000-01-03 02:38:29 +000081 # if there is a parent, then its importer should manage this import
82 if parent:
83 module = parent.__importer__._do_import(parent, parts, fromlist)
84 if module:
85 return module
Greg Stein281b8d81999-11-07 12:54:45 +000086
Greg Steinf23aa1e2000-01-03 02:38:29 +000087 # has the top module already been imported?
88 try:
89 top_module = sys.modules[parts[0]]
90 except KeyError:
Greg Stein281b8d81999-11-07 12:54:45 +000091
Greg Steinf23aa1e2000-01-03 02:38:29 +000092 # look for the topmost module
93 top_module = self._import_top_module(parts[0])
94 if not top_module:
95 # the topmost module wasn't found at all.
96 raise ImportError, 'No module named ' + fqname
97 return self.__chain_import(name, globals, locals, fromlist)
98
99 # fast-path simple imports
100 if len(parts) == 1:
101 if not fromlist:
102 return top_module
103
104 if not top_module.__dict__.get('__ispkg__'):
105 # __ispkg__ isn't defined (the module was not imported by us), or
106 # it is zero.
107 #
108 # In the former case, there is no way that we could import
109 # sub-modules that occur in the fromlist (but we can't raise an
110 # error because it may just be names) because we don't know how
111 # to deal with packages that were imported by other systems.
112 #
113 # In the latter case (__ispkg__ == 0), there can't be any sub-
114 # modules present, so we can just return.
115 #
116 # In both cases, since len(parts) == 1, the top_module is also
117 # the "bottom" which is the defined return when a fromlist exists.
118 return top_module
119
120 importer = top_module.__dict__.get('__importer__')
121 if importer:
122 return importer._finish_import(top_module, parts[1:], fromlist)
123
124 # If the importer does not exist, then we have to bail. A missing importer
125 # means that something else imported the module, and we have no knowledge
126 # of how to get sub-modules out of the thing.
127 raise ImportError, 'No module named ' + fqname
128 return self.__chain_import(name, globals, locals, fromlist)
129
130 def _determine_import_context(self, globals):
131 """Returns the context in which a module should be imported.
132
133 The context could be a loaded (package) module and the imported module
134 will be looked for within that package. The context could also be None,
135 meaning there is no context -- the module should be looked for as a
136 "top-level" module.
137 """
138
139 if not globals or not globals.get('__importer__'):
140 # globals does not refer to one of our modules or packages. That
141 # implies there is no relative import context (as far as we are
142 # concerned), and it should just pick it off the standard path.
143 return None
144
145 # The globals refer to a module or package of ours. It will define
146 # the context of the new import. Get the module/package fqname.
147 parent_fqname = globals['__name__']
148
149 # if a package is performing the import, then return itself (imports
150 # refer to pkg contents)
151 if globals['__ispkg__']:
152 parent = sys.modules[parent_fqname]
153 assert globals is parent.__dict__
154 return parent
155
156 i = strop.rfind(parent_fqname, '.')
157
158 # a module outside of a package has no particular import context
159 if i == -1:
160 return None
161
162 # if a module in a package is performing the import, then return the
163 # package (imports refer to siblings)
164 parent_fqname = parent_fqname[:i]
165 parent = sys.modules[parent_fqname]
166 assert parent.__name__ == parent_fqname
167 return parent
168
169 def _import_top_module(self, name):
170 # scan sys.path looking for a location in the filesystem that contains
171 # the module, or an Importer object that can import the module.
172 for item in sys.path:
173 if type(item) == _StringType:
174 module = self.fs_imp.import_from_dir(item, name)
175 else:
176 module = item.import_top(name)
177 if module:
178 return module
179 return None
180
181 def _reload_hook(self, module):
182 "Python calls this hook to reload a module."
183
184 # reloading of a module may or may not be possible (depending on the
185 # importer), but at least we can validate that it's ours to reload
186 importer = module.__dict__.get('__importer__')
187 if not importer:
188 return self.__chain_reload(module)
189
190 # okay. it is using the imputil system, and we must delegate it, but
191 # we don't know what to do (yet)
192 ### we should blast the module dict and do another get_code(). need to
193 ### flesh this out and add proper docco...
194 raise SystemError, "reload not yet implemented"
195
196
197class Importer:
198 "Base class for replacing standard import functions."
199
200 def install(self):
201 sys.path.insert(0, self)
202
203 def import_top(self, name):
204 "Import a top-level module."
205 return self._import_one(None, name, name)
206
207 ######################################################################
208 #
209 # PRIVATE METHODS
210 #
211 def _finish_import(self, top, parts, fromlist):
Greg Stein281b8d81999-11-07 12:54:45 +0000212 # if "a.b.c" was provided, then load the ".b.c" portion down from
213 # below the top-level module.
Greg Steinf23aa1e2000-01-03 02:38:29 +0000214 bottom = self._load_tail(top, parts)
Greg Stein281b8d81999-11-07 12:54:45 +0000215
216 # if the form is "import a.b.c", then return "a"
217 if not fromlist:
218 # no fromlist: return the top of the import tree
219 return top
220
Greg Steinf23aa1e2000-01-03 02:38:29 +0000221 # the top module was imported by self.
Greg Stein281b8d81999-11-07 12:54:45 +0000222 #
Greg Steinf23aa1e2000-01-03 02:38:29 +0000223 # this means that the bottom module was also imported by self (just
224 # now, or in the past and we fetched it from sys.modules).
Greg Stein281b8d81999-11-07 12:54:45 +0000225 #
226 # since we imported/handled the bottom module, this means that we can
Greg Steinf23aa1e2000-01-03 02:38:29 +0000227 # also handle its fromlist (and reliably use __ispkg__).
Greg Stein281b8d81999-11-07 12:54:45 +0000228
229 # if the bottom node is a package, then (potentially) import some modules.
230 #
231 # note: if it is not a package, then "fromlist" refers to names in
232 # the bottom module rather than modules.
233 # note: for a mix of names and modules in the fromlist, we will
234 # import all modules and insert those into the namespace of
235 # the package module. Python will pick up all fromlist names
236 # from the bottom (package) module; some will be modules that
237 # we imported and stored in the namespace, others are expected
238 # to be present already.
Greg Steinf23aa1e2000-01-03 02:38:29 +0000239 if bottom.__ispkg__:
Greg Stein281b8d81999-11-07 12:54:45 +0000240 self._import_fromlist(bottom, fromlist)
241
242 # if the form is "from a.b import c, d" then return "b"
243 return bottom
244
Greg Stein281b8d81999-11-07 12:54:45 +0000245 def _import_one(self, parent, modname, fqname):
246 "Import a single module."
247
248 # has the module already been imported?
249 try:
250 return sys.modules[fqname]
251 except KeyError:
252 pass
253
254 # load the module's code, or fetch the module itself
255 result = self.get_code(parent, modname, fqname)
256 if result is None:
257 return None
258
Greg Steinf23aa1e2000-01-03 02:38:29 +0000259 ### backwards-compat
260 if len(result) == 2:
261 result = result + ({},)
Greg Stein281b8d81999-11-07 12:54:45 +0000262
Greg Steinf23aa1e2000-01-03 02:38:29 +0000263 module = self._process_result(result, fqname)
Greg Stein281b8d81999-11-07 12:54:45 +0000264
265 # insert the module into its parent
266 if parent:
267 setattr(parent, modname, module)
268 return module
269
Greg Steinf23aa1e2000-01-03 02:38:29 +0000270 def _process_result(self, (ispkg, code, values), fqname):
271 # did get_code() return an actual module? (rather than a code object)
272 is_module = type(code) is _ModuleType
273
274 # use the returned module, or create a new one to exec code into
275 if is_module:
276 module = code
277 else:
278 module = imp.new_module(fqname)
279
280 ### record packages a bit differently??
281 module.__importer__ = self
282 module.__ispkg__ = ispkg
283
284 # insert additional values into the module (before executing the code)
285 module.__dict__.update(values)
286
287 # the module is almost ready... make it visible
288 sys.modules[fqname] = module
289
290 # execute the code within the module's namespace
291 if not is_module:
292 exec code in module.__dict__
293
294 return module
295
296 def _load_tail(self, m, parts):
Greg Stein281b8d81999-11-07 12:54:45 +0000297 """Import the rest of the modules, down from the top-level module.
298
299 Returns the last module in the dotted list of modules.
300 """
Greg Steinf23aa1e2000-01-03 02:38:29 +0000301 for part in parts:
302 fqname = "%s.%s" % (m.__name__, part)
303 m = self._import_one(m, part, fqname)
304 if not m:
305 raise ImportError, "No module named " + fqname
Greg Stein281b8d81999-11-07 12:54:45 +0000306 return m
307
308 def _import_fromlist(self, package, fromlist):
309 'Import any sub-modules in the "from" list.'
310
311 # if '*' is present in the fromlist, then look for the '__all__' variable
312 # to find additional items (modules) to import.
313 if '*' in fromlist:
314 fromlist = list(fromlist) + list(package.__dict__.get('__all__', []))
315
316 for sub in fromlist:
317 # if the name is already present, then don't try to import it (it
318 # might not be a module!).
319 if sub != '*' and not hasattr(package, sub):
320 subname = "%s.%s" % (package.__name__, sub)
321 submod = self._import_one(package, sub, subname)
322 if not submod:
323 raise ImportError, "cannot import name " + subname
324
Greg Steinf23aa1e2000-01-03 02:38:29 +0000325 def _do_import(self, parent, parts, fromlist):
326 """Attempt to import the module relative to parent.
Greg Stein281b8d81999-11-07 12:54:45 +0000327
Greg Steinf23aa1e2000-01-03 02:38:29 +0000328 This method is used when the import context specifies that <self>
329 imported the parent module.
Greg Stein281b8d81999-11-07 12:54:45 +0000330 """
Greg Steinf23aa1e2000-01-03 02:38:29 +0000331 top_name = parts[0]
332 top_fqname = parent.__name__ + '.' + top_name
333 top_module = self._import_one(parent, top_name, top_fqname)
334 if not top_module:
335 # this importer and parent could not find the module (relatively)
336 return None
337
338 return self._finish_import(top_module, parts[1:], fromlist)
Greg Stein281b8d81999-11-07 12:54:45 +0000339
340 ######################################################################
341 #
342 # METHODS TO OVERRIDE
343 #
344 def get_code(self, parent, modname, fqname):
345 """Find and retrieve the code for the given module.
346
347 parent specifies a parent module to define a context for importing. It
348 may be None, indicating no particular context for the search.
349
350 modname specifies a single module (not dotted) within the parent.
351
352 fqname specifies the fully-qualified module name. This is a (potentially)
353 dotted name from the "root" of the module namespace down to the modname.
354 If there is no parent, then modname==fqname.
355
Greg Steinf23aa1e2000-01-03 02:38:29 +0000356 This method should return None, or a 3-tuple.
Greg Stein281b8d81999-11-07 12:54:45 +0000357
358 * If the module was not found, then None should be returned.
359
360 * The first item of the 2- or 3-tuple should be the integer 0 or 1,
361 specifying whether the module that was found is a package or not.
362
363 * The second item is the code object for the module (it will be
364 executed within the new module's namespace). This item can also
365 be a fully-loaded module object (e.g. loaded from a shared lib).
366
Greg Steinf23aa1e2000-01-03 02:38:29 +0000367 * The third item is a dictionary of name/value pairs that will be
368 inserted into new module before the code object is executed. This
369 is provided in case the module's code expects certain values (such
Greg Stein281b8d81999-11-07 12:54:45 +0000370 as where the module was found). When the second item is a module
371 object, then these names/values will be inserted *after* the module
372 has been loaded/initialized.
373 """
374 raise RuntimeError, "get_code not implemented"
375
376
377######################################################################
378#
Greg Stein63faa011999-11-20 11:22:37 +0000379# Some handy stuff for the Importers
380#
381
382# byte-compiled file suffic character
383_suffix_char = __debug__ and 'c' or 'o'
384
385# byte-compiled file suffix
386_suffix = '.py' + _suffix_char
387
Greg Stein2b234131999-11-24 02:37:05 +0000388# the C_EXTENSION suffixes
389_c_suffixes = filter(lambda x: x[2] == imp.C_EXTENSION, imp.get_suffixes())
Greg Stein63faa011999-11-20 11:22:37 +0000390
391def _compile(pathname, timestamp):
392 """Compile (and cache) a Python source file.
393
394 The file specified by <pathname> is compiled to a code object and
395 returned.
396
397 Presuming the appropriate privileges exist, the bytecodes will be
398 saved back to the filesystem for future imports. The source file's
399 modification timestamp must be provided as a Long value.
400 """
401 codestring = open(pathname, 'r').read()
402 if codestring and codestring[-1] != '\n':
403 codestring = codestring + '\n'
404 code = __builtin__.compile(codestring, pathname, 'exec')
405
406 # try to cache the compiled code
407 try:
408 f = open(pathname + _suffix_char, 'wb')
409 except IOError:
410 pass
411 else:
412 f.write('\0\0\0\0')
413 f.write(struct.pack('<I', timestamp))
414 marshal.dump(code, f)
415 f.flush()
416 f.seek(0, 0)
417 f.write(imp.get_magic())
418 f.close()
419
420 return code
421
422_os_stat = _os_path_join = None
423def _os_bootstrap():
424 "Set up 'os' module replacement functions for use during import bootstrap."
425
426 names = sys.builtin_module_names
427
428 join = None
429 if 'posix' in names:
430 sep = '/'
431 from posix import stat
432 elif 'nt' in names:
433 sep = '\\'
434 from nt import stat
435 elif 'dos' in names:
436 sep = '\\'
437 from dos import stat
438 elif 'os2' in names:
439 sep = '\\'
440 from os2 import stat
441 elif 'mac' in names:
442 from mac import stat
443 def join(a, b):
444 if a == '':
445 return b
446 path = s
447 if ':' not in a:
448 a = ':' + a
449 if a[-1:] <> ':':
450 a = a + ':'
451 return a + b
452 else:
453 raise ImportError, 'no os specific module found'
454
455 if join is None:
456 def join(a, b, sep=sep):
457 if a == '':
458 return b
459 lastchar = a[-1:]
460 if lastchar == '/' or lastchar == sep:
461 return a + b
462 return a + sep + b
463
464 global _os_stat
465 _os_stat = stat
466
467 global _os_path_join
468 _os_path_join = join
469
470def _os_path_isdir(pathname):
471 "Local replacement for os.path.isdir()."
472 try:
473 s = _os_stat(pathname)
474 except OSError:
475 return None
476 return (s[0] & 0170000) == 0040000
477
478def _timestamp(pathname):
479 "Return the file modification time as a Long."
480 try:
481 s = _os_stat(pathname)
482 except OSError:
483 return None
484 return long(s[8])
485
Greg Stein2b234131999-11-24 02:37:05 +0000486def _fs_import(dir, modname, fqname):
Greg Stein63faa011999-11-20 11:22:37 +0000487 "Fetch a module from the filesystem."
488
489 pathname = _os_path_join(dir, modname)
490 if _os_path_isdir(pathname):
Greg Stein6d3165a1999-11-20 11:39:00 +0000491 values = { '__pkgdir__' : pathname, '__path__' : [ pathname ] }
Greg Stein63faa011999-11-20 11:22:37 +0000492 ispkg = 1
493 pathname = _os_path_join(pathname, '__init__')
494 else:
495 values = { }
496 ispkg = 0
497
Greg Stein2b234131999-11-24 02:37:05 +0000498 # look for dynload modules
499 for desc in _c_suffixes:
500 file = pathname + desc[0]
501 try:
502 fp = open(file, desc[1])
503 except IOError:
504 pass
505 else:
506 module = imp.load_module(fqname, fp, file, desc)
507 values['__file__'] = file
508 return 0, module, values
509
Greg Stein63faa011999-11-20 11:22:37 +0000510 t_py = _timestamp(pathname + '.py')
511 t_pyc = _timestamp(pathname + _suffix)
512 if t_py is None and t_pyc is None:
513 return None
514 code = None
515 if t_py is None or (t_pyc is not None and t_pyc >= t_py):
516 file = pathname + _suffix
517 f = open(file, 'rb')
518 if f.read(4) == imp.get_magic():
519 t = struct.unpack('<I', f.read(4))[0]
520 if t == t_py:
521 code = marshal.load(f)
522 f.close()
523 if code is None:
524 file = pathname + '.py'
525 code = _compile(file, t_py)
526
527 values['__file__'] = file
528 return ispkg, code, values
529
530
531######################################################################
532#
Greg Stein281b8d81999-11-07 12:54:45 +0000533# Simple function-based importer
534#
535class FuncImporter(Importer):
536 "Importer subclass to use a supplied function rather than method overrides."
537 def __init__(self, func):
538 self.func = func
539 def get_code(self, parent, modname, fqname):
540 return self.func(parent, modname, fqname)
541
542def install_with(func):
543 FuncImporter(func).install()
544
545
546######################################################################
547#
548# Base class for archive-based importing
549#
550class PackageArchiveImporter(Importer):
Greg Stein63faa011999-11-20 11:22:37 +0000551 """Importer subclass to import from (file) archives.
552
553 This Importer handles imports of the style <archive>.<subfile>, where
554 <archive> can be located using a subclass-specific mechanism and the
555 <subfile> is found in the archive using a subclass-specific mechanism.
556
557 This class defines two hooks for subclasses: one to locate an archive
558 (and possibly return some context for future subfile lookups), and one
559 to locate subfiles.
560 """
Greg Stein281b8d81999-11-07 12:54:45 +0000561
562 def get_code(self, parent, modname, fqname):
563 if parent:
Greg Stein63faa011999-11-20 11:22:37 +0000564 # the Importer._finish_import logic ensures that we handle imports
565 # under the top level module (package / archive).
566 assert parent.__importer__ == self
567
Greg Stein281b8d81999-11-07 12:54:45 +0000568 # if a parent "package" is provided, then we are importing a sub-file
569 # from the archive.
570 result = self.get_subfile(parent.__archive__, modname)
571 if result is None:
572 return None
573 if type(result) == type(()):
574 return (0,) + result
575 return 0, result
576
577 # no parent was provided, so the archive should exist somewhere on the
578 # default "path".
579 archive = self.get_archive(modname)
580 if archive is None:
581 return None
582 return 1, "", {'__archive__':archive}
583
584 def get_archive(self, modname):
585 """Get an archive of modules.
586
587 This method should locate an archive and return a value which can be
588 used by get_subfile to load modules from it. The value may be a simple
589 pathname, an open file, or a complex object that caches information
590 for future imports.
591
592 Return None if the archive was not found.
593 """
594 raise RuntimeError, "get_archive not implemented"
595
596 def get_subfile(self, archive, modname):
597 """Get code from a subfile in the specified archive.
598
599 Given the specified archive (as returned by get_archive()), locate
600 and return a code object for the specified module name.
601
602 A 2-tuple may be returned, consisting of a code object and a dict
603 of name/values to place into the target module.
604
605 Return None if the subfile was not found.
606 """
607 raise RuntimeError, "get_subfile not implemented"
608
609
610class PackageArchive(PackageArchiveImporter):
611 "PackageArchiveImporter subclass that refers to a specific archive."
612
613 def __init__(self, modname, archive_pathname):
614 self.__modname = modname
615 self.__path = archive_pathname
616
617 def get_archive(self, modname):
618 if modname == self.__modname:
619 return self.__path
620 return None
621
622 # get_subfile is passed the full pathname of the archive
623
624
625######################################################################
626#
627# Emulate the standard directory-based import mechanism
628#
Greg Stein281b8d81999-11-07 12:54:45 +0000629class DirectoryImporter(Importer):
630 "Importer subclass to emulate the standard importer."
631
632 def __init__(self, dir):
633 self.dir = dir
Greg Stein281b8d81999-11-07 12:54:45 +0000634
635 def get_code(self, parent, modname, fqname):
636 if parent:
637 dir = parent.__pkgdir__
638 else:
639 dir = self.dir
640
Greg Stein63faa011999-11-20 11:22:37 +0000641 # defer the loading of OS-related facilities
642 if not _os_stat:
643 _os_bootstrap()
Greg Stein281b8d81999-11-07 12:54:45 +0000644
Greg Stein63faa011999-11-20 11:22:37 +0000645 # Return the module (and other info) if found in the specified
646 # directory. Otherwise, return None.
Greg Stein2b234131999-11-24 02:37:05 +0000647 return _fs_import(dir, modname, fqname)
Greg Stein281b8d81999-11-07 12:54:45 +0000648
649 def __repr__(self):
650 return '<%s.%s for "%s" at 0x%x>' % (self.__class__.__module__,
651 self.__class__.__name__,
652 self.dir,
653 id(self))
654
Greg Stein63faa011999-11-20 11:22:37 +0000655######################################################################
656#
Greg Stein7ec28d21999-11-20 12:31:07 +0000657# Emulate the standard path-style import mechanism
Greg Stein63faa011999-11-20 11:22:37 +0000658#
Greg Stein7ec28d21999-11-20 12:31:07 +0000659class PathImporter(Importer):
660 def __init__(self, path=sys.path):
661 self.path = path
Greg Stein63faa011999-11-20 11:22:37 +0000662
663 # we're definitely going to be importing something in the future,
664 # so let's just load the OS-related facilities.
665 if not _os_stat:
666 _os_bootstrap()
667
668 def get_code(self, parent, modname, fqname):
669 if parent:
670 # we are looking for a module inside of a specific package
Greg Stein2b234131999-11-24 02:37:05 +0000671 return _fs_import(parent.__pkgdir__, modname, fqname)
Greg Stein63faa011999-11-20 11:22:37 +0000672
673 # scan sys.path, looking for the requested module
Greg Stein7ec28d21999-11-20 12:31:07 +0000674 for dir in self.path:
Greg Stein2b234131999-11-24 02:37:05 +0000675 result = _fs_import(dir, modname, fqname)
Greg Stein63faa011999-11-20 11:22:37 +0000676 if result:
Greg Stein63faa011999-11-20 11:22:37 +0000677 return result
678
679 # not found
680 return None
681
682
683######################################################################
684#
685# Emulate the import mechanism for builtin and frozen modules
686#
687class BuiltinImporter(Importer):
688 def get_code(self, parent, modname, fqname):
689 if parent:
690 # these modules definitely do not occur within a package context
691 return None
692
693 # look for the module
694 if imp.is_builtin(modname):
695 type = imp.C_BUILTIN
696 elif imp.is_frozen(modname):
697 type = imp.PY_FROZEN
698 else:
699 # not found
700 return None
701
702 # got it. now load and return it.
703 module = imp.load_module(modname, None, modname, ('', '', type))
704 return 0, module, { }
705
706
707######################################################################
Greg Steinf23aa1e2000-01-03 02:38:29 +0000708#
709# Internal importer used for importing from the filesystem
710#
711class _FilesystemImporter(Importer):
712 def __init__(self, suffixes):
713 # this list is shared with the ImportManager.
714 self.suffixes = suffixes
715
716 def import_from_dir(self, dir, fqname):
717 result = self._import_pathname(_os_path_join(dir, fqname), fqname)
718 if result:
719 return self._process_result(result, fqname)
720 return None
721
722 def get_code(self, parent, modname, fqname):
723 # This importer is never used with an empty parent. Its existence is
724 # private to the ImportManager. The ImportManager uses the
725 # import_from_dir() method to import top-level modules/packages.
726 # This method is only used when we look for a module within a package.
727 assert parent
728
729 return self._import_pathname(_os_path_join(parent.__pkgdir__, modname),
730 fqname)
731
732 def _import_pathname(self, pathname, fqname):
733 if _os_path_isdir(pathname):
734 result = self._import_pathname(_os_path_join(pathname, '__init__'),
735 fqname)
736 if result:
737 values = result[2]
738 values['__pkgdir__'] = pathname
739 values['__path__'] = [ pathname ]
740 return 1, result[1], values
741 return None
742
743 for suffix, importer in self.suffixes:
744 filename = pathname + suffix
745 try:
746 finfo = _os_stat(filename)
747 except OSError:
748 pass
749 else:
750 return importer.import_file(filename, finfo, fqname)
751 return None
752
753######################################################################
754#
755# SUFFIX-BASED IMPORTERS
756#
757
758class SuffixImporter:
759 def import_file(self, filename, finfo, fqname):
760 raise RuntimeError
761
762class PySuffixImporter(SuffixImporter):
763 def import_file(self, filename, finfo, fqname):
764 file = filename[:-3] + _suffix
765 t_py = long(finfo[8])
766 t_pyc = _timestamp(file)
767
768 code = None
769 if t_pyc is not None and t_pyc >= t_py:
770 f = open(file, 'rb')
771 if f.read(4) == imp.get_magic():
772 t = struct.unpack('<I', f.read(4))[0]
773 if t == t_py:
774 code = marshal.load(f)
775 f.close()
776 if code is None:
777 file = filename
778 code = _compile(file, t_py)
779
780 return 0, code, { '__file__' : file }
781
782class DynLoadSuffixImporter(SuffixImporter):
783 def __init__(self, desc):
784 self.desc = desc
785
786 def import_file(self, filename, finfo, fqname):
787 fp = open(filename, self.desc[1])
788 module = imp.load_module(fqname, fp, filename, self.desc)
789 module.__file__ = filename
790 return 0, module, { }
791
792
793######################################################################
Greg Stein63faa011999-11-20 11:22:37 +0000794
Greg Stein281b8d81999-11-07 12:54:45 +0000795def _test_dir():
796 "Debug/test function to create DirectoryImporters from sys.path."
797 path = sys.path[:]
798 path.reverse()
799 for d in path:
800 DirectoryImporter(d).install()
801
Greg Stein63faa011999-11-20 11:22:37 +0000802def _test_revamp():
803 "Debug/test function for the revamped import system."
Greg Stein7ec28d21999-11-20 12:31:07 +0000804 PathImporter().install()
Greg Stein32efef31999-11-24 02:38:37 +0000805 BuiltinImporter().install()
Greg Stein63faa011999-11-20 11:22:37 +0000806
807def _print_importers():
808 items = sys.modules.items()
809 items.sort()
810 for name, module in items:
811 if module:
812 print name, module.__dict__.get('__importer__', '-- no importer')
813 else:
814 print name, '-- non-existent module'
815
Greg Steinf23aa1e2000-01-03 02:38:29 +0000816def _test_revamp():
817 ImportManager().install()
818 sys.path.insert(0, BuiltinImporter())
819
Greg Stein281b8d81999-11-07 12:54:45 +0000820######################################################################