Search code examples
pythonattrmetaclass

Applying attrs.frozen in metaclass removes Python type annotations


I try to apply attrs.frozen to all inheriting classes. To do that I used a metaclass:

class MetaKlass(type):

    def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]):
        new = super().__new__(mcs, name, bases, attrs)
        if TYPE_CHECKING or '__attrs_attrs__' not in attrs:
            return frozen(new)
        return new


class Klass(metaclass=MetaKlass):
    attribute: int

This code does not produce proper type hinting in VSCode, even though Klass.__init__.__annotations__ contains {'return': None, 'attribute': int} as expected.

Is there a way to inform type checker that the metaclass produces the same result as

@frozen
class Klass:
    attribute: int

Solution

  • Static type checking code does not run the code. That is why it is called "static". As such, any metaclass code is not executed at all: no tool "emulate" what a metaclass would do: they just check the plain character arrangement in a class statement and its block + evaluate in an emulation like way, whatever code is present in the annotations themselves (inside the annotations). Although annotations have to be syntactic valid Python, and they are actually run when running the code, the type checking code does not do that. (in most tools. there may be a non-mainstream type checking tool that will actually check things at runtime)

    All this means your if TYPE_CHECKING statement inside the metaclass' __new__ method is never executed.