From ce4ec155e75b4a40f6619be3ebb36010a17f42ef Mon Sep 17 00:00:00 2001 From: ashishpatel26 Date: Mon, 1 Jun 2026 12:24:21 +0530 Subject: [PATCH 1/3] Conformance: align dataclass descriptor tests with runtime --- .../results/mypy/dataclasses_descriptors.toml | 17 +++++----- .../pycroscope/dataclasses_descriptors.toml | 25 ++++++--------- .../pyrefly/dataclasses_descriptors.toml | 13 ++++---- .../pyright/dataclasses_descriptors.toml | 15 +++++++-- conformance/results/results.html | 12 +++---- .../results/ty/dataclasses_descriptors.toml | 14 ++++++--- .../zuban/dataclasses_descriptors.toml | 14 ++++++++- conformance/tests/dataclasses_descriptors.py | 31 ++++++++++++++----- 8 files changed, 89 insertions(+), 52 deletions(-) diff --git a/conformance/results/mypy/dataclasses_descriptors.toml b/conformance/results/mypy/dataclasses_descriptors.toml index e47310293..1b75be2b2 100644 --- a/conformance/results/mypy/dataclasses_descriptors.toml +++ b/conformance/results/mypy/dataclasses_descriptors.toml @@ -1,18 +1,15 @@ conformant = "Partial" notes = """ -Assumes descriptor behavior only when field is assigned in class body. -Does not correctly evaluate type of descriptor access. +Does not preserve a non-data descriptor object stored in a dataclass instance when a class attribute of the same name is also present. """ 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] +dataclasses_descriptors.py:74: error: Expression is of type "list[int]", not "Desc2[int]" [assert-type] +dataclasses_descriptors.py:74: error: Cannot access instance-only attribute "x" on class object [misc] +dataclasses_descriptors.py:75: error: Expression is of type "list[str]", not "Desc2[str]" [assert-type] +dataclasses_descriptors.py:75: error: Cannot access instance-only attribute "y" on class object [misc] +dataclasses_descriptors.py:85: error: Expression is of type "str", not "Desc2[str]" [assert-type] """ conformance_automated = "Fail" 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]'] +Line 85: Unexpected errors ['dataclasses_descriptors.py:85: error: Expression is of type "str", not "Desc2[str]" [assert-type]'] """ diff --git a/conformance/results/pycroscope/dataclasses_descriptors.toml b/conformance/results/pycroscope/dataclasses_descriptors.toml index e5410991c..06a707919 100644 --- a/conformance/results/pycroscope/dataclasses_descriptors.toml +++ b/conformance/results/pycroscope/dataclasses_descriptors.toml @@ -1,23 +1,18 @@ conformant = "Partial" notes = """ -Conformance suite is questionable; see https://github.com/python/typing/issues/2259 +Does not preserve a non-data descriptor object stored in a dataclass instance when a class attribute of the same name is also present. +Does not preserve type parameters when accessing a non-data descriptor through the dataclass. """ conformance_automated = "Fail" 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'] +Line 76: Unexpected errors ['.\\\\dataclasses_descriptors.py:76:12: list[Any[generic_argument]] is not equivalent to list[str]'] +Line 85: Unexpected errors ['.\\\\dataclasses_descriptors.py:85:12: Any[generic_argument] is not equivalent to .\\\\dataclasses_descriptors.py.Desc2[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 +.\\dataclasses_descriptors.py:74:12: Any[error] is not equivalent to .\\dataclasses_descriptors.py.Desc2[int] +.\\dataclasses_descriptors.py:74:12: has no attribute 'x' [undefined_attribute] +.\\dataclasses_descriptors.py:75:12: Any[error] is not equivalent to .\\dataclasses_descriptors.py.Desc2[str] +.\\dataclasses_descriptors.py:75:12: has no attribute 'y' [undefined_attribute] +.\\dataclasses_descriptors.py:76:12: list[Any[generic_argument]] is not equivalent to list[str] +.\\dataclasses_descriptors.py:85:12: Any[generic_argument] is not equivalent to .\\dataclasses_descriptors.py.Desc2[str] """ diff --git a/conformance/results/pyrefly/dataclasses_descriptors.toml b/conformance/results/pyrefly/dataclasses_descriptors.toml index 03625f94d..3b39881fc 100644 --- a/conformance/results/pyrefly/dataclasses_descriptors.toml +++ b/conformance/results/pyrefly/dataclasses_descriptors.toml @@ -1,14 +1,15 @@ 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. +Does not preserve a non-data descriptor object stored in a dataclass instance when a class attribute of the same name is also present. """ 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 33: Unexpected errors ['Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition]'] +Line 85: Unexpected errors ['assert_type(str, Desc2[str]) failed [assert-type]'] """ 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:33:5-6: Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition] +ERROR dataclasses_descriptors.py:67:5-6: Cannot set field `z` to non-data descriptor `Desc2` [bad-class-definition] +ERROR dataclasses_descriptors.py:85:12-31: assert_type(str, Desc2[str]) failed [assert-type] """ diff --git a/conformance/results/pyright/dataclasses_descriptors.toml b/conformance/results/pyright/dataclasses_descriptors.toml index 5e485e856..59eba6efe 100644 --- a/conformance/results/pyright/dataclasses_descriptors.toml +++ b/conformance/results/pyright/dataclasses_descriptors.toml @@ -1,6 +1,17 @@ -conformant = "Pass" +conformant = "Partial" +notes = """ +Does not preserve non-data descriptor objects stored in dataclass instances. +""" output = """ +dataclasses_descriptors.py:74:13 - error: "assert_type" mismatch: expected "Desc2[int]" but received "list[int]" (reportAssertTypeFailure) +dataclasses_descriptors.py:75:13 - error: "assert_type" mismatch: expected "Desc2[str]" but received "list[str]" (reportAssertTypeFailure) +dataclasses_descriptors.py:83:13 - error: "assert_type" mismatch: expected "Desc2[int]" but received "int" (reportAssertTypeFailure) +dataclasses_descriptors.py:84:13 - error: "assert_type" mismatch: expected "Desc2[str]" but received "str" (reportAssertTypeFailure) +dataclasses_descriptors.py:85:13 - error: "assert_type" mismatch: expected "Desc2[str]" but received "str" (reportAssertTypeFailure) """ -conformance_automated = "Pass" +conformance_automated = "Fail" errors_diff = """ +Line 83: Unexpected errors ['dataclasses_descriptors.py:83:13 - error: "assert_type" mismatch: expected "Desc2[int]" but received "int" (reportAssertTypeFailure)'] +Line 84: Unexpected errors ['dataclasses_descriptors.py:84:13 - error: "assert_type" mismatch: expected "Desc2[str]" but received "str" (reportAssertTypeFailure)'] +Line 85: Unexpected errors ['dataclasses_descriptors.py:85:13 - error: "assert_type" mismatch: expected "Desc2[str]" but received "str" (reportAssertTypeFailure)'] """ diff --git a/conformance/results/results.html b/conformance/results/results.html index 733c4d22f..71f2f1523 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.

+
Partial

Does not preserve a non-data descriptor object stored in a dataclass instance when a class attribute of the same name is also present.

+
Partial

Does not preserve non-data descriptor objects stored in dataclass instances.

+
Partial

Does not preserve non-data descriptor objects stored in dataclass instances.

+
Partial

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

Does not preserve a non-data descriptor object stored in a dataclass instance when a class attribute of the same name is also present.

+
Partial

Does not preserve a non-data descriptor object stored in a dataclass instance when a class attribute of the same name is also present.

Does not preserve type parameters when accessing a non-data descriptor through the dataclass.

+
Partial

Does not preserve non-data descriptor objects stored in dataclass instances.

     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 91ad20b90..3e28120de 100644 --- a/conformance/results/ty/dataclasses_descriptors.toml +++ b/conformance/results/ty/dataclasses_descriptors.toml @@ -1,13 +1,17 @@ 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. +Does not preserve non-data descriptor objects stored in dataclass instances. """ 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`'] +Line 83: Unexpected errors ['dataclasses_descriptors.py:83:1: error[type-assertion-failure] Type `int | Desc2[int]` does not match asserted type `Desc2[int]`'] +Line 84: Unexpected errors ['dataclasses_descriptors.py:84:1: error[type-assertion-failure] Type `str | Desc2[str]` does not match asserted type `Desc2[str]`'] +Line 85: Unexpected errors ['dataclasses_descriptors.py:85:1: error[type-assertion-failure] Type `str` does not match asserted type `Desc2[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` +dataclasses_descriptors.py:74:1: error[type-assertion-failure] Type `list[int]` does not match asserted type `Desc2[int]` +dataclasses_descriptors.py:75:1: error[type-assertion-failure] Type `list[str]` does not match asserted type `Desc2[str]` +dataclasses_descriptors.py:83:1: error[type-assertion-failure] Type `int | Desc2[int]` does not match asserted type `Desc2[int]` +dataclasses_descriptors.py:84:1: error[type-assertion-failure] Type `str | Desc2[str]` does not match asserted type `Desc2[str]` +dataclasses_descriptors.py:85:1: error[type-assertion-failure] Type `str` does not match asserted type `Desc2[str]` """ diff --git a/conformance/results/zuban/dataclasses_descriptors.toml b/conformance/results/zuban/dataclasses_descriptors.toml index cdd4d0cd9..03d0482af 100644 --- a/conformance/results/zuban/dataclasses_descriptors.toml +++ b/conformance/results/zuban/dataclasses_descriptors.toml @@ -1,5 +1,17 @@ -conformance_automated = "Pass" +conformance_automated = "Fail" +conformant = "Partial" +notes = """ +Does not preserve non-data descriptor objects stored in dataclass instances. +""" errors_diff = """ +Line 83: Unexpected errors ['dataclasses_descriptors.py:83: error: Expression is of type "int", not "Desc2[int]" [misc]'] +Line 84: Unexpected errors ['dataclasses_descriptors.py:84: error: Expression is of type "str", not "Desc2[str]" [misc]'] +Line 85: Unexpected errors ['dataclasses_descriptors.py:85: error: Expression is of type "str", not "Desc2[str]" [misc]'] """ output = """ +dataclasses_descriptors.py:74: error: Expression is of type "list[int]", not "Desc2[int]" [misc] +dataclasses_descriptors.py:75: error: Expression is of type "list[str]", not "Desc2[str]" [misc] +dataclasses_descriptors.py:83: error: Expression is of type "int", not "Desc2[int]" [misc] +dataclasses_descriptors.py:84: error: Expression is of type "str", not "Desc2[str]" [misc] +dataclasses_descriptors.py:85: error: Expression is of type "str", not "Desc2[str]" [misc] """ diff --git a/conformance/tests/dataclasses_descriptors.py b/conformance/tests/dataclasses_descriptors.py index f2f30a623..176ea8f43 100644 --- a/conformance/tests/dataclasses_descriptors.py +++ b/conformance/tests/dataclasses_descriptors.py @@ -3,7 +3,8 @@ """ # This portion of the dataclass spec is under-specified in the documentation, -# but its behavior can be determined from the runtime implementation. +# but the expected behavior follows the runtime implementation. +# See https://github.com/python/typing/issues/2259. from dataclasses import dataclass from typing import Any, Generic, TypeVar, assert_type, overload @@ -38,6 +39,14 @@ class DC1: assert_type(DC1.y, Desc1) +# ``Desc2`` is a non-data descriptor (it implements only ``__get__``). A +# non-data descriptor is shadowed by an instance's ``__dict__``, so its +# ``__get__`` is not invoked for attributes that the dataclass ``__init__`` +# stores on the instance. Such attributes keep the value that was assigned to +# them. The descriptor protocol only runs for attributes that are present in the +# class namespace. + + class Desc2(Generic[T]): @overload def __get__(self, instance: None, owner: Any) -> list[T]: @@ -55,14 +64,22 @@ def __get__(self, instance: object | None, owner: Any) -> list[T] | T: class DC2: x: Desc2[int] y: Desc2[str] - z: Desc2[str] = Desc2() + z: Desc2[str] = Desc2() # E?: a non-data descriptor default may be rejected -assert_type(DC2.x, list[int]) -assert_type(DC2.y, list[str]) +# ``x`` and ``y`` are not present in the class namespace, so accessing them on +# the class is an ``AttributeError`` at runtime; a type checker may report an +# error here. ``z`` is present in the class namespace, so class access runs +# ``Desc2.__get__(None)`` and yields ``list[str]``. +assert_type(DC2.x, Desc2[int]) # E? +assert_type(DC2.y, Desc2[str]) # E? assert_type(DC2.z, list[str]) +# All three attributes are stored on the instance by ``__init__``. Because +# ``Desc2`` is a non-data descriptor, the instance ``__dict__`` shadows it and +# ``__get__`` never runs, so each attribute keeps the assigned ``Desc2`` object +# (even ``z``, which is also present in the class namespace). dc2 = DC2(Desc2(), Desc2(), Desc2()) -assert_type(dc2.x, int) -assert_type(dc2.y, str) -assert_type(dc2.z, str) +assert_type(dc2.x, Desc2[int]) +assert_type(dc2.y, Desc2[str]) +assert_type(dc2.z, Desc2[str]) From dea18cae652bfc68a24d184a04509eec4ed5a28b Mon Sep 17 00:00:00 2001 From: ashishpatel26 Date: Mon, 22 Jun 2026 16:08:58 +0530 Subject: [PATCH 2/3] Fix Windows path separators in pycroscope TOML results The TOML was generated on Windows so pycroscope output paths used backslashes (.\) instead of the forward slashes (./) that Linux CI produces. Replace all .\ with ./ so the 'assert conformance results are up to date' step passes on Ubuntu runners. --- .../pycroscope/dataclasses_descriptors.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/conformance/results/pycroscope/dataclasses_descriptors.toml b/conformance/results/pycroscope/dataclasses_descriptors.toml index 06a707919..e9e6a7546 100644 --- a/conformance/results/pycroscope/dataclasses_descriptors.toml +++ b/conformance/results/pycroscope/dataclasses_descriptors.toml @@ -5,14 +5,14 @@ Does not preserve type parameters when accessing a non-data descriptor through t """ conformance_automated = "Fail" errors_diff = """ -Line 76: Unexpected errors ['.\\\\dataclasses_descriptors.py:76:12: list[Any[generic_argument]] is not equivalent to list[str]'] -Line 85: Unexpected errors ['.\\\\dataclasses_descriptors.py:85:12: Any[generic_argument] is not equivalent to .\\\\dataclasses_descriptors.py.Desc2[str]'] +Line 76: Unexpected errors ['./dataclasses_descriptors.py:76:12: list[Any[generic_argument]] is not equivalent to list[str]'] +Line 85: Unexpected errors ['./dataclasses_descriptors.py:85:12: Any[generic_argument] is not equivalent to ./dataclasses_descriptors.py.Desc2[str]'] """ output = """ -.\\dataclasses_descriptors.py:74:12: Any[error] is not equivalent to .\\dataclasses_descriptors.py.Desc2[int] -.\\dataclasses_descriptors.py:74:12: has no attribute 'x' [undefined_attribute] -.\\dataclasses_descriptors.py:75:12: Any[error] is not equivalent to .\\dataclasses_descriptors.py.Desc2[str] -.\\dataclasses_descriptors.py:75:12: has no attribute 'y' [undefined_attribute] -.\\dataclasses_descriptors.py:76:12: list[Any[generic_argument]] is not equivalent to list[str] -.\\dataclasses_descriptors.py:85:12: Any[generic_argument] is not equivalent to .\\dataclasses_descriptors.py.Desc2[str] +./dataclasses_descriptors.py:74:12: Any[error] is not equivalent to ./dataclasses_descriptors.py.Desc2[int] +./dataclasses_descriptors.py:74:12: has no attribute 'x' [undefined_attribute] +./dataclasses_descriptors.py:75:12: Any[error] is not equivalent to ./dataclasses_descriptors.py.Desc2[str] +./dataclasses_descriptors.py:75:12: has no attribute 'y' [undefined_attribute] +./dataclasses_descriptors.py:76:12: list[Any[generic_argument]] is not equivalent to list[str] +./dataclasses_descriptors.py:85:12: Any[generic_argument] is not equivalent to ./dataclasses_descriptors.py.Desc2[str] """ From e4392758459b6e8d3e9181afeaf34a8252a12cf5 Mon Sep 17 00:00:00 2001 From: ashishpatel26 Date: Mon, 22 Jun 2026 19:51:43 +0530 Subject: [PATCH 3/3] conformance: fix pyrefly dataclasses_descriptors TOML with missing error lines --- conformance/results/pyrefly/dataclasses_descriptors.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/conformance/results/pyrefly/dataclasses_descriptors.toml b/conformance/results/pyrefly/dataclasses_descriptors.toml index c737cfe92..b0dcda1b6 100644 --- a/conformance/results/pyrefly/dataclasses_descriptors.toml +++ b/conformance/results/pyrefly/dataclasses_descriptors.toml @@ -6,10 +6,16 @@ Does not allow non-data descriptors as dataclass fields. conformance_automated = "Fail" errors_diff = """ Line 33: Unexpected errors ['Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition]'] +Line 83: Unexpected errors ['assert_type(int, Desc2[int]) failed [assert-type]'] +Line 84: Unexpected errors ['assert_type(str, Desc2[str]) failed [assert-type]'] Line 85: Unexpected errors ['assert_type(str, Desc2[str]) failed [assert-type]'] """ output = """ ERROR dataclasses_descriptors.py:33:5-6: Cannot set field `y` to data descriptor `Desc1` with inconsistent types [bad-class-definition] ERROR dataclasses_descriptors.py:67:5-6: Cannot set field `z` to non-data descriptor `Desc2` [bad-class-definition] +ERROR dataclasses_descriptors.py:74:12-31: assert_type(list[int], Desc2[int]) failed [assert-type] +ERROR dataclasses_descriptors.py:75:12-31: assert_type(list[str], Desc2[str]) failed [assert-type] +ERROR dataclasses_descriptors.py:83:12-31: assert_type(int, Desc2[int]) failed [assert-type] +ERROR dataclasses_descriptors.py:84:12-31: assert_type(str, Desc2[str]) failed [assert-type] ERROR dataclasses_descriptors.py:85:12-31: assert_type(str, Desc2[str]) failed [assert-type] """