Skip to content

Commit aec6cb6

Browse files
experiment with node metaclass for ctor warning
1 parent e0ad722 commit aec6cb6

File tree

3 files changed

+26
-42
lines changed

3 files changed

+26
-42
lines changed

src/_pytest/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,9 @@ def __init__(self, config):
384384

385385
self.config.pluginmanager.register(self, name="session")
386386

387-
@nodes.Node.constructor
388387
@classmethod
389388
def from_config(cls, config):
390-
return cls(config)
389+
return cls._create(config)
391390

392391
def __repr__(self):
393392
return "<%s %s exitstatus=%r testsfailed=%d testscollected=%d>" % (

src/_pytest/nodes.py

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,32 @@ def ischildnode(baseid, nodeid):
6767
return node_parts[: len(base_parts)] == base_parts
6868

6969

70-
class Node:
70+
class NodeMeta(type):
71+
__in_named_ctor = False
72+
73+
def __call__(self, *k, **kw):
74+
if not self.__in_named_ctor:
75+
warnings.warn(
76+
NODE_USE_FROM_PARENT.format(name=self.__name__),
77+
stacklevel=3,
78+
)
79+
return self._create(*k, **kw)
80+
81+
@contextmanager
82+
def __ctor_entered(self):
83+
self.__in_named_ctor = True
84+
yield
85+
self.__in_named_ctor = False
86+
87+
def _create(self, *k, **kw):
88+
with self.__ctor_entered():
89+
return super().__call__(*k, **kw)
90+
91+
92+
class Node(metaclass=NodeMeta):
7193
""" base class for Collector and Item the test collection tree.
7294
Collector subclasses have children, Items are terminal nodes."""
7395

74-
__in_named_ctor = False
75-
7696
def __init__(
7797
self, name, parent=None, config=None, session=None, fspath=None, nodeid=None
7898
):
@@ -111,33 +131,9 @@ def __init__(
111131
if self.name != "()":
112132
self._nodeid += "::" + self.name
113133

114-
if not type(self).__in_named_ctor:
115-
warnings.warn(
116-
NODE_USE_FROM_PARENT.format(name=type(self).__name__),
117-
stacklevel=3,
118-
)
119-
120-
@classmethod
121-
@contextmanager
122-
def __ctor_entered(cls):
123-
cls.__in_named_ctor = True
124-
yield
125-
cls.__in_named_ctor = False
126-
127-
@staticmethod
128-
def constructor(ctor):
129-
@classmethod
130-
@wraps(ctor)
131-
def wrapped(cls, *k, **kw):
132-
with cls.__ctor_entered():
133-
return ctor.__get__(None, cls)(*k, **kw)
134-
135-
return wrapped
136-
137134
@classmethod
138135
def from_parent(cls, parent, **kw):
139-
with cls.__ctor_entered():
140-
return cls(**kw, parent=parent)
136+
return cls._create(**kw, parent=parent)
141137

142138
@property
143139
def ihook(self):

src/_pytest/python.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -429,11 +429,6 @@ def _genfunctions(self, name, funcobj):
429429
class Module(nodes.File, PyCollector):
430430
""" Collector for test classes and functions. """
431431

432-
@nodes.Node.constructor
433-
@classmethod
434-
def from_parent(cls, parent, **kw):
435-
return cls(parent=parent, **kw)
436-
437432
def _getobj(self):
438433
return self._importtestmodule()
439434

@@ -689,10 +684,9 @@ def _get_first_non_fixture_func(obj, names):
689684
class Class(PyCollector):
690685
""" Collector for test methods. """
691686

692-
@nodes.Node.constructor
693687
@classmethod
694688
def from_parent(cls, parent, *, name, obj=None):
695-
return cls(name=name, parent=parent)
689+
return cls._create(name=name, parent=parent)
696690

697691
def collect(self):
698692
if not safe_getattr(self.obj, "__test__", True):
@@ -1407,11 +1401,6 @@ def __init__(
14071401
#: .. versionadded:: 3.0
14081402
self.originalname = originalname
14091403

1410-
@nodes.Node.constructor
1411-
@classmethod
1412-
def from_parent(cls, parent, **kw):
1413-
return cls(parent=parent, **kw)
1414-
14151404
def _initrequest(self):
14161405
self.funcargs = {}
14171406
self._request = fixtures.FixtureRequest(self)

0 commit comments

Comments
 (0)