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