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

Disambiguation Improvement Idea #35

Open
mentalisttraceur opened this issue Apr 7, 2024 · 0 comments
Open

Disambiguation Improvement Idea #35

mentalisttraceur opened this issue Apr 7, 2024 · 0 comments

Comments

@mentalisttraceur
Copy link

mentalisttraceur commented Apr 7, 2024

I was thinking...

  1. If an object is a lambda (which we can detect with reasonably reliable accuracy by looking at .__code__.co_name - see https://stackoverflow.com/a/56451124/4372452), then the only way it can be decorated with @ syntax is if it was returned from a nested decorator:

    @foo
    @baz  # this could return a `lambda`
    def qux():
        ...
  2. Ditto for callable objects which are neither classes nor functions but just instances of a class which has a __call__ method: they can also only be decorated with @ syntax if they are returned from a nested decorator.

And then I thought well it sure would be nice if there was some standard way that all proper decorators were required to use to mark any such wrapper that they return as a wrapper, such a shame that this doesn't exist, maybe we could invent- oh right __wrapped__.

The only exceptions I can think of are functools.partial and bound methods. If we think it is sufficiently reasonable/acceptable for decorators to return those, then they are always ambiguous, because for one reason or another you can't set __wrapped__ on them, so we can't justifiably expect people to do that if returning them from a decorator. So we must let them fall through to the more complex tricks for determining what to do with regular functions and classes.

So, putting that all together, I would do something like this:

from functools import partial
from types import FunctionType, MethodType


def can_arg_be_a_decorator_target(arg):
    if isclass(arg):
        return True
    elif isinstance(arg, FunctionType):
        if arg.__code__.co_name == '<lambda>':
            return hasattr(arg, '__wrapped__')
        return True
    elif callable(arg):
        if isinstance(arg, (partial, MethodType)):
            return True
        return hasattr(arg, '__wrapped__')
    return False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant