blob: c178e3ab9a0011c7cb93e99c8ec1923039b6099b [file] [log] [blame]
Tor Norbye3a2425a52013-11-04 10:16:08 -08001import 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)