blob: 0f783dea1e200ecf49a2c83cbbe169f027abf3bf [file] [log] [blame]
Guido van Rossuma4deda02002-12-23 16:30:00 +00001"""Utilities to support packages."""
2
3import os
4import sys
Nick Coghlan85e729e2012-07-15 18:09:52 +10005import importlib
Nick Coghlanbe7e49f2012-07-20 23:40:09 +10006import imp
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00007import os.path
Nick Coghlan85e729e2012-07-15 18:09:52 +10008from warnings import warn
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00009from types import ModuleType
10
11__all__ = [
12 'get_importer', 'iter_importers', 'get_loader', 'find_loader',
Éric Araujoa4e2d4f2011-05-02 22:59:15 +020013 'walk_packages', 'iter_modules', 'get_data',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000014 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
15]
16
17def read_code(stream):
18 # This helper is needed in order for the PEP 302 emulation to
19 # correctly handle compiled files
20 import marshal
21
22 magic = stream.read(4)
23 if magic != imp.get_magic():
24 return None
25
Antoine Pitrou5136ac02012-01-13 18:52:16 +010026 stream.read(8) # Skip timestamp and size
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000027 return marshal.load(stream)
28
29
30def simplegeneric(func):
31 """Make a trivial single-dispatch generic function"""
32 registry = {}
Thomas Wouters477c8d52006-05-27 19:21:47 +000033 def wrapper(*args, **kw):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000034 ob = args[0]
35 try:
36 cls = ob.__class__
37 except AttributeError:
38 cls = type(ob)
39 try:
40 mro = cls.__mro__
41 except AttributeError:
42 try:
Thomas Wouters477c8d52006-05-27 19:21:47 +000043 class cls(cls, object):
44 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000045 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:
Thomas Wouters477c8d52006-05-27 19:21:47 +000050 return registry[t](*args, **kw)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000051 else:
Thomas Wouters477c8d52006-05-27 19:21:47 +000052 return func(*args, **kw)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000053 try:
54 wrapper.__name__ = func.__name__
Thomas Wouters477c8d52006-05-27 19:21:47 +000055 except (TypeError, AttributeError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000056 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):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071 """Yields (module_loader, name, ispkg) for all modules recursively
72 on path, or, if path is None, all accessible modules.
73
74 'path' should be either None or a list of paths to look for
75 modules in.
76
77 'prefix' is a string to output on the front of every module name
78 on output.
79
80 Note that this function must import all *packages* (NOT all
81 modules!) on the given path, in order to access the __path__
82 attribute to find submodules.
83
84 'onerror' is a function which gets called with one argument (the
85 name of the package which was being imported) if any exception
86 occurs while trying to import a package. If no onerror function is
87 supplied, ImportErrors are caught and ignored, while all other
88 exceptions are propagated, terminating the search.
89
90 Examples:
91
92 # list all modules python can access
93 walk_packages()
94
95 # list all submodules of ctypes
96 walk_packages(ctypes.__path__, ctypes.__name__+'.')
97 """
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000098
Thomas Wouters477c8d52006-05-27 19:21:47 +000099 def seen(p, m={}):
100 if p in m:
101 return True
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000102 m[p] = True
103
104 for importer, name, ispkg in iter_modules(path, prefix):
105 yield importer, name, ispkg
106
107 if ispkg:
108 try:
109 __import__(name)
110 except ImportError:
111 if onerror is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000112 onerror(name)
113 except Exception:
114 if onerror is not None:
115 onerror(name)
116 else:
117 raise
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000118 else:
119 path = getattr(sys.modules[name], '__path__', None) or []
120
121 # don't traverse path items we've seen before
122 path = [p for p in path if not seen(p)]
123
Philip Jenvey4993cc02012-10-01 12:53:43 -0700124 yield from walk_packages(path, name+'.', onerror)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000125
126
127def iter_modules(path=None, prefix=''):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000128 """Yields (module_loader, name, ispkg) for all submodules on path,
129 or, if path is None, all top-level modules on sys.path.
130
131 'path' should be either None or a list of paths to look for
132 modules in.
133
134 'prefix' is a string to output on the front of every module name
135 on output.
136 """
137
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000138 if path is None:
139 importers = iter_importers()
140 else:
141 importers = map(get_importer, path)
142
143 yielded = {}
144 for i in importers:
145 for name, ispkg in iter_importer_modules(i, prefix):
146 if name not in yielded:
147 yielded[name] = 1
148 yield i, name, ispkg
149
150
151#@simplegeneric
152def iter_importer_modules(importer, prefix=''):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000153 if not hasattr(importer, 'iter_modules'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000154 return []
155 return importer.iter_modules(prefix)
156
157iter_importer_modules = simplegeneric(iter_importer_modules)
158
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000159# Implement a file walker for the normal importlib path hook
160def _iter_file_finder_modules(importer, prefix=''):
161 if importer.path is None or not os.path.isdir(importer.path):
162 return
163
164 yielded = {}
165 import inspect
166 try:
167 filenames = os.listdir(importer.path)
168 except OSError:
169 # ignore unreadable directories like import does
170 filenames = []
171 filenames.sort() # handle packages before same-named modules
172
173 for fn in filenames:
174 modname = inspect.getmodulename(fn)
175 if modname=='__init__' or modname in yielded:
176 continue
177
178 path = os.path.join(importer.path, fn)
179 ispkg = False
180
181 if not modname and os.path.isdir(path) and '.' not in fn:
182 modname = fn
183 try:
184 dircontents = os.listdir(path)
185 except OSError:
186 # ignore unreadable directories like import does
187 dircontents = []
188 for fn in dircontents:
189 subname = inspect.getmodulename(fn)
190 if subname=='__init__':
191 ispkg = True
192 break
193 else:
194 continue # not a package
195
196 if modname and '.' not in modname:
197 yielded[modname] = 1
198 yield prefix + modname, ispkg
199
200iter_importer_modules.register(
201 importlib.machinery.FileFinder, _iter_file_finder_modules)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000202
203class ImpImporter:
204 """PEP 302 Importer that wraps Python's "classic" import algorithm
205
206 ImpImporter(dirname) produces a PEP 302 importer that searches that
207 directory. ImpImporter(None) produces a PEP 302 importer that searches
208 the current sys.path, plus any modules that are frozen or built-in.
209
210 Note that ImpImporter does not currently support being used by placement
211 on sys.meta_path.
212 """
213
214 def __init__(self, path=None):
Nick Coghlan85e729e2012-07-15 18:09:52 +1000215 warn("This emulation is deprecated, use 'importlib' instead",
216 DeprecationWarning)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000217 self.path = path
218
219 def find_module(self, fullname, path=None):
220 # Note: we ignore 'path' argument since it is only used via meta_path
221 subname = fullname.split(".")[-1]
222 if subname != fullname and self.path is None:
223 return None
224 if self.path is None:
225 path = None
226 else:
227 path = [os.path.realpath(self.path)]
228 try:
229 file, filename, etc = imp.find_module(subname, path)
230 except ImportError:
231 return None
232 return ImpLoader(fullname, file, filename, etc)
233
234 def iter_modules(self, prefix=''):
235 if self.path is None or not os.path.isdir(self.path):
236 return
237
238 yielded = {}
239 import inspect
Ned Deilyed27df72011-10-06 14:19:08 -0700240 try:
241 filenames = os.listdir(self.path)
242 except OSError:
243 # ignore unreadable directories like import does
244 filenames = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000245 filenames.sort() # handle packages before same-named modules
246
247 for fn in filenames:
248 modname = inspect.getmodulename(fn)
249 if modname=='__init__' or modname in yielded:
250 continue
251
252 path = os.path.join(self.path, fn)
253 ispkg = False
254
255 if not modname and os.path.isdir(path) and '.' not in fn:
256 modname = fn
Ned Deilyed27df72011-10-06 14:19:08 -0700257 try:
258 dircontents = os.listdir(path)
259 except OSError:
260 # ignore unreadable directories like import does
261 dircontents = []
262 for fn in dircontents:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000263 subname = inspect.getmodulename(fn)
264 if subname=='__init__':
265 ispkg = True
266 break
267 else:
268 continue # not a package
269
270 if modname and '.' not in modname:
271 yielded[modname] = 1
272 yield prefix + modname, ispkg
273
274
275class ImpLoader:
276 """PEP 302 Loader that wraps Python's "classic" import algorithm
277 """
278 code = source = None
279
280 def __init__(self, fullname, file, filename, etc):
Nick Coghlan85e729e2012-07-15 18:09:52 +1000281 warn("This emulation is deprecated, use 'importlib' instead",
282 DeprecationWarning)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000283 self.file = file
284 self.filename = filename
285 self.fullname = fullname
286 self.etc = etc
287
288 def load_module(self, fullname):
289 self._reopen()
290 try:
291 mod = imp.load_module(fullname, self.file, self.filename, self.etc)
292 finally:
293 if self.file:
294 self.file.close()
295 # Note: we don't set __loader__ because we want the module to look
296 # normal; i.e. this is just a wrapper for standard import machinery
297 return mod
298
299 def get_data(self, pathname):
Brett Cannon1ab58df2010-10-29 22:36:53 +0000300 with open(pathname, "rb") as file:
301 return file.read()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000302
303 def _reopen(self):
304 if self.file and self.file.closed:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000305 mod_type = self.etc[2]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000306 if mod_type==imp.PY_SOURCE:
Victor Stinner4e86d5b2011-05-04 13:55:36 +0200307 self.file = open(self.filename, 'r')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000308 elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
309 self.file = open(self.filename, 'rb')
310
311 def _fix_name(self, fullname):
312 if fullname is None:
313 fullname = self.fullname
314 elif fullname != self.fullname:
315 raise ImportError("Loader for module %s cannot handle "
316 "module %s" % (self.fullname, fullname))
317 return fullname
318
319 def is_package(self, fullname):
320 fullname = self._fix_name(fullname)
321 return self.etc[2]==imp.PKG_DIRECTORY
322
323 def get_code(self, fullname=None):
324 fullname = self._fix_name(fullname)
325 if self.code is None:
326 mod_type = self.etc[2]
327 if mod_type==imp.PY_SOURCE:
328 source = self.get_source(fullname)
329 self.code = compile(source, self.filename, 'exec')
330 elif mod_type==imp.PY_COMPILED:
331 self._reopen()
332 try:
333 self.code = read_code(self.file)
334 finally:
335 self.file.close()
336 elif mod_type==imp.PKG_DIRECTORY:
337 self.code = self._get_delegate().get_code()
338 return self.code
339
340 def get_source(self, fullname=None):
341 fullname = self._fix_name(fullname)
342 if self.source is None:
343 mod_type = self.etc[2]
344 if mod_type==imp.PY_SOURCE:
345 self._reopen()
346 try:
347 self.source = self.file.read()
348 finally:
349 self.file.close()
350 elif mod_type==imp.PY_COMPILED:
351 if os.path.exists(self.filename[:-1]):
Victor Stinner4e86d5b2011-05-04 13:55:36 +0200352 f = open(self.filename[:-1], 'r')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000353 self.source = f.read()
354 f.close()
355 elif mod_type==imp.PKG_DIRECTORY:
356 self.source = self._get_delegate().get_source()
357 return self.source
358
359
360 def _get_delegate(self):
361 return ImpImporter(self.filename).find_module('__init__')
362
363 def get_filename(self, fullname=None):
364 fullname = self._fix_name(fullname)
365 mod_type = self.etc[2]
Éric Araujo0cfb81d2011-09-17 03:35:57 +0200366 if mod_type==imp.PKG_DIRECTORY:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000367 return self._get_delegate().get_filename()
Éric Araujo0cfb81d2011-09-17 03:35:57 +0200368 elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000369 return self.filename
370 return None
371
372
373try:
374 import zipimport
375 from zipimport import zipimporter
376
377 def iter_zipimport_modules(importer, prefix=''):
Alexandre Vassalotti515a74f2009-07-05 06:42:44 +0000378 dirlist = sorted(zipimport._zip_directory_cache[importer.archive])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000379 _prefix = importer.prefix
380 plen = len(_prefix)
381 yielded = {}
382 import inspect
383 for fn in dirlist:
384 if not fn.startswith(_prefix):
385 continue
386
387 fn = fn[plen:].split(os.sep)
388
389 if len(fn)==2 and fn[1].startswith('__init__.py'):
390 if fn[0] not in yielded:
391 yielded[fn[0]] = 1
392 yield fn[0], True
393
394 if len(fn)!=1:
395 continue
396
397 modname = inspect.getmodulename(fn[0])
398 if modname=='__init__':
399 continue
400
401 if modname and '.' not in modname and modname not in yielded:
402 yielded[modname] = 1
403 yield prefix + modname, False
404
405 iter_importer_modules.register(zipimporter, iter_zipimport_modules)
406
407except ImportError:
408 pass
409
410
411def get_importer(path_item):
412 """Retrieve a PEP 302 importer for the given path item
413
414 The returned importer is cached in sys.path_importer_cache
415 if it was newly created by a path hook.
416
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000417 The cache (or part of it) can be cleared manually if a
418 rescan of sys.path_hooks is necessary.
419 """
420 try:
421 importer = sys.path_importer_cache[path_item]
422 except KeyError:
423 for path_hook in sys.path_hooks:
424 try:
425 importer = path_hook(path_item)
Brett Cannone0d88a12012-04-25 20:54:04 -0400426 sys.path_importer_cache.setdefault(path_item, importer)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000427 break
428 except ImportError:
429 pass
430 else:
Nick Coghlan85e729e2012-07-15 18:09:52 +1000431 importer = None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000432 return importer
433
434
435def iter_importers(fullname=""):
436 """Yield PEP 302 importers for the given module name
437
438 If fullname contains a '.', the importers will be for the package
Nick Coghlan85e729e2012-07-15 18:09:52 +1000439 containing fullname, otherwise they will be all registered top level
440 importers (i.e. those on both sys.meta_path and sys.path_hooks).
441
442 If the named module is in a package, that package is imported as a side
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000443 effect of invoking this function.
444
Nick Coghlan85e729e2012-07-15 18:09:52 +1000445 If no module name is specified, all top level importers are produced.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000446 """
447 if fullname.startswith('.'):
Nick Coghlan85e729e2012-07-15 18:09:52 +1000448 msg = "Relative module name {!r} not supported".format(fullname)
449 raise ImportError(msg)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000450 if '.' in fullname:
451 # Get the containing package's __path__
Nick Coghlan85e729e2012-07-15 18:09:52 +1000452 pkg_name = fullname.rpartition(".")[0]
453 pkg = importlib.import_module(pkg)
454 path = getattr(sys.modules[pkg], '__path__', None)
455 if path is None:
456 return
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000457 else:
Andrew Svetlov2aa5f3c2012-10-07 23:21:15 +0300458 yield from sys.meta_path
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000459 path = sys.path
460 for item in path:
461 yield get_importer(item)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000462
463def get_loader(module_or_name):
464 """Get a PEP 302 "loader" object for module_or_name
465
Nick Coghlan85e729e2012-07-15 18:09:52 +1000466 Returns None if the module cannot be found or imported.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000467 If the named module is not already imported, its containing package
468 (if any) is imported, in order to establish the package __path__.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000469 """
470 if module_or_name in sys.modules:
471 module_or_name = sys.modules[module_or_name]
472 if isinstance(module_or_name, ModuleType):
473 module = module_or_name
Thomas Wouters477c8d52006-05-27 19:21:47 +0000474 loader = getattr(module, '__loader__', None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000475 if loader is not None:
476 return loader
477 fullname = module.__name__
478 else:
479 fullname = module_or_name
480 return find_loader(fullname)
481
Nick Coghlan85e729e2012-07-15 18:09:52 +1000482
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000483def find_loader(fullname):
484 """Find a PEP 302 "loader" object for fullname
485
Nick Coghlan85e729e2012-07-15 18:09:52 +1000486 This is s convenience wrapper around :func:`importlib.find_loader` that
487 sets the *path* argument correctly when searching for submodules, and
488 also ensures parent packages (if any) are imported before searching for
489 submodules.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000490 """
Nick Coghlan85e729e2012-07-15 18:09:52 +1000491 if fullname.startswith('.'):
492 msg = "Relative module name {!r} not supported".format(fullname)
493 raise ImportError(msg)
494 path = None
495 pkg_name = fullname.rpartition(".")[0]
496 if pkg_name:
497 pkg = importlib.import_module(pkg_name)
498 path = getattr(pkg, "__path__", None)
499 if path is None:
500 return None
501 try:
502 return importlib.find_loader(fullname, path)
503 except (ImportError, AttributeError, TypeError, ValueError) as ex:
504 # This hack fixes an impedance mismatch between pkgutil and
Andrew Svetlov5b898402012-12-18 21:26:36 +0200505 # importlib, where the latter raises other errors for cases where
Andrew Svetlov1f415cf2012-12-19 22:54:47 +0200506 # pkgutil previously raised ImportError
Nick Coghlan85e729e2012-07-15 18:09:52 +1000507 msg = "Error while finding loader for {!r} ({}: {})"
508 raise ImportError(msg.format(fullname, type(ex), ex)) from ex
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000509
Guido van Rossuma4deda02002-12-23 16:30:00 +0000510
511def extend_path(path, name):
512 """Extend a package's path.
513
514 Intended use is to place the following code in a package's __init__.py:
515
516 from pkgutil import extend_path
517 __path__ = extend_path(__path__, __name__)
518
519 This will add to the package's __path__ all subdirectories of
520 directories on sys.path named after the package. This is useful
521 if one wants to distribute different parts of a single logical
522 package as multiple directories.
523
524 It also looks for *.pkg files beginning where * matches the name
525 argument. This feature is similar to *.pth files (see site.py),
526 except that it doesn't special-case lines starting with 'import'.
527 A *.pkg file is trusted at face value: apart from checking for
528 duplicates, all entries found in a *.pkg file are added to the
529 path, regardless of whether they are exist the filesystem. (This
530 is a feature.)
531
532 If the input path is not a list (as is the case for frozen
533 packages) it is returned unchanged. The input path is not
534 modified; an extended copy is returned. Items are only appended
535 to the copy at the end.
536
537 It is assumed that sys.path is a sequence. Items of sys.path that
538 are not (unicode or 8-bit) strings referring to existing
539 directories are ignored. Unicode items of sys.path that cause
540 errors when used as filenames may cause this function to raise an
541 exception (in line with os.path.isdir() behavior).
542 """
543
544 if not isinstance(path, list):
545 # This could happen e.g. when this is called from inside a
546 # frozen package. Return the path unchanged in that case.
547 return path
548
Skip Montanaro7a98be22007-08-16 14:35:24 +0000549 sname_pkg = name + ".pkg"
Guido van Rossuma4deda02002-12-23 16:30:00 +0000550
551 path = path[:] # Start with a copy of the existing path
552
Antoine Pitroub2dd8802012-07-09 21:23:58 +0200553 parent_package, _, final_name = name.rpartition('.')
554 if parent_package:
555 try:
556 search_path = sys.modules[parent_package].__path__
557 except (KeyError, AttributeError):
558 # We can't do anything: find_loader() returns None when
559 # passed a dotted name.
560 return path
561 else:
562 search_path = sys.path
563
564 for dir in search_path:
Eric V. Smith984b11f2012-05-24 20:21:04 -0400565 if not isinstance(dir, str):
Guido van Rossuma4deda02002-12-23 16:30:00 +0000566 continue
Eric V. Smith984b11f2012-05-24 20:21:04 -0400567
568 finder = get_importer(dir)
569 if finder is not None:
570 # Is this finder PEP 420 compliant?
571 if hasattr(finder, 'find_loader'):
Antoine Pitroub2dd8802012-07-09 21:23:58 +0200572 loader, portions = finder.find_loader(final_name)
Eric V. Smith984b11f2012-05-24 20:21:04 -0400573 else:
574 # No, no need to call it
575 loader = None
576 portions = []
577
578 for portion in portions:
579 # XXX This may still add duplicate entries to path on
580 # case-insensitive filesystems
581 if portion not in path:
582 path.append(portion)
583
Guido van Rossuma4deda02002-12-23 16:30:00 +0000584 # XXX Is this the right thing for subpackages like zope.app?
585 # It looks for a file named "zope.app.pkg"
586 pkgfile = os.path.join(dir, sname_pkg)
587 if os.path.isfile(pkgfile):
588 try:
589 f = open(pkgfile)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200590 except OSError as msg:
Guido van Rossuma4deda02002-12-23 16:30:00 +0000591 sys.stderr.write("Can't open %s: %s\n" %
592 (pkgfile, msg))
593 else:
594 for line in f:
595 line = line.rstrip('\n')
596 if not line or line.startswith('#'):
597 continue
598 path.append(line) # Don't check for existence!
599 f.close()
600
601 return path
Christian Heimesdae2a892008-04-19 00:55:37 +0000602
603def get_data(package, resource):
604 """Get a resource from a package.
605
606 This is a wrapper round the PEP 302 loader get_data API. The package
607 argument should be the name of a package, in standard module format
608 (foo.bar). The resource argument should be in the form of a relative
609 filename, using '/' as the path separator. The parent directory name '..'
610 is not allowed, and nor is a rooted name (starting with a '/').
611
612 The function returns a binary string, which is the contents of the
613 specified resource.
614
615 For packages located in the filesystem, which have already been imported,
616 this is the rough equivalent of
617
618 d = os.path.dirname(sys.modules[package].__file__)
619 data = open(os.path.join(d, resource), 'rb').read()
620
621 If the package cannot be located or loaded, or it uses a PEP 302 loader
622 which does not support get_data(), then None is returned.
623 """
624
625 loader = get_loader(package)
626 if loader is None or not hasattr(loader, 'get_data'):
627 return None
628 mod = sys.modules.get(package) or loader.load_module(package)
629 if mod is None or not hasattr(mod, '__file__'):
630 return None
631
632 # Modify the resource name to be compatible with the loader.get_data
633 # signature - an os.path format "filename" starting with the dirname of
634 # the package's __file__
635 parts = resource.split('/')
636 parts.insert(0, os.path.dirname(mod.__file__))
637 resource_name = os.path.join(*parts)
638 return loader.get_data(resource_name)