From 9b8039cf094063a80bd13ce32e3f4b48a77fe89c Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 14 Jan 2020 18:58:02 +0100 Subject: [PATCH 01/14] Sync `{Session,Package}._recurse` --- src/_pytest/main.py | 2 +- src/_pytest/python.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 7ce4c19ea..283ff29b1 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -625,7 +625,7 @@ class Session(nodes.FSCollector): return ihook.pytest_collect_file(path=path, parent=self) - def _recurse(self, dirpath): + def _recurse(self, dirpath: py.path.local) -> bool: if dirpath.basename == "__pycache__": return False ihook = self.gethookproxy(dirpath.dirpath()) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 82dca3bcc..869e45261 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -571,12 +571,12 @@ class Package(Module): func = partial(_call_with_optional_argument, teardown_module, self.obj) self.addfinalizer(func) - def _recurse(self, dirpath): + def _recurse(self, dirpath: py.path.local) -> bool: if dirpath.basename == "__pycache__": return False ihook = self.gethookproxy(dirpath.dirpath()) if ihook.pytest_ignore_collect(path=dirpath, config=self.config): - return + return False for pat in self._norecursepatterns: if dirpath.check(fnmatch=pat): return False From 817c094ce62b322ad5a6ccce07ddd0ea3b75710e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 14 Jan 2020 17:57:24 +0100 Subject: [PATCH 02/14] Clean up Package.__init__ Makes `parent` a required arg, which would have failed before via `parent.session` anyway. Keeps calling/passing unused args for B/C. --- src/_pytest/python.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 869e45261..9def7e49e 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -545,15 +545,23 @@ class Module(nodes.File, PyCollector): class Package(Module): - def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None): + def __init__( + self, + fspath: py.path.local, + parent: nodes.Collector, + # NOTE: following args are unused: + config=None, + session=None, + nodeid=None, + ) -> None: + # NOTE: could be just the following, but kept as-is for compat. + # nodes.FSCollector.__init__(self, fspath, parent=parent) session = parent.session nodes.FSCollector.__init__( self, fspath, parent=parent, config=config, session=session, nodeid=nodeid ) + self.name = fspath.dirname - self.trace = session.trace - self._norecursepatterns = session._norecursepatterns - self.fspath = fspath def setup(self): # not using fixtures to call setup_module here because autouse fixtures From 6b7e1a246cbaec554166b855c74fdb58cf54c08b Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 14 Jan 2020 19:10:56 +0100 Subject: [PATCH 03/14] Sync `{Session,Package}.gethookproxy` Only copy'n'paste error from c416b1d935. --- src/_pytest/python.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 9def7e49e..916ef7bd5 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -594,7 +594,7 @@ class Package(Module): def gethookproxy(self, fspath): # check if we have the common case of running - # hooks with all conftest.py filesall conftest.py + # hooks with all conftest.py files pm = self.config.pluginmanager my_conftestmodules = pm._getconftestmodules(fspath) remove_mods = pm._conftest_plugins.difference(my_conftestmodules) From e2934c3f8c03c83469f4c6670c207773a6e02df4 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 14 Jan 2020 19:15:26 +0100 Subject: [PATCH 04/14] Move common code between Session and Package to FSCollector --- src/_pytest/main.py | 39 +-------------------------------------- src/_pytest/nodes.py | 41 +++++++++++++++++++++++++++++++++++++++++ src/_pytest/python.py | 27 +-------------------------- 3 files changed, 43 insertions(+), 64 deletions(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 283ff29b1..066c885b8 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -348,18 +348,6 @@ def pytest_collection_modifyitems(items, config): items[:] = remaining -class FSHookProxy: - def __init__(self, fspath, pm, remove_mods): - self.fspath = fspath - self.pm = pm - self.remove_mods = remove_mods - - def __getattr__(self, name): - x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) - self.__dict__[name] = x - return x - - class NoMatch(Exception): """ raised if matching cannot locate a matching names. """ @@ -401,7 +389,6 @@ class Session(nodes.FSCollector): self.shouldstop = False self.shouldfail = False self.trace = config.trace.root.get("collection") - self._norecursepatterns = config.getini("norecursedirs") self.startdir = config.invocation_dir self._initialpaths = frozenset() # type: FrozenSet[py.path.local] @@ -450,18 +437,7 @@ class Session(nodes.FSCollector): return path in self._initialpaths def gethookproxy(self, fspath): - # check if we have the common case of running - # hooks with all conftest.py files - pm = self.config.pluginmanager - my_conftestmodules = pm._getconftestmodules(fspath) - remove_mods = pm._conftest_plugins.difference(my_conftestmodules) - if remove_mods: - # one or more conftests are not in use at this fspath - proxy = FSHookProxy(fspath, pm, remove_mods) - else: - # all plugins are active for this fspath - proxy = self.config.hook - return proxy + return super()._gethookproxy(fspath) def perform_collect(self, args=None, genitems=True): hook = self.config.hook @@ -625,19 +601,6 @@ class Session(nodes.FSCollector): return ihook.pytest_collect_file(path=path, parent=self) - def _recurse(self, dirpath: py.path.local) -> bool: - if dirpath.basename == "__pycache__": - return False - ihook = self.gethookproxy(dirpath.dirpath()) - if ihook.pytest_ignore_collect(path=dirpath, config=self.config): - return False - for pat in self._norecursepatterns: - if dirpath.check(fnmatch=pat): - return False - ihook = self.gethookproxy(dirpath) - ihook.pytest_collect_directory(path=dirpath, parent=self) - return True - @staticmethod def _visit_filter(f): return f.check(file=1) diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index ab976efae..f9f1f4f68 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -393,6 +393,18 @@ def _check_initialpaths_for_relpath(session, fspath): return fspath.relto(initial_path) +class FSHookProxy: + def __init__(self, fspath, pm, remove_mods): + self.fspath = fspath + self.pm = pm + self.remove_mods = remove_mods + + def __getattr__(self, name): + x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) + self.__dict__[name] = x + return x + + class FSCollector(Collector): def __init__( self, fspath: py.path.local, parent=None, config=None, session=None, nodeid=None @@ -417,6 +429,35 @@ class FSCollector(Collector): super().__init__(name, parent, config, session, nodeid=nodeid, fspath=fspath) + self._norecursepatterns = self.config.getini("norecursedirs") + + def _gethookproxy(self, fspath): + # check if we have the common case of running + # hooks with all conftest.py files + pm = self.config.pluginmanager + my_conftestmodules = pm._getconftestmodules(fspath) + remove_mods = pm._conftest_plugins.difference(my_conftestmodules) + if remove_mods: + # one or more conftests are not in use at this fspath + proxy = FSHookProxy(fspath, pm, remove_mods) + else: + # all plugins are active for this fspath + proxy = self.config.hook + return proxy + + def _recurse(self, dirpath: py.path.local) -> bool: + if dirpath.basename == "__pycache__": + return False + ihook = self._gethookproxy(dirpath.dirpath()) + if ihook.pytest_ignore_collect(path=dirpath, config=self.config): + return False + for pat in self._norecursepatterns: + if dirpath.check(fnmatch=pat): + return False + ihook = self._gethookproxy(dirpath) + ihook.pytest_collect_directory(path=dirpath, parent=self) + return True + class File(FSCollector): """ base class for collecting tests from a file. """ diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 916ef7bd5..23a67d023 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -35,7 +35,6 @@ from _pytest.compat import safe_isclass from _pytest.compat import STRING_TYPES from _pytest.config import hookimpl from _pytest.deprecated import FUNCARGNAMES -from _pytest.main import FSHookProxy from _pytest.mark import MARK_GEN from _pytest.mark.structures import get_unpacked_marks from _pytest.mark.structures import normalize_mark_list @@ -579,32 +578,8 @@ class Package(Module): func = partial(_call_with_optional_argument, teardown_module, self.obj) self.addfinalizer(func) - def _recurse(self, dirpath: py.path.local) -> bool: - if dirpath.basename == "__pycache__": - return False - ihook = self.gethookproxy(dirpath.dirpath()) - if ihook.pytest_ignore_collect(path=dirpath, config=self.config): - return False - for pat in self._norecursepatterns: - if dirpath.check(fnmatch=pat): - return False - ihook = self.gethookproxy(dirpath) - ihook.pytest_collect_directory(path=dirpath, parent=self) - return True - def gethookproxy(self, fspath): - # check if we have the common case of running - # hooks with all conftest.py files - pm = self.config.pluginmanager - my_conftestmodules = pm._getconftestmodules(fspath) - remove_mods = pm._conftest_plugins.difference(my_conftestmodules) - if remove_mods: - # one or more conftests are not in use at this fspath - proxy = FSHookProxy(fspath, pm, remove_mods) - else: - # all plugins are active for this fspath - proxy = self.config.hook - return proxy + return super()._gethookproxy(fspath) def _collectfile(self, path, handle_dupes=True): assert ( From ae5d16be10c139da6a21eab34f7decbf93af721b Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Mon, 27 Jan 2020 20:57:32 +0100 Subject: [PATCH 05/14] typing: FSHookProxy/gethookproxy Taken out of https://github.com/pytest-dev/pytest/pull/6556. --- src/_pytest/main.py | 2 +- src/_pytest/nodes.py | 9 ++++++--- src/_pytest/python.py | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 066c885b8..e4eb4bbc8 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -436,7 +436,7 @@ class Session(nodes.FSCollector): def isinitpath(self, path): return path in self._initialpaths - def gethookproxy(self, fspath): + def gethookproxy(self, fspath: py.path.local): return super()._gethookproxy(fspath) def perform_collect(self, args=None, genitems=True): diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index f9f1f4f68..5447f2541 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -19,6 +19,7 @@ from _pytest.compat import cached_property from _pytest.compat import getfslineno from _pytest.compat import TYPE_CHECKING from _pytest.config import Config +from _pytest.config import PytestPluginManager from _pytest.fixtures import FixtureDef from _pytest.fixtures import FixtureLookupError from _pytest.fixtures import FixtureLookupErrorRepr @@ -394,12 +395,14 @@ def _check_initialpaths_for_relpath(session, fspath): class FSHookProxy: - def __init__(self, fspath, pm, remove_mods): + def __init__( + self, fspath: py.path.local, pm: PytestPluginManager, remove_mods + ) -> None: self.fspath = fspath self.pm = pm self.remove_mods = remove_mods - def __getattr__(self, name): + def __getattr__(self, name: str): x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) self.__dict__[name] = x return x @@ -431,7 +434,7 @@ class FSCollector(Collector): self._norecursepatterns = self.config.getini("norecursedirs") - def _gethookproxy(self, fspath): + def _gethookproxy(self, fspath: py.path.local): # check if we have the common case of running # hooks with all conftest.py files pm = self.config.pluginmanager diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 23a67d023..c30dbc477 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -578,7 +578,7 @@ class Package(Module): func = partial(_call_with_optional_argument, teardown_module, self.obj) self.addfinalizer(func) - def gethookproxy(self, fspath): + def gethookproxy(self, fspath: py.path.local): return super()._gethookproxy(fspath) def _collectfile(self, path, handle_dupes=True): From 6d7e06e6beb2f30fef966b4b9479fc7d0c94c4ae Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 29 Jan 2020 20:28:04 -0300 Subject: [PATCH 06/14] Use --wrap=preserve in release notes script Follow up to #6621 after premature merge --- scripts/publish-gh-release-notes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/publish-gh-release-notes.py b/scripts/publish-gh-release-notes.py index 583b5bfc7..2531b0221 100644 --- a/scripts/publish-gh-release-notes.py +++ b/scripts/publish-gh-release-notes.py @@ -61,7 +61,9 @@ def parse_changelog(tag_name): def convert_rst_to_md(text): - return pypandoc.convert_text(text, "md", format="rst", extra_args=["--wrap=none"]) + return pypandoc.convert_text( + text, "md", format="rst", extra_args=["--wrap=preserve"] + ) def main(argv): From d91459fc758cd91848ace87f7c4071a38433f647 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 30 Jan 2020 09:32:54 -0400 Subject: [PATCH 07/14] Reword fixture docs for clarity --- doc/en/fixture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 2094027f3..bb1da8a03 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -849,7 +849,7 @@ Running this test will *skip* the invocation of ``data_set`` with value ``2``: Modularity: using fixtures from a fixture function ---------------------------------------------------------- -You can not only use fixtures in test functions but fixture functions +In additon to using fixtures in test functions, fixture functions can use other fixtures themselves. This contributes to a modular design of your fixtures and allows re-use of framework-specific fixtures across many projects. As a simple example, we can extend the previous example From 55bffb7c15a342431c49dc816bcc99e9ffa7e010 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 30 Jan 2020 18:30:51 +0200 Subject: [PATCH 08/14] Fix typo --- doc/en/fixture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index bb1da8a03..b54a12731 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -849,7 +849,7 @@ Running this test will *skip* the invocation of ``data_set`` with value ``2``: Modularity: using fixtures from a fixture function ---------------------------------------------------------- -In additon to using fixtures in test functions, fixture functions +In addition to using fixtures in test functions, fixture functions can use other fixtures themselves. This contributes to a modular design of your fixtures and allows re-use of framework-specific fixtures across many projects. As a simple example, we can extend the previous example From 864338de71d6b56f0029b8ea8f45581001e2bab1 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 30 Jan 2020 19:55:40 +0100 Subject: [PATCH 09/14] Revert "ci: codecov: use `--retry-connrefused` with curl" Not known with `curl` on Travis at least. Reverts https://github.com/pytest-dev/pytest/pull/6573. This reverts commit df1f43ee28d38350542a23acb27647feab46f473. --- scripts/report-coverage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/report-coverage.sh b/scripts/report-coverage.sh index 6aa931383..fbcf20ca9 100755 --- a/scripts/report-coverage.sh +++ b/scripts/report-coverage.sh @@ -14,5 +14,5 @@ python -m coverage combine python -m coverage xml python -m coverage report -m # Set --connect-timeout to work around https://github.com/curl/curl/issues/4461 -curl -S -L --connect-timeout 5 --retry 6 --retry-connrefused -s https://codecov.io/bash -o codecov-upload.sh +curl -S -L --connect-timeout 5 --retry 6 -s https://codecov.io/bash -o codecov-upload.sh bash codecov-upload.sh -Z -X fix -f coverage.xml "$@" From 88b800355a42a697aad123fb9546e4dbadc2cf34 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 28 Jan 2020 17:05:41 +0100 Subject: [PATCH 10/14] typing: pytest_collection --- src/_pytest/assertion/__init__.py | 6 +++++- src/_pytest/hookspec.py | 10 +++++++++- src/_pytest/logging.py | 3 ++- src/_pytest/main.py | 5 ++++- src/_pytest/terminal.py | 2 +- src/_pytest/warnings.py | 4 +++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index f96afce6d..a060723a7 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -7,6 +7,10 @@ from typing import Optional from _pytest.assertion import rewrite from _pytest.assertion import truncate from _pytest.assertion import util +from _pytest.compat import TYPE_CHECKING + +if TYPE_CHECKING: + from _pytest.main import Session def pytest_addoption(parser): @@ -91,7 +95,7 @@ def install_importhook(config): return hook -def pytest_collection(session): +def pytest_collection(session: "Session") -> None: # this hook is only called when test modules are collected # so for example not in the master process of pytest-xdist # (which does not collect test modules) diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index 03e060eb8..2d9834c7f 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -1,6 +1,14 @@ """ hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ +from typing import Any +from typing import Optional + from pluggy import HookspecMarker +from _pytest.compat import TYPE_CHECKING + +if TYPE_CHECKING: + from _pytest.main import Session + hookspec = HookspecMarker("pytest") @@ -158,7 +166,7 @@ def pytest_load_initial_conftests(early_config, parser, args): @hookspec(firstresult=True) -def pytest_collection(session): +def pytest_collection(session: "Session") -> Optional[Any]: """Perform the collection protocol for the given session. Stops at first non-None result, see :ref:`firstresult`. diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index ccd79b834..df0da3daa 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -5,6 +5,7 @@ from contextlib import contextmanager from io import StringIO from typing import AbstractSet from typing import Dict +from typing import Generator from typing import List from typing import Mapping @@ -591,7 +592,7 @@ class LoggingPlugin: ) is not None or self._config.getini("log_cli") @pytest.hookimpl(hookwrapper=True, tryfirst=True) - def pytest_collection(self): + def pytest_collection(self) -> Generator[None, None, None]: with self.live_logs_context(): if self.log_cli_handler: self.log_cli_handler.set_when("collection") diff --git a/src/_pytest/main.py b/src/_pytest/main.py index e4eb4bbc8..e5666da9f 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -8,6 +8,8 @@ import sys from typing import Dict from typing import FrozenSet from typing import List +from typing import Optional +from typing import Union import attr import py @@ -249,7 +251,7 @@ def pytest_cmdline_main(config): return wrap_session(config, _main) -def _main(config, session): +def _main(config: Config, session: "Session") -> Optional[Union[int, ExitCode]]: """ default command line protocol for initialization, session, running tests and reporting. """ config.hook.pytest_collection(session=session) @@ -259,6 +261,7 @@ def _main(config, session): return ExitCode.TESTS_FAILED elif session.testscollected == 0: return ExitCode.NO_TESTS_COLLECTED + return None def pytest_collection(session): diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 804d5928f..2206b5d98 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -514,7 +514,7 @@ class TerminalReporter: # py < 1.6.0 return self._tw.chars_on_current_line - def pytest_collection(self): + def pytest_collection(self) -> None: if self.isatty: if self.config.option.verbose >= 0: self.write("collecting ... ", bold=True) diff --git a/src/_pytest/warnings.py b/src/_pytest/warnings.py index 8ac1ee225..d6c098dd0 100644 --- a/src/_pytest/warnings.py +++ b/src/_pytest/warnings.py @@ -1,8 +1,10 @@ import sys import warnings from contextlib import contextmanager +from typing import Generator import pytest +from _pytest.main import Session def _setoption(wmod, arg): @@ -117,7 +119,7 @@ def pytest_runtest_protocol(item): @pytest.hookimpl(hookwrapper=True, tryfirst=True) -def pytest_collection(session): +def pytest_collection(session: Session) -> Generator[None, None, None]: config = session.config with catch_warnings_for_item( config=config, ihook=config.hook, when="collect", item=None From 442dccef6524b313cc62887e02e964aa285321ee Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 30 Jan 2020 22:55:01 +0100 Subject: [PATCH 11/14] python: factor out async_warn --- src/_pytest/python.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index c30dbc477..1b94aaf00 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -146,27 +146,30 @@ def pytest_configure(config): ) -@hookimpl(trylast=True) -def pytest_pyfunc_call(pyfuncitem): - def async_warn(): - msg = "async def functions are not natively supported and have been skipped.\n" - msg += "You need to install a suitable plugin for your async framework, for example:\n" - msg += " - pytest-asyncio\n" - msg += " - pytest-trio\n" - msg += " - pytest-tornasync" - warnings.warn(PytestUnhandledCoroutineWarning(msg.format(pyfuncitem.nodeid))) - skip(msg="async def function and no async plugin installed (see warnings)") +def async_warn(nodeid: str) -> None: + msg = "async def functions are not natively supported and have been skipped.\n" + msg += ( + "You need to install a suitable plugin for your async framework, for example:\n" + ) + msg += " - pytest-asyncio\n" + msg += " - pytest-trio\n" + msg += " - pytest-tornasync" + warnings.warn(PytestUnhandledCoroutineWarning(msg.format(nodeid))) + skip(msg="async def function and no async plugin installed (see warnings)") + +@hookimpl(trylast=True) +def pytest_pyfunc_call(pyfuncitem: "Function"): testfunction = pyfuncitem.obj if iscoroutinefunction(testfunction) or ( sys.version_info >= (3, 6) and inspect.isasyncgenfunction(testfunction) ): - async_warn() + async_warn(pyfuncitem.nodeid) funcargs = pyfuncitem.funcargs testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} result = testfunction(**testargs) if hasattr(result, "__await__") or hasattr(result, "__aiter__"): - async_warn() + async_warn(pyfuncitem.nodeid) return True From 2902c7263c186721bc9707dd4a6ff878139db819 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 30 Jan 2020 23:02:17 +0100 Subject: [PATCH 12/14] fixtures: move import of ParameterSet to top level This gets typically used always (via `getfixtureinfo`). --- src/_pytest/fixtures.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index e950fc9e8..5b3686b58 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -31,6 +31,7 @@ from _pytest.compat import safe_getattr from _pytest.compat import TYPE_CHECKING from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS from _pytest.deprecated import FUNCARGNAMES +from _pytest.mark import ParameterSet from _pytest.outcomes import fail from _pytest.outcomes import TEST_OUTCOME @@ -1263,8 +1264,6 @@ class FixtureManager: This things are done later as well when dealing with parametrization so this could be improved """ - from _pytest.mark import ParameterSet - parametrize_argnames = [] for marker in node.iter_markers(name="parametrize"): if not marker.kwargs.get("indirect", False): From 5b81bd862c948160773e650d826feed8bb80420f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 30 Jan 2020 23:21:45 +0100 Subject: [PATCH 13/14] minor: doc: getfuncargnames: move TODO out of docstring --- src/_pytest/compat.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index f0b0d548f..085f634a4 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -143,12 +143,12 @@ def getfuncargnames( the case of cls, the function is a static method. The name parameter should be the original name in which the function was collected. - - @RonnyPfannschmidt: This function should be refactored when we - revisit fixtures. The fixture mechanism should ask the node for - the fixture names, and not try to obtain directly from the - function object well after collection has occurred. """ + # TODO(RonnyPfannschmidt): This function should be refactored when we + # revisit fixtures. The fixture mechanism should ask the node for + # the fixture names, and not try to obtain directly from the + # function object well after collection has occurred. + # The parameters attribute of a Signature object contains an # ordered mapping of parameter names to Parameter instances. This # creates a tuple of the names of the parameters that don't have From 8301993e5e8b3780d35a5eb888ba603731f5c809 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 31 Jan 2020 00:16:41 +0100 Subject: [PATCH 14/14] tests: use `-rfEX` `-fE` is the default in `features` now [1], but the idea is to add `X` also to it in the long run, so let's dogfood it ourselves. 1: https://github.com/pytest-dev/pytest/pull/6524 2: https://github.com/pytest-dev/pytest/pull/6524#issuecomment-577650703 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 707f239d0..65af0a4a8 100644 --- a/tox.ini +++ b/tox.ini @@ -147,7 +147,7 @@ commands = python scripts/publish-gh-release-notes.py {posargs} [pytest] minversion = 2.0 -addopts = -ra -p pytester --strict-markers +addopts = -rfEX -p pytester --strict-markers rsyncdirs = tox.ini doc src testing python_files = test_*.py *_test.py testing/*/*.py python_classes = Test Acceptance