1import sys
2from types import ModuleType
3import os, imp
4class ImpLoader:
5  code = source = None
6
7  def __init__(self, fullname, file, filename, etc):
8    self.file = file
9    self.filename = filename
10    self.fullname = fullname
11    self.etc = etc
12
13  def load_module(self, fullname):
14    self._reopen()
15    try:
16      mod = imp.load_module(fullname, self.file, self.filename, self.etc)
17    finally:
18      if self.file:
19        self.file.close()
20    return mod
21
22  def get_data(self, pathname):
23    return open(pathname, "rb").read()
24
25  def _reopen(self):
26    if self.file and self.file.closed:
27      mod_type = self.etc[2]
28      if mod_type==imp.PY_SOURCE:
29        self.file = open(self.filename, 'rU')
30      elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
31        self.file = open(self.filename, 'rb')
32
33  def _fix_name(self, fullname):
34    if fullname is None:
35      fullname = self.fullname
36    elif fullname != self.fullname:
37      raise ImportError("Loader for module %s cannot handle "
38                          "module %s" % (self.fullname, fullname))
39    return fullname
40
41  def is_package(self, fullname):
42    fullname = self._fix_name(fullname)
43    return self.etc[2]==imp.PKG_DIRECTORY
44
45  def get_code(self, fullname=None):
46    fullname = self._fix_name(fullname)
47    if self.code is None:
48      mod_type = self.etc[2]
49      if mod_type==imp.PY_SOURCE:
50        source = self.get_source(fullname)
51        self.code = compile(source, self.filename, 'exec')
52      elif mod_type==imp.PY_COMPILED:
53        self._reopen()
54        try:
55          self.code = read_code(self.file)
56        finally:
57          self.file.close()
58      elif mod_type==imp.PKG_DIRECTORY:
59        self.code = self._get_delegate().get_code()
60    return self.code
61
62  def get_source(self, fullname=None):
63    fullname = self._fix_name(fullname)
64    if self.source is None:
65      mod_type = self.etc[2]
66      if mod_type==imp.PY_SOURCE:
67        self._reopen()
68        try:
69          self.source = self.file.read()
70        finally:
71          self.file.close()
72      elif mod_type==imp.PY_COMPILED:
73        if os.path.exists(self.filename[:-1]):
74          f = open(self.filename[:-1], 'rU')
75          self.source = f.read()
76          f.close()
77      elif mod_type==imp.PKG_DIRECTORY:
78        self.source = self._get_delegate().get_source()
79    return self.source
80
81
82  def _get_delegate(self):
83    return ImpImporter(self.filename).find_module('__init__')
84
85  def get_filename(self, fullname=None):
86    fullname = self._fix_name(fullname)
87    mod_type = self.etc[2]
88    if self.etc[2]==imp.PKG_DIRECTORY:
89        return self._get_delegate().get_filename()
90    elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
91        return self.filename
92    return None
93
94
95class ImpImporter:
96  def __init__(self, path=None):
97    self.path = path
98
99  def find_module(self, fullname, path=None):
100    # Note: we ignore 'path' argument since it is only used via meta_path
101    subname = fullname.split(".")[-1]
102    if subname != fullname and self.path is None:
103      return None
104    if self.path is None:
105      path = None
106    else:
107      path = [os.path.realpath(self.path)]
108    try:
109      file, filename, etc = imp.find_module(subname, path)
110    except ImportError:
111      return None
112    return ImpLoader(fullname, file, filename, etc)
113
114  def iter_modules(self, prefix=''):
115    if self.path is None or not os.path.isdir(self.path):
116      return
117
118    yielded = {}
119    import inspect
120
121    filenames = os.listdir(self.path)
122    filenames.sort()  # handle packages before same-named modules
123
124    for fn in filenames:
125      modname = inspect.getmodulename(fn)
126      if modname=='__init__' or modname in yielded:
127        continue
128
129      path = os.path.join(self.path, fn)
130      ispkg = False
131
132      if not modname and os.path.isdir(path) and '.' not in fn:
133        modname = fn
134        for fn in os.listdir(path):
135          subname = inspect.getmodulename(fn)
136          if subname=='__init__':
137            ispkg = True
138            break
139        else:
140          continue    # not a package
141
142      if modname and '.' not in modname:
143        yielded[modname] = 1
144        yield prefix + modname, ispkg
145
146def get_importer(path_item):
147  try:
148    importer = sys.path_importer_cache[path_item]
149  except KeyError:
150    for path_hook in sys.path_hooks:
151      try:
152        importer = path_hook(path_item)
153        break
154      except ImportError:
155        pass
156    else:
157      importer = None
158    sys.path_importer_cache.setdefault(path_item, importer)
159
160  if importer is None:
161    try:
162      importer = ImpImporter(path_item)
163    except ImportError:
164      importer = None
165  return importer
166
167def iter_importers(fullname=""):
168  if fullname.startswith('.'):
169    raise ImportError("Relative module names not supported")
170  if '.' in fullname:
171    # Get the containing package's __path__
172    pkg = '.'.join(fullname.split('.')[:-1])
173    if pkg not in sys.modules:
174      __import__(pkg)
175    path = getattr(sys.modules[pkg], '__path__', None) or []
176  else:
177    for importer in sys.meta_path:
178      yield importer
179    path = sys.path
180  for item in path:
181    yield get_importer(item)
182  if '.' not in fullname:
183    yield ImpImporter()
184
185def find_loader(fullname):
186  for importer in iter_importers(fullname):
187    loader = importer.find_module(fullname)
188    if loader is not None:
189      return loader
190
191  return None
192
193def get_loader(module_or_name):
194  if module_or_name in sys.modules:
195    module_or_name = sys.modules[module_or_name]
196  if isinstance(module_or_name, ModuleType):
197    module = module_or_name
198    loader = getattr(module, '__loader__', None)
199    if loader is not None:
200      return loader
201    fullname = module.__name__
202  else:
203    fullname = module_or_name
204  return find_loader(fullname)
205
206
207def _get_filename(loader, mod_name):
208  for attr in ("get_filename", "_get_filename"):
209    meth = getattr(loader, attr, None)
210    if meth is not None:
211      return meth(mod_name)
212  return None
213
214def _get_module_details(mod_name):
215  loader = get_loader(mod_name)
216  if loader is None:
217    raise ImportError("No module named %s" % mod_name)
218  if loader.is_package(mod_name):
219    if mod_name == "__main__" or mod_name.endswith(".__main__"):
220      raise ImportError("Cannot use package as __main__ module")
221    try:
222      pkg_main_name = mod_name + ".__main__"
223      return _get_module_details(pkg_main_name)
224    except ImportError, e:
225      raise ImportError(("%s; %r is a package and cannot " +
226                           "be directly executed") %(e, mod_name))
227  code = loader.get_code(mod_name)
228  if code is None:
229    raise ImportError("No code object available for %s" % mod_name)
230  filename = _get_filename(loader, mod_name)
231  return mod_name, loader, code, filename
232
233def _run_code(code, run_globals, init_globals=None,
234              mod_name=None, mod_fname=None,
235              mod_loader=None, pkg_name=None):
236  if init_globals is not None:
237      run_globals.update(init_globals)
238  run_globals.update(__name__ = mod_name,
239                     __file__ = mod_fname,
240                     __loader__ = mod_loader,
241                     __package__ = pkg_name)
242  exec code in run_globals
243  return run_globals
244
245def run_module(mod_name, init_globals=None,
246               run_name=None):
247  mod_name, loader, code, fname = _get_module_details(mod_name)
248  if run_name is None:
249    run_name = mod_name
250
251  ind = mod_name.rfind(".")
252  if ind != -1:
253    pkg_name = mod_name[:ind]
254  else:
255    pkg_name = mod_name
256  return _run_code(code, {}, init_globals, run_name,
257                       fname, loader, pkg_name)