def test_write_pyc(self, testdir, tmpdir, monkeypatch): from _pytest.assertion.rewrite import _write_pyc from _pytest.assertion import AssertionState config = testdir.parseconfig([]) state = AssertionState(config, "rewrite") source_path = str(tmpdir.ensure("source.py")) pycpath = tmpdir.join("pyc").strpath assert _write_pyc(state, [1], os.stat(source_path), pycpath) if sys.platform == "win32": from contextlib import contextmanager @contextmanager def atomic_write_failed(fn, mode="r", overwrite=False): e = OSError() e.errno = 10 raise e yield monkeypatch.setattr(_pytest.assertion.rewrite, "atomic_write", atomic_write_failed) else: def raise_oserror(*args): raise OSError() monkeypatch.setattr("os.rename", raise_oserror) assert not _write_pyc(state, [1], os.stat(source_path), pycpath)
def test_write_pyc(self, testdir, tmpdir, monkeypatch): from _pytest.assertion.rewrite import _write_pyc from _pytest.assertion import AssertionState try: import __builtin__ as b except ImportError: import builtins as b config = testdir.parseconfig([]) state = AssertionState(config, "rewrite") source_path = tmpdir.ensure("source.py") pycpath = tmpdir.join("pyc").strpath assert _write_pyc(state, [1], source_path.stat(), pycpath) def open(*args): e = IOError() e.errno = 10 raise e monkeypatch.setattr(b, "open", open) assert not _write_pyc(state, [1], source_path.stat(), pycpath)
def test_write_pyc(self, testdir, tmpdir, monkeypatch): from _pytest.assertion.rewrite import _write_pyc from _pytest.assertion import AssertionState import atomicwrites from contextlib import contextmanager config = testdir.parseconfig([]) state = AssertionState(config, "rewrite") source_path = tmpdir.ensure("source.py") pycpath = tmpdir.join("pyc").strpath assert _write_pyc(state, [1], source_path.stat(), pycpath) @contextmanager def atomic_write_failed(fn, mode='r', overwrite=False): e = IOError() e.errno = 10 raise e yield # noqa monkeypatch.setattr(atomicwrites, "atomic_write", atomic_write_failed) assert not _write_pyc(state, [1], source_path.stat(), pycpath)
def test_write_pyc(self, testdir, tmpdir, monkeypatch): from _pytest.assertion.rewrite import _write_pyc from _pytest.assertion import AssertionState import atomicwrites from contextlib import contextmanager config = testdir.parseconfig([]) state = AssertionState(config, "rewrite") source_path = tmpdir.ensure("source.py") pycpath = tmpdir.join("pyc").strpath assert _write_pyc(state, [1], source_path.stat(), pycpath) @contextmanager def atomic_write_failed(fn, mode="r", overwrite=False): e = IOError() e.errno = 10 raise e yield monkeypatch.setattr(atomicwrites, "atomic_write", atomic_write_failed) assert not _write_pyc(state, [1], source_path.stat(), pycpath)
def find_module(self, name, path=None): if self.session is None: return None sess = self.session state = sess.config._assertstate state.trace("find_module called for: %s" % name) names = name.rsplit(".", 1) lastname = names[-1] pth = None if path is not None: # Starting with Python 3.3, path is a _NamespacePath(), which # causes problems if not converted to list. path = list(path) if len(path) == 1: pth = path[0] if pth is None: try: fd, fn, desc = imp.find_module(lastname, path) except ImportError: return None if fd is not None: fd.close() tp = desc[2] if tp == imp.PY_COMPILED: if hasattr(imp, "source_from_cache"): fn = imp.source_from_cache(fn) else: fn = fn[:-1] elif tp != imp.PY_SOURCE: # Don't know what this is. return None else: fn = os.path.join(pth, name.rpartition(".")[2] + ".py") self.session = None fn_pypath = py.path.local(fn) self.session = sess # Is this a test file? if not sess.isinitpath(fn): # We have to be very careful here because imports in this code can # trigger a cycle. self.session = None try: for pat in self.fnpats: if str(fn_pypath).endswith(pat): state.trace("matched test file %r" % (fn, )) break else: return None finally: self.session = sess else: state.trace("matched test file (was specified on cmdline): %r" % (fn, )) # The requested module looks like a test file, so rewrite it. This is # the most magical part of the process: load the source, rewrite the # asserts, and load the rewritten source. We also cache the rewritten # module code in a special pyc. We must be aware of the possibility of # concurrent pytest processes rewriting and loading pycs. To avoid # tricky race conditions, we maintain the following invariant: The # cached pyc is always a complete, valid pyc. Operations on it must be # atomic. POSIX's atomic rename comes in handy. write = not sys.dont_write_bytecode cache_dir = os.path.join(fn_pypath.dirname, "__pycache__") if write: try: os.mkdir(cache_dir) except OSError: e = sys.exc_info()[1].errno if e == errno.EEXIST: # Either the __pycache__ directory already exists (the # common case) or it's blocked by a non-dir node. In the # latter case, we'll ignore it in _write_pyc. pass elif e in [errno.ENOENT, errno.ENOTDIR]: # One of the path components was not a directory, likely # because we're in a zip file. write = False elif e in [errno.EACCES, errno.EROFS]: state.trace("read only directory: %r" % fn_pypath.dirname) write = False else: raise cache_name = fn_pypath.basename[:-3] + PYC_TAIL 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, state.trace) if co is None: state.trace("rewriting %r" % (fn, )) self.session = None try: source_stat, co = _rewrite_test(state, fn_pypath) finally: self.session = sess if co is None: # Probably a SyntaxError in the test. return None if write: self.session = None try: _write_pyc(state, co, source_stat, pyc) finally: self.session = sess else: state.trace("found cached rewritten pyc for %r" % (fn, )) self.session = None try: self.modules[name] = co, pyc finally: self.session = sess return self