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/2c5fb3a8b81cc56d8ad57dd1bd83ef7740…
[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.h…
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/2c5fb3a8b81cc56d8ad57dd1bd83ef7740…
+
+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)
--
To view, visit
https://gerrit.wikimedia.org/r/76486
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: If9458fca50f07f08441dbb6e06f78bdbae2065de
Gerrit-PatchSet: 6
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: DrTrigon <dr.trigon(a)surfeu.ch>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Legoktm <legoktm.wikipedia(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot