-
-
Notifications
You must be signed in to change notification settings - Fork 280
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
Use functools.wraps or wrapt for decorators #170
Comments
Original comment by Claudiu Popa (BitBucket: PCManticore, GitHub: @PCManticore): That would be great to have and it should be a pretty simple patch. |
Original comment by BitBucket: ceridwenv, GitHub: @ceridwen: I have it mostly ready using wrapt. Two questions: directly converting path_wrapper to use wrapt like this: @wrapt.decorator
def path_wrapper(func, instance, args, kwargs):
"""return the given infer function wrapped to handle the path"""
# This assumes that context is always passed as a keyword argument.
context = kwargs.pop('context', None)
node, = args
if context is None:
context = contextmod.InferenceContext()
context.push(node)
yielded = set()
print(func, node, context, kwargs)
for res in func(node, context, **kwargs):
# unproxy only true instance, not const, tuple, dict...
if res.__class__ is Instance:
ares = res._proxied
else:
ares = res
if ares not in yielded:
yield res
yielded.add(ares) Doesn't work because Python's late-binding closures mean that by the time the inner function is called, func is bound is to an object. The long-term solution here is to not monkey-patch methods onto classes, but in the short run, what should I do? The obvious easy solution is to turn path_wrapper into a class, which ought to change the binding behavior to eager instead of lazy. I'm not sure I understand the purpose of cachedproperty well enough to know what functionality it should have. Looking at it, I think it wants to be a proxy of some sort. Does it even behave like Please tell me if I'm asking too many questions and you'd rather I just make decisions about picky implementation details on my own. |
Original comment by Sylvain Thénault (BitBucket: sthenault, GitHub: @sthenault?): @cachedproperty is a non-data descriptor, hence decorated function is |
Original comment by Claudiu Popa (BitBucket: PCManticore, GitHub: @PCManticore): You're not asking too many questions, it's actually a good thing to ask if you aren't sure about something. I'm planning to remove the monkey-patching of methods onto classes, hopefully in time for astroid 1.4. Regarding the patch, why not using functools.wraps? What benefits does wrapt bring to the table for this particular use case? |
Original comment by BitBucket: ceridwenv, GitHub: @ceridwen: To preserve introspectability during debugging, mostly. For instance, sometimes I want to examine things like the state of closure variables to make sure they are what I think they are. For now, since you're changing the monkey-patching anyways, I'll just use functools.wraps. Does cachedpropery need introspection support if it's not visible during the runtime? I'm leaning against it. |
Original comment by Claudiu Popa (BitBucket: PCManticore, GitHub: @PCManticore): And wrapt allows that, to examine the state of the closure variables? I think that the cachedproperty doesn't need introspection support, could be left as it is. |
Original comment by BitBucket: ceridwenv, GitHub: @ceridwen: Yes. import functools
import inspect
import wrapt
@wrapt.decorator
def wrapt_pass_through(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
def wraps_pass_through(f, *args, **kwargs):
@functools.wraps
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
def foo():
a = 1
b = 2
def f():
return a + b
return f
def wrapt_function(f):
return wrapt_pass_through(f)
def wraps_function(f):
return wraps_pass_through(f)
print(inspect.getclosurevars(foo()))
print(inspect.getclosurevars(wrapt_function(foo())))
print(inspect.getclosurevars(wraps_function(foo()))) If you run this script, the first two print statements will correctly print |
Original comment by BitBucket: ceridwenv, GitHub: @ceridwen: The main reason I asked about cachedproperty is that it does limited introspection support (it copies |
Original comment by Claudiu Popa (BitBucket: PCManticore, GitHub: @PCManticore): Does this issue still needs to be opened or can we close it? |
Original comment by BitBucket: ceridwenv, GitHub: @ceridwen: Resolved by https://bitbucket.org/logilab/astroid/pull-requests/86/improve-decorator-introspection-using/diff |
Originally reported by: BitBucket: ceridwenv, GitHub: @ceridwen
In spending copious amounts of time debugging my patch, I've noticed that there are lots of decorators that obscure the names of the functions they contain and break introspection. I think it would make debugging easier if the decorators all used functools.wraps or https://pypi.python.org/pypi/wrapt to make it clear what they're wrapping.
The text was updated successfully, but these errors were encountered: