only try to create the __pycache__ dir (not a tree to it) fixes #60
Also, improve error handling surrounding __pycache__ creation.
This commit is contained in:
parent
f86c8469f5
commit
643ab120f4
|
@ -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 error conditions involving the creation of __pycache__
|
||||||
- fix assertion rewriting on inserts involving strings containing '%'
|
- fix assertion rewriting on inserts involving strings containing '%'
|
||||||
- fix assertion rewriting on calls with a ** arg
|
- fix assertion rewriting on calls with a ** arg
|
||||||
- don't cache rewritten modules if bytecode generation is disabled
|
- don't cache rewritten modules if bytecode generation is disabled
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import collections
|
import collections
|
||||||
|
import errno
|
||||||
import itertools
|
import itertools
|
||||||
import imp
|
import imp
|
||||||
import marshal
|
import marshal
|
||||||
|
@ -97,15 +98,23 @@ class AssertionRewritingHook(object):
|
||||||
cache_dir = os.path.join(fn_pypath.dirname, "__pycache__")
|
cache_dir = os.path.join(fn_pypath.dirname, "__pycache__")
|
||||||
if write:
|
if write:
|
||||||
try:
|
try:
|
||||||
py.path.local(cache_dir).ensure(dir=True)
|
os.mkdir(cache_dir)
|
||||||
except py.error.EACCES:
|
except OSError:
|
||||||
state.trace("read only directory: %r" % (fn_pypath.dirname,))
|
e = sys.exc_info()[1].errno
|
||||||
write = False
|
if e == errno.EEXIST:
|
||||||
except py.error.EEXIST:
|
# Either the __pycache__ directory already exists (the
|
||||||
state.trace("failure to create directory: %r" % (
|
# common case) or it's blocked by a non-dir node. In the
|
||||||
fn_pypath.dirname,))
|
# latter case, we'll ignore it in _write_pyc.
|
||||||
raise
|
pass
|
||||||
#write = False
|
elif e == errno.ENOTDIR:
|
||||||
|
# One of the path components was not a directory, likely
|
||||||
|
# because we're in a zip file.
|
||||||
|
write = False
|
||||||
|
elif e == errno.EACCES:
|
||||||
|
state.trace("read only directory: %r" % (fn_pypath.dirname,))
|
||||||
|
write = False
|
||||||
|
else:
|
||||||
|
raise
|
||||||
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
|
# Notice that even if we're in a read-only directory, I'm going to check
|
||||||
|
@ -146,13 +155,21 @@ def _write_pyc(co, source_path, pyc):
|
||||||
# little reason deviate, and I hope sometime to be able to use
|
# little reason deviate, and I hope sometime to be able to use
|
||||||
# imp.load_compiled to load them. (See the comment in load_module above.)
|
# imp.load_compiled to load them. (See the comment in load_module above.)
|
||||||
mtime = int(source_path.mtime())
|
mtime = int(source_path.mtime())
|
||||||
fp = open(pyc, "wb")
|
try:
|
||||||
|
fp = open(pyc, "wb")
|
||||||
|
except IOError:
|
||||||
|
if sys.exc_info()[1].errno == errno.ENOTDIR:
|
||||||
|
# This happens when we get a EEXIST in find_module creating the
|
||||||
|
# __pycache__ directory and __pycache__ is by some non-dir node.
|
||||||
|
return False
|
||||||
|
raise
|
||||||
try:
|
try:
|
||||||
fp.write(imp.get_magic())
|
fp.write(imp.get_magic())
|
||||||
fp.write(struct.pack("<l", mtime))
|
fp.write(struct.pack("<l", mtime))
|
||||||
marshal.dump(co, fp)
|
marshal.dump(co, fp)
|
||||||
finally:
|
finally:
|
||||||
fp.close()
|
fp.close()
|
||||||
|
return True
|
||||||
|
|
||||||
def _rewrite_test(state, fn):
|
def _rewrite_test(state, fn):
|
||||||
"""Try to read and rewrite *fn* and return the code object."""
|
"""Try to read and rewrite *fn* and return the code object."""
|
||||||
|
@ -186,8 +203,8 @@ def _make_rewritten_pyc(state, fn, pyc, co):
|
||||||
# When not on windows, assume rename is atomic. Dump the code object
|
# When not on windows, assume rename is atomic. Dump the code object
|
||||||
# into a file specific to this process and atomically replace it.
|
# into a file specific to this process and atomically replace it.
|
||||||
proc_pyc = pyc + "." + str(os.getpid())
|
proc_pyc = pyc + "." + str(os.getpid())
|
||||||
_write_pyc(co, fn, proc_pyc)
|
if _write_pyc(co, fn, proc_pyc):
|
||||||
os.rename(proc_pyc, pyc)
|
os.rename(proc_pyc, pyc)
|
||||||
return co
|
return co
|
||||||
|
|
||||||
def _read_pyc(source, pyc):
|
def _read_pyc(source, pyc):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import sys
|
import sys
|
||||||
|
import zipfile
|
||||||
import py
|
import py
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -283,6 +284,29 @@ class TestAssertionRewrite:
|
||||||
|
|
||||||
class TestRewriteOnImport:
|
class TestRewriteOnImport:
|
||||||
|
|
||||||
|
def test_pycache_is_a_file(self, testdir):
|
||||||
|
testdir.tmpdir.join("__pycache__").write("Hello")
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_rewritten():
|
||||||
|
assert "@py_builtins" in globals()""")
|
||||||
|
assert testdir.runpytest().ret == 0
|
||||||
|
|
||||||
|
def test_zipfile(self, testdir):
|
||||||
|
z = testdir.tmpdir.join("myzip.zip")
|
||||||
|
z_fn = str(z)
|
||||||
|
f = zipfile.ZipFile(z_fn, "w")
|
||||||
|
try:
|
||||||
|
f.writestr("test_gum/__init__.py", "")
|
||||||
|
f.writestr("test_gum/test_lizard.py", "")
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
z.chmod(256)
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import sys
|
||||||
|
sys.path.append(%r)
|
||||||
|
import test_gum.test_lizard""" % (z_fn,))
|
||||||
|
assert testdir.runpytest().ret == 0
|
||||||
|
|
||||||
def test_readonly(self, testdir):
|
def test_readonly(self, testdir):
|
||||||
sub = testdir.mkdir("testing")
|
sub = testdir.mkdir("testing")
|
||||||
sub.join("test_readonly.py").write(
|
sub.join("test_readonly.py").write(
|
||||||
|
|
Loading…
Reference in New Issue