Merge branch 'pytest-dev:main' into remove-eq-format

This commit is contained in:
Yuval Shimon 2021-12-12 15:16:58 +02:00 committed by GitHub
commit 7cf2b51d8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 9 deletions

View File

@ -33,10 +33,10 @@ if TYPE_CHECKING:
from _pytest.nodes import Collector
from _pytest.nodes import Item
from _pytest.outcomes import Exit
from _pytest.python import Class
from _pytest.python import Function
from _pytest.python import Metafunc
from _pytest.python import Module
from _pytest.python import PyCollector
from _pytest.reports import CollectReport
from _pytest.reports import TestReport
from _pytest.runner import CallInfo
@ -359,7 +359,7 @@ def pytest_pycollect_makemodule(
@hookspec(firstresult=True)
def pytest_pycollect_makeitem(
collector: "PyCollector", name: str, obj: object
collector: Union["Module", "Class"], name: str, obj: object
) -> Union[None, "Item", "Collector", List[Union["Item", "Collector"]]]:
"""Return a custom item/collector for a Python object in a module, or None.

View File

@ -224,11 +224,15 @@ def pytest_pycollect_makemodule(module_path: Path, parent) -> "Module":
@hookimpl(trylast=True)
def pytest_pycollect_makeitem(collector: "PyCollector", name: str, obj: object):
def pytest_pycollect_makeitem(
collector: Union["Module", "Class"], name: str, obj: object
) -> Union[None, nodes.Item, nodes.Collector, List[Union[nodes.Item, nodes.Collector]]]:
assert isinstance(collector, (Class, Module)), type(collector)
# Nothing was collected elsewhere, let's do it here.
if safe_isclass(obj):
if collector.istestclass(obj, name):
return Class.from_parent(collector, name=name, obj=obj)
klass: Class = Class.from_parent(collector, name=name, obj=obj)
return klass
elif collector.istestfunction(obj, name):
# mock seems to store unbound methods (issue473), normalize it.
obj = getattr(obj, "__func__", obj)
@ -247,15 +251,16 @@ def pytest_pycollect_makeitem(collector: "PyCollector", name: str, obj: object):
)
elif getattr(obj, "__test__", True):
if is_generator(obj):
res = Function.from_parent(collector, name=name)
res: Function = Function.from_parent(collector, name=name)
reason = "yield tests were removed in pytest 4.0 - {name} will be ignored".format(
name=name
)
res.add_marker(MARK_GEN.xfail(run=False, reason=reason))
res.warn(PytestCollectionWarning(reason))
return res
else:
res = list(collector._genfunctions(name, obj))
return res
return list(collector._genfunctions(name, obj))
return None
class PyobjMixin(nodes.Node):

View File

@ -27,7 +27,7 @@ from _pytest.outcomes import skip
from _pytest.outcomes import xfail
from _pytest.python import Class
from _pytest.python import Function
from _pytest.python import PyCollector
from _pytest.python import Module
from _pytest.runner import CallInfo
from _pytest.scope import Scope
@ -42,7 +42,7 @@ if TYPE_CHECKING:
def pytest_pycollect_makeitem(
collector: PyCollector, name: str, obj: object
collector: Union[Module, Class], name: str, obj: object
) -> Optional["UnitTestCase"]:
# Has unittest been imported and is obj a subclass of its TestCase?
try:

View File

@ -335,6 +335,54 @@ def test_sessionfinish_with_start(pytester: Pytester) -> None:
assert res.ret == ExitCode.NO_TESTS_COLLECTED
def test_collection_args_do_not_duplicate_modules(pytester: Pytester) -> None:
"""Test that when multiple collection args are specified on the command line
for the same module, only a single Module collector is created.
Regression test for #723, #3358.
"""
pytester.makepyfile(
**{
"d/test_it": """
def test_1(): pass
def test_2(): pass
"""
}
)
result = pytester.runpytest(
"--collect-only",
"d/test_it.py::test_1",
"d/test_it.py::test_2",
)
result.stdout.fnmatch_lines(
[
"<Module d/test_it.py>",
" <Function test_1>",
" <Function test_2>",
],
consecutive=True,
)
# Different, but related case.
result = pytester.runpytest(
"--collect-only",
"--keep-duplicates",
"d",
"d",
)
result.stdout.fnmatch_lines(
[
"<Module d/test_it.py>",
" <Function test_1>",
" <Function test_2>",
" <Function test_1>",
" <Function test_2>",
],
consecutive=True,
)
@pytest.mark.parametrize("path", ["root", "{relative}/root", "{environment}/root"])
def test_rootdir_option_arg(
pytester: Pytester, monkeypatch: MonkeyPatch, path: str