Skip to content

Fixture parametrization breaks if parameter is a numpy array #5946

Closed
@Sup3rGeo

Description

@Sup3rGeo

Description

On latest release and also on master branch, windows 10

The following test:

from numpy import linspace
from pytest import fixture

@fixture(params=linspace(1, 10, 10))
def value(request):
    return request.param

def test_bug(value):
    assert value == value

breaks with:

Traceback (most recent call last):
  File "D:/WORK/pytest-nparray-params-bug/test_bug.py", line 4, in <module>
    @fixture(params=linspace(1, 10, 10))
  File "D:\WORK\pytest-nparray-params-bug\venv\lib\site-packages\_pytest\fixtures.py", line 1123, in fixture
    name=name
  File "D:\WORK\pytest-nparray-params-bug\venv\lib\site-packages\_pytest\fixtures.py", line 1032, in _parse_fixture_args
    key: value for key, value in kwargs.items() if arguments.get(key) != value
  File "D:\WORK\pytest-nparray-params-bug\venv\lib\site-packages\_pytest\fixtures.py", line 1032, in <dictcomp>
    key: value for key, value in kwargs.items() if arguments.get(key) != value
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Cause

It seems that this line:

pytest/src/_pytest/fixtures.py

Lines 1031 to 1033 in b162ab6

kwargs = {
key: value for key, value in kwargs.items() if arguments.get(key) != value
}

Tries to get a boolean result from comparing None != <array> which is ambiguous.

Possible solution

This might be solved by moving the cast to list (line 1137) at the very beginning (1116) of this function:

pytest/src/_pytest/fixtures.py

Lines 1116 to 1139 in b162ab6

fixture_function, arguments = _parse_fixture_args(
callable_or_scope,
*args,
scope=scope,
params=params,
autouse=autouse,
ids=ids,
name=name
)
scope = arguments.get("scope")
params = arguments.get("params")
autouse = arguments.get("autouse")
ids = arguments.get("ids")
name = arguments.get("name")
if fixture_function and params is None and autouse is False:
# direct decoration
return FixtureFunctionMarker(scope, params, autouse, name=name)(
fixture_function
)
if params is not None and not isinstance(params, (list, tuple)):
params = list(params)
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)

I am actually running tests with this change but not 100% certain about side-effects, although it seems to be that casting to list that soon should not cause problems (equivalent of casting to list in user test code).

If you think this is okay I can create the PR.

  • a detailed description of the bug or suggestion
  • output of pip list from the virtual environment you are using
  • pytest and operating system versions
  • minimal example if possible

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: fixturesanything involving fixtures directly or indirectlytopic: parametrizerelated to @pytest.mark.parametrizetype: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions