Skip to content

Commit c416b1d

Browse files
turturicaturturica
turturica
authored and
turturica
committed
Don't stop at the first package when looking up package-scoped fixtures.
Example: package1.subpackage1 package1.subpackage2 package1's setup/teardown were executed again when exiting subpackage1 and entering subpackage2.
1 parent 7d923c3 commit c416b1d

File tree

3 files changed

+51
-4
lines changed

3 files changed

+51
-4
lines changed

_pytest/fixtures.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import functools
44
import inspect
5+
import os
56
import sys
67
import warnings
78
from collections import OrderedDict, deque, defaultdict
@@ -70,6 +71,17 @@ def provide(self):
7071
return decoratescope
7172

7273

74+
def get_scope_package(node, fixturedef):
75+
cls = node.Package
76+
current = node
77+
fixture_package_name = os.path.join(fixturedef.baseid, '__init__.py')
78+
while current and type(current) is not cls or \
79+
fixture_package_name != current.nodeid:
80+
current = current.parent
81+
assert current
82+
return current
83+
84+
7385
def get_scope_node(node, scope):
7486
cls = scopename2class.get(scope)
7587
if cls is None:
@@ -558,7 +570,10 @@ def _getscopeitem(self, scope):
558570
if scope == "function":
559571
# this might also be a non-function Item despite its attribute name
560572
return self._pyfuncitem
561-
node = get_scope_node(self._pyfuncitem, scope)
573+
if scope == 'package':
574+
node = get_scope_package(self._pyfuncitem, self._fixturedef)
575+
else:
576+
node = get_scope_node(self._pyfuncitem, scope)
562577
if node is None and scope == "class":
563578
# fallback to function item itself
564579
node = self._pyfuncitem

_pytest/nodes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def ihook(self):
116116
Function = _CompatProperty("Function")
117117
File = _CompatProperty("File")
118118
Item = _CompatProperty("Item")
119+
Package = _CompatProperty("Package")
119120

120121
def _getcustomclass(self, name):
121122
maybe_compatprop = getattr(type(self), name)

_pytest/python.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
import py
1515
import six
16+
from _pytest.main import FSHookProxy
1617
from _pytest.mark import MarkerError
1718
from _pytest.config import hookimpl
1819

1920
import _pytest
20-
from _pytest.main import Session
2121
import pluggy
2222
from _pytest import fixtures
2323
from _pytest import nodes
@@ -490,7 +490,7 @@ def setup(self):
490490
self.addfinalizer(teardown_module)
491491

492492

493-
class Package(Session, Module):
493+
class Package(Module):
494494

495495
def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
496496
session = parent.session
@@ -503,7 +503,38 @@ def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
503503
for path in list(session.config.pluginmanager._duplicatepaths):
504504
if path.dirname == fspath.dirname and path != fspath:
505505
session.config.pluginmanager._duplicatepaths.remove(path)
506-
pass
506+
507+
def _recurse(self, path):
508+
ihook = self.gethookproxy(path.dirpath())
509+
if ihook.pytest_ignore_collect(path=path, config=self.config):
510+
return
511+
for pat in self._norecursepatterns:
512+
if path.check(fnmatch=pat):
513+
return False
514+
ihook = self.gethookproxy(path)
515+
ihook.pytest_collect_directory(path=path, parent=self)
516+
return True
517+
518+
def gethookproxy(self, fspath):
519+
# check if we have the common case of running
520+
# hooks with all conftest.py filesall conftest.py
521+
pm = self.config.pluginmanager
522+
my_conftestmodules = pm._getconftestmodules(fspath)
523+
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
524+
if remove_mods:
525+
# one or more conftests are not in use at this fspath
526+
proxy = FSHookProxy(fspath, pm, remove_mods)
527+
else:
528+
# all plugis are active for this fspath
529+
proxy = self.config.hook
530+
return proxy
531+
532+
def _collectfile(self, path):
533+
ihook = self.gethookproxy(path)
534+
if not self.isinitpath(path):
535+
if ihook.pytest_ignore_collect(path=path, config=self.config):
536+
return ()
537+
return ihook.pytest_collect_file(path=path, parent=self)
507538

508539
def isinitpath(self, path):
509540
return path in self.session._initialpaths

0 commit comments

Comments
 (0)