blob: 1e0a2be4f0c9c3cf0520599b6f140df5f9179103 [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
Brett Cannonaa936422012-04-27 15:30:58 -040012
Brett Cannone0d88a12012-04-25 20:54:04 -040013import os
Thomas Woutersa9773292006-04-21 09:43:23 +000014import sys
Nick Coghlanbe7e49f2012-07-20 23:40:09 +100015import importlib.machinery # importlib first so we can test #15386 via -m
Brett Cannon82d21072013-06-15 14:27:21 -040016import types
Nick Coghlan85e729e2012-07-15 18:09:52 +100017from pkgutil import read_code, get_loader, get_importer
Thomas Woutersa9773292006-04-21 09:43:23 +000018
19__all__ = [
Nick Coghlan260bd3e2009-11-16 06:49:25 +000020 "run_module", "run_path",
Thomas Woutersa9773292006-04-21 09:43:23 +000021]
22
Nick Coghlan260bd3e2009-11-16 06:49:25 +000023class _TempModule(object):
24 """Temporarily replace a module in sys.modules with an empty namespace"""
25 def __init__(self, mod_name):
26 self.mod_name = mod_name
Brett Cannon82d21072013-06-15 14:27:21 -040027 self.module = types.ModuleType(mod_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +000028 self._saved_module = []
29
30 def __enter__(self):
31 mod_name = self.mod_name
32 try:
33 self._saved_module.append(sys.modules[mod_name])
34 except KeyError:
35 pass
36 sys.modules[mod_name] = self.module
37 return self
38
39 def __exit__(self, *args):
40 if self._saved_module:
41 sys.modules[self.mod_name] = self._saved_module[0]
42 else:
43 del sys.modules[self.mod_name]
44 self._saved_module = []
45
46class _ModifiedArgv0(object):
47 def __init__(self, value):
48 self.value = value
49 self._saved_value = self._sentinel = object()
50
51 def __enter__(self):
52 if self._saved_value is not self._sentinel:
53 raise RuntimeError("Already preserving saved value")
54 self._saved_value = sys.argv[0]
55 sys.argv[0] = self.value
56
57 def __exit__(self, *args):
58 self.value = self._sentinel
59 sys.argv[0] = self._saved_value
Thomas Woutersa9773292006-04-21 09:43:23 +000060
Thomas Woutersed03b412007-08-28 21:37:11 +000061def _run_code(code, run_globals, init_globals=None,
62 mod_name=None, mod_fname=None,
Christian Heimescbf3b5c2007-12-03 21:02:03 +000063 mod_loader=None, pkg_name=None):
Benjamin Petersonf6489f92009-11-25 17:46:26 +000064 """Helper to run code in nominated namespace"""
Thomas Woutersa9773292006-04-21 09:43:23 +000065 if init_globals is not None:
66 run_globals.update(init_globals)
67 run_globals.update(__name__ = mod_name,
68 __file__ = mod_fname,
Barry Warsaw28a691b2010-04-17 00:19:56 +000069 __cached__ = None,
Nick Coghlan761bb112012-07-14 23:59:22 +100070 __doc__ = None,
Christian Heimescbf3b5c2007-12-03 21:02:03 +000071 __loader__ = mod_loader,
72 __package__ = pkg_name)
Georg Brandl7cae87c2006-09-06 06:51:57 +000073 exec(code, run_globals)
Thomas Woutersa9773292006-04-21 09:43:23 +000074 return run_globals
75
76def _run_module_code(code, init_globals=None,
Thomas Woutersed03b412007-08-28 21:37:11 +000077 mod_name=None, mod_fname=None,
Christian Heimescbf3b5c2007-12-03 21:02:03 +000078 mod_loader=None, pkg_name=None):
Benjamin Petersonf6489f92009-11-25 17:46:26 +000079 """Helper to run code in new namespace with sys modified"""
Nick Coghlan260bd3e2009-11-16 06:49:25 +000080 with _TempModule(mod_name) as temp_module, _ModifiedArgv0(mod_fname):
81 mod_globals = temp_module.module.__dict__
Thomas Woutersed03b412007-08-28 21:37:11 +000082 _run_code(code, mod_globals, init_globals,
Nick Coghlan260bd3e2009-11-16 06:49:25 +000083 mod_name, mod_fname, mod_loader, pkg_name)
Thomas Woutersed03b412007-08-28 21:37:11 +000084 # Copy the globals of the temporary module, as they
85 # may be cleared when the temporary module goes away
86 return mod_globals.copy()
Thomas Woutersa9773292006-04-21 09:43:23 +000087
88
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000089# This helper is needed due to a missing component in the PEP 302
90# loader protocol (specifically, "get_filename" is non-standard)
Nick Coghlanf088e5e2008-12-14 11:50:48 +000091# Since we can't introduce new features in maintenance releases,
92# support was added to zipimporter under the name '_get_filename'
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000093def _get_filename(loader, mod_name):
Nick Coghlanf088e5e2008-12-14 11:50:48 +000094 for attr in ("get_filename", "_get_filename"):
95 meth = getattr(loader, attr, None)
96 if meth is not None:
Brett Cannone0d88a12012-04-25 20:54:04 -040097 return os.path.abspath(meth(mod_name))
Nick Coghlanf088e5e2008-12-14 11:50:48 +000098 return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000099
Thomas Woutersed03b412007-08-28 21:37:11 +0000100# Helper to get the loader, code and filename for a module
101def _get_module_details(mod_name):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000102 loader = get_loader(mod_name)
Thomas Woutersa9773292006-04-21 09:43:23 +0000103 if loader is None:
Guido van Rossum806c2462007-08-06 23:33:07 +0000104 raise ImportError("No module named %s" % mod_name)
105 if loader.is_package(mod_name):
Nick Coghlan3f48ae32009-02-08 01:58:26 +0000106 if mod_name == "__main__" or mod_name.endswith(".__main__"):
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000107 raise ImportError("Cannot use package as __main__ module")
Nick Coghlan3f48ae32009-02-08 01:58:26 +0000108 try:
109 pkg_main_name = mod_name + ".__main__"
110 return _get_module_details(pkg_main_name)
111 except ImportError as e:
112 raise ImportError(("%s; %r is a package and cannot " +
113 "be directly executed") %(e, mod_name))
Thomas Woutersa9773292006-04-21 09:43:23 +0000114 code = loader.get_code(mod_name)
115 if code is None:
Guido van Rossum806c2462007-08-06 23:33:07 +0000116 raise ImportError("No code object available for %s" % mod_name)
Thomas Woutersa9773292006-04-21 09:43:23 +0000117 filename = _get_filename(loader, mod_name)
Nick Coghlan3f48ae32009-02-08 01:58:26 +0000118 return mod_name, loader, code, filename
Thomas Woutersed03b412007-08-28 21:37:11 +0000119
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000120# XXX ncoghlan: Should this be documented and made public?
121# (Current thoughts: don't repeat the mistake that lead to its
122# creation when run_module() no longer met the needs of
123# mainmodule.c, but couldn't be changed because it was public)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000124def _run_module_as_main(mod_name, alter_argv=True):
Thomas Woutersed03b412007-08-28 21:37:11 +0000125 """Runs the designated module in the __main__ namespace
126
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000127 Note that the executed module will have full access to the
128 __main__ namespace. If this is not desirable, the run_module()
R. David Murray445448c2009-12-20 17:28:31 +0000129 function should be used to run the module code in a fresh namespace.
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000130
131 At the very least, these variables in __main__ will be overwritten:
132 __name__
Thomas Woutersed03b412007-08-28 21:37:11 +0000133 __file__
Barry Warsaw28a691b2010-04-17 00:19:56 +0000134 __cached__
Thomas Woutersed03b412007-08-28 21:37:11 +0000135 __loader__
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000136 __package__
Thomas Woutersed03b412007-08-28 21:37:11 +0000137 """
Christian Heimesc3f30c42008-02-22 16:37:40 +0000138 try:
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000139 if alter_argv or mod_name != "__main__": # i.e. -m switch
140 mod_name, loader, code, fname = _get_module_details(mod_name)
141 else: # i.e. directory or zipfile execution
142 mod_name, loader, code, fname = _get_main_module_details()
Christian Heimesc3f30c42008-02-22 16:37:40 +0000143 except ImportError as exc:
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000144 # Try to provide a good error message
145 # for directories, zip files and the -m switch
146 if alter_argv:
147 # For -m switch, just display the exception
148 info = str(exc)
149 else:
150 # For directories/zipfiles, let the user
151 # know what the code was looking for
Benjamin Petersone3607952009-11-25 18:38:11 +0000152 info = "can't find '__main__' module in %r" % sys.argv[0]
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000153 msg = "%s: %s" % (sys.executable, info)
Christian Heimesc3f30c42008-02-22 16:37:40 +0000154 sys.exit(msg)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000155 pkg_name = mod_name.rpartition('.')[0]
Thomas Woutersed03b412007-08-28 21:37:11 +0000156 main_globals = sys.modules["__main__"].__dict__
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000157 if alter_argv:
Thomas Woutersed03b412007-08-28 21:37:11 +0000158 sys.argv[0] = fname
159 return _run_code(code, main_globals, None,
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000160 "__main__", fname, loader, pkg_name)
Thomas Woutersed03b412007-08-28 21:37:11 +0000161
162def run_module(mod_name, init_globals=None,
163 run_name=None, alter_sys=False):
164 """Execute a module's code without importing it
165
166 Returns the resulting top level namespace dictionary
167 """
Nick Coghlan3f48ae32009-02-08 01:58:26 +0000168 mod_name, loader, code, fname = _get_module_details(mod_name)
Thomas Woutersa9773292006-04-21 09:43:23 +0000169 if run_name is None:
170 run_name = mod_name
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000171 pkg_name = mod_name.rpartition('.')[0]
Thomas Woutersed03b412007-08-28 21:37:11 +0000172 if alter_sys:
173 return _run_module_code(code, init_globals, run_name,
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000174 fname, loader, pkg_name)
Thomas Woutersed03b412007-08-28 21:37:11 +0000175 else:
176 # Leave the sys module alone
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000177 return _run_code(code, {}, init_globals, run_name,
178 fname, loader, pkg_name)
Thomas Woutersa9773292006-04-21 09:43:23 +0000179
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000180def _get_main_module_details():
181 # Helper that gives a nicer error message when attempting to
182 # execute a zipfile or directory by invoking __main__.py
Nick Coghlan85e729e2012-07-15 18:09:52 +1000183 # Also moves the standard __main__ out of the way so that the
184 # preexisting __loader__ entry doesn't cause issues
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000185 main_name = "__main__"
Nick Coghlan85e729e2012-07-15 18:09:52 +1000186 saved_main = sys.modules[main_name]
187 del sys.modules[main_name]
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000188 try:
189 return _get_module_details(main_name)
190 except ImportError as exc:
191 if main_name in str(exc):
192 raise ImportError("can't find %r module in %r" %
Nick Coghlan85e729e2012-07-15 18:09:52 +1000193 (main_name, sys.path[0])) from exc
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000194 raise
Nick Coghlan85e729e2012-07-15 18:09:52 +1000195 finally:
196 sys.modules[main_name] = saved_main
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000197
Thomas Woutersa9773292006-04-21 09:43:23 +0000198
Nick Coghlan85e729e2012-07-15 18:09:52 +1000199def _get_code_from_file(run_name, fname):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000200 # Check for a compiled file first
201 with open(fname, "rb") as f:
202 code = read_code(f)
203 if code is None:
204 # That didn't work, so try it as normal source code
Victor Stinner6c471022011-07-04 01:45:39 +0200205 with open(fname, "rb") as f:
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000206 code = compile(f.read(), fname, 'exec')
Nick Coghlan85e729e2012-07-15 18:09:52 +1000207 loader = importlib.machinery.SourceFileLoader(run_name, fname)
208 else:
209 loader = importlib.machinery.SourcelessFileLoader(run_name, fname)
210 return code, loader
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000211
212def run_path(path_name, init_globals=None, run_name=None):
213 """Execute code located at the specified filesystem location
214
215 Returns the resulting top level namespace dictionary
216
217 The file path may refer directly to a Python script (i.e.
218 one that could be directly executed with execfile) or else
219 it may refer to a zipfile or directory containing a top
220 level __main__.py script.
221 """
222 if run_name is None:
223 run_name = "<run_path>"
Nick Coghlan761bb112012-07-14 23:59:22 +1000224 pkg_name = run_name.rpartition(".")[0]
Nick Coghlan85e729e2012-07-15 18:09:52 +1000225 importer = get_importer(path_name)
Brett Cannone4f41de2013-06-16 13:13:40 -0400226 # Trying to avoid importing imp so as to not consume the deprecation warning.
227 is_NullImporter = False
228 if type(importer).__module__ == 'imp':
229 if type(importer).__name__ == 'NullImporter':
230 is_NullImporter = True
231 if isinstance(importer, type(None)) or is_NullImporter:
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000232 # Not a valid sys.path entry, so run the code directly
233 # execfile() doesn't help as we want to allow compiled files
Nick Coghlan85e729e2012-07-15 18:09:52 +1000234 code, mod_loader = _get_code_from_file(run_name, path_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000235 return _run_module_code(code, init_globals, run_name, path_name,
Nick Coghlan85e729e2012-07-15 18:09:52 +1000236 mod_loader, pkg_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000237 else:
238 # Importer is defined for path, so add it to
239 # the start of sys.path
240 sys.path.insert(0, path_name)
241 try:
242 # Here's where things are a little different from the run_module
243 # case. There, we only had to replace the module in sys while the
244 # code was running and doing so was somewhat optional. Here, we
245 # have no choice and we have to remove it even while we read the
246 # code. If we don't do this, a __loader__ attribute in the
247 # existing __main__ module may prevent location of the new module.
Nick Coghlan85e729e2012-07-15 18:09:52 +1000248 mod_name, loader, code, fname = _get_main_module_details()
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000249 with _TempModule(run_name) as temp_module, \
250 _ModifiedArgv0(path_name):
251 mod_globals = temp_module.module.__dict__
252 return _run_code(code, mod_globals, init_globals,
Benjamin Peterson01e39792010-10-13 01:04:36 +0000253 run_name, fname, loader, pkg_name).copy()
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000254 finally:
255 try:
256 sys.path.remove(path_name)
257 except ValueError:
258 pass
259
260
Thomas Woutersa9773292006-04-21 09:43:23 +0000261if __name__ == "__main__":
262 # Run the module specified as the next command line argument
263 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000264 print("No module specified for execution", file=sys.stderr)
Thomas Woutersa9773292006-04-21 09:43:23 +0000265 else:
266 del sys.argv[0] # Make the requested module sys.argv[0]
Thomas Woutersed03b412007-08-28 21:37:11 +0000267 _run_module_as_main(sys.argv[0])