Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/719.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed :func:`@pytest.mark.parametrize <pytest.mark.parametrize>` not unpacking single-element tuple values when using a string argnames with a trailing comma (e.g., ``"arg,"``).

The trailing comma form now correctly behaves like the tuple form ``("arg",)``, treating argvalues as a list of tuples to unpack.
6 changes: 5 additions & 1 deletion src/_pytest/mark/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,12 @@ def _parse_parametrize_args(
**kwargs,
) -> tuple[Sequence[str], bool]:
if isinstance(argnames, str):
# A trailing comma indicates tuple-style: "arg," is equivalent to ("arg",)
# In this case, argvalues should be a list of tuples, not wrapped values.
# See https://github.com/pytest-dev/pytest/issues/719
has_trailing_comma = argnames.rstrip().endswith(",")
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
force_tuple = len(argnames) == 1
force_tuple = len(argnames) == 1 and not has_trailing_comma
else:
force_tuple = False
return argnames, force_tuple
Expand Down
75 changes: 75 additions & 0 deletions testing/python/metafunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,46 @@ def func(arg1, arg2="qwe"):
assert metafunc.function is func
assert metafunc.cls is None

def test_parametrize_single_arg_trailing_comma(self) -> None:
"""Test that trailing comma in string argnames behaves like tuple argnames.

Regression test for https://github.com/pytest-dev/pytest/issues/719

When using a single argument with:
- "arg" (string, no comma): argvalues is a list of values
- "arg," (string, trailing comma): argvalues is a list of tuples (like tuple form)
- ("arg",) (tuple): argvalues is a list of tuples
"""

def func(arg):
pass

scenarios = [("a",), ("b",)]

# Tuple form: argvalues are tuples, unpacked to get the value
metafunc = self.Metafunc(func)
metafunc.parametrize(("arg",), scenarios)
assert metafunc._calls[0].params == {"arg": "a"}
assert metafunc._calls[1].params == {"arg": "b"}

# String with trailing comma: should behave like tuple form
metafunc = self.Metafunc(func)
metafunc.parametrize("arg,", scenarios)
assert metafunc._calls[0].params == {"arg": "a"}
assert metafunc._calls[1].params == {"arg": "b"}

# String without comma: argvalues are values directly (tuples are passed as-is)
metafunc = self.Metafunc(func)
metafunc.parametrize("arg", scenarios)
assert metafunc._calls[0].params == {"arg": ("a",)}
assert metafunc._calls[1].params == {"arg": ("b",)}

# String without comma with plain values: values are used directly
metafunc = self.Metafunc(func)
metafunc.parametrize("arg", ["a", "b"])
assert metafunc._calls[0].params == {"arg": "a"}
assert metafunc._calls[1].params == {"arg": "b"}

def test_parametrize_error(self) -> None:
def func(x, y):
pass
Expand Down Expand Up @@ -1256,6 +1296,41 @@ def test_hello(arg1, arg2):
["*(1, 4)*", "*(1, 5)*", "*(2, 4)*", "*(2, 5)*", "*4 failed*"]
)

def test_parametrize_single_arg_trailing_comma_functional(
self, pytester: Pytester
) -> None:
"""Test that trailing comma in string argnames behaves like tuple argnames.

Regression test for https://github.com/pytest-dev/pytest/issues/719
"""
pytester.makepyfile(
"""
import pytest

scenarios = [('a',), ('b',)]

@pytest.mark.parametrize(("arg",), scenarios)
def test_tuple_form(arg):
# Tuple argnames: values are unpacked from tuples
assert arg in ('a', 'b')
assert isinstance(arg, str)

@pytest.mark.parametrize("arg,", scenarios)
def test_string_trailing_comma(arg):
# String with trailing comma: should behave like tuple form
assert arg in ('a', 'b')
assert isinstance(arg, str)

@pytest.mark.parametrize("arg", scenarios)
def test_string_no_comma(arg):
# String without comma: tuples are passed as-is
assert arg in (('a',), ('b',))
assert isinstance(arg, tuple)
"""
)
result = pytester.runpytest("-v")
result.assert_outcomes(passed=6)

def test_parametrize_and_inner_getfixturevalue(self, pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
Expand Down
Loading