From 6d8c84bde912ef203c7a8e31910c0cede935560e Mon Sep 17 00:00:00 2001 From: David Peter Date: Tue, 8 Jul 2025 14:21:20 +0200 Subject: [PATCH 1/2] [ty] Clarify diagnostic message (#19203) This diagnostic message was missing the word "type" --- crates/ty_python_semantic/resources/mdtest/attributes.md | 2 +- crates/ty_python_semantic/src/types/infer.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/attributes.md b/crates/ty_python_semantic/resources/mdtest/attributes.md index 7346db6933..7e39160557 100644 --- a/crates/ty_python_semantic/resources/mdtest/attributes.md +++ b/crates/ty_python_semantic/resources/mdtest/attributes.md @@ -1787,7 +1787,7 @@ date.day = 8 date.month = 4 date.year = 2025 -# error: [unresolved-attribute] "Can not assign object of `Literal["UTC"]` to attribute `tz` on type `Date` with custom `__setattr__` method." +# error: [unresolved-attribute] "Can not assign object of type `Literal["UTC"]` to attribute `tz` on type `Date` with custom `__setattr__` method." date.tz = "UTC" ``` diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 4b23562d20..b3900380d3 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -3495,7 +3495,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { self.context.report_lint(&UNRESOLVED_ATTRIBUTE, target) { builder.into_diagnostic(format_args!( - "Can not assign object of `{}` to attribute \ + "Can not assign object of type `{}` to attribute \ `{attribute}` on type `{}` with \ custom `__setattr__` method.", value_ty.display(db), From 9a4b85d8456fbd152ae7f7ff149f27ac43e0ea00 Mon Sep 17 00:00:00 2001 From: David Peter Date: Tue, 8 Jul 2025 14:33:46 +0200 Subject: [PATCH 2/2] [ty] Add tests for dataclass fields annotated with `Final` (#19202) ## Summary Adds some tests for dataclass fields that are annotated with `Final` (see comment [here](https://github.com/astral-sh/ruff/pull/15768#issuecomment-3044737645)). Turns out that nothing is needed here, everything already works as expected (apart from the fact that we can assign to `Final` fields, which is tracked in https://github.com/astral-sh/ty/issues/158 ## Test Plan New Markdown tests --- .../mdtest/dataclasses/dataclasses.md | 27 +++++++++++++++++++ .../resources/mdtest/type_qualifiers/final.md | 4 +++ 2 files changed, 31 insertions(+) diff --git a/crates/ty_python_semantic/resources/mdtest/dataclasses/dataclasses.md b/crates/ty_python_semantic/resources/mdtest/dataclasses/dataclasses.md index 7ed6ea8962..77a6b22ca0 100644 --- a/crates/ty_python_semantic/resources/mdtest/dataclasses/dataclasses.md +++ b/crates/ty_python_semantic/resources/mdtest/dataclasses/dataclasses.md @@ -444,6 +444,33 @@ To do To do +## `Final` fields + +Dataclass fields can be annotated with `Final`, which means that the field cannot be reassigned +after the instance is created. Fields that are additionally annotated with `ClassVar` are not part +of the `__init__` signature. + +```py +from dataclasses import dataclass +from typing import Final, ClassVar + +@dataclass +class C: + # a `Final` annotation without a right-hand side is not allowed in normal classes, + # but valid for dataclasses. The field will be initialized in the synthesized + # `__init__` method + instance_variable_no_default: Final[int] + instance_variable: Final[int] = 1 + class_variable1: ClassVar[Final[int]] = 1 + class_variable2: ClassVar[Final[int]] = 1 + +reveal_type(C.__init__) # revealed: (self: C, instance_variable_no_default: int, instance_variable: int = Literal[1]) -> None + +c = C(1) +# TODO: this should be an error +c.instance_variable = 2 +``` + ## Inheritance ### Normal class inheriting from a dataclass diff --git a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md index da1398b1ab..224115f942 100644 --- a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md +++ b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md @@ -162,6 +162,10 @@ from typing import Final # TODO: This should be an error NO_RHS: Final + +class C: + # TODO: This should be an error + NO_RHS: Final ``` [`typing.final`]: https://docs.python.org/3/library/typing.html#typing.Final