Skip to content

Disambiguation Improvement Idea #35

Description

@mentalisttraceur

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions