Мне удалось перегрузить __get __ метод для достижения этого, но теперь Pyright жалуется на инициализацию экземпляров.
Код: Выделить всё
module.py
Код: Выделить всё
import dataclasses
import typing as ty
class CmpOperator:
sign: str
def __init__(self, field_name: str, value: ty.Any):
self.field_name = field_name
self.value = value
class GtCmpOperator(CmpOperator):
sign = ">"
class Field[T]:
def __init__(
self,
model_name: str,
name: str,
default_value: T,
python_type: ty.Type[T],
):
self.default_value = default_value
self.model_name = model_name
self.name = name
self.python_type = python_type
def __gt__(self, other: T) -> GtCmpOperator:
return GtCmpOperator(f"{self.model_name}.{self.name}", other)
def init_model(model: ty.Type[ty.Any]) -> None:
if not dataclasses.is_dataclass(model):
raise TypeError(f"Model `{model.__name__}` is not a dataclass")
for field_name, field_type in ty.get_type_hints(model).items():
field = Field(
model.__name__,
field_name,
getattr(model, field_name, None),
field_type,
)
setattr(model, field_name, field)
def some_work[T](model: ty.Type[T], cmp: CmpOperator) -> T:
assert isinstance(cmp, CmpOperator)
< /code>
module.pyi
Код: Выделить всё
import typing as ty
class CmpOperator:
sign: str
def __init__(self, field_name: str, value: ty.Any):
self.field_name: str
self.value: ty.Any
class GtCmpOperator(CmpOperator): ...
class Field[T]:
def __init__(
self,
model_name: str,
name: str,
default_value: T,
python_type: ty.Type[T],
):
self.default_value: T
self.model_name: str
self.name: str
self.python_type: ty.Type[T]
@ty.overload
def __get__(self, obj: None, owner: type) -> ty.Self: ...
@ty.overload
def __get__(self, obj: object, owner: type) -> T: ...
@ty.overload
def __set__(self, obj: None, value: Field) -> None: ...
@ty.overload
def __set__(self, obj: object, value: T) -> None: ...
def __gt__(self, other: T) -> GtCmpOperator: ...
def init_model(model: ty.Type[ty.Any]) -> None: ...
def some_work[T](model: ty.Type[T], cmp: CmpOperator) -> T: ...
< /code>
main.py
import typing as ty
from dataclasses import dataclass
from module import Field, init_model, some_work
@dataclass
class Model1:
field: int = 0
@dataclass
class Model2:
# Literal[0] is not assignable to Field[int]
field: Field[int] = 0
if __name__ == "__main__":
init_model(Model1)
assert isinstance(Model1.field, Field)
assert isinstance(Model1().field, int)
# "bool" is not assignable to "CmpOperator"
obj = some_work(Model1, Model1.field > 0)
# It`s fine
obj = Model1(field=1)
init_model(Model2)
assert isinstance(Model2.field, Field)
assert isinstance(Model2().field, int)
# It`s fine
obj = some_work(Model2, Model2.field > 0)
# Literal[1] is not assignable to Field[int]
obj = Model2(field=1)
< /code>
Asserts are true, but Pyright complains about something in both cases.
Подробнее здесь: https://stackoverflow.com/questions/796 ... e-variable