2006-03-15 07:00:26 -04:00
|
|
|
"""runpy.py - locating and running Python code using the module namespace
|
|
|
|
|
|
|
|
Provides support for locating and running Python scripts using the Python
|
|
|
|
module namespace instead of the native filesystem.
|
|
|
|
|
|
|
|
This allows Python code to play nicely with non-filesystem based PEP 302
|
|
|
|
importers when locating support scripts as well as when importing modules.
|
|
|
|
"""
|
|
|
|
# Written by Nick Coghlan <ncoghlan at gmail.com>
|
|
|
|
# to implement PEP 338 (Executing Modules as Scripts)
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import imp
|
2009-11-15 03:30:34 -04:00
|
|
|
from pkgutil import read_code
|
First phase of refactoring for runpy, pkgutil, pydoc, and setuptools
to share common PEP 302 support code, as described here:
http://mail.python.org/pipermail/python-dev/2006-April/063724.html
This revision strips all the PEP 302 emulation code from runpy,
replacing it with published API classes and functions in pkgutil,
mostly using setuptools' implementation of common functionality,
but adding features from runpy, and doing some refactoring to make
the layer pydoc needs easier to implement on top of this.
One step down, four to go, although step #4 (adding C versions of
the new APIs to 'imp') may not be able to make it in time for
alpha 2. We'll see how that goes.
2006-04-17 17:17:25 -03:00
|
|
|
try:
|
|
|
|
from imp import get_loader
|
|
|
|
except ImportError:
|
|
|
|
from pkgutil import get_loader
|
2006-03-15 07:00:26 -04:00
|
|
|
|
|
|
|
__all__ = [
|
2009-11-15 03:30:34 -04:00
|
|
|
"run_module", "run_path",
|
2006-03-15 07:00:26 -04:00
|
|
|
]
|
|
|
|
|
2009-11-15 03:30:34 -04:00
|
|
|
class _TempModule(object):
|
|
|
|
"""Temporarily replace a module in sys.modules with an empty namespace"""
|
|
|
|
def __init__(self, mod_name):
|
|
|
|
self.mod_name = mod_name
|
|
|
|
self.module = imp.new_module(mod_name)
|
|
|
|
self._saved_module = []
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
mod_name = self.mod_name
|
|
|
|
try:
|
|
|
|
self._saved_module.append(sys.modules[mod_name])
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
sys.modules[mod_name] = self.module
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, *args):
|
|
|
|
if self._saved_module:
|
|
|
|
sys.modules[self.mod_name] = self._saved_module[0]
|
|
|
|
else:
|
|
|
|
del sys.modules[self.mod_name]
|
|
|
|
self._saved_module = []
|
|
|
|
|
|
|
|
class _ModifiedArgv0(object):
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = value
|
|
|
|
self._saved_value = self._sentinel = object()
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
if self._saved_value is not self._sentinel:
|
|
|
|
raise RuntimeError("Already preserving saved value")
|
|
|
|
self._saved_value = sys.argv[0]
|
|
|
|
sys.argv[0] = self.value
|
|
|
|
|
|
|
|
def __exit__(self, *args):
|
|
|
|
self.value = self._sentinel
|
|
|
|
sys.argv[0] = self._saved_value
|
2006-03-15 07:00:26 -04:00
|
|
|
|
2007-08-25 07:50:41 -03:00
|
|
|
def _run_code(code, run_globals, init_globals=None,
|
|
|
|
mod_name=None, mod_fname=None,
|
2007-12-03 08:55:17 -04:00
|
|
|
mod_loader=None, pkg_name=None):
|
2009-11-07 04:15:01 -04:00
|
|
|
"""Helper to run code in nominated namespace"""
|
2006-03-15 07:00:26 -04:00
|
|
|
if init_globals is not None:
|
|
|
|
run_globals.update(init_globals)
|
2006-07-06 09:53:04 -03:00
|
|
|
run_globals.update(__name__ = mod_name,
|
2006-03-15 07:00:26 -04:00
|
|
|
__file__ = mod_fname,
|
2007-12-03 08:55:17 -04:00
|
|
|
__loader__ = mod_loader,
|
|
|
|
__package__ = pkg_name)
|
2006-03-15 07:00:26 -04:00
|
|
|
exec code in run_globals
|
|
|
|
return run_globals
|
|
|
|
|
2006-07-06 09:53:04 -03:00
|
|
|
def _run_module_code(code, init_globals=None,
|
2007-08-25 01:32:07 -03:00
|
|
|
mod_name=None, mod_fname=None,
|
2007-12-03 08:55:17 -04:00
|
|
|
mod_loader=None, pkg_name=None):
|
2009-11-07 04:15:01 -04:00
|
|
|
"""Helper to run code in new namespace with sys modified"""
|
2009-11-15 03:30:34 -04:00
|
|
|
with _TempModule(mod_name) as temp_module, _ModifiedArgv0(mod_fname):
|
|
|
|
mod_globals = temp_module.module.__dict__
|
2007-08-25 07:50:41 -03:00
|
|
|
_run_code(code, mod_globals, init_globals,
|
2009-11-15 03:30:34 -04:00
|
|
|
mod_name, mod_fname, mod_loader, pkg_name)
|
2007-08-25 07:50:41 -03:00
|
|
|
# Copy the globals of the temporary module, as they
|
|
|
|
# may be cleared when the temporary module goes away
|
|
|
|
return mod_globals.copy()
|
2006-03-15 07:00:26 -04:00
|
|
|
|
|
|
|
|
First phase of refactoring for runpy, pkgutil, pydoc, and setuptools
to share common PEP 302 support code, as described here:
http://mail.python.org/pipermail/python-dev/2006-April/063724.html
This revision strips all the PEP 302 emulation code from runpy,
replacing it with published API classes and functions in pkgutil,
mostly using setuptools' implementation of common functionality,
but adding features from runpy, and doing some refactoring to make
the layer pydoc needs easier to implement on top of this.
One step down, four to go, although step #4 (adding C versions of
the new APIs to 'imp') may not be able to make it in time for
alpha 2. We'll see how that goes.
2006-04-17 17:17:25 -03:00
|
|
|
# This helper is needed due to a missing component in the PEP 302
|
|
|
|
# loader protocol (specifically, "get_filename" is non-standard)
|
2008-12-14 06:54:50 -04:00
|
|
|
# Since we can't introduce new features in maintenance releases,
|
|
|
|
# support was added to zipimporter under the name '_get_filename'
|
First phase of refactoring for runpy, pkgutil, pydoc, and setuptools
to share common PEP 302 support code, as described here:
http://mail.python.org/pipermail/python-dev/2006-April/063724.html
This revision strips all the PEP 302 emulation code from runpy,
replacing it with published API classes and functions in pkgutil,
mostly using setuptools' implementation of common functionality,
but adding features from runpy, and doing some refactoring to make
the layer pydoc needs easier to implement on top of this.
One step down, four to go, although step #4 (adding C versions of
the new APIs to 'imp') may not be able to make it in time for
alpha 2. We'll see how that goes.
2006-04-17 17:17:25 -03:00
|
|
|
def _get_filename(loader, mod_name):
|
2008-12-14 06:54:50 -04:00
|
|
|
for attr in ("get_filename", "_get_filename"):
|
|
|
|
meth = getattr(loader, attr, None)
|
|
|
|
if meth is not None:
|
|
|
|
return meth(mod_name)
|
|
|
|
return None
|
First phase of refactoring for runpy, pkgutil, pydoc, and setuptools
to share common PEP 302 support code, as described here:
http://mail.python.org/pipermail/python-dev/2006-April/063724.html
This revision strips all the PEP 302 emulation code from runpy,
replacing it with published API classes and functions in pkgutil,
mostly using setuptools' implementation of common functionality,
but adding features from runpy, and doing some refactoring to make
the layer pydoc needs easier to implement on top of this.
One step down, four to go, although step #4 (adding C versions of
the new APIs to 'imp') may not be able to make it in time for
alpha 2. We'll see how that goes.
2006-04-17 17:17:25 -03:00
|
|
|
|
2007-08-25 07:50:41 -03:00
|
|
|
# Helper to get the loader, code and filename for a module
|
|
|
|
def _get_module_details(mod_name):
|
First phase of refactoring for runpy, pkgutil, pydoc, and setuptools
to share common PEP 302 support code, as described here:
http://mail.python.org/pipermail/python-dev/2006-April/063724.html
This revision strips all the PEP 302 emulation code from runpy,
replacing it with published API classes and functions in pkgutil,
mostly using setuptools' implementation of common functionality,
but adding features from runpy, and doing some refactoring to make
the layer pydoc needs easier to implement on top of this.
One step down, four to go, although step #4 (adding C versions of
the new APIs to 'imp') may not be able to make it in time for
alpha 2. We'll see how that goes.
2006-04-17 17:17:25 -03:00
|
|
|
loader = get_loader(mod_name)
|
2006-03-15 07:00:26 -04:00
|
|
|
if loader is None:
|
2007-07-23 10:41:45 -03:00
|
|
|
raise ImportError("No module named %s" % mod_name)
|
|
|
|
if loader.is_package(mod_name):
|
2009-02-07 21:26:34 -04:00
|
|
|
if mod_name == "__main__" or mod_name.endswith(".__main__"):
|
2009-11-07 04:15:01 -04:00
|
|
|
raise ImportError("Cannot use package as __main__ module")
|
2009-02-07 21:26:34 -04:00
|
|
|
try:
|
|
|
|
pkg_main_name = mod_name + ".__main__"
|
|
|
|
return _get_module_details(pkg_main_name)
|
|
|
|
except ImportError, e:
|
|
|
|
raise ImportError(("%s; %r is a package and cannot " +
|
|
|
|
"be directly executed") %(e, mod_name))
|
2006-03-15 07:00:26 -04:00
|
|
|
code = loader.get_code(mod_name)
|
|
|
|
if code is None:
|
2007-07-23 10:41:45 -03:00
|
|
|
raise ImportError("No code object available for %s" % mod_name)
|
2006-03-15 07:00:26 -04:00
|
|
|
filename = _get_filename(loader, mod_name)
|
2009-02-07 21:26:34 -04:00
|
|
|
return mod_name, loader, code, filename
|
2007-08-25 07:50:41 -03:00
|
|
|
|
|
|
|
|
2009-11-15 03:30:34 -04:00
|
|
|
def _get_main_module_details():
|
|
|
|
# Helper that gives a nicer error message when attempting to
|
|
|
|
# execute a zipfile or directory by invoking __main__.py
|
|
|
|
main_name = "__main__"
|
|
|
|
try:
|
|
|
|
return _get_module_details(main_name)
|
|
|
|
except ImportError as exc:
|
|
|
|
if main_name in str(exc):
|
|
|
|
raise ImportError("can't find %r module in %r" %
|
|
|
|
(main_name, sys.path[0]))
|
|
|
|
raise
|
|
|
|
|
|
|
|
# This function is the actual implementation of the -m switch and direct
|
|
|
|
# execution of zipfiles and directories and is deliberately kept private.
|
|
|
|
# This avoids a repeat of the situation where run_module() no longer met the
|
|
|
|
# needs of mainmodule.c, but couldn't be changed because it was public
|
2009-11-07 04:15:01 -04:00
|
|
|
def _run_module_as_main(mod_name, alter_argv=True):
|
2007-08-25 07:50:41 -03:00
|
|
|
"""Runs the designated module in the __main__ namespace
|
|
|
|
|
2009-11-07 04:15:01 -04:00
|
|
|
Note that the executed module will have full access to the
|
|
|
|
__main__ namespace. If this is not desirable, the run_module()
|
2009-12-20 12:24:46 -04:00
|
|
|
function should be used to run the module code in a fresh namespace.
|
2009-11-07 04:15:01 -04:00
|
|
|
|
|
|
|
At the very least, these variables in __main__ will be overwritten:
|
|
|
|
__name__
|
2007-08-25 07:50:41 -03:00
|
|
|
__file__
|
|
|
|
__loader__
|
2009-11-07 04:15:01 -04:00
|
|
|
__package__
|
2007-08-25 07:50:41 -03:00
|
|
|
"""
|
2008-02-22 06:54:06 -04:00
|
|
|
try:
|
2009-11-15 03:30:34 -04:00
|
|
|
if alter_argv or mod_name != "__main__": # i.e. -m switch
|
|
|
|
mod_name, loader, code, fname = _get_module_details(mod_name)
|
|
|
|
else: # i.e. directory or zipfile execution
|
|
|
|
mod_name, loader, code, fname = _get_main_module_details()
|
2008-02-22 06:54:06 -04:00
|
|
|
except ImportError as exc:
|
2009-11-15 03:30:34 -04:00
|
|
|
msg = "%s: %s" % (sys.executable, str(exc))
|
2008-02-22 06:54:06 -04:00
|
|
|
sys.exit(msg)
|
2007-12-03 08:55:17 -04:00
|
|
|
pkg_name = mod_name.rpartition('.')[0]
|
2007-08-25 07:50:41 -03:00
|
|
|
main_globals = sys.modules["__main__"].__dict__
|
2009-11-07 04:15:01 -04:00
|
|
|
if alter_argv:
|
2007-08-25 07:50:41 -03:00
|
|
|
sys.argv[0] = fname
|
|
|
|
return _run_code(code, main_globals, None,
|
2007-12-03 08:55:17 -04:00
|
|
|
"__main__", fname, loader, pkg_name)
|
2007-08-25 07:50:41 -03:00
|
|
|
|
|
|
|
def run_module(mod_name, init_globals=None,
|
|
|
|
run_name=None, alter_sys=False):
|
|
|
|
"""Execute a module's code without importing it
|
|
|
|
|
|
|
|
Returns the resulting top level namespace dictionary
|
|
|
|
"""
|
2009-02-07 21:26:34 -04:00
|
|
|
mod_name, loader, code, fname = _get_module_details(mod_name)
|
2006-03-15 07:00:26 -04:00
|
|
|
if run_name is None:
|
|
|
|
run_name = mod_name
|
2007-12-03 08:55:17 -04:00
|
|
|
pkg_name = mod_name.rpartition('.')[0]
|
2007-08-25 07:50:41 -03:00
|
|
|
if alter_sys:
|
|
|
|
return _run_module_code(code, init_globals, run_name,
|
2007-12-03 08:55:17 -04:00
|
|
|
fname, loader, pkg_name)
|
2007-08-25 07:50:41 -03:00
|
|
|
else:
|
|
|
|
# Leave the sys module alone
|
2007-12-03 08:55:17 -04:00
|
|
|
return _run_code(code, {}, init_globals, run_name,
|
|
|
|
fname, loader, pkg_name)
|
2006-03-15 07:00:26 -04:00
|
|
|
|
|
|
|
|
2009-11-15 03:30:34 -04:00
|
|
|
# XXX (ncoghlan): Perhaps expose the C API function
|
|
|
|
# as imp.get_importer instead of reimplementing it in Python?
|
|
|
|
def _get_importer(path_name):
|
|
|
|
"""Python version of PyImport_GetImporter C API function"""
|
|
|
|
cache = sys.path_importer_cache
|
|
|
|
try:
|
|
|
|
importer = cache[path_name]
|
|
|
|
except KeyError:
|
|
|
|
# Not yet cached. Flag as using the
|
|
|
|
# standard machinery until we finish
|
|
|
|
# checking the hooks
|
|
|
|
cache[path_name] = None
|
|
|
|
for hook in sys.path_hooks:
|
|
|
|
try:
|
|
|
|
importer = hook(path_name)
|
|
|
|
break
|
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
# The following check looks a bit odd. The trick is that
|
|
|
|
# NullImporter throws ImportError if the supplied path is a
|
|
|
|
# *valid* directory entry (and hence able to be handled
|
|
|
|
# by the standard import machinery)
|
|
|
|
try:
|
|
|
|
importer = imp.NullImporter(path_name)
|
|
|
|
except ImportError:
|
|
|
|
return None
|
|
|
|
cache[path_name] = importer
|
|
|
|
return importer
|
|
|
|
|
|
|
|
def _get_code_from_file(fname):
|
|
|
|
# Check for a compiled file first
|
|
|
|
with open(fname, "rb") as f:
|
|
|
|
code = read_code(f)
|
|
|
|
if code is None:
|
|
|
|
# That didn't work, so try it as normal source code
|
|
|
|
with open(fname, "rU") as f:
|
|
|
|
code = compile(f.read(), fname, 'exec')
|
|
|
|
return code
|
|
|
|
|
|
|
|
def run_path(path_name, init_globals=None, run_name=None):
|
|
|
|
"""Execute code located at the specified filesystem location
|
|
|
|
|
|
|
|
Returns the resulting top level namespace dictionary
|
|
|
|
|
|
|
|
The file path may refer directly to a Python script (i.e.
|
|
|
|
one that could be directly executed with execfile) or else
|
|
|
|
it may refer to a zipfile or directory containing a top
|
|
|
|
level __main__.py script.
|
|
|
|
"""
|
|
|
|
if run_name is None:
|
|
|
|
run_name = "<run_path>"
|
|
|
|
importer = _get_importer(path_name)
|
|
|
|
if isinstance(importer, imp.NullImporter):
|
|
|
|
# Not a valid sys.path entry, so run the code directly
|
|
|
|
# execfile() doesn't help as we want to allow compiled files
|
|
|
|
code = _get_code_from_file(path_name)
|
|
|
|
return _run_module_code(code, init_globals, run_name, path_name)
|
|
|
|
else:
|
|
|
|
# Importer is defined for path, so add it to
|
|
|
|
# the start of sys.path
|
|
|
|
sys.path.insert(0, path_name)
|
|
|
|
try:
|
|
|
|
# Here's where things are a little different from the run_module
|
|
|
|
# case. There, we only had to replace the module in sys while the
|
|
|
|
# code was running and doing so was somewhat optional. Here, we
|
|
|
|
# have no choice and we have to remove it even while we read the
|
|
|
|
# code. If we don't do this, a __loader__ attribute in the
|
|
|
|
# existing __main__ module may prevent location of the new module.
|
|
|
|
main_name = "__main__"
|
|
|
|
saved_main = sys.modules[main_name]
|
|
|
|
del sys.modules[main_name]
|
|
|
|
try:
|
|
|
|
mod_name, loader, code, fname = _get_main_module_details()
|
|
|
|
finally:
|
|
|
|
sys.modules[main_name] = saved_main
|
|
|
|
pkg_name = ""
|
|
|
|
with _TempModule(run_name) as temp_module, \
|
|
|
|
_ModifiedArgv0(path_name):
|
|
|
|
mod_globals = temp_module.module.__dict__
|
|
|
|
return _run_code(code, mod_globals, init_globals,
|
2010-10-12 22:10:16 -03:00
|
|
|
run_name, fname, loader, pkg_name).copy()
|
2009-11-15 03:30:34 -04:00
|
|
|
finally:
|
|
|
|
try:
|
|
|
|
sys.path.remove(path_name)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2006-03-15 07:00:26 -04:00
|
|
|
if __name__ == "__main__":
|
|
|
|
# Run the module specified as the next command line argument
|
|
|
|
if len(sys.argv) < 2:
|
|
|
|
print >> sys.stderr, "No module specified for execution"
|
|
|
|
else:
|
|
|
|
del sys.argv[0] # Make the requested module sys.argv[0]
|
2007-08-25 07:50:41 -03:00
|
|
|
_run_module_as_main(sys.argv[0])
|