Skip to content

Commit 36b7ebe

Browse files
committed
Different fix for conftest loading
1 parent a8e5769 commit 36b7ebe

File tree

3 files changed

+20
-42
lines changed

3 files changed

+20
-42
lines changed

src/_pytest/main.py

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from typing import Dict
1313
from typing import final
1414
from typing import FrozenSet
15-
from typing import Generator
1615
from typing import Iterable
1716
from typing import Iterator
1817
from typing import List
@@ -501,11 +500,11 @@ def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
501500
config = self.config
502501
col: Optional[nodes.Collector]
503502
cols: Sequence[nodes.Collector]
503+
ihook = self.ihook
504504
for direntry in scandir(self.path):
505505
if direntry.is_dir():
506506
if direntry.name == "__pycache__":
507507
continue
508-
ihook = self.ihook
509508
path = Path(direntry.path)
510509
if not self.session.isinitpath(path, with_parents=True):
511510
if ihook.pytest_ignore_collect(collection_path=path, config=config):
@@ -515,7 +514,6 @@ def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
515514
yield col
516515

517516
elif direntry.is_file():
518-
ihook = self.ihook
519517
path = Path(direntry.path)
520518
if not self.session.isinitpath(path):
521519
if ihook.pytest_ignore_collect(collection_path=path, config=config):
@@ -558,7 +556,6 @@ def __init__(self, config: Config) -> None:
558556
self._initialpaths_with_parents: FrozenSet[Path] = frozenset()
559557
self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
560558
self._initial_parts: List[Tuple[Path, List[str]]] = []
561-
self._in_genitems = False
562559
self._collection_cache: Dict[nodes.Collector, CollectReport] = {}
563560
self.items: List[nodes.Item] = []
564561

@@ -611,29 +608,6 @@ def pytest_runtest_logreport(
611608

612609
pytest_collectreport = pytest_runtest_logreport
613610

614-
@hookimpl(wrapper=True)
615-
def pytest_collect_directory(
616-
self,
617-
) -> Generator[None, Optional[nodes.Collector], Optional[nodes.Collector]]:
618-
col = yield
619-
620-
# Eagerly load conftests for the directory.
621-
# This is needed because a conftest error needs to happen while
622-
# collecting a collector, so it is caught by its CollectReport.
623-
# Without this, the conftests are loaded inside of genitems itself
624-
# which leads to an internal error.
625-
# This should only be done for genitems; if done unconditionally, it
626-
# will load conftests for non-selected directories which is to be
627-
# avoided.
628-
if self._in_genitems and col is not None:
629-
self.config.pluginmanager._loadconftestmodules(
630-
col.path,
631-
self.config.getoption("importmode"),
632-
rootpath=self.config.rootpath,
633-
)
634-
635-
return col
636-
637611
def isinitpath(
638612
self,
639613
path: Union[str, "os.PathLike[str]"],
@@ -664,15 +638,6 @@ def gethookproxy(self, fspath: "os.PathLike[str]") -> pluggy.HookRelay:
664638
pm = self.config.pluginmanager
665639
# Check if we have the common case of running
666640
# hooks with all conftest.py files.
667-
#
668-
# TODO: pytest relies on this call to load non-initial conftests. This
669-
# is incidental. It will be better to load conftests at a more
670-
# well-defined place.
671-
pm._loadconftestmodules(
672-
path,
673-
self.config.getoption("importmode"),
674-
rootpath=self.config.rootpath,
675-
)
676641
my_conftestmodules = pm._getconftestmodules(path)
677642
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
678643
proxy: pluggy.HookRelay
@@ -753,7 +718,6 @@ def perform_collect( # noqa: F811
753718

754719
self._notfound = []
755720
self._initial_parts = []
756-
self._in_genitems = False
757721
self._collection_cache = {}
758722
self.items = []
759723
items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
@@ -788,7 +752,6 @@ def perform_collect( # noqa: F811
788752

789753
raise UsageError(*errors)
790754

791-
self._in_genitems = True
792755
if not genitems:
793756
items = rep.result
794757
else:
@@ -803,7 +766,6 @@ def perform_collect( # noqa: F811
803766
finally:
804767
self._notfound = []
805768
self._initial_parts = []
806-
self._in_genitems = False
807769
self._collection_cache = {}
808770
hook.pytest_collection_finish(session=self)
809771

src/_pytest/python.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -719,12 +719,12 @@ def sort_key(entry: "os.DirEntry[str]") -> object:
719719
config = self.config
720720
col: Optional[nodes.Collector]
721721
cols: Sequence[nodes.Collector]
722+
ihook = self.ihook
722723
for direntry in scandir(self.path, sort_key):
723724
if direntry.is_dir():
724725
if direntry.name == "__pycache__":
725726
continue
726727
path = Path(direntry.path)
727-
ihook = self.ihook
728728
if not self.session.isinitpath(path, with_parents=True):
729729
if ihook.pytest_ignore_collect(collection_path=path, config=config):
730730
continue
@@ -734,7 +734,6 @@ def sort_key(entry: "os.DirEntry[str]") -> object:
734734

735735
elif direntry.is_file():
736736
path = Path(direntry.path)
737-
ihook = self.ihook
738737
if not self.session.isinitpath(path):
739738
if ihook.pytest_ignore_collect(collection_path=path, config=config):
740739
continue

src/_pytest/runner.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from _pytest.config.argparsing import Parser
2929
from _pytest.deprecated import check_ispytest
3030
from _pytest.nodes import Collector
31+
from _pytest.nodes import Directory
3132
from _pytest.nodes import Item
3233
from _pytest.nodes import Node
3334
from _pytest.outcomes import Exit
@@ -368,7 +369,23 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport:
368369

369370

370371
def pytest_make_collect_report(collector: Collector) -> CollectReport:
371-
call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
372+
def collect() -> List[Union[Item, Collector]]:
373+
# Before collecting, if this is a Directory, load the conftests.
374+
# If a conftest import fails to load, it is considered a collection
375+
# error of the Directory collector. This is why it's done inside of the
376+
# CallInfo wrapper.
377+
#
378+
# Note: initial conftests are loaded early, not here.
379+
if isinstance(collector, Directory):
380+
collector.config.pluginmanager._loadconftestmodules(
381+
collector.path,
382+
collector.config.getoption("importmode"),
383+
rootpath=collector.config.rootpath,
384+
)
385+
386+
return list(collector.collect())
387+
388+
call = CallInfo.from_call(collect, "collect")
372389
longrepr: Union[None, Tuple[str, int, str], str, TerminalRepr] = None
373390
if not call.excinfo:
374391
outcome: Literal["passed", "skipped", "failed"] = "passed"

0 commit comments

Comments
 (0)