[py-dev] Decorators and funcargs in py.test
Vyacheslav Rafalskiy
rafalskiy at gmail.com
Mon Jun 6 15:24:55 CEST 2011
Thanks Holger,
It is clearer now.
Vyacheslav
On Fri, Jun 3, 2011 at 1:38 PM, holger krekel <holger at merlinux.eu> wrote:
> On Fri, Jun 03, 2011 at 12:06 -0400, Vyacheslav Rafalskiy wrote:
>> On Thu, Jun 2, 2011 at 12:46 AM, holger krekel <holger at merlinux.eu> wrote:
>> > On Wed, Jun 01, 2011 at 17:16 -0400, Vyacheslav Rafalskiy wrote:
>> >> >> #---------->> in test_1.py
>> >> >> @pytest.mark.timeout(10)
>> >> >> def test_f1():
>> >> >> # test here
>> >> >>
>> >> >> #---------->> in conftest.py
>> >> >> def pytest_runtest_call(item):
>> >> >> if hasattr(item.obj, 'timeout'):
>> >> >> timeout = item.obj.timeout.args[0]
>> >> >> item.obj = run_with_timeout(timeout)(item.obj)
>> >> >>
>> >> >> Your comments are welcome.
>> >> >
>> >> > it's basically ok but there are some bits that could
>> >> > be improved. You are actually implementing the general
>> >> > test item call. Also I am not sure why you assign
>> >> > "item.obj = ...".
>> >>
>> >> I replace (or so I think) the original test function by the decorated
>> >> one. It gets called elsewhere.
>> >
>> > ah, of course :)
>> >
>> >> > I'd probably write something like this:
>> >> >
>> >> > @pytest.mark.tryfirst
>> >> > def pytest_pyfunc_call(pyfuncitem, __multicall__):
>> >> > if 'timeout' in pyfuncitem.keywords:
>> >> > timeout = pyfuncitem.keywords['timeout'].args[0]
>> >> > run_with_timeout(timeout)(__multicall__.execute)
>> >>
>> >> this will take a while to digest
>> >
>> > it's actually wrong if run_with_timeout is only decorating
>> > but not running the function. I think it makes sense to
>> > rather directly call a helper which calls the function
>> > (note that __multicall__.execute() will execute the remainder
>> > of the hook chain one of which will actually execute the
>> > function). Such a helper would look like
>> > call_with_timeout(timeout, func) i guess.
>>
>> To call the function I need to know what arguments to give it to.
>> The following seems to work, but this is just a guess:
>>
>> def pytest_runtest_call(item):
>> if hasattr(item.obj, 'timeout'):
>> timeout = item.obj.timeout.args[0]
>> run_with_timeout(timeout)(item.obj)(**item.funcargs)
>>
>> I still don't quite get your example, specifically the
>> __multicall__.execute part.
>
> A few things that might help you to understand:
>
> * There can be multiple hook functions implementing the same hook.
> * MultiCall instances manage the calling into a list of hook
> implementation functions.
> * A hook impl function can use zero or any number of available
> arguments. i.e. if a hookspec is "pyest_myfunc(x,y,z)" then
> a hook impl function can just receive only one of them "pytest_myfunc(x)"
> This slicing is done from the MultiCall class.
> * the actual call to a hook impl function is always done by
> passing keyword arguments (i.e. **kwargs) and thus ordering
> of parameters is irrelevant.
> * a hook impl function can receive a "__multicall__" parameter
> which is its managing class and which it can use to call
> __multicall__.execute() to execute the rest of the hook implementations.
> * with all this in mind the few lines of code in _pytest.core.MultiCall
> hopefully make more sense :)
>
> best,
> holger
>
>> Btw, the pytest_pyfunc_call() parameters seem to be in the wrong order
>> based on _pytest.python.py and the prototype in _pytest.hookspec.py
>> only lists one parameter.
>>
>>
>> Vyacheslav
>>
>
More information about the Pytest-dev
mailing list