Commit 9a198e54 authored by Jason Madden's avatar Jason Madden

Use runpy.run_path for 'python -m gevent.monkey'.

This lets us run packages and compiled files, as well as automatically taking care of all the import related globals like __file__ and __package__.

Fixes #1157
parent 892bd17b
......@@ -60,6 +60,10 @@ Enhancements
time-sensitive parts of the hub itself. Please report any
compatibility issues.
- ``python -m gevent.monkey <script>`` accepts more values for
``<script>``, including paths to packages or compiled bytecode.
Reported in :issue:`1157` by Eddie Linder.
Monitoring and Debugging
------------------------
......
......@@ -766,13 +766,13 @@ def main():
patch_all(**args)
if argv:
sys.argv = argv
__package__ = None
assert __package__ is None
globals()['__file__'] = sys.argv[0] # issue #302
globals()['__package__'] = None # issue #975: make script be its own package
with open(sys.argv[0]) as f:
# Be sure to exec in globals to avoid import pollution. Also #975.
exec(f.read(), globals())
import runpy
# Use runpy.run_path to closely (exactly) match what the
# interpreter does given 'python <path>'. This includes allowing
# passing .pyc/.pyo files and packages with a __main__ and
# potentially even zip files. Previously we used exec, which only
# worked if we directly read a python source file.
runpy.run_path(sys.argv[0], run_name='__main__')
else:
print(script_help)
......@@ -795,6 +795,12 @@ You can exclude a module with --no-module, e.g. --no-thread. You can
specify a module to patch with --module, e.g. --socket. In the latter
case only the modules specified on the command line will be patched.
.. versionchanged:: 1.3b1
The *script* argument can now be any argument that can be passed to `runpy.run_path`,
just like the interpreter itself does, for example a package directory containing ``__main__.py``.
Previously it had to be the path to
a .py source file.
MONKEY OPTIONS: --verbose %s""" % ', '.join('--[no-]%s' % m for m in modules)
return script_help, patch_all_args, modules
......
from __future__ import print_function
# This file makes this directory into a package.
# it exists to test 'python -m gevent.monkey monkey_package'
print(__file__)
print(__name__)
......@@ -3,11 +3,24 @@ import sys
if 'gevent' not in sys.modules:
from subprocess import Popen
from subprocess import PIPE
# Run a simple script
args = [sys.executable, '-m', 'gevent.monkey', __file__]
p = Popen(args)
code = p.wait()
assert code == 0, code
# Run a __main__ inside a package.
args = [sys.executable, '-m', 'gevent.monkey', 'monkey_package']
p = Popen(args, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
lines = out.splitlines()
assert lines[0].endswith(b'__main__.py'), (out, err)
assert lines[1] == b'__main__', (lines, out, err)
# Python 3.7 tends to produce some inscrutable
# warning from importlib._bootstrap.py on stderr
# "ImportWarning: can't resolve package from __spec__ or __package__".
# So we don't check that err is empty.
else:
from textwrap import dedent
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment