diff --git a/conformance/results/mypy/dataclasses_descriptors.toml b/conformance/results/mypy/dataclasses_descriptors.toml index e4731029..5e485e85 100644 --- a/conformance/results/mypy/dataclasses_descriptors.toml +++ b/conformance/results/mypy/dataclasses_descriptors.toml @@ -1,18 +1,6 @@ -conformant = "Partial" -notes = """ -Assumes descriptor behavior only when field is assigned in class body. -Does not correctly evaluate type of descriptor access. -""" +conformant = "Pass" output = """ -dataclasses_descriptors.py:61: error: Cannot access instance-only attribute "x" on class object [misc] -dataclasses_descriptors.py:62: error: Cannot access instance-only attribute "y" on class object [misc] -dataclasses_descriptors.py:66: error: Expression is of type "Desc2[int]", not "int" [assert-type] -dataclasses_descriptors.py:67: error: Expression is of type "Desc2[str]", not "str" [assert-type] """ -conformance_automated = "Fail" +conformance_automated = "Pass" errors_diff = """ -Line 61: Unexpected errors ['dataclasses_descriptors.py:61: error: Cannot access instance-only attribute "x" on class object [misc]'] -Line 62: Unexpected errors ['dataclasses_descriptors.py:62: error: Cannot access instance-only attribute "y" on class object [misc]'] -Line 66: Unexpected errors ['dataclasses_descriptors.py:66: error: Expression is of type "Desc2[int]", not "int" [assert-type]'] -Line 67: Unexpected errors ['dataclasses_descriptors.py:67: error: Expression is of type "Desc2[str]", not "str" [assert-type]'] """ diff --git a/conformance/results/pycroscope/dataclasses_descriptors.toml b/conformance/results/pycroscope/dataclasses_descriptors.toml index e5410991..be211bd5 100644 --- a/conformance/results/pycroscope/dataclasses_descriptors.toml +++ b/conformance/results/pycroscope/dataclasses_descriptors.toml @@ -1,23 +1,6 @@ -conformant = "Partial" -notes = """ -Conformance suite is questionable; see https://github.com/python/typing/issues/2259 -""" -conformance_automated = "Fail" +conformant = "Pass" +conformance_automated = "Pass" errors_diff = """ -Line 61: Unexpected errors ['./dataclasses_descriptors.py:61:12: Any[error] is not equivalent to list[int]', "./dataclasses_descriptors.py:61:12: has no attribute 'x' [undefined_attribute]"] -Line 62: Unexpected errors ['./dataclasses_descriptors.py:62:12: Any[error] is not equivalent to list[str]', "./dataclasses_descriptors.py:62:12: has no attribute 'y' [undefined_attribute]"] -Line 63: Unexpected errors ['./dataclasses_descriptors.py:63:12: list[Any[generic_argument]] is not equivalent to list[str]'] -Line 66: Unexpected errors ['./dataclasses_descriptors.py:66:12: ./dataclasses_descriptors.py.Desc2[int] is not equivalent to int'] -Line 67: Unexpected errors ['./dataclasses_descriptors.py:67:12: ./dataclasses_descriptors.py.Desc2[str] is not equivalent to str'] -Line 68: Unexpected errors ['./dataclasses_descriptors.py:68:12: Any[generic_argument] is not equivalent to str'] """ output = """ -./dataclasses_descriptors.py:61:12: Any[error] is not equivalent to list[int] -./dataclasses_descriptors.py:61:12: has no attribute 'x' [undefined_attribute] -./dataclasses_descriptors.py:62:12: Any[error] is not equivalent to list[str] -./dataclasses_descriptors.py:62:12: has no attribute 'y' [undefined_attribute] -./dataclasses_descriptors.py:63:12: list[Any[generic_argument]] is not equivalent to list[str] -./dataclasses_descriptors.py:66:12: ./dataclasses_descriptors.py.Desc2[int] is not equivalent to int -./dataclasses_descriptors.py:67:12: ./dataclasses_descriptors.py.Desc2[str] is not equivalent to str -./dataclasses_descriptors.py:68:12: Any[generic_argument] is not equivalent to str """ diff --git a/conformance/results/pyrefly/dataclasses_descriptors.toml b/conformance/results/pyrefly/dataclasses_descriptors.toml index e2ae83bf..1f7c9fc1 100644 --- a/conformance/results/pyrefly/dataclasses_descriptors.toml +++ b/conformance/results/pyrefly/dataclasses_descriptors.toml @@ -1,22 +1,11 @@ conformant = "Partial" notes = """ -* Assumes descriptor behavior only when field is assigned in class body -* Doesn't allow non-data descriptors or data descriptors with differing `__get__` and `__set__` types +Rejects a data descriptor field whose `__get__` and `__set__` have differing types. """ conformance_automated = "Fail" errors_diff = """ -Line 32: Unexpected errors ['Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition]'] -Line 58: Unexpected errors ['Cannot set field `z` to non-data descriptor `Desc2` [bad-class-definition]'] -Line 61: Unexpected errors ['assert_type(Desc2[int], list[int]) failed [assert-type]'] -Line 62: Unexpected errors ['assert_type(Desc2[str], list[str]) failed [assert-type]'] -Line 66: Unexpected errors ['assert_type(Desc2[int], int) failed [assert-type]'] -Line 67: Unexpected errors ['assert_type(Desc2[str], str) failed [assert-type]'] +Line 35: Unexpected errors ['Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition]'] """ output = """ -ERROR dataclasses_descriptors.py:32:5-6: Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition] -ERROR dataclasses_descriptors.py:58:5-6: Cannot set field `z` to non-data descriptor `Desc2` [bad-class-definition] -ERROR dataclasses_descriptors.py:61:12-30: assert_type(Desc2[int], list[int]) failed [assert-type] -ERROR dataclasses_descriptors.py:62:12-30: assert_type(Desc2[str], list[str]) failed [assert-type] -ERROR dataclasses_descriptors.py:66:12-24: assert_type(Desc2[int], int) failed [assert-type] -ERROR dataclasses_descriptors.py:67:12-24: assert_type(Desc2[str], str) failed [assert-type] +ERROR dataclasses_descriptors.py:35:5-6: Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition] """ diff --git a/conformance/results/results.html b/conformance/results/results.html index 0edd52cc..3ff0d30c 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -900,12 +900,12 @@

Python Type System Conformance Test Results

Dataclasses      dataclasses_descriptors -
Partial

Assumes descriptor behavior only when field is assigned in class body.

Does not correctly evaluate type of descriptor access.

Pass Pass -
Partial

* Assumes descriptor behavior only when field is assigned in class body

* Doesn't allow non-data descriptors or data descriptors with differing `__get__` and `__set__` types

-
Partial

Conformance suite is questionable; see https://github.com/python/typing/issues/2259

-
Partial

Only infers a descriptor `__get__` method as being called when a descriptor attribute is accessed on an instance if the descriptor attribute is present in the class namespace.

+Pass +
Partial

Rejects a data descriptor field whose `__get__` and `__set__` have differing types.

+Pass +Pass      dataclasses_final
Partial

Wrongly requires a Final dataclass field to be initialized at class level.

Doesn't support Final nested inside ClassVar.

diff --git a/conformance/results/ty/dataclasses_descriptors.toml b/conformance/results/ty/dataclasses_descriptors.toml index 91ad20b9..32a11cf9 100644 --- a/conformance/results/ty/dataclasses_descriptors.toml +++ b/conformance/results/ty/dataclasses_descriptors.toml @@ -1,13 +1,6 @@ -conformance_automated = "Fail" -conformant = "Partial" -notes = """ -Only infers a descriptor `__get__` method as being called when a descriptor attribute is accessed on an instance if the descriptor attribute is present in the class namespace. -""" +conformance_automated = "Pass" +conformant = "Pass" errors_diff = """ -Line 66: Unexpected errors ['dataclasses_descriptors.py:66:1: error[type-assertion-failure] Type `int | Desc2[int]` does not match asserted type `int`'] -Line 67: Unexpected errors ['dataclasses_descriptors.py:67:1: error[type-assertion-failure] Type `str | Desc2[str]` does not match asserted type `str`'] """ output = """ -dataclasses_descriptors.py:66:1: error[type-assertion-failure] Type `int | Desc2[int]` does not match asserted type `int` -dataclasses_descriptors.py:67:1: error[type-assertion-failure] Type `str | Desc2[str]` does not match asserted type `str` """ diff --git a/conformance/tests/dataclasses_descriptors.py b/conformance/tests/dataclasses_descriptors.py index f2f30a62..eba91c8e 100644 --- a/conformance/tests/dataclasses_descriptors.py +++ b/conformance/tests/dataclasses_descriptors.py @@ -2,13 +2,16 @@ Tests the handling of descriptors within a dataclass. """ -# This portion of the dataclass spec is under-specified in the documentation, -# but its behavior can be determined from the runtime implementation. +# A data descriptor used as a dataclass field is handled according to the +# runtime implementation: the field type is the type returned by ``__get__``. +# +# The behavior of non-data descriptors (descriptors with only ``__get__``) used +# as dataclass fields is under-specified and type checkers disagree, so those +# cases are intentionally omitted here. See +# https://github.com/python/typing/issues/2259. from dataclasses import dataclass -from typing import Any, Generic, TypeVar, assert_type, overload - -T = TypeVar("T") +from typing import Any, assert_type, overload class Desc1: @@ -36,33 +39,3 @@ class DC1: assert_type(dc1.y, int) assert_type(DC1.y, Desc1) - - -class Desc2(Generic[T]): - @overload - def __get__(self, instance: None, owner: Any) -> list[T]: - ... - - @overload - def __get__(self, instance: object, owner: Any) -> T: - ... - - def __get__(self, instance: object | None, owner: Any) -> list[T] | T: - raise NotImplementedError - - -@dataclass -class DC2: - x: Desc2[int] - y: Desc2[str] - z: Desc2[str] = Desc2() - - -assert_type(DC2.x, list[int]) -assert_type(DC2.y, list[str]) -assert_type(DC2.z, list[str]) - -dc2 = DC2(Desc2(), Desc2(), Desc2()) -assert_type(dc2.x, int) -assert_type(dc2.y, str) -assert_type(dc2.z, str)