After creating this feature request in pyright repo, i was told that this is not supported by python type spec and it’s best to discuss it here.
The problem
In django-modeltranslation, before we added types, we used class variable to populate instance variable with same name, but different type. And now this decision is biting our asses.
Here’s cleaned up code:
from typing import Any, ClassVar, Iterable
class TranslationField:
...
class FieldsAggregationMetaClass(type):
fields: ClassVar[Iterable[str]]
def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> type: ...
class TranslationOptions(metaclass=FieldsAggregationMetaClass):
def __init__(self) -> None:
self.fields: dict[str, set[TranslationField]] = {f: set() for f in self.fields}
class BookTranslationOptions(TranslationOptions):
fields = ["name"]
This leads to error when assigning fields
, because it’s being treated as instance variable, not class var.
Pyright:
error: Expression of type "list[str]" is incompatible with declared type "dict[str, set[TranslationField]]"
"list[str]" is incompatible with "dict[str, set[TranslationField]]" (reportAssignmentType)
Mypy:
typing-test.py: note: In class "BookTranslationOptions":
typing-test.py:20: error: Incompatible types in assignment (expression has type "List[str]", base class
"TranslationOptions" defined the type as "Dict[str, Set[TranslationField]]") [assignment]
fields = ["name"]
^~~~~~~~
Suggestion
It would be really nice, if on the class level fields
was treated as class variable, allowing assignling a list. But on the instance level - it was using type from __init__
(or type from annotation without ClassVar.
If it’s possible at runtime, maybe it should be supported by typing spec? What do you think?
Any suggestions how to fix this by refactoring is also welcome. Probably, we should rewrite TranslationOptions and use self._fields
instead, or something like this. But i really don’t want to rewrite all of this, and maybe just use Any
as a type. It’s a library after all, and not a public interface.