Skip to content

Disambiguation Improvement Idea #35

@mentalisttraceur

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

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