merge PR192, streamline a bit.
This commit is contained in:
commit
d16fdb378c
|
@ -3,6 +3,10 @@ NEXT
|
||||||
|
|
||||||
- No longer show line numbers in the --verbose output, the output is now
|
- No longer show line numbers in the --verbose output, the output is now
|
||||||
purely the nodeid. The line number is still shown in failure reports.
|
purely the nodeid. The line number is still shown in failure reports.
|
||||||
|
Thanks Floris Bruynooghe.
|
||||||
|
|
||||||
|
- fix issue437 where assertion rewriting could cause pytest-xdist slaves
|
||||||
|
to collect different tests. Thanks Bruno Oliveira.
|
||||||
|
|
||||||
- fix issue547 capsys/capfd also work when output capturing ("-s") is disabled.
|
- fix issue547 capsys/capfd also work when output capturing ("-s") is disabled.
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ class AssertionRewritingHook(object):
|
||||||
pyc = os.path.join(cache_dir, cache_name)
|
pyc = os.path.join(cache_dir, cache_name)
|
||||||
# Notice that even if we're in a read-only directory, I'm going
|
# Notice that even if we're in a read-only directory, I'm going
|
||||||
# to check for a cached pyc. This may not be optimal...
|
# to check for a cached pyc. This may not be optimal...
|
||||||
co = _read_pyc(fn_pypath, pyc)
|
co = _read_pyc(fn_pypath, pyc, state.trace)
|
||||||
if co is None:
|
if co is None:
|
||||||
state.trace("rewriting %r" % (fn,))
|
state.trace("rewriting %r" % (fn,))
|
||||||
co = _rewrite_test(state, fn_pypath)
|
co = _rewrite_test(state, fn_pypath)
|
||||||
|
@ -289,7 +289,7 @@ def _make_rewritten_pyc(state, fn, pyc, co):
|
||||||
if _write_pyc(state, co, fn, proc_pyc):
|
if _write_pyc(state, co, fn, proc_pyc):
|
||||||
os.rename(proc_pyc, pyc)
|
os.rename(proc_pyc, pyc)
|
||||||
|
|
||||||
def _read_pyc(source, pyc):
|
def _read_pyc(source, pyc, trace=lambda x: None):
|
||||||
"""Possibly read a pytest pyc containing rewritten code.
|
"""Possibly read a pytest pyc containing rewritten code.
|
||||||
|
|
||||||
Return rewritten code if successful or None if not.
|
Return rewritten code if successful or None if not.
|
||||||
|
@ -298,23 +298,27 @@ def _read_pyc(source, pyc):
|
||||||
fp = open(pyc, "rb")
|
fp = open(pyc, "rb")
|
||||||
except IOError:
|
except IOError:
|
||||||
return None
|
return None
|
||||||
try:
|
with fp:
|
||||||
try:
|
try:
|
||||||
mtime = int(source.mtime())
|
mtime = int(source.mtime())
|
||||||
data = fp.read(8)
|
data = fp.read(8)
|
||||||
except EnvironmentError:
|
except EnvironmentError as e:
|
||||||
|
trace('_read_pyc(%s): EnvironmentError %s' % (source, e))
|
||||||
return None
|
return None
|
||||||
# Check for invalid or out of date pyc file.
|
# Check for invalid or out of date pyc file.
|
||||||
if (len(data) != 8 or data[:4] != imp.get_magic() or
|
if (len(data) != 8 or data[:4] != imp.get_magic() or
|
||||||
struct.unpack("<l", data[4:])[0] != mtime):
|
struct.unpack("<l", data[4:])[0] != mtime):
|
||||||
|
trace('_read_pyc(%s): invalid or out of date pyc' % source)
|
||||||
return None
|
return None
|
||||||
|
try:
|
||||||
co = marshal.load(fp)
|
co = marshal.load(fp)
|
||||||
|
except Exception as e:
|
||||||
|
trace('_read_pyc(%s): marshal.load error %s' % (source, e))
|
||||||
|
return None
|
||||||
if not isinstance(co, types.CodeType):
|
if not isinstance(co, types.CodeType):
|
||||||
# That's interesting....
|
trace('_read_pyc(%s): not a code object' % source)
|
||||||
return None
|
return None
|
||||||
return co
|
return co
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
def rewrite_asserts(mod):
|
def rewrite_asserts(mod):
|
||||||
|
|
|
@ -539,3 +539,25 @@ class TestAssertionRewriteHookDetails(object):
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
'* 1 passed*',
|
'* 1 passed*',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_read_pyc(self, tmpdir):
|
||||||
|
"""
|
||||||
|
Ensure that the `_read_pyc` can properly deal with corrupted pyc files.
|
||||||
|
In those circumstances it should just give up instead of generating
|
||||||
|
an exception that is propagated to the caller.
|
||||||
|
"""
|
||||||
|
import py_compile
|
||||||
|
from _pytest.assertion.rewrite import _read_pyc
|
||||||
|
|
||||||
|
source = tmpdir.join('source.py')
|
||||||
|
pyc = source + 'c'
|
||||||
|
|
||||||
|
source.write('def test(): pass')
|
||||||
|
py_compile.compile(str(source), str(pyc))
|
||||||
|
|
||||||
|
contents = pyc.read(mode='rb')
|
||||||
|
strip_bytes = 20 # header is around 8 bytes, strip a little more
|
||||||
|
assert len(contents) > strip_bytes
|
||||||
|
pyc.write(contents[:strip_bytes], mode='wb')
|
||||||
|
|
||||||
|
assert _read_pyc(source, str(pyc)) is None # no error
|
||||||
|
|
Loading…
Reference in New Issue