def hook(self, pytestconfig, monkeypatch, testdir): """Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track if PathFinder.find_spec has been called. """ import importlib.machinery self.find_spec_calls = [] self.initial_paths = set() class StubSession: _initialpaths = self.initial_paths def isinitpath(self, p): return p in self._initialpaths def spy_find_spec(name, path): self.find_spec_calls.append(name) return importlib.machinery.PathFinder.find_spec(name, path) hook = AssertionRewritingHook(pytestconfig) # use default patterns, otherwise we inherit pytest's testing config hook.fnpats[:] = ["test_*.py", "*_test.py"] monkeypatch.setattr(hook, "_find_spec", spy_find_spec) hook.set_session(StubSession()) testdir.syspathinsert() return hook
def run(source_code_or_function, rewrite_assertions=True): """ Create module object, execute it and return Can be used as a decorator of the function from the source code of which the module will be constructed :param source_code_or_function string or function with body as a source code for created module :param rewrite_assertions: whether to rewrite assertions in module or not """ if isinstance(source_code_or_function, FunctionType): source_code = _extract_source_code_from_function(source_code_or_function) else: source_code = source_code_or_function module_name, filename = _create_module_file(source_code, tmp_path, request.node.name) if rewrite_assertions: loader = AssertionRewritingHook(config=request.config) loader.mark_rewrite(module_name) else: loader = None spec = importlib.util.spec_from_file_location(module_name, filename, loader=loader) sys.modules[module_name] = module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module
def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch): """Fix infinite recursion when writing pyc files: if an import happens to be triggered when writing the pyc file, this would cause another call to the hook, which would trigger another pyc writing, which could trigger another import, and so on. (#3506)""" from _pytest.assertion import rewrite testdir.syspathinsert() testdir.makepyfile(test_foo="def test_foo(): pass") testdir.makepyfile(test_bar="def test_bar(): pass") original_write_pyc = rewrite._write_pyc write_pyc_called = [] def spy_write_pyc(*args, **kwargs): # make a note that we have called _write_pyc write_pyc_called.append(True) # try to import a module at this point: we should not try to rewrite this module assert hook.find_spec("test_bar") is None return original_write_pyc(*args, **kwargs) monkeypatch.setattr(rewrite, "_write_pyc", spy_write_pyc) monkeypatch.setattr(sys, "dont_write_bytecode", False) hook = AssertionRewritingHook(pytestconfig) spec = hook.find_spec("test_foo") assert spec is not None module = importlib.util.module_from_spec(spec) hook.exec_module(module) assert len(write_pyc_called) == 1
def _import_execute(module_name: str, source: str, rewrite_assertions: bool = False): if rewrite_assertions: loader = AssertionRewritingHook(config=request.config) loader.mark_rewrite(module_name) else: loader = None example_bash_file = tmp_work_path / 'example.sh' example_bash_file.write_text('#!/bin/sh\necho testing') example_bash_file.chmod(0o755) (tmp_work_path / 'first/path').mkdir(parents=True, exist_ok=True) (tmp_work_path / 'second/path').mkdir(parents=True, exist_ok=True) module_path = tmp_work_path / f'{module_name}.py' module_path.write_text(source) spec = importlib.util.spec_from_file_location('__main__', str(module_path), loader=loader) module = importlib.util.module_from_spec(spec) try: spec.loader.exec_module(module) except KeyboardInterrupt: print('KeyboardInterrupt')
def test_rewrite_warning(self, pytestconfig, monkeypatch): hook = AssertionRewritingHook(pytestconfig) warnings = [] def mywarn(code, msg): warnings.append((code, msg)) monkeypatch.setattr(hook.config, 'warn', mywarn) hook.mark_rewrite('_pytest') assert '_pytest' in warnings[0][1]
def test_remember_rewritten_modules(self, pytestconfig, testdir, monkeypatch): """ AssertionRewriteHook should remember rewritten modules so it doesn't give false positives (#2005). """ monkeypatch.syspath_prepend(testdir.tmpdir) testdir.makepyfile(test_remember_rewritten_modules='') warnings = [] hook = AssertionRewritingHook(pytestconfig) monkeypatch.setattr(hook.config, 'warn', lambda code, msg: warnings.append(msg)) hook.find_module('test_remember_rewritten_modules') hook.load_module('test_remember_rewritten_modules') hook.mark_rewrite('test_remember_rewritten_modules') hook.mark_rewrite('test_remember_rewritten_modules') assert warnings == []
def test_remember_rewritten_modules(self, pytestconfig, testdir, monkeypatch): """`AssertionRewriteHook` should remember rewritten modules so it doesn't give false positives (#2005).""" monkeypatch.syspath_prepend(testdir.tmpdir) testdir.makepyfile(test_remember_rewritten_modules="") warnings = [] hook = AssertionRewritingHook(pytestconfig) monkeypatch.setattr( hook, "_warn_already_imported", lambda code, msg: warnings.append(msg) ) spec = hook.find_spec("test_remember_rewritten_modules") assert spec is not None module = importlib.util.module_from_spec(spec) hook.exec_module(module) hook.mark_rewrite("test_remember_rewritten_modules") hook.mark_rewrite("test_remember_rewritten_modules") assert warnings == []
def test_remember_rewritten_modules_warnings_stack_level( self, pytestconfig, testdir, monkeypatch): """ AssertionRewriteHook should raise warning with expected stack level """ def mock__issue_warning_captured(warning, hook, stacklevel=0): assert 5 == stacklevel monkeypatch.syspath_prepend(testdir.tmpdir) monkeypatch.setattr(_pytest.warnings, "_issue_warning_captured", mock__issue_warning_captured) testdir.makepyfile(test_remember_rewritten_modules="") hook = AssertionRewritingHook(pytestconfig) spec = hook.find_spec("test_remember_rewritten_modules") module = importlib.util.module_from_spec(spec) hook.exec_module(module) hook.mark_rewrite(*{"builtins": "<module 'builtins' (built-in)>"})