diff --git a/.travis.yml b/.travis.yml index af33d672e4c..bf53436080c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ stages: python: '3.7' cache: false + - pip install --upgrade virtualenv>=16.3.0 env: global: - PYTEST_ADDOPTS=-vv diff --git a/changelog/4507.bugfix.rst b/changelog/4507.bugfix.rst new file mode 100644 index 00000000000..49b4f1c7b87 --- /dev/null +++ b/changelog/4507.bugfix.rst @@ -0,0 +1 @@ +Sort out warnings we get at the import time of the internal modules. diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index 496931e0fcc..7fca2854d23 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -11,7 +11,9 @@ import attr import py -import pytest +from .config import hookimpl +from .fixtures import fixture +from .nodes import Item from .pathlib import Path from .pathlib import resolve_from_str from .pathlib import rm_rf @@ -276,7 +278,7 @@ def pytest_collection_modifyitems(self, session, config, items): items[:] = self._get_increasing_order( new_items.values() ) + self._get_increasing_order(other_items.values()) - self.cached_nodeids = [x.nodeid for x in items if isinstance(x, pytest.Item)] + self.cached_nodeids = [x.nodeid for x in items if isinstance(x, Item)] def _get_increasing_order(self, items): return sorted(items, key=lambda item: item.fspath.mtime(), reverse=True) @@ -354,14 +356,14 @@ def pytest_cmdline_main(config): return wrap_session(config, cacheshow) -@pytest.hookimpl(tryfirst=True) +@hookimpl(tryfirst=True) def pytest_configure(config): config.cache = Cache.for_config(config) config.pluginmanager.register(LFPlugin(config), "lfplugin") config.pluginmanager.register(NFPlugin(config), "nfplugin") -@pytest.fixture +@fixture def cache(request): """ Return a cache object that can persist state between testing sessions. diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index f89aaefba40..866c9d60a6d 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -10,7 +10,10 @@ from io import UnsupportedOperation from tempfile import TemporaryFile -import pytest +from .config import hookimpl +from .fixtures import fixture +from .nodes import File +from .outcomes import skip from _pytest.compat import CaptureIO patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"} @@ -35,7 +38,7 @@ def pytest_addoption(parser): ) -@pytest.hookimpl(hookwrapper=True) +@hookimpl(hookwrapper=True) def pytest_load_initial_conftests(early_config, parser, args): ns = early_config.known_args_namespace if ns.capture == "fd": @@ -193,9 +196,9 @@ def item_capture(self, when, item): # Hooks - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_make_collect_report(self, collector): - if isinstance(collector, pytest.File): + if isinstance(collector, File): self.resume_global_capture() outcome = yield self.suspend_global_capture() @@ -208,32 +211,32 @@ def pytest_make_collect_report(self, collector): else: yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_protocol(self, item): self._current_item = item yield self._current_item = None - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_setup(self, item): with self.item_capture("setup", item): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): with self.item_capture("call", item): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_teardown(self, item): with self.item_capture("teardown", item): yield - @pytest.hookimpl(tryfirst=True) + @hookimpl(tryfirst=True) def pytest_keyboard_interrupt(self, excinfo): self.stop_global_capturing() - @pytest.hookimpl(tryfirst=True) + @hookimpl(tryfirst=True) def pytest_internalerror(self, excinfo): self.stop_global_capturing() @@ -251,7 +254,7 @@ def _ensure_only_one_capture_fixture(request, name): ) -@pytest.fixture +@fixture def capsys(request): """Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``. @@ -264,7 +267,7 @@ def capsys(request): yield fixture -@pytest.fixture +@fixture def capsysbinary(request): """Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``. @@ -277,7 +280,7 @@ def capsysbinary(request): yield fixture -@pytest.fixture +@fixture def capfd(request): """Enable text capturing of writes to file descriptors ``1`` and ``2``. @@ -287,14 +290,14 @@ def capfd(request): """ _ensure_only_one_capture_fixture(request, "capfd") if not hasattr(os, "dup"): - pytest.skip( + skip( "capfd fixture needs os.dup function which is not available in this system" ) with _install_capture_fixture_on_item(request, FDCapture) as fixture: yield fixture -@pytest.fixture +@fixture def capfdbinary(request): """Enable bytes capturing of writes to file descriptors ``1`` and ``2``. @@ -304,7 +307,7 @@ def capfdbinary(request): """ _ensure_only_one_capture_fixture(request, "capfdbinary") if not hasattr(os, "dup"): - pytest.skip( + skip( "capfdbinary fixture needs os.dup function which is not available in this system" ) with _install_capture_fixture_on_item(request, FDCaptureBinary) as fixture: diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index c1bd2e7ebd9..ea90851c243 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -17,7 +17,6 @@ from pluggy import PluginManager import _pytest._code -import _pytest.assertion import _pytest.hookspec # the extension point definitions from .exceptions import PrintHelp from .exceptions import UsageError @@ -238,7 +237,9 @@ def __init__(self): self.enable_tracing() # Config._consider_importhook will set a real object if required. - self.rewrite_hook = _pytest.assertion.DummyRewriteHook() + from _pytest.assertion import DummyRewriteHook + + self.rewrite_hook = DummyRewriteHook() # Used to know when we are importing conftests after the pytest_configure stage self._configured = False diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index ca6e4675f5a..7b41922ff0d 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -6,13 +6,16 @@ import warnings from contextlib import contextmanager -import pytest from _pytest._code.code import ExceptionInfo from _pytest._code.code import ReprFileLocation from _pytest._code.code import TerminalRepr from _pytest.compat import safe_getattr +from _pytest.fixtures import fixture from _pytest.fixtures import FixtureRequest +from _pytest.nodes import Item +from _pytest.outcomes import skip from _pytest.outcomes import Skipped +from _pytest.python import Module from _pytest.warning_types import PytestWarning DOCTEST_REPORT_CHOICE_NONE = "none" @@ -176,7 +179,7 @@ def _get_runner(checker=None, verbose=None, optionflags=0, continue_on_failure=T ) -class DoctestItem(pytest.Item): +class DoctestItem(Item): def __init__(self, name, parent, runner=None, dtest=None): super().__init__(name, parent) self.runner = runner @@ -308,7 +311,7 @@ def _get_continue_on_failure(config): return continue_on_failure -class DoctestTextfile(pytest.Module): +class DoctestTextfile(Module): obj = None def collect(self): @@ -345,7 +348,7 @@ def _check_all_skipped(test): all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples) if all_skipped: - pytest.skip("all tests skipped by +SKIP option") + skip("all tests skipped by +SKIP option") def _is_mocked(obj): @@ -387,7 +390,7 @@ def _mock_aware_unwrap(obj, stop=None): inspect.unwrap = real_unwrap -class DoctestModule(pytest.Module): +class DoctestModule(Module): def collect(self): import doctest @@ -415,7 +418,7 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen): module = self.fspath.pyimport() except ImportError: if self.config.getvalue("doctest_ignore_import_errors"): - pytest.skip("unable to import module %r" % self.fspath) + skip("unable to import module %r" % self.fspath) else: raise # uses internal doctest module parsing mechanism @@ -540,7 +543,7 @@ def _get_report_choice(key): }[key] -@pytest.fixture(scope="session") +@fixture(scope="session") def doctest_namespace(): """ Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests. diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index b379fae01dc..80463ba88c2 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -5,7 +5,7 @@ import py -import pytest +from _pytest.config import hookimpl from _pytest.config import PrintHelp @@ -83,11 +83,13 @@ def pytest_addoption(parser): ) -@pytest.hookimpl(hookwrapper=True) +@hookimpl(hookwrapper=True) def pytest_cmdline_parse(): outcome = yield config = outcome.get_result() if config.option.debug: + import pytest + path = os.path.abspath("pytestdebug.log") debugfile = open(path, "w") debugfile.write( @@ -115,6 +117,8 @@ def unset_tracing(): def showversion(config): + import pytest + p = py.path.local(pytest.__file__) sys.stderr.write( "This is pytest version {}, imported from {}\n".format(pytest.__version__, p) @@ -223,6 +227,8 @@ def getpluginversioninfo(config): def pytest_report_header(config): lines = [] + import pytest + if config.option.debug or config.option.traceconfig: lines.append( "using: pytest-{} pylib-{}".format(pytest.__version__, py.__version__) diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index ea33e606c30..cfb3cc10bee 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -16,9 +16,9 @@ import py -import pytest from _pytest import nodes from _pytest.config import filename_arg +from _pytest.fixtures import fixture class Junit(py.xml.Namespace): @@ -290,7 +290,7 @@ def _warn_incompatibility_with_xunit2(request, fixture_name): ) -@pytest.fixture +@fixture def record_property(request): """Add an extra properties the calling test. User properties become part of the test report and are available to the @@ -311,7 +311,7 @@ def append_property(name, value): return append_property -@pytest.fixture +@fixture def record_xml_attribute(request): """Add extra xml attributes to the tag for the calling test. The fixture is callable with ``(name, value)``, with value being @@ -348,7 +348,7 @@ def _check_record_param_type(param, v): raise TypeError(msg.format(param=param, g=type(v).__name__)) -@pytest.fixture(scope="session") +@fixture(scope="session") def record_testsuite_property(request): """ Records a new ```` tag as child of the root ````. This is suitable to diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 2861baefda3..cd4b3f8ccf4 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -5,9 +5,11 @@ import py -import pytest +from .config import hookimpl from _pytest.compat import nullcontext from _pytest.config import create_terminal_writer +from _pytest.config import UsageError +from _pytest.fixtures import fixture from _pytest.pathlib import Path DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s" @@ -350,7 +352,7 @@ def at_level(self, level, logger=None): logger.setLevel(orig_level) -@pytest.fixture +@fixture def caplog(request): """Access and control log capturing. @@ -384,7 +386,7 @@ def get_actual_log_level(config, *setting_names): return int(getattr(logging, log_level, log_level)) except ValueError: # Python logging does not recognise this as a logging level - raise pytest.UsageError( + raise UsageError( "'{}' is not recognized as a logging level name for " "'{}'. Please consider passing the " "logging level num instead.".format(log_level, setting_name) @@ -392,7 +394,7 @@ def get_actual_log_level(config, *setting_names): # run after terminalreporter/capturemanager are configured -@pytest.hookimpl(trylast=True) +@hookimpl(trylast=True) def pytest_configure(config): config.pluginmanager.register(LoggingPlugin(config), "logging-plugin") @@ -510,7 +512,7 @@ def _log_cli_enabled(self): "--log-cli-level" ) is not None or self._config.getini("log_cli") - @pytest.hookimpl(hookwrapper=True, tryfirst=True) + @hookimpl(hookwrapper=True, tryfirst=True) def pytest_collection(self): with self.live_logs_context(): if self.log_cli_handler: @@ -560,39 +562,39 @@ def _runtest_for_main(self, item, when): log = log_handler.stream.getvalue().strip() item.add_report_section(when, "log", log) - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_setup(self, item): with self._runtest_for(item, "setup"): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): with self._runtest_for(item, "call"): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_teardown(self, item): with self._runtest_for(item, "teardown"): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_logstart(self): if self.log_cli_handler: self.log_cli_handler.reset() with self._runtest_for(None, "start"): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_logfinish(self): with self._runtest_for(None, "finish"): yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtest_logreport(self): with self._runtest_for(None, "logreport"): yield - @pytest.hookimpl(hookwrapper=True, tryfirst=True) + @hookimpl(hookwrapper=True, tryfirst=True) def pytest_sessionfinish(self): with self.live_logs_context(): if self.log_cli_handler: @@ -610,7 +612,7 @@ def pytest_sessionfinish(self): else: yield - @pytest.hookimpl(hookwrapper=True, tryfirst=True) + @hookimpl(hookwrapper=True, tryfirst=True) def pytest_sessionstart(self): with self.live_logs_context(): if self.log_cli_handler: @@ -621,7 +623,7 @@ def pytest_sessionstart(self): else: yield - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_runtestloop(self, session): """Runs all collected test items.""" diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index 090bf61d6e9..e3e4427801c 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -5,7 +5,7 @@ import warnings from contextlib import contextmanager -import pytest +from .warning_types import PytestWarning from _pytest.fixtures import fixture from _pytest.pathlib import Path @@ -225,7 +225,7 @@ def setenv(self, name, value, prepend=None): and prepend the ``value`` adjoined with the ``prepend`` character.""" if not isinstance(value, str): warnings.warn( - pytest.PytestWarning( + PytestWarning( "Value of environment variable {name} type should be str, but got " "{value!r} (type: {type}); converted to str implicitly".format( name=name, value=value, type=type(value).__name__ diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py index ce0e73accc2..c350adefeb4 100644 --- a/src/_pytest/pastebin.py +++ b/src/_pytest/pastebin.py @@ -1,7 +1,7 @@ """ submit failure or test session information to a pastebin service. """ import tempfile -import pytest +from _pytest.config import hookimpl def pytest_addoption(parser): @@ -17,7 +17,7 @@ def pytest_addoption(parser): ) -@pytest.hookimpl(trylast=True) +@hookimpl(trylast=True) def pytest_configure(config): if config.option.pastebin == "all": tr = config.pluginmanager.getplugin("terminalreporter") diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 2068761faf9..49f4eb6bc62 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -14,15 +14,23 @@ import py -import pytest from _pytest._code import Source from _pytest._io.saferepr import saferepr from _pytest.capture import MultiCapture from _pytest.capture import SysCapture +from _pytest.config import _prepareconfig +from _pytest.config import hookimpl +from _pytest.config import main +from _pytest.fixtures import fixture from _pytest.main import ExitCode from _pytest.main import Session from _pytest.monkeypatch import MonkeyPatch +from _pytest.outcomes import fail +from _pytest.outcomes import importorskip +from _pytest.outcomes import skip +from _pytest.outcomes import xfail from _pytest.pathlib import Path +from _pytest.warning_types import PytestWarning IGNORE_PAM = [ # filenames added when obtaining details about the current user "/var/lib/sss/mc/passwd" @@ -106,13 +114,13 @@ def isopen(line): def matching_platform(self): try: - subprocess.check_output(("lsof", "-v")) + subprocess.check_output(("lsof", "-v"), stderr=subprocess.STDOUT) except (OSError, subprocess.CalledProcessError): return False else: return True - @pytest.hookimpl(hookwrapper=True, tryfirst=True) + @hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_protocol(self, item): lines1 = self.get_open_files() yield @@ -133,13 +141,13 @@ def pytest_runtest_protocol(self, item): error.append(error[0]) error.append("*** function %s:%s: %s " % item.location) error.append("See issue #2366") - item.warn(pytest.PytestWarning("\n".join(error))) + item.warn(PytestWarning("\n".join(error))) # used at least by pytest-xdist plugin -@pytest.fixture +@fixture def _pytest(request): """Return a helper which offers a gethookrecorder(hook) method which returns a HookRecorder instance which helps to make assertions about called @@ -222,7 +230,7 @@ def assert_contains(self, entries): break print("NONAMEMATCH", name, "with", call) else: - pytest.fail("could not find {!r} check {!r}".format(name, check)) + fail("could not find {!r} check {!r}".format(name, check)) def popcall(self, name): __tracebackhide__ = True @@ -232,7 +240,7 @@ def popcall(self, name): return call lines = ["could not find call {!r}, in:".format(name)] lines.extend([" %s" % x for x in self.calls]) - pytest.fail("\n".join(lines)) + fail("\n".join(lines)) def getcall(self, name): values = self.getcalls(name) @@ -307,22 +315,22 @@ def clear(self): self.calls[:] = [] -@pytest.fixture +@fixture def linecomp(request): return LineComp() -@pytest.fixture(name="LineMatcher") +@fixture(name="LineMatcher") def LineMatcher_fixture(request): return LineMatcher -@pytest.fixture +@fixture def testdir(request, tmpdir_factory): return Testdir(request, tmpdir_factory) -@pytest.fixture +@fixture def _sys_snapshot(): snappaths = SysPathsSnapshot() snapmods = SysModulesSnapshot() @@ -331,7 +339,7 @@ def _sys_snapshot(): snappaths.restore() -@pytest.fixture +@fixture def _config_for_test(): from _pytest.config import get_config @@ -821,7 +829,7 @@ def pytest_configure(x, config): rec.append(self.make_hook_recorder(config.pluginmanager)) plugins.append(Collect()) - ret = pytest.main(list(args), plugins=plugins) + ret = main(list(args), plugins=plugins) if len(rec) == 1: reprec = rec.pop() else: @@ -908,9 +916,7 @@ def parseconfig(self, *args): """ args = self._ensure_basetemp(args) - import _pytest.config - - config = _pytest.config._prepareconfig(args, self.plugins) + config = _prepareconfig(args, self.plugins) # we don't know what the test will do with this half-setup config # object and thus we make sure it gets unconfigured properly in any # case (otherwise capturing could still be active, for example) @@ -1183,11 +1189,11 @@ def spawn(self, cmd, expect_timeout=10.0): The pexpect child is returned. """ - pexpect = pytest.importorskip("pexpect", "3.0") + pexpect = importorskip("pexpect", "3.0") if hasattr(sys, "pypy_version_info") and "64" in platform.machine(): - pytest.skip("pypy-64 bit not supported") + skip("pypy-64 bit not supported") if sys.platform.startswith("freebsd"): - pytest.xfail("pexpect does not work reliably on freebsd") + xfail("pexpect does not work reliably on freebsd") logfile = self.tmpdir.join("spawn.out").open("wb") # Do not load user config. @@ -1366,4 +1372,4 @@ def _match_lines(self, lines2, match_func, match_nickname): extralines.append(nextline) else: self._log("remains unmatched: {!r}".format(line)) - pytest.fail(self._log_text) + fail(self._log_text) diff --git a/src/_pytest/setuponly.py b/src/_pytest/setuponly.py index 70d6ed12f86..769b494213e 100644 --- a/src/_pytest/setuponly.py +++ b/src/_pytest/setuponly.py @@ -1,6 +1,6 @@ import sys -import pytest +from _pytest.config import hookimpl def pytest_addoption(parser): @@ -19,7 +19,7 @@ def pytest_addoption(parser): ) -@pytest.hookimpl(hookwrapper=True) +@hookimpl(hookwrapper=True) def pytest_fixture_setup(fixturedef, request): yield config = request.config @@ -78,7 +78,7 @@ def _show_fixture_action(fixturedef, msg): sys.stderr.write(err) -@pytest.hookimpl(tryfirst=True) +@hookimpl(tryfirst=True) def pytest_cmdline_main(config): if config.option.setuponly: config.option.setupshow = True diff --git a/src/_pytest/setupplan.py b/src/_pytest/setupplan.py index 697746f205a..99f8de44b22 100644 --- a/src/_pytest/setupplan.py +++ b/src/_pytest/setupplan.py @@ -1,4 +1,4 @@ -import pytest +from _pytest.config import hookimpl def pytest_addoption(parser): @@ -12,7 +12,7 @@ def pytest_addoption(parser): ) -@pytest.hookimpl(tryfirst=True) +@hookimpl(tryfirst=True) def pytest_fixture_setup(fixturedef, request): # Will return a dummy fixture if the setuponly option is provided. if request.config.option.setupplan: @@ -20,7 +20,7 @@ def pytest_fixture_setup(fixturedef, request): return fixturedef.cached_result -@pytest.hookimpl(tryfirst=True) +@hookimpl(tryfirst=True) def pytest_cmdline_main(config): if config.option.setupplan: config.option.setuponly = True diff --git a/src/_pytest/stepwise.py b/src/_pytest/stepwise.py index 6fa21cd1c65..f3846df85bc 100644 --- a/src/_pytest/stepwise.py +++ b/src/_pytest/stepwise.py @@ -1,4 +1,4 @@ -import pytest +from _pytest.config import hookimpl def pytest_addoption(parser): @@ -18,7 +18,7 @@ def pytest_addoption(parser): ) -@pytest.hookimpl +@hookimpl def pytest_configure(config): config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin") diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 05d5427c308..163d9b0d09b 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -14,7 +14,8 @@ import py from more_itertools import collapse -import pytest +from .config import hookimpl +from .nodes import Item from _pytest import nodes from _pytest.main import ExitCode @@ -166,7 +167,7 @@ def getreportopt(config): return reportopts -@pytest.hookimpl(trylast=True) # after _pytest.runner +@hookimpl(trylast=True) # after _pytest.runner def pytest_report_teststatus(report): if report.passed: letter = "." @@ -497,7 +498,7 @@ def pytest_collectreport(self, report): self.stats.setdefault("error", []).append(report) elif report.skipped: self.stats.setdefault("skipped", []).append(report) - items = [x for x in report.result if isinstance(x, pytest.Item)] + items = [x for x in report.result if isinstance(x, Item)] self._numcollected += len(items) if self.isatty: self.report_collect() @@ -542,7 +543,11 @@ def report_collect(self, final=False): else: self.write_line(line) - @pytest.hookimpl(trylast=True) + @hookimpl(trylast=True) + def pytest_collection_modifyitems(self): + self.report_collect(True) + + @hookimpl(trylast=True) def pytest_sessionstart(self, session): self._session = session self._sessionstarttime = time.time() @@ -554,6 +559,9 @@ def pytest_sessionstart(self, session): if hasattr(sys, "pypy_version_info"): verinfo = ".".join(map(str, sys.pypy_version_info[:3])) msg += "[pypy-{}-{}]".format(verinfo, sys.pypy_version_info[3]) + import pytest + import py + msg += ", pytest-{}, py-{}, pluggy-{}".format( pytest.__version__, py.__version__, pluggy.__version__ ) @@ -643,7 +651,7 @@ def _printcollecteditems(self, items): for line in col._obj.__doc__.strip().splitlines(): self._tw.line("{}{}".format(indent + " ", line.strip())) - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_sessionfinish(self, exitstatus): outcome = yield outcome.get_result() @@ -664,7 +672,7 @@ def pytest_sessionfinish(self, exitstatus): del self._keyboardinterrupt_memo self.summary_stats() - @pytest.hookimpl(hookwrapper=True) + @hookimpl(hookwrapper=True) def pytest_terminal_summary(self): self.summary_errors() self.summary_failures() diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index 48680c07ea5..01a6d725533 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -7,13 +7,13 @@ import attr import py -import pytest +from .fixtures import fixture +from .monkeypatch import MonkeyPatch from .pathlib import ensure_reset_dir from .pathlib import LOCK_TIMEOUT from .pathlib import make_numbered_dir from .pathlib import make_numbered_dir_with_cleanup from .pathlib import Path -from _pytest.monkeypatch import MonkeyPatch @attr.s @@ -132,23 +132,24 @@ def pytest_configure(config): available at pytest_configure time, but ideally should be moved entirely to the tmpdir_factory session fixture. """ + mp = MonkeyPatch() tmppath_handler = TempPathFactory.from_config(config) t = TempdirFactory(tmppath_handler) config._cleanup.append(mp.undo) mp.setattr(config, "_tmp_path_factory", tmppath_handler, raising=False) mp.setattr(config, "_tmpdirhandler", t, raising=False) - mp.setattr(pytest, "ensuretemp", t.ensuretemp, raising=False) + mp.setattr("pytest.ensuretemp", t.ensuretemp, raising=False) -@pytest.fixture(scope="session") +@fixture(scope="session") def tmpdir_factory(request): """Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session. """ return request.config._tmpdirhandler -@pytest.fixture(scope="session") +@fixture(scope="session") def tmp_path_factory(request): """Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session. """ @@ -163,7 +164,7 @@ def _mk_tmp(request, factory): return factory.mktemp(name, numbered=True) -@pytest.fixture +@fixture def tmpdir(tmp_path): """Return a temporary directory path object which is unique to each test function invocation, @@ -176,7 +177,7 @@ def tmpdir(tmp_path): return py.path.local(tmp_path) -@pytest.fixture +@fixture def tmp_path(request, tmp_path_factory): """Return a temporary directory path object which is unique to each test function invocation, diff --git a/src/_pytest/warnings.py b/src/_pytest/warnings.py index f47eee0d4f0..21ced3fda61 100644 --- a/src/_pytest/warnings.py +++ b/src/_pytest/warnings.py @@ -2,7 +2,8 @@ import warnings from contextlib import contextmanager -import pytest +from _pytest.config import hookimpl +from _pytest.warning_types import PytestDeprecationWarning SHOW_PYTEST_WARNINGS_ARG = "-Walways::pytest.RemovedInPytest4Warning" @@ -74,8 +75,7 @@ def catch_warnings_for_item(config, ihook, when, item): warnings.filterwarnings("always", category=DeprecationWarning) warnings.filterwarnings("always", category=PendingDeprecationWarning) - warnings.filterwarnings("error", category=pytest.RemovedInPytest4Warning) - warnings.filterwarnings("error", category=pytest.PytestDeprecationWarning) + warnings.filterwarnings("error", category=PytestDeprecationWarning) # filters should have this precedence: mark, cmdline options, ini # filters should be applied in the inverse order of precedence @@ -111,7 +111,7 @@ def warning_record_to_str(warning_message): return msg -@pytest.hookimpl(hookwrapper=True, tryfirst=True) +@hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_protocol(item): with catch_warnings_for_item( config=item.config, ihook=item.ihook, when="runtest", item=item @@ -119,7 +119,7 @@ def pytest_runtest_protocol(item): yield -@pytest.hookimpl(hookwrapper=True, tryfirst=True) +@hookimpl(hookwrapper=True, tryfirst=True) def pytest_collection(session): config = session.config with catch_warnings_for_item( @@ -128,7 +128,7 @@ def pytest_collection(session): yield -@pytest.hookimpl(hookwrapper=True) +@hookimpl(hookwrapper=True) def pytest_terminal_summary(terminalreporter): config = terminalreporter.config with catch_warnings_for_item( diff --git a/testing/test_own_modules.py b/testing/test_own_modules.py new file mode 100644 index 00000000000..34f96cd7b12 --- /dev/null +++ b/testing/test_own_modules.py @@ -0,0 +1,39 @@ +import subprocess +import sys +import types +from typing import Dict + +import _pytest +import pytest +from _pytest.mark import MarkDecorator + +KNOWN_BAD: Dict[str, MarkDecorator] = {} + + +def _modvalues(module): + for submodule in vars(module).values(): + if isinstance(submodule, types.ModuleType): + name = submodule.__name__ + yield pytest.param(name, marks=KNOWN_BAD.get(name, [])) + + +def _get_modules(): + yield from _modvalues(_pytest) + yield from _modvalues(_pytest.config) + yield from _modvalues(_pytest.mark) + + +@pytest.mark.parametrize("module_name", sorted(_get_modules())) +def test_module_warning_free(module_name): + # fmt: off + subprocess.check_call([ + sys.executable, + "-W", "error", + # from virtualenv on appveyor + "-W", "ignore:.*mode is deprecated.*:DeprecationWarning", + # from bruno testing in a venv + "-W", "ignore:.*Not importing directory.*:ImportWarning", + # virtualenv bug + "-W", "ignore:the imp:DeprecationWarning:distutils", + "-c", "import " + module_name, + ])