Skip to content

Commit 71ab6b8

Browse files
Merge pull request pytest-dev#1295 from nicoddemus/monkeypatch-perf
Make monkeypatch calls O(1)
2 parents 0ef73ed + 638b3f5 commit 71ab6b8

File tree

2 files changed

+9
-7
lines changed

2 files changed

+9
-7
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
- fix #900: Better error message in case the target of a ``monkeypatch`` call
1313
raises an ``ImportError``.
1414

15+
- fix #1292: monkeypatch calls (setattr, setenv, etc.) are now O(1).
16+
Thanks David R. MacIver for the report and Bruno Oliveira for the PR.
17+
1518

1619
2.8.5
1720
-----

_pytest/monkeypatch.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def setattr(self, target, name, value=notset, raising=True):
126126
# avoid class descriptors like staticmethod/classmethod
127127
if inspect.isclass(target):
128128
oldval = target.__dict__.get(name, notset)
129-
self._setattr.insert(0, (target, name, oldval))
129+
self._setattr.append((target, name, oldval))
130130
setattr(target, name, value)
131131

132132
def delattr(self, target, name=notset, raising=True):
@@ -152,13 +152,12 @@ def delattr(self, target, name=notset, raising=True):
152152
if raising:
153153
raise AttributeError(name)
154154
else:
155-
self._setattr.insert(0, (target, name,
156-
getattr(target, name, notset)))
155+
self._setattr.append((target, name, getattr(target, name, notset)))
157156
delattr(target, name)
158157

159158
def setitem(self, dic, name, value):
160159
""" Set dictionary entry ``name`` to value. """
161-
self._setitem.insert(0, (dic, name, dic.get(name, notset)))
160+
self._setitem.append((dic, name, dic.get(name, notset)))
162161
dic[name] = value
163162

164163
def delitem(self, dic, name, raising=True):
@@ -171,7 +170,7 @@ def delitem(self, dic, name, raising=True):
171170
if raising:
172171
raise KeyError(name)
173172
else:
174-
self._setitem.insert(0, (dic, name, dic.get(name, notset)))
173+
self._setitem.append((dic, name, dic.get(name, notset)))
175174
del dic[name]
176175

177176
def setenv(self, name, value, prepend=None):
@@ -223,13 +222,13 @@ def undo(self):
223222
calling `undo()` will undo all of the changes made in
224223
both functions.
225224
"""
226-
for obj, name, value in self._setattr:
225+
for obj, name, value in reversed(self._setattr):
227226
if value is not notset:
228227
setattr(obj, name, value)
229228
else:
230229
delattr(obj, name)
231230
self._setattr[:] = []
232-
for dictionary, name, value in self._setitem:
231+
for dictionary, name, value in reversed(self._setitem):
233232
if value is notset:
234233
try:
235234
del dictionary[name]

0 commit comments

Comments
 (0)