typing icon indicating copy to clipboard operation
typing copied to clipboard

Interaction between ClassVar/Final and Annotated

Open finite-state-machine opened this issue 2 years ago • 3 comments

The documentation (typing, PEP 526, PEP 591, PEP 593) is silent on how Annotated and ClassVar/Final should be nested.

Intuitively, Annotated should appear on the outside, as the annotation applies to the whole ClassVar/Final variable, and as it's easiest to strip from that point.

In fact, this is not accepted by the Python runtime:


from typing import (
        Annotated,
        ClassVar,
        )

class Foo:
    a: Annotated[ClassVar[int], 'hello'] = 42
            # raises: TypeError: typing.ClassVar[int] is not valid as
            #                    type argument
    b: ClassVar[Annotated[int, 'hello']] = 42
            # accepted by the Python runtime

My intuition says that this behaviour is undesirable.

Even if this behaviour is correct, in my humble opinion, the documentation should be amended to speak to how Annotated and ClassVar/Final interact.

finite-state-machine avatar Jun 18 '22 18:06 finite-state-machine

FWIW this first case was actually relaxed in python 3.11 so both forms work now.

% python3.11
Python 3.11.0b2 (v3.11.0b2:72f00f420a, May 31 2022, 01:35:28) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import typing
>>> typing.Annotated[typing.ClassVar[int], ""]
typing.Annotated[typing.ClassVar[int], '']
>>> typing.ClassVar[typing.Annotated[int, ""]]
typing.ClassVar[typing.Annotated[int, '']]

Gobot1234 avatar Jun 18 '22 18:06 Gobot1234

Thanks, @Gobot1234. If that's the case, I think this issue can be considered resolved.

finite-state-machine avatar Jun 18 '22 21:06 finite-state-machine

As @Gobot1234 said the runtime restriction will be relaxed in 3.11. My general goal is to keep the runtime permissive, so it's easy for type checkers and users to experiment with new forms of type annotations.

That said, it's not unreasonable for type checkers to reject this form. Annotated is meant to be used on types, and ClassVar/Final are type modifiers, not types themselves. So you could make the argument that Annotated should not be used outside ClassVar/Final. I'm fine with leaving that up to individual type checker authors for now.

JelleZijlstra avatar Jun 20 '22 21:06 JelleZijlstra

Per this gist, what's happening today with mypy isn't maximally permissive, but it is consistent with the runtime:

from typing import (
        ClassVar,
        )
from typing_extensions import (
        Annotated,
        )

class Foo:
    a: Annotated[ClassVar[int], 'hello'] = 42
            # accepted by the Python runtime (3.8, 3.11)
            # mypy error:
            #   Invalid type: ClassVar nested inside other type  [valid-type]
    b: ClassVar[Annotated[int, 'hello']] = 42
            # accepted by the Python runtime (3.8, 3.11)
            # accepted by mypy

If others are agreed, I think it's reasonable to close this issue.

finite-state-machine avatar Oct 30 '23 14:10 finite-state-machine