Skip to content

[ty] Emit diagnostics for invalid dynamic namedtuple fields#22575

Merged
charliermarsh merged 1 commit intomainfrom
charlie/func-diag
Jan 14, 2026
Merged

[ty] Emit diagnostics for invalid dynamic namedtuple fields#22575
charliermarsh merged 1 commit intomainfrom
charlie/func-diag

Conversation

@charliermarsh
Copy link
Member

Summary

Removes some TODOs from the dynamic namedtuple implementation.

@charliermarsh charliermarsh added the ty Multi-file analysis & type inference label Jan 14, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Jan 14, 2026

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2026-01-14 18:39:50.447232489 +0000
+++ new-output.txt	2026-01-14 18:39:50.759234420 +0000
@@ -762,6 +762,10 @@
 namedtuples_define_functional.py:37:21: error[too-many-positional-arguments] Too many positional arguments: expected 3, got 4
 namedtuples_define_functional.py:42:18: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `Literal["1"]`
 namedtuples_define_functional.py:43:15: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `float`
+namedtuples_define_functional.py:52:25: error[invalid-named-tuple] Duplicate field name `a` in `namedtuple()`: Field `a` already defined; will raise `ValueError` at runtime
+namedtuples_define_functional.py:53:25: error[invalid-named-tuple] Field name `def` in `namedtuple()` cannot be a Python keyword: Will raise `ValueError` at runtime
+namedtuples_define_functional.py:54:25: error[invalid-named-tuple] Field name `def` in `namedtuple()` cannot be a Python keyword: Will raise `ValueError` at runtime
+namedtuples_define_functional.py:55:25: error[invalid-named-tuple] Field name `_d` in `namedtuple()` cannot start with an underscore: Will raise `ValueError` at runtime
 namedtuples_define_functional.py:69:1: error[missing-argument] No argument provided for required parameter `a`
 namedtuples_type_compat.py:22:23: error[invalid-assignment] Object of type `Point` is not assignable to `tuple[int, int]`
 namedtuples_type_compat.py:23:28: error[invalid-assignment] Object of type `Point` is not assignable to `tuple[int, str, str]`
@@ -1049,4 +1053,4 @@
 typeddicts_usage.py:28:17: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
 typeddicts_usage.py:28:18: error[invalid-key] Unknown key "title" for TypedDict `Movie`: Unknown key "title"
 typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions
-Found 1051 diagnostics
+Found 1055 diagnostics

@astral-sh-bot
Copy link

astral-sh-bot bot commented Jan 14, 2026

mypy_primer results

Changes were detected when running on open source projects
static-frame (https://github.com/static-frame/static-frame)
- static_frame/core/bus.py:675:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemILocReduces[Bus[Any], object_]`, found `InterGetItemILocReduces[Self@iloc | Bus[Any], object_ | Self@iloc]`
+ static_frame/core/bus.py:671:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[Bus[Any], object_]`, found `InterGetItemLocReduces[Bus[Any] | Bottom[Index[Any]] | Bottom[Series[Any, Any]] | ... omitted 6 union elements, object_]`
+ static_frame/core/bus.py:675:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemILocReduces[Bus[Any], object_]`, found `InterGetItemILocReduces[Bus[Any] | Bottom[Index[Any]] | TypeBlocks | ... omitted 6 union elements, object_ | Self@iloc]`
- static_frame/core/node_selector.py:526:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[TVContainer_co@InterfaceSelectQuartet, Any]`, found `InterGetItemLocReduces[Bottom[Series[Any, Any]] | Unknown, Any]`
+ static_frame/core/node_selector.py:526:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[TVContainer_co@InterfaceSelectQuartet, Any]`, found `InterGetItemLocReduces[Unknown | Bottom[Series[Any, Any]], Any]`
+ static_frame/core/series.py:772:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemILocReduces[Series[Any, Any], TVDtype@Series]`, found `InterGetItemILocReduces[Series[Any, Any] | Bottom[Index[Any]] | TypeBlocks | ... omitted 6 union elements, TVDtype@Series]`
+ static_frame/core/series.py:4072:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemILocReduces[SeriesHE[Any, Any], TVDtype@SeriesHE]`, found `InterGetItemILocReduces[Bottom[Series[Any, Any]] | ndarray[Never, Never] | TypeBlocks | ... omitted 7 union elements, TVDtype@SeriesHE]`
+ static_frame/core/yarn.py:418:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemILocReduces[Yarn[Any], object_]`, found `InterGetItemILocReduces[Yarn[Any] | Bottom[Index[Any]] | TypeBlocks | ... omitted 6 union elements, object_]`
- Found 1822 diagnostics
+ Found 1826 diagnostics

No memory usage changes detected ✅

Comment on lines 6829 to 6830
if seen_names.contains(name_str) {
if let Some(builder) =
Copy link
Member

Choose a reason for hiding this comment

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

Looks like claude still doesn't know how to do let chains 😅

let name_str = field_name.as_str();

// Check for duplicate field names.
if seen_names.contains(name_str) {
Copy link
Member

@MichaReiser MichaReiser Jan 14, 2026

Choose a reason for hiding this comment

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

I think you can use seen_names.insert(name_str) here. This adds the name if it doesn't exist yet and otherwise does nothing.

I'd also be somewhat inclined to not build the hash set and instead use a window iterating over field_names to see if the same name appears anywhere later in field_names. Unless we assume that field_names is very large, in which case we want to avoid the O(n^2) search

Comment on lines 6904 to 6908
if defaults_count > num_fields {
if let Some(defaults_kw) = defaults_kw {
if let Some(builder) =
self.context.report_lint(&INVALID_NAMED_TUPLE, defaults_kw)
{
Copy link
Member

Choose a reason for hiding this comment

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

NIt: let chains

@charliermarsh charliermarsh marked this pull request as ready for review January 14, 2026 16:34
@charliermarsh charliermarsh marked this pull request as draft January 14, 2026 16:51
@charliermarsh
Copy link
Member Author

(Will mark for review once upstream merges + rebased + addressed Micha's initial comments.)

@charliermarsh charliermarsh marked this pull request as ready for review January 14, 2026 18:18
Base automatically changed from charlie/default-show to main January 14, 2026 18:28
@charliermarsh charliermarsh enabled auto-merge (squash) January 14, 2026 18:38
@charliermarsh charliermarsh enabled auto-merge (squash) January 14, 2026 18:39
@charliermarsh charliermarsh merged commit b07a53a into main Jan 14, 2026
48 checks passed
@charliermarsh charliermarsh deleted the charlie/func-diag branch January 14, 2026 18:42
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