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

Improved interface for pytest.mark.parametrize #94

Closed
pytestbot opened this issue Nov 30, 2011 · 9 comments
Closed

Improved interface for pytest.mark.parametrize #94

pytestbot opened this issue Nov 30, 2011 · 9 comments
Labels
type: enhancement new feature or API change, should be merged into features branch

Comments

@pytestbot
Copy link
Contributor

Originally reported by: BitBucket: sienkiew, GitHub: sienkiew


In trying out the new pytest.mark.parametrize feature, I found a use case that is somewhat awkward:

#!python

    @pytest.mark.parametrize( ( 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' ) ,
        [ tuple(range(0,26)), tuple(range(100,126)) ], ids = [ 'first', 'second' ] )
    def test_foo( a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z ) :
        ....

It occurs to me that it is not really necessary to list the parameters in the call to parametrize(), since it already knows what the parameters to the function are.

In _pytest/python.py near line 610, the method parametrize() could start with

#!python

        # if they did not explicitly specify parameters, find them automatically
        if argnames == '-' :
            argnames = tuple( self.funcargnames )
            if len(argnames) == 1 :
                argvalues = [(val,) for val in argvalues]

Then you can re-write my example as:

#!python

    @pytest.mark.parametrize( '-' ,
        [ tuple(range(0,26)), tuple(range(100,126)) ], ids = [ 'first', 'second' ] )
    def test_foo( a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z ) :

The '-' for the parameters is really only there so you can still list the parameters explicitly, as documented in py.test 2.2; you could remove that parameter completely if you wanted to.

I don't fully understand the internals of py.test, so I am reluctant to try to make a formal patch with tests, but you can have this idea.


@pytestbot
Copy link
Contributor Author

Original comment by holger krekel (BitBucket: hpk42, GitHub: hpk42):


It is possible to only parametrize one argument, for example:
{{{
#!python
@pyest.mark.parametrize("num", [1,2,3])
def test_example(tmpdir, num):
...
}}}

This would create three calls and each invocation gets a unique temporary directory. Moreover you could have parametrization from different places in more complex setups. I.e. some plugin may parametrizes a certain argument but you still want to do be able to locally use the "parametrize" decorator to parametrize a different argument.

So I am not sure how useful it really is to introduce a shortcut like the one you suggested (I'd take "*" though).

@pytestbot
Copy link
Contributor Author

Original comment by Ronny Pfannschmidt (BitBucket: RonnyPfannschmidt, GitHub: RonnyPfannschmidt):


the example seems a bit tooooooo detached from reality,
a more close example might help

@pytestbot
Copy link
Contributor Author

Original comment by BitBucket: sienkiew, GitHub: sienkiew:


Holger: I did not know that you could do that. I read about parametrize on pytest.org, but I did not see/recognize the implications that you are describing. (This kind of thing is why I did not submit it as a patch. There is a lot about pytest that I do not know).

Whether '*' is a good shortcut depends on how you think people will use it. If you expect that it will be common to use parametrize without another decorator that also provides function parameters, then it is useful. If you expect that it will be rare to use parametrize without a second decorator, then this feature is less useful.

I think it will be common enough. The first example in the documentation fits this case. (The remaining examples use the pytest_generate_tests callback, which is more elaborate than I would like to do in my tests.)

I type fast, so I am not concerned much about the time it takes to type, but I do often find systems annoying when they insist that you enter/edit the same information twice. Of course, if you are expecting a separate decorator to provide some of the parameters, that is unavoidable, but I expect that to be a less common case.

Ronny:

Of course, it is a contrived example. I was playing with a new feature of the system. Here is another contrived example copied out of my sample tests, but you might find that it looks more realistic:

{{{
#!python

params = [ ( (255,0,0), 'red' ),
      ( (0,255,0), 'green' ),
      ( (0,0,255), 'blue' ),
      ( (0,255,255), 'cyan'),
      ...
     ]

@pytest.mark.parametrize(
    ( 'red', 'green', 'blue' ),
    [ x[0] for x in params ],
    ids=[ x[1] for x in params ]
    )
def test_colorx( red, green, blue ):
    ...

}}}

@pytestbot
Copy link
Contributor Author

Original comment by Ronny Pfannschmidt (BitBucket: RonnyPfannschmidt, GitHub: RonnyPfannschmidt):


im wondering if a slightly different approach might not fit in that particular case

somthing like the following comes to mind

{{{
#!python
C = namedtuple('Color', 'name red green blue')

colors = [
C('red', 255,0,0),
C('green', 0,255,0),
C('blue', 0,0,255),
C('cyan', 0,255,255),
...
]

@pytest.makr.parametrize('color', colors', ids=lambda x:x.name)
def test_colorx(color):
...
}}}

to be a bit more flexible, it could also be possible to pass something like a sorted mapping

@pytestbot
Copy link
Contributor Author

Original comment by Ronny Pfannschmidt (BitBucket: RonnyPfannschmidt, GitHub: RonnyPfannschmidt):


actually, another possible idea is to have something like an items parameter

and basically {{{ids, values = zip(items)}}}

that can directly work together with single name and multi name parameters,
since that transformation can be done before the tuple building

@pytestbot
Copy link
Contributor Author

Original comment by Ronny Pfannschmidt (BitBucket: RonnyPfannschmidt, GitHub: RonnyPfannschmidt):


i threw together https://bitbucket.org/RonnyPfannschmidt/pytest-patches/src/eb655e46c059/parametrize-items as proof of concept, feedback welcome

@pytestbot
Copy link
Contributor Author

Original comment by holger krekel (BitBucket: hpk42, GitHub: hpk42):


As to Ronny's patch i am reluctant to add redundant ways to call to the parametrize decorator. I think we should rather extend the documentation with examples how to build your own decorator on top of parametrize.

I like Ronny's named-tuple suggestion btw - Sienkiew, what do you think of it?

@pytestbot
Copy link
Contributor Author

Original comment by BitBucket: sienkiew, GitHub: sienkiew:


(Reply via [email protected]):

Ronny's example of a named tuple can be generalized to a class of solutions. It is the same as what you said in your first comment: pass in a single complex data item instead of many simple items. I would not complain if you just recommended it as the preferred way to handle lots of parameters.

I don't see a great need to build decorators on top of parameterize. Ronny's example in comment 4 covers most of the examples I can think of. It can also be trivially extended to dynamically generated tests: instead of "colors = [ ..." write "colors = myfn( ...) ". Once you have that ability, I don't know what a custom decorator would do.

Mark S.

@pytestbot
Copy link
Contributor Author

Original comment by Ronny Pfannschmidt (BitBucket: RonnyPfannschmidt, GitHub: RonnyPfannschmidt):


closing this since a working solutions seems to be found

@pytestbot pytestbot added the type: enhancement new feature or API change, should be merged into features branch label Jun 15, 2015
fkohlgrueber pushed a commit to fkohlgrueber/pytest that referenced this issue Oct 27, 2018
The default behaviour is that now all lines break *before* delimiters,
instead of afterwards. The special cases for this are commas and
behaviour around args.

Resolves pytest-dev#73
mgorny pushed a commit to mgorny/pytest that referenced this issue May 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement new feature or API change, should be merged into features branch
Projects
None yet
Development

No branches or pull requests

1 participant