Xqt has submitted this change and it was merged.
Change subject: Updated pwb.py to better mirror direct script runs ......................................................................
Updated pwb.py to better mirror direct script runs
Before, execfile() ran the script in environment that pwb.py has, which included os and path imports, and several other variables.
This commit uses run_python_file from Ned Batchelors' coverage.py [1], available under the BSD license [2]. See also his blog posts on the subject [3,4].
This commit also adds a test that shells out to compare the locals() for runs through pwb.py as well as to a script directly.
After this change, the effects of changeset 76484 can be seen using pwb.py
[1] https://bitbucket.org/ned/coveragepy/src/b5abcee50dbe/coverage/execfile.py [2] https://bitbucket.org/ned/coveragepy/src/2c5fb3a8b81cc56d8ad57dd1bd83ef7740f... [3] http://nedbatchelder.com/blog/200904/running_a_python_file_as_main.html [4] http://nedbatchelder.com/blog/200905/running_a_python_file_as_main_take_2.ht...
Change-Id: If9458fca50f07f08441dbb6e06f78bdbae2065de --- M pwb.py A tests/pwb/print_locals.py A tests/pwb_tests.py 3 files changed, 89 insertions(+), 13 deletions(-)
Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
diff --git a/pwb.py b/pwb.py index ae732ed..94fef0c 100644 --- a/pwb.py +++ b/pwb.py @@ -12,8 +12,50 @@ # Distributed under the terms of the MIT license. #
-import sys + +# The following snippet was developed by Ned Batchelder (and others) +# for coverage.py [1], and is available under the BSD license (see [2]) +# [1] https://bitbucket.org/ned/coveragepy/src/b5abcee50dbe/coverage/execfile.py +# [2] https://bitbucket.org/ned/coveragepy/src/2c5fb3a8b81cc56d8ad57dd1bd83ef7740f... + +import imp import os +import sys + + +def run_python_file(filename, args): + """Run a python file as if it were the main program on the command line. + + `filename` is the path to the file to execute, it need not be a .py file. + `args` is the argument array to present as sys.argv, including the first + element representing the file being executed. + + """ + # Create a module to serve as __main__ + old_main_mod = sys.modules['__main__'] + main_mod = imp.new_module('__main__') + sys.modules['__main__'] = main_mod + main_mod.__file__ = filename + main_mod.__builtins__ = sys.modules['__builtin__'] + + # Set sys.argv and the first path element properly. + old_argv = sys.argv + old_path0 = sys.path[0] + sys.argv = args + sys.path[0] = os.path.dirname(filename) + + try: + source = open(filename).read() + exec compile(source, filename, "exec") in main_mod.__dict__ + finally: + # Restore the old __main__ + sys.modules['__main__'] = old_main_mod + + # Restore the old argv and path + sys.argv = old_argv + sys.path[0] = old_path0 + +#### end of snippet
if sys.version_info[0] != 2: raise RuntimeError("ERROR: Pywikipediabot only runs under Python 2") @@ -33,21 +75,20 @@ os.environ["PYWIKIBOT2_DIR"] = os.path.split(__file__)[0]
if not os.path.exists(os.path.join(os.environ["PYWIKIBOT2_DIR"], "user-config.py")): - execfile('generate_user_files.py') + run_python_file('generate_user_files.py', ['generate_user_files.py'])
-sys.argv.pop(0) -if len(sys.argv) > 0: - if not os.path.exists(sys.argv[0]): - testpath = os.path.join(os.path.split(__file__)[0], 'scripts', sys.argv[0]) +if len(sys.argv) > 1: + fn = sys.argv[1] + args = sys.argv[1:] + + if not os.path.exists(fn): + testpath = os.path.join(os.path.split(__file__)[0], 'scripts', fn) if os.path.exists(testpath): - sys.argv[0] = testpath + fn = testpath else: testpath = testpath + '.py' if os.path.exists(testpath): - sys.argv[0] = testpath + fn = testpath else: - raise Exception("%s not found!" % sys.argv[0]) - sys.path.append(os.path.split(sys.argv[0])[0]) - execfile(sys.argv[0]) -else: - sys.argv.append('') + raise Exception("%s not found!" % fn) + run_python_file(fn, args) diff --git a/tests/pwb/print_locals.py b/tests/pwb/print_locals.py new file mode 100644 index 0000000..1b84ac0 --- /dev/null +++ b/tests/pwb/print_locals.py @@ -0,0 +1,4 @@ +"""docstring""" + +for k,v in locals().copy().iteritems(): + print repr(k), ":", repr(v) diff --git a/tests/pwb_tests.py b/tests/pwb_tests.py new file mode 100644 index 0000000..4cb9759 --- /dev/null +++ b/tests/pwb_tests.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# +# (C) Pywikipedia bot team, 2007 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id$' + +import os +import sys +import subprocess + +import unittest + +pypath = sys.executable +basepath = os.path.split(os.path.split(__file__)[0])[0] +pwbpath = os.path.join(basepath, 'pwb.py') +testbasepath = os.path.join(basepath, 'tests', 'pwb') + +class TestPwb(unittest.TestCase): + def testScriptEnvironment(self): + """Make sure the environment is not contaminated, and is the same as + the environment we get when directly running a script.""" + test = os.path.join(testbasepath, 'print_locals.py') + + direct = subprocess.check_output([pypath, test]) + vpwb = subprocess.check_output([pypath, pwbpath, test]) + self.assertEqual(direct, vpwb) + +if __name__=="__main__": + unittest.main(verbosity=10)
pywikibot-commits@lists.wikimedia.org