blob: 20e64989427aeff891aa8024dfda02745117375b [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
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000124 for item in walk_packages(path, name+'.', onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000125 yield item
126
127
128def iter_modules(path=None, prefix=''):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000129 """Yields (module_loader, name, ispkg) for all submodules on path,
130 or, if path is None, all top-level modules on sys.path.
131
132 'path' should be either None or a list of paths to look for
133 modules in.
134
135 'prefix' is a string to output on the front of every module name
136 on output.
137 """
138
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000139 if path is None:
140 importers = iter_importers()
141 else:
142 importers = map(get_importer, path)
143
144 yielded = {}
145 for i in importers:
146 for name, ispkg in iter_importer_modules(i, prefix):
147 if name not in yielded:
148 yielded[name] = 1
149 yield i, name, ispkg
150
151
152#@simplegeneric
153def iter_importer_modules(importer, prefix=''):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000154 if not hasattr(importer, 'iter_modules'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000155 return []
156 return importer.iter_modules(prefix)
157
158iter_importer_modules = simplegeneric(iter_importer_modules)
159
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000160# Implement a file walker for the normal importlib path hook
161def _iter_file_finder_modules(importer, prefix=''):
162 if importer.path is None or not os.path.isdir(importer.path):
163 return
164
165 yielded = {}
166 import inspect
167 try:
168 filenames = os.listdir(importer.path)
169 except OSError:
170 # ignore unreadable directories like import does
171 filenames = []
172 filenames.sort() # handle packages before same-named modules
173
174 for fn in filenames:
175 modname = inspect.getmodulename(fn)
176 if modname=='__init__' or modname in yielded:
177 continue
178
179 path = os.path.join(importer.path, fn)
180 ispkg = False
181
182 if not modname and os.path.isdir(path) and '.' not in fn:
183 modname = fn
184 try:
185 dircontents = os.listdir(path)
186 except OSError:
187 # ignore unreadable directories like import does
188 dircontents = []
189 for fn in dircontents:
190 subname = inspect.getmodulename(fn)
191 if subname=='__init__':
192 ispkg = True
193 break
194 else:
195 continue # not a package
196
197 if modname and '.' not in modname:
198 yielded[modname] = 1
199 yield prefix + modname, ispkg
200
201iter_importer_modules.register(
202 importlib.machinery.FileFinder, _iter_file_finder_modules)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000203
204class ImpImporter:
205 """PEP 302 Importer that wraps Python's "classic" import algorithm
206
207 ImpImporter(dirname) produces a PEP 302 importer that searches that
208 directory. ImpImporter(None) produces a PEP 302 importer that searches
209 the current sys.path, plus any modules that are frozen or built-in.
210
211 Note that ImpImporter does not currently support being used by placement
212 on sys.meta_path.
213 """
214
215 def __init__(self, path=None):
Nick Coghlan85e729e2012-07-15 18:09:52 +1000216 warn("This emulation is deprecated, use 'importlib' instead",
217 DeprecationWarning)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000218 self.path = path
219
220 def find_module(self, fullname, path=None):
221 # Note: we ignore 'path' argument since it is only used via meta_path
222 subname = fullname.split(".")[-1]
223 if subname != fullname and self.path is None:
224 return None
225 if self.path is None:
226 path = None
227 else:
228 path = [os.path.realpath(self.path)]
229 try:
230 file, filename, etc = imp.find_module(subname, path)
231 except ImportError:
232 return None
233 return ImpLoader(fullname, file, filename, etc)
234
235 def iter_modules(self, prefix=''):
236 if self.path is None or not os.path.isdir(self.path):
237 return
238
239 yielded = {}
240 import inspect
Ned Deilyed27df72011-10-06 14:19:08 -0700241 try:
242 filenames = os.listdir(self.path)
243 except OSError:
244 # ignore unreadable directories like import does
245 filenames = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000246 filenames.sort() # handle packages before same-named modules
247
248 for fn in filenames:
249 modname = inspect.getmodulename(fn)
250 if modname=='__init__' or modname in yielded:
251 continue
252
253 path = os.path.join(self.path, fn)
254 ispkg = False
255
256 if not modname and os.path.isdir(path) and '.' not in fn:
257 modname = fn
Ned Deilyed27df72011-10-06 14:19:08 -0700258 try:
259 dircontents = os.listdir(path)
260 except OSError:
261 # ignore unreadable directories like import does
262 dircontents = []
263 for fn in dircontents:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000264 subname = inspect.getmodulename(fn)
265 if subname=='__init__':
266 ispkg = True
267 break
268 else:
269 continue # not a package
270
271 if modname and '.' not in modname:
272 yielded[modname] = 1
273 yield prefix + modname, ispkg
274
275
276class ImpLoader:
277 """PEP 302 Loader that wraps Python's "classic" import algorithm
278 """
279 code = source = None
280
281 def __init__(self, fullname, file, filename, etc):
Nick Coghlan85e729e2012-07-15 18:09:52 +1000282 warn("This emulation is deprecated, use 'importlib' instead",
283 DeprecationWarning)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000284 self.file = file
285 self.filename = filename
286 self.fullname = fullname
287 self.etc = etc
288
289 def load_module(self, fullname):
290 self._reopen()
291 try:
292 mod = imp.load_module(fullname, self.file, self.filename, self.etc)
293 finally:
294 if self.file:
295 self.file.close()
296 # Note: we don't set __loader__ because we want the module to look
297 # normal; i.e. this is just a wrapper for standard import machinery
298 return mod
299
300 def get_data(self, pathname):
Brett Cannon1ab58df2010-10-29 22:36:53 +0000301 with open(pathname, "rb") as file:
302 return file.read()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000303
304 def _reopen(self):
305 if self.file and self.file.closed:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000306 mod_type = self.etc[2]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000307 if mod_type==imp.PY_SOURCE:
Victor Stinner4e86d5b2011-05-04 13:55:36 +0200308 self.file = open(self.filename, 'r')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000309 elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
310 self.file = open(self.filename, 'rb')
311
312 def _fix_name(self, fullname):
313 if fullname is None:
314 fullname = self.fullname
315 elif fullname != self.fullname:
316 raise ImportError("Loader for module %s cannot handle "
317 "module %s" % (self.fullname, fullname))
318 return fullname
319
320 def is_package(self, fullname):
321 fullname = self._fix_name(fullname)
322 return self.etc[2]==imp.PKG_DIRECTORY
323
324 def get_code(self, fullname=None):
325 fullname = self._fix_name(fullname)
326 if self.code is None:
327 mod_type = self.etc[2]
328 if mod_type==imp.PY_SOURCE:
329 source = self.get_source(fullname)
330 self.code = compile(source, self.filename, 'exec')
331 elif mod_type==imp.PY_COMPILED:
332 self._reopen()
333 try:
334 self.code = read_code(self.file)
335 finally:
336 self.file.close()
337 elif mod_type==imp.PKG_DIRECTORY:
338 self.code = self._get_delegate().get_code()
339 return self.code
340
341 def get_source(self, fullname=None):
342 fullname = self._fix_name(fullname)
343 if self.source is None:
344 mod_type = self.etc[2]
345 if mod_type==imp.PY_SOURCE:
346 self._reopen()
347 try:
348 self.source = self.file.read()
349 finally:
350 self.file.close()
351 elif mod_type==imp.PY_COMPILED:
352 if os.path.exists(self.filename[:-1]):
Victor Stinner4e86d5b2011-05-04 13:55:36 +0200353 f = open(self.filename[:-1], 'r')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000354 self.source = f.read()
355 f.close()
356 elif mod_type==imp.PKG_DIRECTORY:
357 self.source = self._get_delegate().get_source()
358 return self.source
359
360
361 def _get_delegate(self):
362 return ImpImporter(self.filename).find_module('__init__')
363
364 def get_filename(self, fullname=None):
365 fullname = self._fix_name(fullname)
366 mod_type = self.etc[2]
Éric Araujo0cfb81d2011-09-17 03:35:57 +0200367 if mod_type==imp.PKG_DIRECTORY:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000368 return self._get_delegate().get_filename()
Éric Araujo0cfb81d2011-09-17 03:35:57 +0200369 elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000370 return self.filename
371 return None
372
373
374try:
375 import zipimport
376 from zipimport import zipimporter
377
378 def iter_zipimport_modules(importer, prefix=''):
Alexandre Vassalotti515a74f2009-07-05 06:42:44 +0000379 dirlist = sorted(zipimport._zip_directory_cache[importer.archive])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000380 _prefix = importer.prefix
381 plen = len(_prefix)
382 yielded = {}
383 import inspect
384 for fn in dirlist:
385 if not fn.startswith(_prefix):
386 continue
387
388 fn = fn[plen:].split(os.sep)
389
390 if len(fn)==2 and fn[1].startswith('__init__.py'):
391 if fn[0] not in yielded:
392 yielded[fn[0]] = 1
393 yield fn[0], True
394
395 if len(fn)!=1:
396 continue
397
398 modname = inspect.getmodulename(fn[0])
399 if modname=='__init__':
400 continue
401
402 if modname and '.' not in modname and modname not in yielded:
403 yielded[modname] = 1
404 yield prefix + modname, False
405
406 iter_importer_modules.register(zipimporter, iter_zipimport_modules)
407
408except ImportError:
409 pass
410
411
412def get_importer(path_item):
413 """Retrieve a PEP 302 importer for the given path item
414
415 The returned importer is cached in sys.path_importer_cache
416 if it was newly created by a path hook.
417
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000418 The cache (or part of it) can be cleared manually if a
419 rescan of sys.path_hooks is necessary.
420 """
421 try:
422 importer = sys.path_importer_cache[path_item]
423 except KeyError:
424 for path_hook in sys.path_hooks:
425 try:
426 importer = path_hook(path_item)
Brett Cannone0d88a12012-04-25 20:54:04 -0400427 sys.path_importer_cache.setdefault(path_item, importer)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000428 break
429 except ImportError:
430 pass
431 else:
Nick Coghlan85e729e2012-07-15 18:09:52 +1000432 importer = None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000433 return importer
434
435
436def iter_importers(fullname=""):
437 """Yield PEP 302 importers for the given module name
438
439 If fullname contains a '.', the importers will be for the package
Nick Coghlan85e729e2012-07-15 18:09:52 +1000440 containing fullname, otherwise they will be all registered top level
441 importers (i.e. those on both sys.meta_path and sys.path_hooks).
442
443 If the named module is in a package, that package is imported as a side
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000444 effect of invoking this function.
445
Nick Coghlan85e729e2012-07-15 18:09:52 +1000446 If no module name is specified, all top level importers are produced.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000447 """
448 if fullname.startswith('.'):
Nick Coghlan85e729e2012-07-15 18:09:52 +1000449 msg = "Relative module name {!r} not supported".format(fullname)
450 raise ImportError(msg)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000451 if '.' in fullname:
452 # Get the containing package's __path__
Nick Coghlan85e729e2012-07-15 18:09:52 +1000453 pkg_name = fullname.rpartition(".")[0]
Nick Coghlanc4e0d982013-04-14 22:30:42 +1000454 pkg = importlib.import_module(pkg_name)
455 path = getattr(pkg, '__path__', None)
Nick Coghlan85e729e2012-07-15 18:09:52 +1000456 if path is None:
457 return
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000458 else:
459 for importer in sys.meta_path:
460 yield importer
461 path = sys.path
462 for item in path:
463 yield get_importer(item)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000464
465def get_loader(module_or_name):
466 """Get a PEP 302 "loader" object for module_or_name
467
Nick Coghlan85e729e2012-07-15 18:09:52 +1000468 Returns None if the module cannot be found or imported.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000469 If the named module is not already imported, its containing package
470 (if any) is imported, in order to establish the package __path__.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000471 """
472 if module_or_name in sys.modules:
473 module_or_name = sys.modules[module_or_name]
474 if isinstance(module_or_name, ModuleType):
475 module = module_or_name
Thomas Wouters477c8d52006-05-27 19:21:47 +0000476 loader = getattr(module, '__loader__', None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000477 if loader is not None:
478 return loader
479 fullname = module.__name__
480 else:
481 fullname = module_or_name
482 return find_loader(fullname)
483
Nick Coghlan85e729e2012-07-15 18:09:52 +1000484
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000485def find_loader(fullname):
486 """Find a PEP 302 "loader" object for fullname
487
Nick Coghlan85e729e2012-07-15 18:09:52 +1000488 This is s convenience wrapper around :func:`importlib.find_loader` that
489 sets the *path* argument correctly when searching for submodules, and
490 also ensures parent packages (if any) are imported before searching for
491 submodules.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000492 """
Nick Coghlan85e729e2012-07-15 18:09:52 +1000493 if fullname.startswith('.'):
494 msg = "Relative module name {!r} not supported".format(fullname)
495 raise ImportError(msg)
496 path = None
497 pkg_name = fullname.rpartition(".")[0]
498 if pkg_name:
499 pkg = importlib.import_module(pkg_name)
500 path = getattr(pkg, "__path__", None)
501 if path is None:
502 return None
503 try:
504 return importlib.find_loader(fullname, path)
505 except (ImportError, AttributeError, TypeError, ValueError) as ex:
506 # This hack fixes an impedance mismatch between pkgutil and
Andrew Svetlov5b898402012-12-18 21:26:36 +0200507 # importlib, where the latter raises other errors for cases where
Andrew Svetlov1f415cf2012-12-19 22:54:47 +0200508 # pkgutil previously raised ImportError
Nick Coghlan85e729e2012-07-15 18:09:52 +1000509 msg = "Error while finding loader for {!r} ({}: {})"
510 raise ImportError(msg.format(fullname, type(ex), ex)) from ex
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000511
Guido van Rossuma4deda02002-12-23 16:30:00 +0000512
513def extend_path(path, name):
514 """Extend a package's path.
515
516 Intended use is to place the following code in a package's __init__.py:
517
518 from pkgutil import extend_path
519 __path__ = extend_path(__path__, __name__)
520
521 This will add to the package's __path__ all subdirectories of
522 directories on sys.path named after the package. This is useful
523 if one wants to distribute different parts of a single logical
524 package as multiple directories.
525
526 It also looks for *.pkg files beginning where * matches the name
527 argument. This feature is similar to *.pth files (see site.py),
528 except that it doesn't special-case lines starting with 'import'.
529 A *.pkg file is trusted at face value: apart from checking for
530 duplicates, all entries found in a *.pkg file are added to the
531 path, regardless of whether they are exist the filesystem. (This
532 is a feature.)
533
534 If the input path is not a list (as is the case for frozen
535 packages) it is returned unchanged. The input path is not
536 modified; an extended copy is returned. Items are only appended
537 to the copy at the end.
538
539 It is assumed that sys.path is a sequence. Items of sys.path that
540 are not (unicode or 8-bit) strings referring to existing
541 directories are ignored. Unicode items of sys.path that cause
542 errors when used as filenames may cause this function to raise an
543 exception (in line with os.path.isdir() behavior).
544 """
545
546 if not isinstance(path, list):
547 # This could happen e.g. when this is called from inside a
548 # frozen package. Return the path unchanged in that case.
549 return path
550
Skip Montanaro7a98be22007-08-16 14:35:24 +0000551 sname_pkg = name + ".pkg"
Guido van Rossuma4deda02002-12-23 16:30:00 +0000552
553 path = path[:] # Start with a copy of the existing path
554
Antoine Pitroub2dd8802012-07-09 21:23:58 +0200555 parent_package, _, final_name = name.rpartition('.')
556 if parent_package:
557 try:
558 search_path = sys.modules[parent_package].__path__
559 except (KeyError, AttributeError):
560 # We can't do anything: find_loader() returns None when
561 # passed a dotted name.
562 return path
563 else:
564 search_path = sys.path
565
566 for dir in search_path:
Eric V. Smith984b11f2012-05-24 20:21:04 -0400567 if not isinstance(dir, str):
Guido van Rossuma4deda02002-12-23 16:30:00 +0000568 continue
Eric V. Smith984b11f2012-05-24 20:21:04 -0400569
570 finder = get_importer(dir)
571 if finder is not None:
572 # Is this finder PEP 420 compliant?
573 if hasattr(finder, 'find_loader'):
Antoine Pitroub2dd8802012-07-09 21:23:58 +0200574 loader, portions = finder.find_loader(final_name)
Eric V. Smith984b11f2012-05-24 20:21:04 -0400575 else:
576 # No, no need to call it
577 loader = None
578 portions = []
579
580 for portion in portions:
581 # XXX This may still add duplicate entries to path on
582 # case-insensitive filesystems
583 if portion not in path:
584 path.append(portion)
585
Guido van Rossuma4deda02002-12-23 16:30:00 +0000586 # XXX Is this the right thing for subpackages like zope.app?
587 # It looks for a file named "zope.app.pkg"
588 pkgfile = os.path.join(dir, sname_pkg)
589 if os.path.isfile(pkgfile):
590 try:
591 f = open(pkgfile)
Guido van Rossumb940e112007-01-10 16:19:56 +0000592 except IOError as msg:
Guido van Rossuma4deda02002-12-23 16:30:00 +0000593 sys.stderr.write("Can't open %s: %s\n" %
594 (pkgfile, msg))
595 else:
596 for line in f:
597 line = line.rstrip('\n')
598 if not line or line.startswith('#'):
599 continue
600 path.append(line) # Don't check for existence!
601 f.close()
602
603 return path
Christian Heimesdae2a892008-04-19 00:55:37 +0000604
605def get_data(package, resource):
606 """Get a resource from a package.
607
608 This is a wrapper round the PEP 302 loader get_data API. The package
609 argument should be the name of a package, in standard module format
610 (foo.bar). The resource argument should be in the form of a relative
611 filename, using '/' as the path separator. The parent directory name '..'
612 is not allowed, and nor is a rooted name (starting with a '/').
613
614 The function returns a binary string, which is the contents of the
615 specified resource.
616
617 For packages located in the filesystem, which have already been imported,
618 this is the rough equivalent of
619
620 d = os.path.dirname(sys.modules[package].__file__)
621 data = open(os.path.join(d, resource), 'rb').read()
622
623 If the package cannot be located or loaded, or it uses a PEP 302 loader
624 which does not support get_data(), then None is returned.
625 """
626
627 loader = get_loader(package)
628 if loader is None or not hasattr(loader, 'get_data'):
629 return None
630 mod = sys.modules.get(package) or loader.load_module(package)
631 if mod is None or not hasattr(mod, '__file__'):
632 return None
633
634 # Modify the resource name to be compatible with the loader.get_data
635 # signature - an os.path format "filename" starting with the dirname of
636 # the package's __file__
637 parts = resource.split('/')
638 parts.insert(0, os.path.dirname(mod.__file__))
639 resource_name = os.path.join(*parts)
640 return loader.get_data(resource_name)