blob: afb00982923dc989f35aa1afe00f9294fd1c7952 [file] [log] [blame]
Thomas Woutersa9773292006-04-21 09:43:23 +00001"""runpy.py - locating and running Python code using the module namespace
2
3Provides support for locating and running Python scripts using the Python
4module namespace instead of the native filesystem.
5
6This allows Python code to play nicely with non-filesystem based PEP 302
7importers when locating support scripts as well as when importing modules.
8"""
9# Written by Nick Coghlan <ncoghlan at gmail.com>
10# to implement PEP 338 (Executing Modules as Scripts)
11
12import sys
13import imp
14
15__all__ = [
16 "run_module",
17]
18
19try:
20 _get_loader = imp.get_loader
21except AttributeError:
22 # get_loader() is not provided by the imp module, so emulate it
23 # as best we can using the PEP 302 import machinery exposed since
24 # Python 2.3. The emulation isn't perfect, but the differences
25 # in the way names are shadowed shouldn't matter in practice.
26 import os.path
27 import marshal # Handle compiled Python files
28
29 # This helper is needed in order for the PEP 302 emulation to
30 # correctly handle compiled files
31 def _read_compiled_file(compiled_file):
32 magic = compiled_file.read(4)
33 if magic != imp.get_magic():
34 return None
35 try:
36 compiled_file.read(4) # Skip timestamp
37 return marshal.load(compiled_file)
38 except Exception:
39 return None
40
41 class _AbsoluteImporter(object):
42 """PEP 302 importer wrapper for top level import machinery"""
43 def find_module(self, mod_name, path=None):
44 if path is not None:
45 return None
46 try:
47 file, filename, mod_info = imp.find_module(mod_name)
48 except ImportError:
49 return None
50 suffix, mode, mod_type = mod_info
51 if mod_type == imp.PY_SOURCE:
52 loader = _SourceFileLoader(mod_name, file,
53 filename, mod_info)
54 elif mod_type == imp.PY_COMPILED:
55 loader = _CompiledFileLoader(mod_name, file,
56 filename, mod_info)
57 elif mod_type == imp.PKG_DIRECTORY:
58 loader = _PackageDirLoader(mod_name, file,
59 filename, mod_info)
60 elif mod_type == imp.C_EXTENSION:
61 loader = _FileSystemLoader(mod_name, file,
62 filename, mod_info)
63 else:
64 loader = _BasicLoader(mod_name, file,
65 filename, mod_info)
66 return loader
67
68
69 class _FileSystemImporter(object):
70 """PEP 302 importer wrapper for filesystem based imports"""
71 def __init__(self, path_item=None):
72 if path_item is not None:
73 if path_item != '' and not os.path.isdir(path_item):
74 raise ImportError("%s is not a directory" % path_item)
75 self.path_dir = path_item
76 else:
77 raise ImportError("Filesystem importer requires "
78 "a directory name")
79
80 def find_module(self, mod_name, path=None):
81 if path is not None:
82 return None
83 path_dir = self.path_dir
84 if path_dir == '':
85 path_dir = os.getcwd()
86 sub_name = mod_name.rsplit(".", 1)[-1]
87 try:
88 file, filename, mod_info = imp.find_module(sub_name,
89 [path_dir])
90 except ImportError:
91 return None
92 if not filename.startswith(path_dir):
93 return None
94 suffix, mode, mod_type = mod_info
95 if mod_type == imp.PY_SOURCE:
96 loader = _SourceFileLoader(mod_name, file,
97 filename, mod_info)
98 elif mod_type == imp.PY_COMPILED:
99 loader = _CompiledFileLoader(mod_name, file,
100 filename, mod_info)
101 elif mod_type == imp.PKG_DIRECTORY:
102 loader = _PackageDirLoader(mod_name, file,
103 filename, mod_info)
104 elif mod_type == imp.C_EXTENSION:
105 loader = _FileSystemLoader(mod_name, file,
106 filename, mod_info)
107 else:
108 loader = _BasicLoader(mod_name, file,
109 filename, mod_info)
110 return loader
111
112
113 class _BasicLoader(object):
114 """PEP 302 loader wrapper for top level import machinery"""
115 def __init__(self, mod_name, file, filename, mod_info):
116 self.mod_name = mod_name
117 self.file = file
118 self.filename = filename
119 self.mod_info = mod_info
120
121 def _fix_name(self, mod_name):
122 if mod_name is None:
123 mod_name = self.mod_name
124 elif mod_name != self.mod_name:
125 raise ImportError("Loader for module %s cannot handle "
126 "module %s" % (self.mod_name, mod_name))
127 return mod_name
128
129 def load_module(self, mod_name=None):
130 mod_name = self._fix_name(mod_name)
131 mod = imp.load_module(mod_name, self.file,
132 self.filename, self.mod_info)
133 mod.__loader__ = self # for introspection
134 return mod
135
136 def get_code(self, mod_name=None):
137 return None
138
139 def get_source(self, mod_name=None):
140 return None
141
142 def is_package(self, mod_name=None):
143 return False
144
145 def close(self):
146 if self.file:
147 self.file.close()
148
149 def __del__(self):
150 self.close()
151
152
153 class _FileSystemLoader(_BasicLoader):
154 """PEP 302 loader wrapper for filesystem based imports"""
155 def get_code(self, mod_name=None):
156 mod_name = self._fix_name(mod_name)
157 return self._get_code(mod_name)
158
159 def get_data(self, pathname):
160 return open(pathname, "rb").read()
161
162 def get_filename(self, mod_name=None):
163 mod_name = self._fix_name(mod_name)
164 return self._get_filename(mod_name)
165
166 def get_source(self, mod_name=None):
167 mod_name = self._fix_name(mod_name)
168 return self._get_source(mod_name)
169
170 def is_package(self, mod_name=None):
171 mod_name = self._fix_name(mod_name)
172 return self._is_package(mod_name)
173
174 def _get_code(self, mod_name):
175 return None
176
177 def _get_filename(self, mod_name):
178 return self.filename
179
180 def _get_source(self, mod_name):
181 return None
182
183 def _is_package(self, mod_name):
184 return False
185
186 class _PackageDirLoader(_FileSystemLoader):
187 """PEP 302 loader wrapper for PKG_DIRECTORY directories"""
188 def _is_package(self, mod_name):
189 return True
190
191
192 class _SourceFileLoader(_FileSystemLoader):
193 """PEP 302 loader wrapper for PY_SOURCE modules"""
194 def _get_code(self, mod_name):
195 return compile(self._get_source(mod_name),
196 self.filename, 'exec')
197
198 def _get_source(self, mod_name):
199 f = self.file
200 f.seek(0)
201 return f.read()
202
203
204 class _CompiledFileLoader(_FileSystemLoader):
205 """PEP 302 loader wrapper for PY_COMPILED modules"""
206 def _get_code(self, mod_name):
207 f = self.file
208 f.seek(0)
209 return _read_compiled_file(f)
210
211
212 def _get_importer(path_item):
213 """Retrieve a PEP 302 importer for the given path item
214
215 The returned importer is cached in sys.path_importer_cache
216 if it was newly created by a path hook.
217
218 If there is no importer, a wrapper around the basic import
219 machinery is returned. This wrapper is never inserted into
220 the importer cache (None is inserted instead).
221
222 The cache (or part of it) can be cleared manually if a
223 rescan of sys.path_hooks is necessary.
224 """
225 try:
226 importer = sys.path_importer_cache[path_item]
227 except KeyError:
228 for path_hook in sys.path_hooks:
229 try:
230 importer = path_hook(path_item)
231 break
232 except ImportError:
233 pass
234 else:
235 importer = None
236 sys.path_importer_cache[path_item] = importer
237 if importer is None:
238 try:
239 importer = _FileSystemImporter(path_item)
240 except ImportError:
241 pass
242 return importer
243
244
245 def _get_path_loader(mod_name, path=None):
246 """Retrieve a PEP 302 loader using a path importer"""
247 if path is None:
248 path = sys.path
249 absolute_loader = _AbsoluteImporter().find_module(mod_name)
250 if isinstance(absolute_loader, _FileSystemLoader):
251 # Found in filesystem, so scan path hooks
252 # before accepting this one as the right one
253 loader = None
254 else:
255 # Not found in filesystem, so use top-level loader
256 loader = absolute_loader
257 else:
258 loader = absolute_loader = None
259 if loader is None:
260 for path_item in path:
261 importer = _get_importer(path_item)
262 if importer is not None:
263 loader = importer.find_module(mod_name)
264 if loader is not None:
265 # Found a loader for our module
266 break
267 else:
268 # No path hook found, so accept the top level loader
269 loader = absolute_loader
270 return loader
271
272 def _get_package(pkg_name):
273 """Retrieve a named package"""
274 pkg = __import__(pkg_name)
275 sub_pkg_names = pkg_name.split(".")
276 for sub_pkg in sub_pkg_names[1:]:
277 pkg = getattr(pkg, sub_pkg)
278 return pkg
279
280 def _get_loader(mod_name, path=None):
281 """Retrieve a PEP 302 loader for the given module or package
282
283 If the module or package is accessible via the normal import
284 mechanism, a wrapper around the relevant part of that machinery
285 is returned.
286
287 Non PEP 302 mechanisms (e.g. the Windows registry) used by the
288 standard import machinery to find files in alternative locations
289 are partially supported, but are searched AFTER sys.path. Normally,
290 these locations are searched BEFORE sys.path, preventing sys.path
291 entries from shadowing them.
292 For this to cause a visible difference in behaviour, there must
293 be a module or package name that is accessible via both sys.path
294 and one of the non PEP 302 file system mechanisms. In this case,
295 the emulation will find the former version, while the builtin
296 import mechanism will find the latter.
297 Items of the following types can be affected by this discrepancy:
298 imp.C_EXTENSION
299 imp.PY_SOURCE
300 imp.PY_COMPILED
301 imp.PKG_DIRECTORY
302 """
303 try:
304 loader = sys.modules[mod_name].__loader__
305 except (KeyError, AttributeError):
306 loader = None
307 if loader is None:
308 imp.acquire_lock()
309 try:
310 # Module not in sys.modules, or uses an unhooked loader
311 parts = mod_name.rsplit(".", 1)
312 if len(parts) == 2:
313 # Sub package, so use parent package's path
314 pkg_name, sub_name = parts
315 if pkg_name and pkg_name[0] != '.':
316 if path is not None:
317 raise ImportError("Path argument must be None "
318 "for a dotted module name")
319 pkg = _get_package(pkg_name)
320 try:
321 path = pkg.__path__
322 except AttributeError:
323 raise ImportError(pkg_name +
324 " is not a package")
325 else:
326 raise ImportError("Relative import syntax is not "
327 "supported by _get_loader()")
328 else:
329 # Top level module, so stick with default path
330 sub_name = mod_name
331
332 for importer in sys.meta_path:
333 loader = importer.find_module(mod_name, path)
334 if loader is not None:
335 # Found a metahook to handle the module
336 break
337 else:
338 # Handling via the standard path mechanism
339 loader = _get_path_loader(mod_name, path)
340 finally:
341 imp.release_lock()
342 return loader
343
344
345# This helper is needed due to a missing component in the PEP 302
346# loader protocol (specifically, "get_filename" is non-standard)
347def _get_filename(loader, mod_name):
348 try:
349 get_filename = loader.get_filename
350 except AttributeError:
351 return None
352 else:
353 return get_filename(mod_name)
354
355# ------------------------------------------------------------
356# Done with the import machinery emulation, on with the code!
357
358def _run_code(code, run_globals, init_globals,
359 mod_name, mod_fname, mod_loader):
360 """Helper for _run_module_code"""
361 if init_globals is not None:
362 run_globals.update(init_globals)
363 run_globals.update(__name__ = mod_name,
364 __file__ = mod_fname,
365 __loader__ = mod_loader)
366 exec code in run_globals
367 return run_globals
368
369def _run_module_code(code, init_globals=None,
370 mod_name=None, mod_fname=None,
371 mod_loader=None, alter_sys=False):
372 """Helper for run_module"""
373 # Set up the top level namespace dictionary
374 if alter_sys:
375 # Modify sys.argv[0] and sys.module[mod_name]
376 temp_module = imp.new_module(mod_name)
377 mod_globals = temp_module.__dict__
378 saved_argv0 = sys.argv[0]
379 restore_module = mod_name in sys.modules
380 if restore_module:
381 saved_module = sys.modules[mod_name]
382 imp.acquire_lock()
383 try:
384 sys.argv[0] = mod_fname
385 sys.modules[mod_name] = temp_module
386 try:
387 _run_code(code, mod_globals, init_globals,
388 mod_name, mod_fname, mod_loader)
389 finally:
390 sys.argv[0] = saved_argv0
391 if restore_module:
392 sys.modules[mod_name] = saved_module
393 else:
394 del sys.modules[mod_name]
395 finally:
396 imp.release_lock()
397 # Copy the globals of the temporary module, as they
398 # may be cleared when the temporary module goes away
399 return mod_globals.copy()
400 else:
401 # Leave the sys module alone
402 return _run_code(code, {}, init_globals,
403 mod_name, mod_fname, mod_loader)
404
405
406def run_module(mod_name, init_globals=None,
407 run_name=None, alter_sys=False):
408 """Execute a module's code without importing it
409
410 Returns the resulting top level namespace dictionary
411 """
412 loader = _get_loader(mod_name)
413 if loader is None:
414 raise ImportError("No module named " + mod_name)
415 code = loader.get_code(mod_name)
416 if code is None:
417 raise ImportError("No code object available for " + mod_name)
418 filename = _get_filename(loader, mod_name)
419 if run_name is None:
420 run_name = mod_name
421 return _run_module_code(code, init_globals, run_name,
422 filename, loader, alter_sys)
423
424
425if __name__ == "__main__":
426 # Run the module specified as the next command line argument
427 if len(sys.argv) < 2:
428 print >> sys.stderr, "No module specified for execution"
429 else:
430 del sys.argv[0] # Make the requested module sys.argv[0]
431 run_module(sys.argv[0], run_name="__main__", alter_sys=True)