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

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

Open
Darkdragon84 opened this issue Aug 12, 2024 · 4 comments

Comments

@Darkdragon84
Copy link

Darkdragon84 commented Aug 12, 2024

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?

@hynek
Copy link
Member

hynek commented Aug 13, 2024

Checking the class's __dict__ is how we check for direct attributes since 24.1, too.

@Darkdragon84
Copy link
Author

thanks for confirming 👍 would it make sense to add anything along those lines to attr.has?

@hynek
Copy link
Member

hynek commented Aug 17, 2024

I think it makes sense to expand has a bit (also maybe accept instances), but it would’ve to be gated behind an option I’m afraid. :|

@Darkdragon84
Copy link
Author

oh that's totally fine! Thanks for considering this 🙏

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

2 participants