fix #6341 - disallow session/config in Node.from_parent

This commit is contained in:
Ronny Pfannschmidt 2019-12-31 20:20:28 +01:00
parent 466bbbf8e8
commit 8ba0b7bc2a
6 changed files with 49 additions and 9 deletions

View File

@ -4,3 +4,7 @@ Instead they are new constructed via ``Node.from_parent``.
This transitional mechanism enables us to detangle the very intensely This transitional mechanism enables us to detangle the very intensely
entangled ``Node`` relationships by enforcing more controlled creation/configruation patterns. entangled ``Node`` relationships by enforcing more controlled creation/configruation patterns.
As part of that session/config are already disallowed parameters and as we work on the details we might need disallow a few more as well.
Subclasses are expected to use `super().from_parent` if they intend to expand the creation of `Nodes`.

View File

@ -216,8 +216,14 @@ class DoctestItem(pytest.Item):
self.fixture_request = None self.fixture_request = None
@classmethod @classmethod
def from_parent(cls, parent, *, name, runner, dtest): def from_parent( # type: ignore
return cls._create(name=name, parent=parent, runner=runner, dtest=dtest) cls, parent: "Union[DoctestTextfile, DoctestModule]", *, name, runner, dtest
):
# incompatible signature due to to imposed limits on sublcass
"""
the public named constructor
"""
return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
def setup(self): def setup(self):
if self.dtest is not None: if self.dtest is not None:

View File

@ -144,8 +144,22 @@ class Node(metaclass=NodeMeta):
self._nodeid += "::" + self.name self._nodeid += "::" + self.name
@classmethod @classmethod
def from_parent(cls, parent, *, name): def from_parent(cls, parent: "Node", **kw):
return cls._create(parent=parent, name=name) """
Public Constructor for Nodes
This indirection got introduced in order to enable removing
the fragile logic from the node constructors.
Subclasses can use ``super().from_parent(...)`` when overriding the construction
:param parent: the parent node of this test Node
"""
if "config" in kw:
raise TypeError("config is not a valid argument for from_parent")
if "session" in kw:
raise TypeError("session is not a valid argument for from_parent")
return cls._create(parent=parent, **kw)
@property @property
def ihook(self): def ihook(self):
@ -434,7 +448,10 @@ class FSCollector(Collector):
@classmethod @classmethod
def from_parent(cls, parent, *, fspath): def from_parent(cls, parent, *, fspath):
return cls._create(parent=parent, fspath=fspath) """
The public constructor
"""
return super().from_parent(parent=parent, fspath=fspath)
class File(FSCollector): class File(FSCollector):

View File

@ -679,7 +679,10 @@ class Class(PyCollector):
@classmethod @classmethod
def from_parent(cls, parent, *, name, obj=None): def from_parent(cls, parent, *, name, obj=None):
return cls._create(name=name, parent=parent) """
The public constructor
"""
return super().from_parent(name=name, parent=parent)
def collect(self): def collect(self):
if not safe_getattr(self.obj, "__test__", True): if not safe_getattr(self.obj, "__test__", True):
@ -1458,8 +1461,11 @@ class Function(FunctionMixin, nodes.Item):
self.originalname = originalname self.originalname = originalname
@classmethod @classmethod
def from_parent(cls, parent, **kw): def from_parent(cls, parent, **kw): # todo: determine sound type limitations
return cls._create(parent=parent, **kw) """
The public constructor
"""
return super().from_parent(parent=parent, **kw)
def _initrequest(self): def _initrequest(self):
self.funcargs = {} self.funcargs = {}

View File

@ -284,7 +284,7 @@ class TestFunction:
session = testdir.Session.from_config(config) session = testdir.Session.from_config(config)
session._fixturemanager = FixtureManager(session) session._fixturemanager = FixtureManager(session)
return pytest.Function.from_parent(config=config, parent=session, **kwargs) return pytest.Function.from_parent(parent=session, **kwargs)
def test_function_equality(self, testdir, tmpdir): def test_function_equality(self, testdir, tmpdir):
def func1(): def func1():

View File

@ -22,6 +22,13 @@ def test_ischildnode(baseid, nodeid, expected):
assert result is expected assert result is expected
def test_node_from_parent_disallowed_arguments():
with pytest.raises(TypeError, match="session is"):
nodes.Node.from_parent(None, session=None)
with pytest.raises(TypeError, match="config is"):
nodes.Node.from_parent(None, config=None)
def test_std_warn_not_pytestwarning(testdir): def test_std_warn_not_pytestwarning(testdir):
items = testdir.getitems( items = testdir.getitems(
""" """