diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 6c3b68172ae..b9d6525f2fa 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -384,10 +384,9 @@ def __init__(self, config): self.config.pluginmanager.register(self, name="session") - @nodes.Node.constructor @classmethod def from_config(cls, config): - return cls(config) + return cls._create(config) def __repr__(self): return "<%s %s exitstatus=%r testsfailed=%d testscollected=%d>" % ( diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index ae9c6086b66..9abcf0c85cc 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -67,12 +67,32 @@ def ischildnode(baseid, nodeid): return node_parts[: len(base_parts)] == base_parts -class Node: +class NodeMeta(type): + __in_named_ctor = False + + def __call__(self, *k, **kw): + if not self.__in_named_ctor: + warnings.warn( + NODE_USE_FROM_PARENT.format(name=self.__name__), + stacklevel=3, + ) + return self._create(*k, **kw) + + @contextmanager + def __ctor_entered(self): + self.__in_named_ctor = True + yield + self.__in_named_ctor = False + + def _create(self, *k, **kw): + with self.__ctor_entered(): + return super().__call__(*k, **kw) + + +class Node(metaclass=NodeMeta): """ base class for Collector and Item the test collection tree. Collector subclasses have children, Items are terminal nodes.""" - __in_named_ctor = False - def __init__( self, name, parent=None, config=None, session=None, fspath=None, nodeid=None ): @@ -111,33 +131,9 @@ def __init__( if self.name != "()": self._nodeid += "::" + self.name - if not type(self).__in_named_ctor: - warnings.warn( - NODE_USE_FROM_PARENT.format(name=type(self).__name__), - stacklevel=3, - ) - - @classmethod - @contextmanager - def __ctor_entered(cls): - cls.__in_named_ctor = True - yield - cls.__in_named_ctor = False - - @staticmethod - def constructor(ctor): - @classmethod - @wraps(ctor) - def wrapped(cls, *k, **kw): - with cls.__ctor_entered(): - return ctor.__get__(None, cls)(*k, **kw) - - return wrapped - @classmethod def from_parent(cls, parent, **kw): - with cls.__ctor_entered(): - return cls(**kw, parent=parent) + return cls._create(**kw, parent=parent) @property def ihook(self): diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 7320edf832d..d6818f2e189 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -429,11 +429,6 @@ def _genfunctions(self, name, funcobj): class Module(nodes.File, PyCollector): """ Collector for test classes and functions. """ - @nodes.Node.constructor - @classmethod - def from_parent(cls, parent, **kw): - return cls(parent=parent, **kw) - def _getobj(self): return self._importtestmodule() @@ -689,10 +684,9 @@ def _get_first_non_fixture_func(obj, names): class Class(PyCollector): """ Collector for test methods. """ - @nodes.Node.constructor @classmethod def from_parent(cls, parent, *, name, obj=None): - return cls(name=name, parent=parent) + return cls._create(name=name, parent=parent) def collect(self): if not safe_getattr(self.obj, "__test__", True): @@ -1407,11 +1401,6 @@ def __init__( #: .. versionadded:: 3.0 self.originalname = originalname - @nodes.Node.constructor - @classmethod - def from_parent(cls, parent, **kw): - return cls(parent=parent, **kw) - def _initrequest(self): self.funcargs = {} self._request = fixtures.FixtureRequest(self)