Re: [py-dev] Using funcargs with decorators

2012-10-15 Thread Antonio Cuni
On 10/12/2012 06:50 PM, Floris Bruynooghe wrote:
> Are these being addressed by PEP 362?  I must admit I haven't had time
> to read this yet, but if functools.wraps gets updated it was my
> understanding that the *args, **kwargs inspection issue should be
> solved and if you can set attributes on the signature object it could
> stay persistent in the face of composition of decorators?

I was not aware of PEP 362, which seems a good step in that direction, but
indeed if functools.wraps does not update the signature automatically, it
won't be used much in practice I fear.

ciao,
Anto
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-12 Thread Floris Bruynooghe
On 12 October 2012 10:11, Antonio Cuni  wrote:
> On 10/11/2012 11:53 PM, holger krekel wrote:
>>
>> On a sidenote, i am not sure Python's decorator design was such
>> a great idea.  Maybe it should have been restricted to setting attributes
>> (like C# and also java IIRC) and then a way to get those attributed
>> functions on a per-class, per-module or even global basis.
>
> well, there are obviously things which you can't do by just setting
> attributes, and moreover nothing would stop people to do the old "fn =
> decor(fn)" trick.
>
> I think that in general the *args, **kwargs pattern works well enough. The
> only two drawbacks I can see in day-to-day usage are:
>
> - that the name of the decorated function is different than the original one,
> although nowadays we have @functools.wraps (but it's still not widely used).
>
> - that decorators are not composable is one wraps and the other sets an
> attribute: depending on the order they are applied we might set the attribute
> on the wrapper or wrapped object.

Are these being addressed by PEP 362?  I must admit I haven't had time
to read this yet, but if functools.wraps gets updated it was my
understanding that the *args, **kwargs inspection issue should be
solved and if you can set attributes on the signature object it could
stay persistent in the face of composition of decorators?


Regards,
Floris
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-12 Thread Antonio Cuni
On 10/11/2012 11:53 PM, holger krekel wrote:
> 
> On a sidenote, i am not sure Python's decorator design was such
> a great idea.  Maybe it should have been restricted to setting attributes
> (like C# and also java IIRC) and then a way to get those attributed
> functions on a per-class, per-module or even global basis.

well, there are obviously things which you can't do by just setting
attributes, and moreover nothing would stop people to do the old "fn =
decor(fn)" trick.

I think that in general the *args, **kwargs pattern works well enough. The
only two drawbacks I can see in day-to-day usage are:

- that the name of the decorated function is different than the original one,
although nowadays we have @functools.wraps (but it's still not widely used).

- that decorators are not composable is one wraps and the other sets an
attribute: depending on the order they are applied we might set the attribute
on the wrapper or wrapped object.

For more advanced usages, it would be nice to have an automatic way to "copy"
the signature from the wrapped to the wrapper: this alone would solve both the
pypy and the OP problems.

Additional bonus: a standard way to declare (via a function attribute) that
this function object is a wrapper for this other, to be used e.g. by debuggers
to show the "correct" source code. E.g., I have a "source" command in pdb++
which breaks in case of wrappers:

@mydecor
def foo(...):
...

(pdb++) source foo
def mydecor(fn):
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
return wrapped

ciao,
Anto
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-11 Thread holger krekel
Hi Anto,

On Thu, Oct 11, 2012 at 22:10 +0200, Antonio Cuni wrote:
> Hi Holger, Sebastian,
> 
> On 10/11/2012 03:16 PM, holger krekel wrote:
> > ah, now i get it.  You want to assign the function back.
> > That is indeed not going to work as pytest then sees the rollback
> > function (i assume you return another function from this decorator).
> > What is the decorator-returned function doing?  
> 
> I admit I did not follow the discussion deeply. However, if the problem is
> that py.test sees the decorated function (which presumably uses *args and
> **kwargs) instead of the original one, it can be solved by using the same
> technique I used for enforceargs in pypy:
> 
> https://bitbucket.org/pypy/pypy/src/7f6d5c878b90/pypy/rlib/objectmodel.py#cl-170
> 
> in practice, the trick is to exec() a function def with the correct argument
> list instead of just relying on *args, **kwargs. This way, py.test should be
> able to find the correct signature.

I agree that is one way to solve it.  However, if "hiding" the
function can be avoided alltogether, then it's even better.

On a sidenote, i am not sure Python's decorator design was such
a great idea.  Maybe it should have been restricted to setting attributes
(like C# and also java IIRC) and then a way to get those attributed
functions on a per-class, per-module or even global basis.

best,
holger
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-11 Thread Antonio Cuni
Hi Holger, Sebastian,

On 10/11/2012 03:16 PM, holger krekel wrote:
> ah, now i get it.  You want to assign the function back.
> That is indeed not going to work as pytest then sees the rollback
> function (i assume you return another function from this decorator).
> What is the decorator-returned function doing?  

I admit I did not follow the discussion deeply. However, if the problem is
that py.test sees the decorated function (which presumably uses *args and
**kwargs) instead of the original one, it can be solved by using the same
technique I used for enforceargs in pypy:

https://bitbucket.org/pypy/pypy/src/7f6d5c878b90/pypy/rlib/objectmodel.py#cl-170

in practice, the trick is to exec() a function def with the correct argument
list instead of just relying on *args, **kwargs. This way, py.test should be
able to find the correct signature.

ciao,
anto
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-11 Thread holger krekel
Hi Sebastian,

On Thu, Oct 11, 2012 at 14:44 +0200, Sebastian Rahlf wrote:
> Hi Holger!
> 
> >> At work we use a decorator @rollback on selected test functions which
> >> will rollback any db changes made during that test.
> >>
> >> I've recently started using pytest's dependency injection for a few
> >> use cases, both with @pytest.mark.parametrize(...) and the
> >> pytest_funcarg__XXX hook.
> >> Unfortunately, this clashes with our decorated test functions.
> >>
> >> How can I make this work?
> >>
> >> My first idea was using a custom marker, say @pytest.mark.rollback and
> >> do something like:
> >>
> >> def rollback(meth):
> >> """Original rollback function"""
> >> ...
> >>
> >> def pytest_runtest_setup(item):
> >> if not isinstance(item, pytest.Function):
> >> return
> >> if hasattr(item.obj, 'rollback'):
> >> item = rollback(item)
> >>
> >> Would an approach like this actually work?
> >
> > I think so - probably you need to call "rollback(item.obj") though.
> 
> Thanks for your feedback. I've tried it again with the following code:
> 
> # conftest.py
> import pytest
> from unittests import rollback
> 
> def pytest_configure(config):
> # register an additional marker
> config.addinivalue_line("markers",
> "rollback: rollback any db changes after test")
> 
> def pytest_runtest_setup(item):
> if not isinstance(item, pytest.Function):
> return
> if hasattr(item.obj, 'rollback'):
> item.obj = rollback(item.obj)
> 
> # test_my_tests.py
> 
> import pytest
> 
> @pytest.mark.rollback
> def test_rollback(monkepatch):
> # ...
> assert True
> 
> What I get is a "TypeError: test_rollback() takes exactly 1 argument (0 
> given)".
> How can I make this work?

ah, now i get it.  You want to assign the function back.
That is indeed not going to work as pytest then sees the rollback
function (i assume you return another function from this decorator).
What is the decorator-returned function doing?  

Did you check out the transact example in
http://pytest.org/dev/fixture.html that i referenced in the
stackoverflow anwser?

best,
holger
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-11 Thread Sebastian Rahlf
Hi Holger!

>> At work we use a decorator @rollback on selected test functions which
>> will rollback any db changes made during that test.
>>
>> I've recently started using pytest's dependency injection for a few
>> use cases, both with @pytest.mark.parametrize(...) and the
>> pytest_funcarg__XXX hook.
>> Unfortunately, this clashes with our decorated test functions.
>>
>> How can I make this work?
>>
>> My first idea was using a custom marker, say @pytest.mark.rollback and
>> do something like:
>>
>> def rollback(meth):
>> """Original rollback function"""
>> ...
>>
>> def pytest_runtest_setup(item):
>> if not isinstance(item, pytest.Function):
>> return
>> if hasattr(item.obj, 'rollback'):
>> item = rollback(item)
>>
>> Would an approach like this actually work?
>
> I think so - probably you need to call "rollback(item.obj") though.

Thanks for your feedback. I've tried it again with the following code:

# conftest.py
import pytest
from unittests import rollback

def pytest_configure(config):
# register an additional marker
config.addinivalue_line("markers",
"rollback: rollback any db changes after test")

def pytest_runtest_setup(item):
if not isinstance(item, pytest.Function):
return
if hasattr(item.obj, 'rollback'):
item.obj = rollback(item.obj)

# test_my_tests.py

import pytest

@pytest.mark.rollback
def test_rollback(monkepatch):
# ...
assert True

What I get is a "TypeError: test_rollback() takes exactly 1 argument (0 given)".
How can I make this work?

Cheers,
Seb.
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev


Re: [py-dev] Using funcargs with decorators

2012-10-11 Thread holger krekel
Hi Sebastian,

On Thu, Oct 11, 2012 at 11:47 +0200, Sebastian Rahlf wrote:
> Hi!
> 
> At work we use a decorator @rollback on selected test functions which
> will rollback any db changes made during that test.
> 
> I've recently started using pytest's dependency injection for a few
> use cases, both with @pytest.mark.parametrize(...) and the
> pytest_funcarg__XXX hook.
> Unfortunately, this clashes with our decorated test functions.
> 
> How can I make this work?
> 
> My first idea was using a custom marker, say @pytest.mark.rollback and
> do something like:
> 
> def rollback(meth):
> """Original rollback function"""
> ...
> 
> def pytest_runtest_setup(item):
> if not isinstance(item, pytest.Function):
> return
> if hasattr(item.obj, 'rollback'):
> item = rollback(item)
> 
> Would an approach like this actually work?

I think so - probably you need to call "rollback(item.obj") though.

> Sebastian
> 
> P.S. I've posted this to stackoverflow before I remembered that there
> is a mailing list
> http://stackoverflow.com/questions/12836134/pytest-using-dependency-injection-with-decorators

I answered there as well.

best,
holger


___
> py-dev mailing list
> py-dev@codespeak.net
> http://codespeak.net/mailman/listinfo/py-dev
> 
___
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev