Skip to content

distinguish a class that inherits from an attrs class from a true (decorated) attrs class #1334

Open
@Darkdragon84

Description

This question is related to issue #1332, where I needed an __init_subclass__ to be run only once for subclasses of an attrs base class. The issue with using built-in __init_subclass__ is that it doesn't play well with decorated classes, such as attrs or dataclass classes. Hence the addition of a new __attrs_init_subclass__ classmethod.

However, this method (rightfully) only gets called for subclasses that are explicitly decorated as attrs classes. I need a way to run code in an __init_subclass__ method of an attrs class for both attrs and plain old Python (POP) subclasses. I first thought of checking attrs.has on the subclass to see if it is an attrs or POP class. But of course the subclass inherits the __attrs_attrs__ field from the attrs base class, so this can't be used to make the distinction.

My question is thus: How can I distinguish a class that inherits from an attrs class from a true (decorated) attrs class? Some search suggests one way to achieve this is to check whether __attrs_attrs__ is in the class dict of the subclass.

from attrs import frozen


def is_directly_decorated(cls) -> bool:
    return "__attrs_attrs__" in cls.__dict__


def print_if_directly_decorated(cls):
    print(
        f"{cls.__name__} "
        + ("is" if is_directly_decorated(cls) else "isn't")
        + " directly decorated"
    )


@frozen
class BaseAttr: ...


class Sub(BaseAttr): ...


@frozen
class SubAttr(BaseAttr): ...


print_if_directly_decorated(Sub)
print_if_directly_decorated(SubAttr)

this gives

Sub isn't directly decorated
SubAttr is directly decorated

Is this a safe way to do this? Or can I exploit some built-in or attrs functions/methods to make this distinction?

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions