@@ -807,3 +807,217 @@ reveal_type(bar.base) # N: Revealed type is "builtins.int"
807807
808808[typing fixtures/typing-full.pyi]
809809[builtins fixtures/dataclasses.pyi]
810+
811+ [case testDataclassTransformSimpleDescriptor]
812+ # flags: --python-version 3.11
813+
814+ from typing import dataclass_transform, overload, Any
815+
816+ @dataclass_transform()
817+ def my_dataclass(cls): ...
818+
819+ class Desc:
820+ @overload
821+ def __get__(self, instance: None, owner: Any) -> Desc: ...
822+ @overload
823+ def __get__(self, instance: object, owner: Any) -> str: ...
824+ def __get__(self, instance: object | None, owner: Any) -> Desc | str: ...
825+
826+ def __set__(self, instance: Any, value: str) -> None: ...
827+
828+ @my_dataclass
829+ class C:
830+ x: Desc
831+ y: int
832+
833+ C(x='x', y=1)
834+ C(x=1, y=1) # E: Argument "x" to "C" has incompatible type "int"; expected "str"
835+ reveal_type(C(x='x', y=1).x) # N: Revealed type is "builtins.str"
836+ reveal_type(C(x='x', y=1).y) # N: Revealed type is "builtins.int"
837+ reveal_type(C.x) # N: Revealed type is "__main__.Desc"
838+
839+ [typing fixtures/typing-full.pyi]
840+ [builtins fixtures/dataclasses.pyi]
841+
842+ [case testDataclassTransformUnannotatedDescriptor]
843+ # flags: --python-version 3.11
844+
845+ from typing import dataclass_transform, overload, Any
846+
847+ @dataclass_transform()
848+ def my_dataclass(cls): ...
849+
850+ class Desc:
851+ @overload
852+ def __get__(self, instance: None, owner: Any) -> Desc: ...
853+ @overload
854+ def __get__(self, instance: object, owner: Any) -> str: ...
855+ def __get__(self, instance: object | None, owner: Any) -> Desc | str: ...
856+
857+ def __set__(*args, **kwargs): ...
858+
859+ @my_dataclass
860+ class C:
861+ x: Desc
862+ y: int
863+
864+ C(x='x', y=1)
865+ C(x=1, y=1)
866+ reveal_type(C(x='x', y=1).x) # N: Revealed type is "builtins.str"
867+ reveal_type(C(x='x', y=1).y) # N: Revealed type is "builtins.int"
868+ reveal_type(C.x) # N: Revealed type is "__main__.Desc"
869+
870+ [typing fixtures/typing-full.pyi]
871+ [builtins fixtures/dataclasses.pyi]
872+
873+ [case testDataclassTransformGenericDescriptor]
874+ # flags: --python-version 3.11
875+
876+ from typing import dataclass_transform, overload, Any, TypeVar, Generic
877+
878+ @dataclass_transform()
879+ def my_dataclass(frozen: bool = False): ...
880+
881+ T = TypeVar("T")
882+
883+ class Desc(Generic[T]):
884+ @overload
885+ def __get__(self, instance: None, owner: Any) -> Desc[T]: ...
886+ @overload
887+ def __get__(self, instance: object, owner: Any) -> T: ...
888+ def __get__(self, instance: object | None, owner: Any) -> Desc | T: ...
889+
890+ def __set__(self, instance: Any, value: T) -> None: ...
891+
892+ @my_dataclass()
893+ class C:
894+ x: Desc[str]
895+
896+ C(x='x')
897+ C(x=1) # E: Argument "x" to "C" has incompatible type "int"; expected "str"
898+ reveal_type(C(x='x').x) # N: Revealed type is "builtins.str"
899+ reveal_type(C.x) # N: Revealed type is "__main__.Desc[builtins.str]"
900+
901+ @my_dataclass()
902+ class D(C):
903+ y: Desc[int]
904+
905+ d = D(x='x', y=1)
906+ reveal_type(d.x) # N: Revealed type is "builtins.str"
907+ reveal_type(d.y) # N: Revealed type is "builtins.int"
908+ reveal_type(D.x) # N: Revealed type is "__main__.Desc[builtins.str]"
909+ reveal_type(D.y) # N: Revealed type is "__main__.Desc[builtins.int]"
910+
911+ @my_dataclass(frozen=True)
912+ class F:
913+ x: Desc[str] = Desc()
914+
915+ F(x='x')
916+ F(x=1) # E: Argument "x" to "F" has incompatible type "int"; expected "str"
917+ reveal_type(F(x='x').x) # N: Revealed type is "builtins.str"
918+ reveal_type(F.x) # N: Revealed type is "__main__.Desc[builtins.str]"
919+
920+ [typing fixtures/typing-full.pyi]
921+ [builtins fixtures/dataclasses.pyi]
922+
923+ [case testDataclassTransformGenericDescriptorWithInheritance]
924+ # flags: --python-version 3.11
925+
926+ from typing import dataclass_transform, overload, Any, TypeVar, Generic
927+
928+ @dataclass_transform()
929+ def my_dataclass(cls): ...
930+
931+ T = TypeVar("T")
932+
933+ class Desc(Generic[T]):
934+ @overload
935+ def __get__(self, instance: None, owner: Any) -> Desc[T]: ...
936+ @overload
937+ def __get__(self, instance: object, owner: Any) -> T: ...
938+ def __get__(self, instance: object | None, owner: Any) -> Desc | T: ...
939+
940+ def __set__(self, instance: Any, value: T) -> None: ...
941+
942+ class Desc2(Desc[str]):
943+ pass
944+
945+ @my_dataclass
946+ class C:
947+ x: Desc2
948+
949+ C(x='x')
950+ C(x=1) # E: Argument "x" to "C" has incompatible type "int"; expected "str"
951+ reveal_type(C(x='x').x) # N: Revealed type is "builtins.str"
952+ reveal_type(C.x) # N: Revealed type is "__main__.Desc[builtins.str]"
953+
954+ [typing fixtures/typing-full.pyi]
955+ [builtins fixtures/dataclasses.pyi]
956+
957+ [case testDataclassTransformDescriptorWithDifferentGetSetTypes]
958+ # flags: --python-version 3.11
959+
960+ from typing import dataclass_transform, overload, Any
961+
962+ @dataclass_transform()
963+ def my_dataclass(cls): ...
964+
965+ class Desc:
966+ @overload
967+ def __get__(self, instance: None, owner: Any) -> int: ...
968+ @overload
969+ def __get__(self, instance: object, owner: Any) -> str: ...
970+ def __get__(self, instance, owner): ...
971+
972+ def __set__(self, instance: Any, value: bytes) -> None: ...
973+
974+ @my_dataclass
975+ class C:
976+ x: Desc
977+
978+ c = C(x=b'x')
979+ C(x=1) # E: Argument "x" to "C" has incompatible type "int"; expected "bytes"
980+ reveal_type(c.x) # N: Revealed type is "builtins.str"
981+ reveal_type(C.x) # N: Revealed type is "builtins.int"
982+ c.x = b'x'
983+ c.x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "bytes")
984+
985+ [typing fixtures/typing-full.pyi]
986+ [builtins fixtures/dataclasses.pyi]
987+
988+ [case testDataclassTransformUnsupportedDescriptors]
989+ # flags: --python-version 3.11
990+
991+ from typing import dataclass_transform, overload, Any
992+
993+ @dataclass_transform()
994+ def my_dataclass(cls): ...
995+
996+ class Desc:
997+ @overload
998+ def __get__(self, instance: None, owner: Any) -> int: ...
999+ @overload
1000+ def __get__(self, instance: object, owner: Any) -> str: ...
1001+ def __get__(self, instance, owner): ...
1002+
1003+ def __set__(*args, **kwargs) -> None: ...
1004+
1005+ class Desc2:
1006+ @overload
1007+ def __get__(self, instance: None, owner: Any) -> int: ...
1008+ @overload
1009+ def __get__(self, instance: object, owner: Any) -> str: ...
1010+ def __get__(self, instance, owner): ...
1011+
1012+ @overload
1013+ def __set__(self, instance: Any, value: bytes) -> None: ...
1014+ @overload
1015+ def __set__(self) -> None: ...
1016+ def __set__(self, *args, **kawrga) -> None: ...
1017+
1018+ @my_dataclass
1019+ class C:
1020+ x: Desc # E: Unsupported signature for "__set__" in "Desc"
1021+ y: Desc2 # E: Unsupported "__set__" in "Desc2"
1022+ [typing fixtures/typing-full.pyi]
1023+ [builtins fixtures/dataclasses.pyi]
0 commit comments