Skip to content

Commit d282424

Browse files
authored
Fix unguarded == comparison in fixtures. (#6541)
Fix unguarded `==` comparison in fixtures.
2 parents 4ff90b1 + 80d4dd6 commit d282424

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ Guido Wesdorp
112112
Guoqiang Zhang
113113
Harald Armin Massa
114114
Henk-Jaap Wagenaar
115+
Holger Kohr
115116
Hugo van Kemenade
116117
Hui Wang (coldnight)
117118
Ian Bicking

changelog/6497.bugfix.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix bug in the comparison of request key with cached key in fixture.
2+
3+
A construct ``if key == cached_key:`` can fail either because ``==`` is explicitly disallowed, or for, e.g., NumPy arrays, where the result of ``a == b`` cannot generally be converted to `bool`.
4+
The implemented fix replaces `==` with ``is``.

src/_pytest/fixtures.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,9 @@ def execute(self, request):
898898
cached_result = getattr(self, "cached_result", None)
899899
if cached_result is not None:
900900
result, cache_key, err = cached_result
901-
if my_cache_key == cache_key:
901+
# note: comparison with `==` can fail (or be expensive) for e.g.
902+
# numpy arrays (#6497)
903+
if my_cache_key is cache_key:
902904
if err is not None:
903905
_, val, tb = err
904906
raise val.with_traceback(tb)

testing/python/fixtures.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,38 @@ def test_nothing(badscope):
11021102
"*Fixture 'badscope' from test_invalid_scope.py got an unexpected scope value 'functions'"
11031103
)
11041104

1105+
@pytest.mark.parametrize("scope", ["function", "session"])
1106+
def test_parameters_without_eq_semantics(self, scope, testdir):
1107+
testdir.makepyfile(
1108+
"""
1109+
class NoEq1: # fails on `a == b` statement
1110+
def __eq__(self, _):
1111+
raise RuntimeError
1112+
1113+
class NoEq2: # fails on `if a == b:` statement
1114+
def __eq__(self, _):
1115+
class NoBool:
1116+
def __bool__(self):
1117+
raise RuntimeError
1118+
return NoBool()
1119+
1120+
import pytest
1121+
@pytest.fixture(params=[NoEq1(), NoEq2()], scope={scope!r})
1122+
def no_eq(request):
1123+
return request.param
1124+
1125+
def test1(no_eq):
1126+
pass
1127+
1128+
def test2(no_eq):
1129+
pass
1130+
""".format(
1131+
scope=scope
1132+
)
1133+
)
1134+
result = testdir.runpytest()
1135+
result.stdout.fnmatch_lines(["*4 passed*"])
1136+
11051137
def test_funcarg_parametrized_and_used_twice(self, testdir):
11061138
testdir.makepyfile(
11071139
"""

0 commit comments

Comments
 (0)