Replace `==` with `is` for comparison of cache keys

Closes #6497
This commit is contained in:
Holger Kohr 2020-01-25 20:28:00 +01:00 committed by Bruno Oliveira
parent 18ac7e0b79
commit 80d4dd6f0b
4 changed files with 40 additions and 1 deletions

View File

@ -112,6 +112,7 @@ Guido Wesdorp
Guoqiang Zhang Guoqiang Zhang
Harald Armin Massa Harald Armin Massa
Henk-Jaap Wagenaar Henk-Jaap Wagenaar
Holger Kohr
Hugo van Kemenade Hugo van Kemenade
Hui Wang (coldnight) Hui Wang (coldnight)
Ian Bicking Ian Bicking

View File

@ -0,0 +1,4 @@
Fix bug in the comparison of request key with cached key in fixture.
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`.
The implemented fix replaces `==` with ``is``.

View File

@ -898,7 +898,9 @@ class FixtureDef:
cached_result = getattr(self, "cached_result", None) cached_result = getattr(self, "cached_result", None)
if cached_result is not None: if cached_result is not None:
result, cache_key, err = cached_result result, cache_key, err = cached_result
if my_cache_key == cache_key: # note: comparison with `==` can fail (or be expensive) for e.g.
# numpy arrays (#6497)
if my_cache_key is cache_key:
if err is not None: if err is not None:
_, val, tb = err _, val, tb = err
raise val.with_traceback(tb) raise val.with_traceback(tb)

View File

@ -1102,6 +1102,38 @@ class TestFixtureUsages:
"*Fixture 'badscope' from test_invalid_scope.py got an unexpected scope value 'functions'" "*Fixture 'badscope' from test_invalid_scope.py got an unexpected scope value 'functions'"
) )
@pytest.mark.parametrize("scope", ["function", "session"])
def test_parameters_without_eq_semantics(self, scope, testdir):
testdir.makepyfile(
"""
class NoEq1: # fails on `a == b` statement
def __eq__(self, _):
raise RuntimeError
class NoEq2: # fails on `if a == b:` statement
def __eq__(self, _):
class NoBool:
def __bool__(self):
raise RuntimeError
return NoBool()
import pytest
@pytest.fixture(params=[NoEq1(), NoEq2()], scope={scope!r})
def no_eq(request):
return request.param
def test1(no_eq):
pass
def test2(no_eq):
pass
""".format(
scope=scope
)
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*4 passed*"])
def test_funcarg_parametrized_and_used_twice(self, testdir): def test_funcarg_parametrized_and_used_twice(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """