Skip to content

Conversation

@AlexWaygood
Copy link
Member

Summary

Currently we treat declared attributes on NamedTuple classes just like declared attributes on any other class. But this is not correct! At runtime, the NamedTuple machinery synthesizes a read-only property for each attribute declared on a NamedTuple class. This PR implements that behaviour.

Test Plan

Mdtests

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Aug 13, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 13, 2025

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-08-14 21:23:47.772361962 +0000
+++ new-output.txt	2025-08-14 21:23:47.841362883 +0000
@@ -1,5 +1,5 @@
 WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(71d5)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(682a)): execute: too many cycle iterations`
 _directives_deprecated_library.py:15:31: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
 _directives_deprecated_library.py:30:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
 _directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@__add__`
@@ -676,6 +676,7 @@
 namedtuples_type_compat.py:23:1: error[invalid-assignment] Object of type `Point` is not assignable to `tuple[int, str, str]`
 namedtuples_usage.py:34:7: error[index-out-of-bounds] Index 3 is out of bounds for tuple `Point` with length 3
 namedtuples_usage.py:35:7: error[index-out-of-bounds] Index -4 is out of bounds for tuple `Point` with length 3
+namedtuples_usage.py:40:1: error[invalid-assignment] Invalid assignment to data descriptor attribute `x` on type `Point` with custom `__set__` method
 namedtuples_usage.py:41:1: error[invalid-assignment] Cannot assign to object of type `Point` with no `__setitem__` method
 namedtuples_usage.py:52:1: error[invalid-assignment] Too many values to unpack: Expected 2
 namedtuples_usage.py:53:1: error[invalid-assignment] Not enough values to unpack: Expected 4
@@ -859,5 +860,5 @@
 typeddicts_operations.py:60:1: error[type-assertion-failure] Argument does not have asserted type `str | None`
 typeddicts_type_consistency.py:101:1: error[invalid-assignment] Object of type `Unknown | None` is not assignable to `str`
 typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions. Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?
-Found 860 diagnostics
+Found 861 diagnostics
 WARN A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 13, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

@AlexWaygood AlexWaygood force-pushed the alex/namedtuple-properties branch from c7c86e7 to a5e16e4 Compare August 13, 2025 16:28
@AlexWaygood
Copy link
Member Author

The new diagnostic in the typing conformance suite is correct -- this is a place where we previously had a false negative

@AlexWaygood
Copy link
Member Author

AlexWaygood commented Aug 13, 2025

There are some performance regressions of 1-2% on this PR due to the fact that we now need to eagerly check whether a class is an "exact NamedTuple" class (one that has NamedTuple directly in its class bases) on every attribute access on a class. #19901 (stacked on top of this PR) improves the situation there by adding caching to the mechanism we use for checking whether a class is a NamedTuple class.

@AlexWaygood AlexWaygood force-pushed the alex/namedtuple-properties branch 2 times, most recently from 9a70798 to c0e5e1a Compare August 14, 2025 10:55
@AlexWaygood
Copy link
Member Author

Only 1% regressions on Codspeed after rebasing on top of #19912.

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!

@AlexWaygood AlexWaygood force-pushed the alex/namedtuple-properties branch from c0e5e1a to 9587358 Compare August 14, 2025 21:22
@AlexWaygood AlexWaygood enabled auto-merge (squash) August 14, 2025 21:22
@AlexWaygood AlexWaygood merged commit f609345 into main Aug 14, 2025
37 checks passed
@AlexWaygood AlexWaygood deleted the alex/namedtuple-properties branch August 14, 2025 21:25
dcreager added a commit that referenced this pull request Aug 14, 2025
* main:
  [ty] Add diagnostics for invalid `await` expressions (#19711)
  [ty] Synthesize read-only properties for all declared members on `NamedTuple` classes (#19899)
  [ty] Remove use of `ClassBase::try_from_type` from `super()` machinery (#19902)
  [ty] Speedup project file discovery  (#19913)
  [`pyflakes`] Add secondary annotation showing previous definition (`F811`) (#19900)
  Bump 0.12.9 (#19917)
  [ty] support `kw_only=True` for `dataclass()` and `field()` (#19677)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants