28 lines
1.1 KiB
Python
28 lines
1.1 KiB
Python
from abc import ABCMeta
|
|
|
|
|
|
class AutoSlots(ABCMeta):
|
|
"""
|
|
Metaclass for automatically generating __slots__ based on superclass type annotations.
|
|
|
|
Superclasses must set `__slots__ = ()` to make this work properly.
|
|
|
|
This is a workaround for the fact that non-empty `__slots__` can't be used
|
|
with multiple inheritance. Since we only use multiple inheritance with abstract
|
|
classes, they can have empty `__slots__` and their attribute type annotations
|
|
can be used to generate a full `__slots__` for the concrete class.
|
|
"""
|
|
def __new__(cls, name, bases, dctn): # noqa: ANN001,ANN204
|
|
parents = set()
|
|
for base in bases:
|
|
parents |= set(base.mro())
|
|
|
|
slots = list(dctn.get('__slots__', ()))
|
|
for parent in parents:
|
|
if not hasattr(parent, '__annotations__'):
|
|
continue
|
|
slots.extend(parent.__annotations__.keys())
|
|
|
|
# Deduplicate (dict to preserve order)
|
|
dctn['__slots__'] = tuple(dict.fromkeys(slots))
|
|
return super().__new__(cls, name, bases, dctn)
|