This is a feature request, unless I'm missing some existing functionality.
As I understand it, the way to annotate class attributes is with typing.ClassVar. However this is incompatible with certain fancy classes like Enum and NamedTuple. For types derived from those, I am able to add class attributes after closing the definition, like so:
class State(Enum):
OFF = 0
ON = 1
State.labels: Tuple[str,...] = ('Off', 'On')
In this contrived example, we are attaching related information to the class, rather than defining it as a completely separate top-level variable like State_labels, which I think is a reasonable design choice (encapsulation, etc).
This solution works in Python: labels is indeed a class variable and not an Enum variant. Similarly, a post-definition assignment to a NamedTuple creates a class variable and not a new named field. Sadly, Mypy rejects such code.
I understand that one of Mypy's core principles is to flag suspect attribute mutation, so this behavior is not so surprising. But given that adding attributes post-definition is the only way (that I know of) to add class variables to enums and NamedTuples, I think we should consider loosening the rules in some principled way.
One obvious solution would be to add a special type hint:
State.labels: Tuple[str,...] = ('Off', 'On') # type: add-classvar
Or, Mypy could take the type annotation left of the = as an indication that the programmer is intentionally defining a new attribute. I have not thought about this extensively, but at the moment this approach appeals to me the most.
If this is too loose for the community's tastes, we could tighten the exception to:
- Attribute additions that immediately follow the class def.
- Attribute additions only to the types that require it such as
Enum and NamedTuple.
I hesitate to suggest these restrictions though, because broadly speaking I think that Mypy should strive to allow for precise annotation of legal Python code, even if the code is not in a "static" style. By allowing the programmer to explicitly indicate that they are adding a type var to an existing class, we will allow Mypy to properly type check a broader range of legal Python programs.
Thanks for considering this. I realize it might be a lot to ask for!
This is a feature request, unless I'm missing some existing functionality.
As I understand it, the way to annotate class attributes is with
typing.ClassVar. However this is incompatible with certain fancy classes like Enum and NamedTuple. For types derived from those, I am able to add class attributes after closing the definition, like so:In this contrived example, we are attaching related information to the class, rather than defining it as a completely separate top-level variable like
State_labels, which I think is a reasonable design choice (encapsulation, etc).This solution works in Python:
labelsis indeed a class variable and not an Enum variant. Similarly, a post-definition assignment to a NamedTuple creates a class variable and not a new named field. Sadly, Mypy rejects such code.I understand that one of Mypy's core principles is to flag suspect attribute mutation, so this behavior is not so surprising. But given that adding attributes post-definition is the only way (that I know of) to add class variables to enums and NamedTuples, I think we should consider loosening the rules in some principled way.
One obvious solution would be to add a special type hint:
Or, Mypy could take the type annotation left of the
=as an indication that the programmer is intentionally defining a new attribute. I have not thought about this extensively, but at the moment this approach appeals to me the most.If this is too loose for the community's tastes, we could tighten the exception to:
EnumandNamedTuple.I hesitate to suggest these restrictions though, because broadly speaking I think that Mypy should strive to allow for precise annotation of legal Python code, even if the code is not in a "static" style. By allowing the programmer to explicitly indicate that they are adding a type var to an existing class, we will allow Mypy to properly type check a broader range of legal Python programs.
Thanks for considering this. I realize it might be a lot to ask for!