Package Version
---------- -------
colorama 0.4.6
iniconfig 2.3.0
packaging 26.0
pip 26.0
pluggy 1.6.0
Pygments 2.19.2
pytest 9.0.2
setuptools 80.10.2
wheel 0.46.3
import pytest
something_or_none = None
def fake_do_something(*_, **__) -> int:
return 7
def test_something(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(
something_or_none, 'do_something', fake_do_something, raising=False
)
assert 7 == something_or_none.do_something('a', 'b', c='c')
========================================= test session starts =========================================
platform win32 -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0
rootdir: ...
collected 1 item
...\test_example.py FE [100%]
=============================================== ERRORS ================================================
_________________________________ ERROR at teardown of test_something _________________________________
cls = <class '_pytest.runner.CallInfo'>
func = <function call_and_report.<locals>.<lambda> at 0x0000023F84FC5940>, when = 'teardown'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
@classmethod
def from_call(
cls,
func: Callable[[], TResult],
when: Literal["collect", "setup", "call", "teardown"],
reraise: type[BaseException] | tuple[type[BaseException], ...] | None = None,
) -> CallInfo[TResult]:
"""Call func, wrapping the result in a CallInfo.
:param func:
The function to call. Called without arguments.
:type func: Callable[[], _pytest.runner.TResult]
:param when:
The phase in which the function is called.
:param reraise:
Exception or exceptions that shall propagate if raised by the
function, instead of being wrapped in the CallInfo.
"""
excinfo = None
instant = timing.Instant()
try:
> result: TResult | None = func()
^^^^^^
..\..\..\...\Lib\site-packages\_pytest\runner.py:353:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\..\...\Lib\site-packages\_pytest\runner.py:245: in <lambda>
lambda: runtest_hook(item=item, **kwds),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
..\..\..\...\Lib\site-packages\pluggy\_hooks.py:512: in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
..\..\..\...\Lib\site-packages\pluggy\_manager.py:120: in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
..\..\..\...\Lib\site-packages\_pytest\logging.py:858: in pytest_runtest_teardown
yield
..\..\..\...\Lib\site-packages\_pytest\capture.py:905: in pytest_runtest_teardown
return (yield)
^^^^^
..\..\..\...\Lib\site-packages\_pytest\runner.py:194: in pytest_runtest_teardown
item.session._setupstate.teardown_exact(nextitem)
..\..\..\...\Lib\site-packages\_pytest\runner.py:566: in teardown_exact
raise exceptions[0]
..\..\..\...\Lib\site-packages\_pytest\runner.py:555: in teardown_exact
fin()
..\..\..\...\Lib\site-packages\_pytest\fixtures.py:1053: in finish
raise exceptions[0]
..\..\..\...\Lib\site-packages\_pytest\fixtures.py:1042: in finish
fin()
..\..\..\...\Lib\site-packages\_pytest\fixtures.py:924: in _teardown_yield_fixture
next(it)
..\..\..\...\Lib\site-packages\_pytest\monkeypatch.py:59: in monkeypatch
mpatch.undo()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.monkeypatch.MonkeyPatch object at 0x0000023F8683D4C0>
def undo(self) -> None:
"""Undo previous changes.
This call consumes the undo stack. Calling it a second time has no
effect unless you do more monkeypatching after the undo call.
There is generally no need to call `undo()`, since it is
called automatically during tear-down.
.. note::
The same `monkeypatch` fixture is used across a
single test function invocation. If `monkeypatch` is used both by
the test function itself and one of the test fixtures,
calling `undo()` will undo all of the changes made in
both functions.
Prefer to use :meth:`context() <pytest.MonkeyPatch.context>` instead.
"""
for obj, name, value in reversed(self._setattr):
if value is not notset:
setattr(obj, name, value)
else:
> delattr(obj, name)
E AttributeError: 'NoneType' object has no attribute 'do_something'
..\..\..\...\Lib\site-packages\_pytest\monkeypatch.py:416: AttributeError
============================================== FAILURES ===============================================
___________________________________________ test_something ____________________________________________
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000023F8683D4C0>
def test_something(monkeypatch: pytest.MonkeyPatch):
> monkeypatch.setattr(
something_or_none, 'do_something', fake_do_something, raising=False
)
E AttributeError: 'NoneType' object has no attribute 'do_something'
...\tests\test_example.py:12: AttributeError
======================================= short test summary info =======================================
FAILED .../tests/test_example.py::test_something - AttributeError: 'NoneType' object has no attribute 'do_something'
ERROR .../tests/test_example.py::test_something - AttributeError: 'NoneType' object has no attribute 'do_something'
===================================== 1 failed, 1 error in 0.22s ======================================
Description
When using
monkeypatchfixture to patch and attribute withraising=False,AttributeErroris raised at test tear down when attribute is tried to be restituted.Output of
pip listPytest and operating system versions
Windows 11 with pytest 9.0.2
Minimal example
When doing
pytest <test_file.py>I am getting (paths are masked):