Skip to content

Commit

Permalink
Merge pull request pytest-dev#6640 from bluetech/master-to-features
Browse files Browse the repository at this point in the history
Merge master to features - one last time
  • Loading branch information
bluetech committed Jan 31, 2020
2 parents 4de8e68 + a435faa commit 4038d6c
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 99 deletions.
2 changes: 1 addition & 1 deletion doc/en/fixture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 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
Expand Down
4 changes: 3 additions & 1 deletion scripts/publish-gh-release-notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion scripts/report-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 "$@"
6 changes: 5 additions & 1 deletion src/_pytest/assertion/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
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):
Expand Down Expand Up @@ -91,7 +95,7 @@ def undo():
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)
Expand Down
10 changes: 5 additions & 5 deletions src/_pytest/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,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
Expand Down
3 changes: 1 addition & 2 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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

Expand Down Expand Up @@ -1262,8 +1263,6 @@ def _get_direct_parametrize_args(self, node):
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):
Expand Down
10 changes: 9 additions & 1 deletion src/_pytest/hookspec.py
Original file line number Diff line number Diff line change
@@ -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")

Expand Down Expand Up @@ -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`.
Expand Down
3 changes: 2 additions & 1 deletion src/_pytest/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from io import StringIO
from typing import AbstractSet
from typing import Dict
from typing import Generator
from typing import List
from typing import Mapping

Expand Down Expand Up @@ -597,7 +598,7 @@ def _log_cli_enabled(self):
) 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")
Expand Down
46 changes: 6 additions & 40 deletions src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
from typing import Dict
from typing import FrozenSet
from typing import List
from typing import Optional
from typing import Sequence
from typing import Tuple
from typing import Union

import attr
import py
Expand Down Expand Up @@ -253,7 +255,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)
Expand All @@ -263,6 +265,7 @@ def _main(config, session):
return ExitCode.TESTS_FAILED
elif session.testscollected == 0:
return ExitCode.NO_TESTS_COLLECTED
return None


def pytest_collection(session):
Expand Down Expand Up @@ -352,18 +355,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. """

Expand Down Expand Up @@ -405,7 +396,6 @@ def __init__(self, config: Config) -> None:
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]

Expand Down Expand Up @@ -466,19 +456,8 @@ def pytest_runtest_logreport(self, report):
def isinitpath(self, path):
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
def gethookproxy(self, fspath: py.path.local):
return super()._gethookproxy(fspath)

def perform_collect(self, args=None, genitems=True):
hook = self.config.hook
Expand Down Expand Up @@ -643,19 +622,6 @@ def _collectfile(self, path, handle_dupes=True):

return ihook.pytest_collect_file(path=path, parent=self)

def _recurse(self, dirpath):
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)
Expand Down
44 changes: 44 additions & 0 deletions src/_pytest/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from _pytest.compat import getfslineno
from _pytest.compat import TYPE_CHECKING
from _pytest.config import Config
from _pytest.config import PytestPluginManager
from _pytest.deprecated import NODE_USE_FROM_PARENT
from _pytest.fixtures import FixtureDef
from _pytest.fixtures import FixtureLookupError
Expand Down Expand Up @@ -423,6 +424,20 @@ def _check_initialpaths_for_relpath(session, fspath):
return fspath.relto(initial_path)


class FSHookProxy:
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: str):
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
Expand All @@ -447,13 +462,42 @@ def __init__(

super().__init__(name, parent, config, session, nodeid=nodeid, fspath=fspath)

self._norecursepatterns = self.config.getini("norecursedirs")

@classmethod
def from_parent(cls, parent, *, fspath):
"""
The public constructor
"""
return super().from_parent(parent=parent, fspath=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
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. """
Expand Down

0 comments on commit 4038d6c

Please sign in to comment.