Commit b53c9b21 authored by Jason Madden's avatar Jason Madden

Write modified module source to a tempfile so we get correct tracebacks.

Fixes #1306

There's probably some sort of performance penalty, but we don't run all that many monkey files (22 or so), and they take long enough that I suspect its lost in the overhead.
parent 2686eb89
import sys import sys
import os import os
kwargs = {} kwargs = {}
if sys.argv[1] == '--Event': if sys.argv[1] == '--Event':
...@@ -14,7 +15,9 @@ del sys.argv[1] ...@@ -14,7 +15,9 @@ del sys.argv[1]
print('Running with patch_all(%s): %s' % (','.join('%s=%r' % x for x in kwargs.items()), test_filename)) print('Running with patch_all(%s): %s' % (','.join('%s=%r' % x for x in kwargs.items()), test_filename))
from gevent import monkey; monkey.patch_all(**kwargs) from gevent import monkey
monkey.patch_all(**kwargs)
from greentest.sysinfo import RUNNING_ON_APPVEYOR from greentest.sysinfo import RUNNING_ON_APPVEYOR
from greentest.sysinfo import PY37 from greentest.sysinfo import PY37
from greentest.patched_tests_setup import disable_tests_in_source from greentest.patched_tests_setup import disable_tests_in_source
...@@ -39,6 +42,11 @@ if RUNNING_ON_APPVEYOR and PY37: ...@@ -39,6 +42,11 @@ if RUNNING_ON_APPVEYOR and PY37:
__file__ = os.path.join(os.getcwd(), test_filename) __file__ = os.path.join(os.getcwd(), test_filename)
test_name = os.path.splitext(test_filename)[0] test_name = os.path.splitext(test_filename)[0]
# It's important that the `module_source` be a native
# string. Passing unicode to `compile` on Python 2 can
# do bad things: it conflicts with a 'coding:' directive,
# and it can cause some TypeError with string literals
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
module_file = open(test_filename, encoding='utf-8') module_file = open(test_filename, encoding='utf-8')
else: else:
...@@ -46,5 +54,22 @@ else: ...@@ -46,5 +54,22 @@ else:
with module_file: with module_file:
module_source = module_file.read() module_source = module_file.read()
module_source = disable_tests_in_source(module_source, test_name) module_source = disable_tests_in_source(module_source, test_name)
module_code = compile(module_source, os.path.abspath(test_filename), 'exec')
exec(module_code, globals()) # We write the module source to a file so that tracebacks
# show correctly, since disabling the tests changes line
# numbers. However, note that __file__ must still point to the
# real location so that data files can be found.
# See https://github.com/gevent/gevent/issues/1306
import tempfile
temp_handle, temp_path = tempfile.mkstemp(prefix=test_name, suffix='.py', text=True)
os.write(temp_handle,
module_source.encode('utf-8') if not isinstance(module_source, bytes) else module_source)
os.close(temp_handle)
try:
module_code = compile(module_source,
temp_path,
'exec',
dont_inherit=True)
exec(module_code, globals())
finally:
os.remove(temp_path)
...@@ -153,6 +153,10 @@ disabled_tests = [ ...@@ -153,6 +153,10 @@ disabled_tests = [
'test_asyncore.BaseTestAPI.test_handle_expt', 'test_asyncore.BaseTestAPI.test_handle_expt',
# sends some OOB data and expect it to be detected as such; gevent.select.select does not support that # sends some OOB data and expect it to be detected as such; gevent.select.select does not support that
# This one likes to check its own filename, but we rewrite
# the file to a temp location during patching.
'test_asyncore.HelperFunctionTests.test_compact_traceback',
'test_signal.WakeupSignalTests.test_wakeup_fd_early', 'test_signal.WakeupSignalTests.test_wakeup_fd_early',
# expects time.sleep() to return prematurely in case of a signal; # expects time.sleep() to return prematurely in case of a signal;
# gevent.sleep() is better than that and does not get interrupted (unless signal handler raises an error) # gevent.sleep() is better than that and does not get interrupted (unless signal handler raises an error)
...@@ -1048,6 +1052,7 @@ _wrapped_tests_by_file = _build_test_structure(wrapped_tests) ...@@ -1048,6 +1052,7 @@ _wrapped_tests_by_file = _build_test_structure(wrapped_tests)
def disable_tests_in_source(source, filename): def disable_tests_in_source(source, filename):
# Source and filename are both native strings.
if filename.startswith('./'): if filename.startswith('./'):
# turn "./test_socket.py" (used for auto-complete) into "test_socket.py" # turn "./test_socket.py" (used for auto-complete) into "test_socket.py"
......
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