Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parametrize: allow ellipsis to avoid repeating argument list? #518

Closed
pytestbot opened this issue May 24, 2014 · 4 comments
Closed

parametrize: allow ellipsis to avoid repeating argument list? #518

pytestbot opened this issue May 24, 2014 · 4 comments
Labels
type: proposal proposal for a new feature, often to gather opinions or design the API around the new feature

Comments

@pytestbot
Copy link
Contributor

Originally reported by: Matthias Geier (BitBucket: geier, GitHub: geier)


I'm new to py.test, so please forgive me if this is nonsense ...

I really like py.test and especially the parametrize-feature but I found it gets a bit tedious if I have many arguments in my test function.

The problem is that I basically have to repeat the whole list of arguments: I have to write them once in the string-argument to the parametrize decorator and then again in the argument list of the test function itself.

Here's an example:

#!python

import pytest

testparams = [
    (1, 2, 3, 4, 5, 6, 7, 8),
    (8, 7, 6, 5, 4, 3, 2, 1),
]

@pytest.mark.parametrize("a, b, c, d, e, f, g, h", testparams)
def test_many_args(a, b, c, d, e, f, g, h):
    assert False

I thought it would be nice if the decorator could automatically deduce the list of arguments from the test function, like this:

#!python

@pytest.mark.parametrize(..., testparams)
def test_many_args(a, b, c, d, e, f, g, h):
    assert False

In Python 2.x, you'd have to use Ellipsis instead of ..., of course.

I tried to implement this and came up with a little patch:

#!diff

diff -r 95655acb1f90 _pytest/python.py
--- a/_pytest/python.py Mon May 19 20:32:09 2014 +0200
+++ b/_pytest/python.py Sat May 24 16:14:38 2014 +0200
@@ -796,7 +796,9 @@
             unwrapped_argvalues.append(argval)
         argvalues = unwrapped_argvalues

-        if not isinstance(argnames, (tuple, list)):
+        if argnames is Ellipsis:
+            argnames = inspect.getargspec(self.function)[0][:len(argval)]
+        elif not isinstance(argnames, (tuple, list)):
             argnames = [x.strip() for x in argnames.split(",") if x.strip()]
             if len(argnames) == 1:
                 argvalues = [(val,) for val in argvalues]

I'm sorry that I didn't make a pull request, but I have no clue about Mercurial.
But I guess the change is small enough.

Fixture arguments to the test function do still work, but now they have to be in the end of the argument list, e.g.:

#!python

@pytest.fixture
def myfixture():
    pass

@pytest.mark.parametrize(..., testparams)
def test_many_args_and_fixture(a, b, c, d, e, f, g, h, myfixture):
    assert False

What do you think of this idea?
Has something like this been discussed already?


@pytestbot
Copy link
Contributor Author

Original comment by Matthias Geier (BitBucket: geier, GitHub: geier):


My patch doesn't work if the number of arguments is 1.
This is a quite uncommon case, because this feature would normally only be used with many arguments, but this edge case should of course still work.
This is a variation of my patch which hopefully solves this problem:

#!diff

diff -r 557ba6edb022 _pytest/python.py
--- a/_pytest/python.py Thu Jul 03 16:51:17 2014 +0200
+++ b/_pytest/python.py Sun Jul 06 11:38:43 2014 +0200
@@ -805,7 +805,15 @@
         argvalues = unwrapped_argvalues

         if not isinstance(argnames, (tuple, list)):
-            argnames = [x.strip() for x in argnames.split(",") if x.strip()]
+            if argnames is Ellipsis:
+                try:
+                    autoargs = len(argval)
+                except TypeError:
+                    autoargs = 1
+                argnames = inspect.getargspec(self.function)[0][:autoargs]
+            else:
+                argnames = [x.strip() for x in argnames.split(",")
+                            if x.strip()]
             if len(argnames) == 1:
                 argvalues = [(val,) for val in argvalues]
         if not argvalues:

@pytestbot
Copy link
Contributor Author

Original comment by Matthias Geier (BitBucket: geier, GitHub: geier):


I found out that this issue is a duplicate of #94, which is marked "wontfix".

However, in my proposal, arbitrary other fixtures can be used in the argument list, they only have to be in the end of the list.

My concrete use case for this feature would be to have a dictionary of test cases and one test function that is parametrized with this dictionary.
The keys of this dictionary would be strings to be used in the ids argument, the values would be tuples with the arguments to the test function.
A real example for this use case can be found here: https://github.com/spatialaudio/schunk/blob/master/test/test_dummyconnection.py.

Of course I could also just pass the tuples as a single argument, but then I would loose the very helpful display of argument names in case of a test failure.

@pytestbot pytestbot added the type: proposal proposal for a new feature, often to gather opinions or design the API around the new feature label Jun 15, 2015
@mgeier
Copy link

mgeier commented Jun 16, 2015

I'm the author of this issue, @pytestbot didn't realize that I have a different user name on bitbucket and github.

@The-Compiler
Copy link
Member

Closing this as it's been handled in #780

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: proposal proposal for a new feature, often to gather opinions or design the API around the new feature
Projects
None yet
Development

No branches or pull requests

3 participants