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
|
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__ = [
|
|
|
|
"run_module",
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2007-08-25 07:50:41 -03:00
|
|
|
def _run_code(code, run_globals, init_globals=None,
|
|
|
|
mod_name=None, mod_fname=None,
|
|
|
|
mod_loader=None):
|
2006-03-15 07:00:26 -04:00
|
|
|
"""Helper for _run_module_code"""
|
|
|
|
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,
|
|
|
|
__loader__ = mod_loader)
|
|
|
|
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-08-25 07:50:41 -03:00
|
|
|
mod_loader=None):
|
2006-03-15 07:00:26 -04:00
|
|
|
"""Helper for run_module"""
|
|
|
|
# Set up the top level namespace dictionary
|
2007-08-25 07:50:41 -03:00
|
|
|
temp_module = imp.new_module(mod_name)
|
|
|
|
mod_globals = temp_module.__dict__
|
|
|
|
# Modify sys.argv[0] and sys.module[mod_name]
|
|
|
|
saved_argv0 = sys.argv[0]
|
|
|
|
restore_module = mod_name in sys.modules
|
|
|
|
if restore_module:
|
|
|
|
saved_module = sys.modules[mod_name]
|
|
|
|
sys.argv[0] = mod_fname
|
|
|
|
sys.modules[mod_name] = temp_module
|
|
|
|
try:
|
|
|
|
_run_code(code, mod_globals, init_globals,
|
|
|
|
mod_name, mod_fname, mod_loader)
|
|
|
|
finally:
|
|
|
|
sys.argv[0] = saved_argv0
|
2007-08-25 01:32:07 -03:00
|
|
|
if restore_module:
|
|
|
|
sys.modules[mod_name] = saved_module
|
|
|
|
else:
|
|
|
|
del sys.modules[mod_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)
|
|
|
|
def _get_filename(loader, mod_name):
|
|
|
|
try:
|
|
|
|
get_filename = loader.get_filename
|
|
|
|
except AttributeError:
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return get_filename(mod_name)
|
|
|
|
|
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):
|
|
|
|
raise ImportError(("%s is a package and cannot " +
|
|
|
|
"be directly executed") % 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)
|
2007-08-25 07:50:41 -03:00
|
|
|
return loader, code, filename
|
|
|
|
|
|
|
|
|
|
|
|
# XXX ncoghlan: Should this be documented and made public?
|
|
|
|
def _run_module_as_main(mod_name, set_argv0=True):
|
|
|
|
"""Runs the designated module in the __main__ namespace
|
|
|
|
|
|
|
|
These __*__ magic variables will be overwritten:
|
|
|
|
__file__
|
|
|
|
__loader__
|
|
|
|
"""
|
|
|
|
loader, code, fname = _get_module_details(mod_name)
|
|
|
|
main_globals = sys.modules["__main__"].__dict__
|
|
|
|
if set_argv0:
|
|
|
|
sys.argv[0] = fname
|
|
|
|
return _run_code(code, main_globals, None,
|
|
|
|
"__main__", fname, loader)
|
|
|
|
|
|
|
|
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
|
|
|
|
"""
|
|
|
|
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-08-25 07:50:41 -03:00
|
|
|
if alter_sys:
|
|
|
|
return _run_module_code(code, init_globals, run_name,
|
|
|
|
fname, loader)
|
|
|
|
else:
|
|
|
|
# Leave the sys module alone
|
|
|
|
return _run_code(code, {}, init_globals,
|
|
|
|
run_name, fname, loader)
|
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])
|