You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
python.py:813 (in "parametrize") raises "TypeError: object of type 'int' has no len()" in some cases #638
Originally reported by: Eric Dand (BitBucket: eric_dand, GitHub: eric_dand)
Passing a one-element array for argnames and an array of ints as argvalues to parametrize causes the assert at line 813 to fail. This is only caused by this edge case:
If argnames is a single-element string (ie. no commas, not enclosed in an array), 788-791 will try to split argnames by commas, find at 790 that len(argnames) == 1, and will box up argvalues's values into tuples.
If argnames is an array that has more than one element, each element of argvalues should be a tuple. This is then the intended behaviour, and therefore not an issue.
If argnames is a single-element array, however, it sidesteps the check at 788, if not isinstance(argnames, (tuple, list)):, wrongly assuming there is more than one element in argname, and therefore does not pack up argvalues into tuples.
The simplest fix is to simply dedent lines 790 and 791 to check the length of argnames regardless of whether it was passed as a string or not. I'm not sure if this change is entirely safe, but it did resolve the issue in my case.
#!python
def pytest_addoption(parser):
parser.addoption("--all", action="store_true",
help="run all combinations")
def pytest_generate_tests(metafunc):
if 'param1' in metafunc.fixturenames:
if metafunc.config.option.all:
end = 5
else:
end = 2
import pdb; pdb.set_trace()
metafunc.parametrize(['param1'], range(end))
Your change would fix compute4 but break compute2 and compute3.
In general I think it is safest not to change argvalues very much, as we cannot reliably tell if tuples/lists represent different test cases or a single value within a test case. I would treat the syntax of compute1 as a convenience, i.e. when you specify a single argname in a plain string you don't have to bother packing your argvalues into tuples.
$ ./venv/bin/pytest t.py
============================= test session starts ==============================
platform linux -- Python 3.6.5, pytest-3.6.4.dev9+g42bbb4fa.d20180707, py-1.5.4, pluggy-0.6.0
rootdir: /tmp/pytest, inifile: tox.ini
collected 0 items / 1 errors
==================================== ERRORS ====================================
____________________________ ERROR collecting t.py _____________________________
venv/lib/python3.6/site-packages/pluggy/__init__.py:617: in __call__
return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
venv/lib/python3.6/site-packages/pluggy/__init__.py:222: in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
venv/lib/python3.6/site-packages/pluggy/__init__.py:216: in <lambda>
firstresult=hook.spec_opts.get('firstresult'),
venv/lib/python3.6/site-packages/_pytest/python.py:243: in pytest_pycollect_makeitem
res = list(collector._genfunctions(name, obj))
venv/lib/python3.6/site-packages/_pytest/python.py:433: in _genfunctions
self.ihook.pytest_generate_tests(metafunc=metafunc)
venv/lib/python3.6/site-packages/pluggy/__init__.py:617: in __call__
return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
venv/lib/python3.6/site-packages/pluggy/__init__.py:222: in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
venv/lib/python3.6/site-packages/pluggy/__init__.py:216: in <lambda>
firstresult=hook.spec_opts.get('firstresult'),
venv/lib/python3.6/site-packages/_pytest/python.py:164: in pytest_generate_tests
metafunc.parametrize(*marker.args, **marker.kwargs)
venv/lib/python3.6/site-packages/_pytest/python.py:923: in parametrize
ids = idmaker(argnames, parameters, idfn, ids, self.config)
venv/lib/python3.6/site-packages/_pytest/python.py:1075: in idmaker
for valindex, parameterset in enumerate(parametersets)
venv/lib/python3.6/site-packages/_pytest/python.py:1075: in <listcomp>
for valindex, parameterset in enumerate(parametersets)
venv/lib/python3.6/site-packages/_pytest/python.py:1065: in _idvalset
for val, argname in zip(parameterset.values, argnames)
E TypeError: zip argument #1 must support iteration
=========================== short test summary info ============================
ERROR t.py
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.26 seconds ============================
I'm not sure this is solvable without breaking existing cases, as @pfctdayelise points out. Perhaps we should instead focus in improving the message at least?
My first ever test with pytest I seem to have hit this issue with the below example test
(the error was if len(param.values) != len(argnames): E TypeError: object of type 'int' has no len())
Activity
pytestbot commentedon Jan 20, 2015
Original comment by Brianna Laugher (BitBucket: pfctdayelise, GitHub: pfctdayelise):
Hi Eric, I had trouble recreating this problem based on your description. Would you be able to provide a brief example test that causes the problem?
pytestbot commentedon Jan 22, 2015
Original comment by Eric Dand (BitBucket: eric_dand, GitHub: eric_dand):
Adapted minimally from http://pytest.org/latest/example/parametrize.html:
conftest.py:
test_compute.py (unchanged):
The only change I made to the above code was to put braces around
'param1'in the call tometafunc.parametrize.pytestbot commentedon Jan 24, 2015
Original comment by Brianna Laugher (BitBucket: pfctdayelise, GitHub: pfctdayelise):
Your fix is not going to work for the case where there is only one argname, and the argvalues are already packed into tuples. e.g.
Your change would fix compute4 but break compute2 and compute3.
In general I think it is safest not to change argvalues very much, as we cannot reliably tell if tuples/lists represent different test cases or a single value within a test case. I would treat the syntax of compute1 as a convenience, i.e. when you specify a single argname in a plain string you don't have to bother packing your argvalues into tuples.
asottile commentedon Jul 8, 2018
Here's a minimal reproduction:
nicoddemus commentedon Jan 17, 2019
I'm not sure this is solvable without breaking existing cases, as @pfctdayelise points out. Perhaps we should instead focus in improving the message at least?
barclay13 commentedon May 30, 2019
My first ever test with pytest I seem to have hit this issue with the below example test
(the error was
if len(param.values) != len(argnames): E TypeError: object of type 'int' has no len())asottile commentedon May 30, 2019
You need an additional set of iterable. The second parameter is an iterable of case tuples:
barclay13 commentedon May 30, 2019
@asottile Thanks, that worked perfectly. Perhaps an alternative error message might guide other users more clearly.
Thanks for your help.
Fix pytest error