fix assertion rewriting in read-only directories (refs #60)

This commit is contained in:
Benjamin Peterson 2011-07-12 17:09:14 -05:00
parent f3bc197afb
commit 14ceaf2459
3 changed files with 31 additions and 9 deletions

View File

@ -1,6 +1,7 @@
Changes between 2.1.0 and 2.1.1.DEV Changes between 2.1.0 and 2.1.1.DEV
---------------------------------------------- ----------------------------------------------
- fix assertion rewriting in read-only directories
- fix issue59: provide system-out/err tags for junitxml output - fix issue59: provide system-out/err tags for junitxml output
- fix assertion rewriting on boolean operations with 3 or more operands - fix assertion rewriting on boolean operations with 3 or more operands

View File

@ -90,16 +90,26 @@ class AssertionRewritingHook(object):
# cached pyc is always a complete, valid pyc. Operations on it must be # cached pyc is always a complete, valid pyc. Operations on it must be
# atomic. POSIX's atomic rename comes in handy. # atomic. POSIX's atomic rename comes in handy.
cache_dir = os.path.join(fn_pypath.dirname, "__pycache__") cache_dir = os.path.join(fn_pypath.dirname, "__pycache__")
try:
py.path.local(cache_dir).ensure(dir=True) py.path.local(cache_dir).ensure(dir=True)
except py.error.EACCES:
state.trace("read only directory: %r" % (fn_pypath.dirname,))
write = False
else:
write = True
cache_name = fn_pypath.basename[:-3] + "." + PYTEST_TAG + ".pyc" cache_name = fn_pypath.basename[:-3] + "." + PYTEST_TAG + ".pyc"
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 to check
# for a cached pyc. This may not be optimal...
co = _read_pyc(fn_pypath, pyc) co = _read_pyc(fn_pypath, pyc)
if co is None: if co is None:
state.trace("rewriting %r" % (fn,)) state.trace("rewriting %r" % (fn,))
co = _make_rewritten_pyc(state, fn_pypath, pyc) co = _rewrite_test(state, fn_pypath)
if co is None: if co is None:
# Probably a SyntaxError in the module. # Probably a SyntaxError in the test.
return None return None
if write:
_make_rewritten_pyc(state, fn_pypath, pyc, co)
else: else:
state.trace("found cached rewritten pyc for %r" % (fn,)) state.trace("found cached rewritten pyc for %r" % (fn,))
self.modules[name] = co, pyc self.modules[name] = co, pyc
@ -135,12 +145,8 @@ def _write_pyc(co, source_path, pyc):
finally: finally:
fp.close() fp.close()
def _make_rewritten_pyc(state, fn, pyc): def _rewrite_test(state, fn):
"""Try to rewrite *fn* and dump the rewritten code to *pyc*. """Try to read and rewrite *fn* and return the code object."""
Return the code object of the rewritten module on success. Return None if
there are problems parsing or compiling the module.
"""
try: try:
source = fn.read("rb") source = fn.read("rb")
except EnvironmentError: except EnvironmentError:
@ -159,6 +165,10 @@ def _make_rewritten_pyc(state, fn, pyc):
# assertion rewriting, but I don't know of a fast way to tell. # assertion rewriting, but I don't know of a fast way to tell.
state.trace("failed to compile: %r" % (fn,)) state.trace("failed to compile: %r" % (fn,))
return None return None
return co
def _make_rewritten_pyc(state, fn, pyc, co):
"""Try to dump rewritten code to *pyc*."""
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
# Windows grants exclusive access to open files and doesn't have atomic # Windows grants exclusive access to open files and doesn't have atomic
# rename, so just write into the final file. # rename, so just write into the final file.

View File

@ -266,3 +266,14 @@ class TestAssertionRewrite:
return False return False
assert myany(A() < 0) assert myany(A() < 0)
assert "<MY42 object> < 0" in getmsg(f) assert "<MY42 object> < 0" in getmsg(f)
class TestRewriteOnImport:
def test_readonly(self, testdir):
sub = testdir.mkdir("testing")
sub.join("test_readonly.py").write("""
def test_rewritten():
assert "@py_builtins" in globals()""")
sub.chmod(320)
assert testdir.runpytest().ret == 0