blob: 1683fae379a978b34cf249df8c92a92226e50491 [file] [log] [blame]
Guido van Rossuma4deda02002-12-23 16:30:00 +00001"""Utilities to support packages."""
2
Phillip J. Ebyab1d2452006-04-17 20:17:25 +00003# NOTE: This module must remain compatible with Python 2.3, as it is shared
4# by setuptools for distribution with Python 2.3 and up.
5
Guido van Rossuma4deda02002-12-23 16:30:00 +00006import os
7import sys
Phillip J. Ebyab1d2452006-04-17 20:17:25 +00008import imp
9import os.path
10from types import ModuleType
11
12__all__ = [
13 'get_importer', 'iter_importers', 'get_loader', 'find_loader',
Phillip J. Ebyceb30872006-04-18 00:59:55 +000014 'walk_packages', 'iter_modules',
Phillip J. Ebyab1d2452006-04-17 20:17:25 +000015 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
16]
17
18def read_code(stream):
19 # This helper is needed in order for the PEP 302 emulation to
20 # correctly handle compiled files
21 import marshal
22
23 magic = stream.read(4)
24 if magic != imp.get_magic():
25 return None
26
27 stream.read(4) # Skip timestamp
28 return marshal.load(stream)
29
30
Phillip J. Ebyceb30872006-04-18 00:59:55 +000031def simplegeneric(func):
32 """Make a trivial single-dispatch generic function"""
33 registry = {}
Neal Norwitz0bbbb002006-04-28 04:32:20 +000034 def wrapper(*args, **kw):
Phillip J. Ebyceb30872006-04-18 00:59:55 +000035 ob = args[0]
36 try:
37 cls = ob.__class__
38 except AttributeError:
39 cls = type(ob)
40 try:
41 mro = cls.__mro__
42 except AttributeError:
43 try:
Neal Norwitz0bbbb002006-04-28 04:32:20 +000044 class cls(cls, object):
45 pass
Phillip J. Ebyceb30872006-04-18 00:59:55 +000046 mro = cls.__mro__[1:]
47 except TypeError:
Tim Peters584b0e02006-04-18 17:32:12 +000048 mro = object, # must be an ExtensionClass or some such :(
Phillip J. Ebyceb30872006-04-18 00:59:55 +000049 for t in mro:
50 if t in registry:
Neal Norwitz0bbbb002006-04-28 04:32:20 +000051 return registry[t](*args, **kw)
Phillip J. Ebyceb30872006-04-18 00:59:55 +000052 else:
Neal Norwitz0bbbb002006-04-28 04:32:20 +000053 return func(*args, **kw)
Phillip J. Ebyceb30872006-04-18 00:59:55 +000054 try:
55 wrapper.__name__ = func.__name__
Neal Norwitz0bbbb002006-04-28 04:32:20 +000056 except (TypeError, AttributeError):
Phillip J. Ebyceb30872006-04-18 00:59:55 +000057 pass # Python 2.3 doesn't allow functions to be renamed
58
59 def register(typ, func=None):
60 if func is None:
61 return lambda f: register(typ, f)
62 registry[typ] = func
63 return func
64
65 wrapper.__dict__ = func.__dict__
66 wrapper.__doc__ = func.__doc__
67 wrapper.register = register
Tim Peters584b0e02006-04-18 17:32:12 +000068 return wrapper
Phillip J. Ebyceb30872006-04-18 00:59:55 +000069
70
71def walk_packages(path=None, prefix='', onerror=None):
72 """Yield submodule names+loaders recursively, for path or sys.path"""
73
Neal Norwitz0bbbb002006-04-28 04:32:20 +000074 def seen(p, m={}):
75 if p in m:
76 return True
Phillip J. Ebyceb30872006-04-18 00:59:55 +000077 m[p] = True
78
79 for importer, name, ispkg in iter_modules(path, prefix):
80 yield importer, name, ispkg
81
82 if ispkg:
83 try:
84 __import__(name)
85 except ImportError:
86 if onerror is not None:
87 onerror()
88 else:
89 path = getattr(sys.modules[name], '__path__', None) or []
90
91 # don't traverse path items we've seen before
92 path = [p for p in path if not seen(p)]
93
94 for item in walk_packages(path, name+'.'):
95 yield item
96
97
98def iter_modules(path=None, prefix=''):
99 """Yield submodule names+loaders for path or sys.path"""
100 if path is None:
101 importers = iter_importers()
102 else:
103 importers = map(get_importer, path)
104
105 yielded = {}
106 for i in importers:
107 for name, ispkg in iter_importer_modules(i, prefix):
108 if name not in yielded:
109 yielded[name] = 1
110 yield i, name, ispkg
111
112
113#@simplegeneric
114def iter_importer_modules(importer, prefix=''):
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000115 if not hasattr(importer, 'iter_modules'):
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000116 return []
117 return importer.iter_modules(prefix)
118
119iter_importer_modules = simplegeneric(iter_importer_modules)
120
121
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000122class ImpImporter:
123 """PEP 302 Importer that wraps Python's "classic" import algorithm
124
125 ImpImporter(dirname) produces a PEP 302 importer that searches that
126 directory. ImpImporter(None) produces a PEP 302 importer that searches
127 the current sys.path, plus any modules that are frozen or built-in.
128
129 Note that ImpImporter does not currently support being used by placement
130 on sys.meta_path.
131 """
132
133 def __init__(self, path=None):
134 self.path = path
135
136 def find_module(self, fullname, path=None):
137 # Note: we ignore 'path' argument since it is only used via meta_path
138 subname = fullname.split(".")[-1]
139 if subname != fullname and self.path is None:
140 return None
141 if self.path is None:
142 path = None
143 else:
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000144 path = [os.path.realpath(self.path)]
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000145 try:
146 file, filename, etc = imp.find_module(subname, path)
147 except ImportError:
148 return None
149 return ImpLoader(fullname, file, filename, etc)
150
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000151 def iter_modules(self, prefix=''):
152 if self.path is None or not os.path.isdir(self.path):
153 return
154
155 yielded = {}
156 import inspect
157
158 filenames = os.listdir(self.path)
159 filenames.sort() # handle packages before same-named modules
160
161 for fn in filenames:
162 modname = inspect.getmodulename(fn)
163 if modname=='__init__' or modname in yielded:
164 continue
Tim Peters584b0e02006-04-18 17:32:12 +0000165
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000166 path = os.path.join(self.path, fn)
167 ispkg = False
168
169 if not modname and os.path.isdir(path) and '.' not in fn:
170 modname = fn
171 for fn in os.listdir(path):
172 subname = inspect.getmodulename(fn)
173 if subname=='__init__':
174 ispkg = True
175 break
176 else:
177 continue # not a package
178
179 if modname and '.' not in modname:
180 yielded[modname] = 1
181 yield prefix + modname, ispkg
182
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000183
184class ImpLoader:
185 """PEP 302 Loader that wraps Python's "classic" import algorithm
186 """
187 code = source = None
188
189 def __init__(self, fullname, file, filename, etc):
190 self.file = file
191 self.filename = filename
192 self.fullname = fullname
193 self.etc = etc
194
195 def load_module(self, fullname):
196 self._reopen()
197 try:
198 mod = imp.load_module(fullname, self.file, self.filename, self.etc)
199 finally:
200 if self.file:
201 self.file.close()
202 # Note: we don't set __loader__ because we want the module to look
203 # normal; i.e. this is just a wrapper for standard import machinery
204 return mod
205
206 def get_data(self, pathname):
207 return open(pathname, "rb").read()
208
209 def _reopen(self):
210 if self.file and self.file.closed:
Neal Norwitzf992a2b2006-06-11 07:26:27 +0000211 mod_type = self.etc[2]
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000212 if mod_type==imp.PY_SOURCE:
213 self.file = open(self.filename, 'rU')
214 elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
215 self.file = open(self.filename, 'rb')
216
217 def _fix_name(self, fullname):
218 if fullname is None:
219 fullname = self.fullname
220 elif fullname != self.fullname:
221 raise ImportError("Loader for module %s cannot handle "
222 "module %s" % (self.fullname, fullname))
223 return fullname
224
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000225 def is_package(self, fullname):
226 fullname = self._fix_name(fullname)
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000227 return self.etc[2]==imp.PKG_DIRECTORY
228
229 def get_code(self, fullname=None):
230 fullname = self._fix_name(fullname)
231 if self.code is None:
232 mod_type = self.etc[2]
233 if mod_type==imp.PY_SOURCE:
234 source = self.get_source(fullname)
235 self.code = compile(source, self.filename, 'exec')
236 elif mod_type==imp.PY_COMPILED:
237 self._reopen()
238 try:
239 self.code = read_code(self.file)
240 finally:
241 self.file.close()
242 elif mod_type==imp.PKG_DIRECTORY:
243 self.code = self._get_delegate().get_code()
244 return self.code
245
246 def get_source(self, fullname=None):
247 fullname = self._fix_name(fullname)
248 if self.source is None:
249 mod_type = self.etc[2]
250 if mod_type==imp.PY_SOURCE:
251 self._reopen()
252 try:
253 self.source = self.file.read()
254 finally:
255 self.file.close()
256 elif mod_type==imp.PY_COMPILED:
257 if os.path.exists(self.filename[:-1]):
258 f = open(self.filename[:-1], 'rU')
259 self.source = f.read()
260 f.close()
261 elif mod_type==imp.PKG_DIRECTORY:
262 self.source = self._get_delegate().get_source()
263 return self.source
264
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000265
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000266 def _get_delegate(self):
267 return ImpImporter(self.filename).find_module('__init__')
268
269 def get_filename(self, fullname=None):
270 fullname = self._fix_name(fullname)
271 mod_type = self.etc[2]
272 if self.etc[2]==imp.PKG_DIRECTORY:
273 return self._get_delegate().get_filename()
274 elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
275 return self.filename
276 return None
277
278
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000279try:
280 import zipimport
281 from zipimport import zipimporter
Tim Peters584b0e02006-04-18 17:32:12 +0000282
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000283 def iter_zipimport_modules(importer, prefix=''):
284 dirlist = zipimport._zip_directory_cache[importer.archive].keys()
285 dirlist.sort()
286 _prefix = importer.prefix
287 plen = len(_prefix)
288 yielded = {}
289 import inspect
290 for fn in dirlist:
291 if not fn.startswith(_prefix):
292 continue
293
294 fn = fn[plen:].split(os.sep)
295
296 if len(fn)==2 and fn[1].startswith('__init__.py'):
297 if fn[0] not in yielded:
298 yielded[fn[0]] = 1
299 yield fn[0], True
300
301 if len(fn)!=1:
302 continue
303
304 modname = inspect.getmodulename(fn[0])
305 if modname=='__init__':
306 continue
307
308 if modname and '.' not in modname and modname not in yielded:
309 yielded[modname] = 1
310 yield prefix + modname, False
311
312 iter_importer_modules.register(zipimporter, iter_zipimport_modules)
313
314except ImportError:
315 pass
316
317
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000318def get_importer(path_item):
319 """Retrieve a PEP 302 importer for the given path item
320
321 The returned importer is cached in sys.path_importer_cache
322 if it was newly created by a path hook.
323
324 If there is no importer, a wrapper around the basic import
325 machinery is returned. This wrapper is never inserted into
326 the importer cache (None is inserted instead).
327
328 The cache (or part of it) can be cleared manually if a
329 rescan of sys.path_hooks is necessary.
330 """
331 try:
332 importer = sys.path_importer_cache[path_item]
333 except KeyError:
334 for path_hook in sys.path_hooks:
335 try:
336 importer = path_hook(path_item)
337 break
338 except ImportError:
339 pass
340 else:
341 importer = None
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000342 sys.path_importer_cache.setdefault(path_item, importer)
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000343
Georg Brandlf4ef1162006-05-26 18:03:31 +0000344 # The boolean values are used for caching valid and invalid
345 # file paths for the built-in import machinery
346 if importer in (None, True, False):
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000347 try:
348 importer = ImpImporter(path_item)
349 except ImportError:
Georg Brandlf4ef1162006-05-26 18:03:31 +0000350 importer = None
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000351 return importer
352
353
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000354def iter_importers(fullname=""):
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000355 """Yield PEP 302 importers for the given module name
356
357 If fullname contains a '.', the importers will be for the package
358 containing fullname, otherwise they will be importers for sys.meta_path,
359 sys.path, and Python's "classic" import machinery, in that order. If
360 the named module is in a package, that package is imported as a side
361 effect of invoking this function.
362
363 Non PEP 302 mechanisms (e.g. the Windows registry) used by the
364 standard import machinery to find files in alternative locations
365 are partially supported, but are searched AFTER sys.path. Normally,
366 these locations are searched BEFORE sys.path, preventing sys.path
367 entries from shadowing them.
368
369 For this to cause a visible difference in behaviour, there must
370 be a module or package name that is accessible via both sys.path
371 and one of the non PEP 302 file system mechanisms. In this case,
372 the emulation will find the former version, while the builtin
373 import mechanism will find the latter.
374
375 Items of the following types can be affected by this discrepancy:
376 imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY
377 """
378 if fullname.startswith('.'):
379 raise ImportError("Relative module names not supported")
380 if '.' in fullname:
381 # Get the containing package's __path__
382 pkg = '.'.join(fullname.split('.')[:-1])
383 if pkg not in sys.modules:
384 __import__(pkg)
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000385 path = getattr(sys.modules[pkg], '__path__', None) or []
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000386 else:
387 for importer in sys.meta_path:
388 yield importer
389 path = sys.path
390 for item in path:
391 yield get_importer(item)
392 if '.' not in fullname:
393 yield ImpImporter()
394
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000395def get_loader(module_or_name):
396 """Get a PEP 302 "loader" object for module_or_name
397
398 If the module or package is accessible via the normal import
399 mechanism, a wrapper around the relevant part of that machinery
400 is returned. Returns None if the module cannot be found or imported.
401 If the named module is not already imported, its containing package
402 (if any) is imported, in order to establish the package __path__.
403
404 This function uses iter_importers(), and is thus subject to the same
405 limitations regarding platform-specific special import locations such
406 as the Windows registry.
407 """
408 if module_or_name in sys.modules:
409 module_or_name = sys.modules[module_or_name]
410 if isinstance(module_or_name, ModuleType):
411 module = module_or_name
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000412 loader = getattr(module, '__loader__', None)
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000413 if loader is not None:
414 return loader
415 fullname = module.__name__
416 else:
417 fullname = module_or_name
418 return find_loader(fullname)
419
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000420def find_loader(fullname):
421 """Find a PEP 302 "loader" object for fullname
422
423 If fullname contains dots, path must be the containing package's __path__.
424 Returns None if the module cannot be found or imported. This function uses
425 iter_importers(), and is thus subject to the same limitations regarding
426 platform-specific special import locations such as the Windows registry.
427 """
428 for importer in iter_importers(fullname):
429 loader = importer.find_module(fullname)
430 if loader is not None:
431 return loader
432
433 return None
434
Guido van Rossuma4deda02002-12-23 16:30:00 +0000435
436def extend_path(path, name):
437 """Extend a package's path.
438
439 Intended use is to place the following code in a package's __init__.py:
440
441 from pkgutil import extend_path
442 __path__ = extend_path(__path__, __name__)
443
444 This will add to the package's __path__ all subdirectories of
445 directories on sys.path named after the package. This is useful
446 if one wants to distribute different parts of a single logical
447 package as multiple directories.
448
449 It also looks for *.pkg files beginning where * matches the name
450 argument. This feature is similar to *.pth files (see site.py),
451 except that it doesn't special-case lines starting with 'import'.
452 A *.pkg file is trusted at face value: apart from checking for
453 duplicates, all entries found in a *.pkg file are added to the
454 path, regardless of whether they are exist the filesystem. (This
455 is a feature.)
456
457 If the input path is not a list (as is the case for frozen
458 packages) it is returned unchanged. The input path is not
459 modified; an extended copy is returned. Items are only appended
460 to the copy at the end.
461
462 It is assumed that sys.path is a sequence. Items of sys.path that
463 are not (unicode or 8-bit) strings referring to existing
464 directories are ignored. Unicode items of sys.path that cause
465 errors when used as filenames may cause this function to raise an
466 exception (in line with os.path.isdir() behavior).
467 """
468
469 if not isinstance(path, list):
470 # This could happen e.g. when this is called from inside a
471 # frozen package. Return the path unchanged in that case.
472 return path
473
474 pname = os.path.join(*name.split('.')) # Reconstitute as relative path
475 # Just in case os.extsep != '.'
476 sname = os.extsep.join(name.split('.'))
477 sname_pkg = sname + os.extsep + "pkg"
478 init_py = "__init__" + os.extsep + "py"
479
480 path = path[:] # Start with a copy of the existing path
481
482 for dir in sys.path:
Raymond Hettinger7a70ea42003-09-17 05:50:59 +0000483 if not isinstance(dir, basestring) or not os.path.isdir(dir):
Guido van Rossuma4deda02002-12-23 16:30:00 +0000484 continue
485 subdir = os.path.join(dir, pname)
486 # XXX This may still add duplicate entries to path on
487 # case-insensitive filesystems
488 initfile = os.path.join(subdir, init_py)
489 if subdir not in path and os.path.isfile(initfile):
490 path.append(subdir)
491 # XXX Is this the right thing for subpackages like zope.app?
492 # It looks for a file named "zope.app.pkg"
493 pkgfile = os.path.join(dir, sname_pkg)
494 if os.path.isfile(pkgfile):
495 try:
496 f = open(pkgfile)
497 except IOError, msg:
498 sys.stderr.write("Can't open %s: %s\n" %
499 (pkgfile, msg))
500 else:
501 for line in f:
502 line = line.rstrip('\n')
503 if not line or line.startswith('#'):
504 continue
505 path.append(line) # Don't check for existence!
506 f.close()
507
508 return path