diff --git a/py/test/collect.py b/py/test/collect.py index c12f726d4..ae6af6fd2 100644 --- a/py/test/collect.py +++ b/py/test/collect.py @@ -27,35 +27,6 @@ def configproperty(name): return self._config.getvalue(name, self.fspath) return property(fget) -class SetupState(object): - """ shared state for setting up/tearing down test items or collectors. """ - def __init__(self): - self.stack = [] - - def teardown_all(self): - while self.stack: - col = self.stack.pop() - col.teardown() - - def teardown_exact(self, item): - if self.stack and self.stack[-1] == item: - col = self.stack.pop() - col.teardown() - - def prepare(self, colitem): - """ setup objects along the collector chain to the test-method - Teardown any unneccessary previously setup objects.""" - - needed_collectors = colitem.listchain() - while self.stack: - if self.stack == needed_collectors[:len(self.stack)]: - break - col = self.stack.pop() - col.teardown() - for col in needed_collectors[len(self.stack):]: - col.setup() - self.stack.append(col) - class ReprMetaInfo(object): def __init__(self, fspath=None, lineno=None, modpath=None): self.fspath = fspath @@ -95,10 +66,6 @@ class Node(object): stdout/stderr capturing and execution of test items """ ReprMetaInfo = ReprMetaInfo - # XXX we keep global SetupState here because - # pycollect's Generators participate - # in setup/teardown procedures during collect. - _setupstate = SetupState() def __init__(self, name, parent=None, config=None): self.name = name self.parent = parent diff --git a/py/test/config.py b/py/test/config.py index 8d3ae0127..880bdc47f 100644 --- a/py/test/config.py +++ b/py/test/config.py @@ -40,6 +40,7 @@ class Config(object): self.bus = pytestplugins.pyplugins self.pytestplugins = pytestplugins self._conftest = Conftest(onimport=self.pytestplugins.consider_conftest) + self._setupstate = SetupState() def _processopt(self, opt): if hasattr(opt, 'default') and opt.dest: @@ -210,11 +211,6 @@ class Config(object): raise ValueError("unknown io capturing: " + iocapture) -# this is the one per-process instance of py.test configuration -config_per_process = Config( - pytestplugins=py.test._PytestPlugins(py._com.pyplugins) -) - # # helpers # @@ -240,3 +236,38 @@ def gettopdir(args): return p else: return pkgdir.dirpath() + +class SetupState(object): + """ shared state for setting up/tearing down test items or collectors. """ + def __init__(self): + self.stack = [] + + def teardown_all(self): + while self.stack: + col = self.stack.pop() + col.teardown() + + def teardown_exact(self, item): + if self.stack and self.stack[-1] == item: + col = self.stack.pop() + col.teardown() + + def prepare(self, colitem): + """ setup objects along the collector chain to the test-method + Teardown any unneccessary previously setup objects.""" + + needed_collectors = colitem.listchain() + while self.stack: + if self.stack == needed_collectors[:len(self.stack)]: + break + col = self.stack.pop() + col.teardown() + for col in needed_collectors[len(self.stack):]: + col.setup() + self.stack.append(col) + +# this is the one per-process instance of py.test configuration +config_per_process = Config( + pytestplugins=py.test._PytestPlugins(py._com.pyplugins) +) + diff --git a/py/test/plugin/pytest_pytester.py b/py/test/plugin/pytest_pytester.py index 30e96afd5..2ec7050f3 100644 --- a/py/test/plugin/pytest_pytester.py +++ b/py/test/plugin/pytest_pytester.py @@ -5,7 +5,6 @@ pytes plugin for easing testing of pytest runs themselves. import py from py.__.test import event from py.__.test.config import Config as pytestConfig -from py.__.test.collect import Node, SetupState class PytesterPlugin: def pytest_pyfuncarg_linecomp(self, pyfuncitem): @@ -134,20 +133,13 @@ class TmpTestdir: return self.inline_run(*l) def inline_run(self, *args): - # for the inlined test session we should not modify - # our caller's test state - oldstate = Node._setupstate - Node._setupstate = SetupState() - try: - config = self.parseconfig(*args) - config.pytestplugins.do_configure(config) - session = config.initsession() - sorter = EventRecorder(config.bus) - session.main() - config.pytestplugins.do_unconfigure(config) - return sorter - finally: - Node._setupstate = oldstate + config = self.parseconfig(*args) + config.pytestplugins.do_configure(config) + session = config.initsession() + sorter = EventRecorder(config.bus) + session.main() + config.pytestplugins.do_unconfigure(config) + return sorter def config_preparse(self): config = self.Config() diff --git a/py/test/pycollect.py b/py/test/pycollect.py index 0248bf1b4..6a21caba6 100644 --- a/py/test/pycollect.py +++ b/py/test/pycollect.py @@ -289,7 +289,7 @@ class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector): # test generators are collectors yet participate in # the test-item setup and teardown protocol. # otherwise we could avoid global setupstate - self._setupstate.prepare(self) + self._config._setupstate.prepare(self) l = [] for i, x in py.builtin.enumerate(self.obj()): name, call, args = self.getcallargs(x) diff --git a/py/test/runner.py b/py/test/runner.py index 377df4f87..e1c20c01e 100644 --- a/py/test/runner.py +++ b/py/test/runner.py @@ -50,9 +50,9 @@ class RobustRun(object): class ItemRunner(RobustRun): def setup(self): - self.colitem._setupstate.prepare(self.colitem) + self.colitem._config._setupstate.prepare(self.colitem) def teardown(self): - self.colitem._setupstate.teardown_exact(self.colitem) + self.colitem._config._setupstate.teardown_exact(self.colitem) def execute(self): #self.colitem.config.pytestplugins.pre_execute(self.colitem) self.colitem.runtest() diff --git a/py/test/session.py b/py/test/session.py index aca33c6f2..3ba4fa005 100644 --- a/py/test/session.py +++ b/py/test/session.py @@ -124,7 +124,7 @@ class Session(object): if not self.config.option.collectonly: self.runtest(item) - py.test.collect.Item._setupstate.teardown_all() + self.config._setupstate.teardown_all() except KeyboardInterrupt: captured_excinfo = py.code.ExceptionInfo() exitstatus = outcome.EXIT_INTERRUPTED