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

Open
#1,334 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
25/100
Issue type
Documentation
Clarity
Needs clarification
Activity status
Stale
Tech stack
python
Domain
documentation

Research direction

Start by reviewing issue 1332 and the documented attrs_init_subclass behavior, then inspect how attrs.has and attrs_attrs are described. Compare the shown cls.dict check for plain and decorated subclasses. Done means establishing whether this distinction is supported and documenting the safe, recommended approach or identifying the needed API clarification.

Written by the indexing model from the issue text.

Description

This question is related to issue https://github.com/python-attrs/attrs/issues/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?

Dominant language
Python
Stars
5.8k
Forks
480
Avg merge
2h 15m
Merged PRs (30d)
2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from python-attrs/attrs

All issues in python-attrs/attrs

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.