attrs icon indicating copy to clipboard operation
attrs copied to clipboard

Passing arguments to `__attrs_init_subclass__`

Open tartopohm opened this issue 1 year ago • 2 comments

Hello, thanks for the great work!

My question/issue is related to __attrs_init_subclass__ that was recently added. PEP 487 allows for passing arguments (not sure whether that's the proper name) at class definition. The use case, for me, would be to have some sort of abstract class attributes that should be defined by concrete classes.

To make it short, reusing the example from the docs, this works

class Base:
   @classmethod
   def __init_subclass__(cls, foo):
       cls.foo = foo
       print(f"Base has been subclassed by attrs {cls} and foo={cls.foo}.")


class Derived(Base, foo=42):
   pass
>>> Base has been subclassed by attrs <class '__main__.Derived'> and foo=42.

while

import attrs


class Base:
   @classmethod
   def __attrs_init_subclass__(cls, foo):
       cls.foo = foo
       print(f"Base has been subclassed by attrs {cls} and foo={cls.foo}.")


@attrs.define
class Derived(Base, foo=12):
   pass

does not, throwing TypeError: Derived.__init_subclass__() takes no keyword arguments.

Would there be any workaround?

tartopohm avatar Aug 13 '24 10:08 tartopohm

Yeah I was considering to add it, but 24.1 was 8 months overdue so this fell off the wagon, since I wasn’t sure what’s involved.

hynek avatar Aug 13 '24 14:08 hynek

Fair enough. I am completely swamped at the moment, so no promises, but I'll try to look into it if I can find the time.

tartopohm avatar Aug 18 '24 19:08 tartopohm

I had a brief look, but it looks like there is no way to access the x after the class is created. So, I don't think this is even possible to implement without some hairy metaclasses magic. Happy to be corrected, tho!

hynek avatar Sep 28 '25 13:09 hynek

How about passing the init arguments to the decorator?

import attrs


class Base:
   @classmethod
   def __attrs_init_subclass__(cls, foo):
       cls.foo = foo
       print(f"Base has been subclassed by attrs {cls} and foo={cls.foo}.")


@attrs.define(metaclass_args={"foo": 12})
class Derived(Base):
   pass

Enegg avatar Oct 20 '25 16:10 Enegg