blob: ddf2a727615e912bbd495cf16c1d6bd7095e3de4 [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:
211 if mod_type==imp.PY_SOURCE:
212 self.file = open(self.filename, 'rU')
213 elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
214 self.file = open(self.filename, 'rb')
215
216 def _fix_name(self, fullname):
217 if fullname is None:
218 fullname = self.fullname
219 elif fullname != self.fullname:
220 raise ImportError("Loader for module %s cannot handle "
221 "module %s" % (self.fullname, fullname))
222 return fullname
223
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000224 def is_package(self, fullname):
225 fullname = self._fix_name(fullname)
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000226 return self.etc[2]==imp.PKG_DIRECTORY
227
228 def get_code(self, fullname=None):
229 fullname = self._fix_name(fullname)
230 if self.code is None:
231 mod_type = self.etc[2]
232 if mod_type==imp.PY_SOURCE:
233 source = self.get_source(fullname)
234 self.code = compile(source, self.filename, 'exec')
235 elif mod_type==imp.PY_COMPILED:
236 self._reopen()
237 try:
238 self.code = read_code(self.file)
239 finally:
240 self.file.close()
241 elif mod_type==imp.PKG_DIRECTORY:
242 self.code = self._get_delegate().get_code()
243 return self.code
244
245 def get_source(self, fullname=None):
246 fullname = self._fix_name(fullname)
247 if self.source is None:
248 mod_type = self.etc[2]
249 if mod_type==imp.PY_SOURCE:
250 self._reopen()
251 try:
252 self.source = self.file.read()
253 finally:
254 self.file.close()
255 elif mod_type==imp.PY_COMPILED:
256 if os.path.exists(self.filename[:-1]):
257 f = open(self.filename[:-1], 'rU')
258 self.source = f.read()
259 f.close()
260 elif mod_type==imp.PKG_DIRECTORY:
261 self.source = self._get_delegate().get_source()
262 return self.source
263
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000264
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000265 def _get_delegate(self):
266 return ImpImporter(self.filename).find_module('__init__')
267
268 def get_filename(self, fullname=None):
269 fullname = self._fix_name(fullname)
270 mod_type = self.etc[2]
271 if self.etc[2]==imp.PKG_DIRECTORY:
272 return self._get_delegate().get_filename()
273 elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
274 return self.filename
275 return None
276
277
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000278try:
279 import zipimport
280 from zipimport import zipimporter
Tim Peters584b0e02006-04-18 17:32:12 +0000281
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000282 def iter_zipimport_modules(importer, prefix=''):
283 dirlist = zipimport._zip_directory_cache[importer.archive].keys()
284 dirlist.sort()
285 _prefix = importer.prefix
286 plen = len(_prefix)
287 yielded = {}
288 import inspect
289 for fn in dirlist:
290 if not fn.startswith(_prefix):
291 continue
292
293 fn = fn[plen:].split(os.sep)
294
295 if len(fn)==2 and fn[1].startswith('__init__.py'):
296 if fn[0] not in yielded:
297 yielded[fn[0]] = 1
298 yield fn[0], True
299
300 if len(fn)!=1:
301 continue
302
303 modname = inspect.getmodulename(fn[0])
304 if modname=='__init__':
305 continue
306
307 if modname and '.' not in modname and modname not in yielded:
308 yielded[modname] = 1
309 yield prefix + modname, False
310
311 iter_importer_modules.register(zipimporter, iter_zipimport_modules)
312
313except ImportError:
314 pass
315
316
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000317def get_importer(path_item):
318 """Retrieve a PEP 302 importer for the given path item
319
320 The returned importer is cached in sys.path_importer_cache
321 if it was newly created by a path hook.
322
323 If there is no importer, a wrapper around the basic import
324 machinery is returned. This wrapper is never inserted into
325 the importer cache (None is inserted instead).
326
327 The cache (or part of it) can be cleared manually if a
328 rescan of sys.path_hooks is necessary.
329 """
330 try:
331 importer = sys.path_importer_cache[path_item]
332 except KeyError:
333 for path_hook in sys.path_hooks:
334 try:
335 importer = path_hook(path_item)
336 break
337 except ImportError:
338 pass
339 else:
340 importer = None
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000341 sys.path_importer_cache.setdefault(path_item, importer)
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000342
343 if importer is None:
344 try:
345 importer = ImpImporter(path_item)
346 except ImportError:
347 pass
348 return importer
349
350
Phillip J. Ebyceb30872006-04-18 00:59:55 +0000351def iter_importers(fullname=""):
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000352 """Yield PEP 302 importers for the given module name
353
354 If fullname contains a '.', the importers will be for the package
355 containing fullname, otherwise they will be importers for sys.meta_path,
356 sys.path, and Python's "classic" import machinery, in that order. If
357 the named module is in a package, that package is imported as a side
358 effect of invoking this function.
359
360 Non PEP 302 mechanisms (e.g. the Windows registry) used by the
361 standard import machinery to find files in alternative locations
362 are partially supported, but are searched AFTER sys.path. Normally,
363 these locations are searched BEFORE sys.path, preventing sys.path
364 entries from shadowing them.
365
366 For this to cause a visible difference in behaviour, there must
367 be a module or package name that is accessible via both sys.path
368 and one of the non PEP 302 file system mechanisms. In this case,
369 the emulation will find the former version, while the builtin
370 import mechanism will find the latter.
371
372 Items of the following types can be affected by this discrepancy:
373 imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY
374 """
375 if fullname.startswith('.'):
376 raise ImportError("Relative module names not supported")
377 if '.' in fullname:
378 # Get the containing package's __path__
379 pkg = '.'.join(fullname.split('.')[:-1])
380 if pkg not in sys.modules:
381 __import__(pkg)
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000382 path = getattr(sys.modules[pkg], '__path__', None) or []
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000383 else:
384 for importer in sys.meta_path:
385 yield importer
386 path = sys.path
387 for item in path:
388 yield get_importer(item)
389 if '.' not in fullname:
390 yield ImpImporter()
391
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000392def get_loader(module_or_name):
393 """Get a PEP 302 "loader" object for module_or_name
394
395 If the module or package is accessible via the normal import
396 mechanism, a wrapper around the relevant part of that machinery
397 is returned. Returns None if the module cannot be found or imported.
398 If the named module is not already imported, its containing package
399 (if any) is imported, in order to establish the package __path__.
400
401 This function uses iter_importers(), and is thus subject to the same
402 limitations regarding platform-specific special import locations such
403 as the Windows registry.
404 """
405 if module_or_name in sys.modules:
406 module_or_name = sys.modules[module_or_name]
407 if isinstance(module_or_name, ModuleType):
408 module = module_or_name
Neal Norwitz0bbbb002006-04-28 04:32:20 +0000409 loader = getattr(module, '__loader__', None)
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000410 if loader is not None:
411 return loader
412 fullname = module.__name__
413 else:
414 fullname = module_or_name
415 return find_loader(fullname)
416
Phillip J. Ebyab1d2452006-04-17 20:17:25 +0000417def find_loader(fullname):
418 """Find a PEP 302 "loader" object for fullname
419
420 If fullname contains dots, path must be the containing package's __path__.
421 Returns None if the module cannot be found or imported. This function uses
422 iter_importers(), and is thus subject to the same limitations regarding
423 platform-specific special import locations such as the Windows registry.
424 """
425 for importer in iter_importers(fullname):
426 loader = importer.find_module(fullname)
427 if loader is not None:
428 return loader
429
430 return None
431
Guido van Rossuma4deda02002-12-23 16:30:00 +0000432
433def extend_path(path, name):
434 """Extend a package's path.
435
436 Intended use is to place the following code in a package's __init__.py:
437
438 from pkgutil import extend_path
439 __path__ = extend_path(__path__, __name__)
440
441 This will add to the package's __path__ all subdirectories of
442 directories on sys.path named after the package. This is useful
443 if one wants to distribute different parts of a single logical
444 package as multiple directories.
445
446 It also looks for *.pkg files beginning where * matches the name
447 argument. This feature is similar to *.pth files (see site.py),
448 except that it doesn't special-case lines starting with 'import'.
449 A *.pkg file is trusted at face value: apart from checking for
450 duplicates, all entries found in a *.pkg file are added to the
451 path, regardless of whether they are exist the filesystem. (This
452 is a feature.)
453
454 If the input path is not a list (as is the case for frozen
455 packages) it is returned unchanged. The input path is not
456 modified; an extended copy is returned. Items are only appended
457 to the copy at the end.
458
459 It is assumed that sys.path is a sequence. Items of sys.path that
460 are not (unicode or 8-bit) strings referring to existing
461 directories are ignored. Unicode items of sys.path that cause
462 errors when used as filenames may cause this function to raise an
463 exception (in line with os.path.isdir() behavior).
464 """
465
466 if not isinstance(path, list):
467 # This could happen e.g. when this is called from inside a
468 # frozen package. Return the path unchanged in that case.
469 return path
470
471 pname = os.path.join(*name.split('.')) # Reconstitute as relative path
472 # Just in case os.extsep != '.'
473 sname = os.extsep.join(name.split('.'))
474 sname_pkg = sname + os.extsep + "pkg"
475 init_py = "__init__" + os.extsep + "py"
476
477 path = path[:] # Start with a copy of the existing path
478
479 for dir in sys.path:
Raymond Hettinger7a70ea42003-09-17 05:50:59 +0000480 if not isinstance(dir, basestring) or not os.path.isdir(dir):
Guido van Rossuma4deda02002-12-23 16:30:00 +0000481 continue
482 subdir = os.path.join(dir, pname)
483 # XXX This may still add duplicate entries to path on
484 # case-insensitive filesystems
485 initfile = os.path.join(subdir, init_py)
486 if subdir not in path and os.path.isfile(initfile):
487 path.append(subdir)
488 # XXX Is this the right thing for subpackages like zope.app?
489 # It looks for a file named "zope.app.pkg"
490 pkgfile = os.path.join(dir, sname_pkg)
491 if os.path.isfile(pkgfile):
492 try:
493 f = open(pkgfile)
494 except IOError, msg:
495 sys.stderr.write("Can't open %s: %s\n" %
496 (pkgfile, msg))
497 else:
498 for line in f:
499 line = line.rstrip('\n')
500 if not line or line.startswith('#'):
501 continue
502 path.append(line) # Don't check for existence!
503 f.close()
504
505 return path