[ty] Recognize __dataclass_transform__ to support SQLModel#23070
[ty] Recognize __dataclass_transform__ to support SQLModel#23070sharkdp merged 3 commits intoastral-sh:mainfrom
__dataclass_transform__ to support SQLModel#23070Conversation
39e2de7 to
1bb0c47
Compare
For backwards compatibility with pre-3.11 Python, ty now recognizes any function named `__dataclass_transform__` as equivalent to `typing.dataclass_transform`, regardless of which module it is defined in. This matches pyright's behavior and enables proper type checking for libraries like SQLModel that use this pattern. See: microsoft/pyright#5402 Co-Authored-By: Claude Opus 4.5 <[email protected]>
1bb0c47 to
d729052
Compare
sharkdp
left a comment
There was a problem hiding this comment.
Thank you! This is not a standardized feature, but was apparently previously part of the spec (microsoft/pyright#1782 (comment)). I see no harm in supporting it.
Only a few minor comments.
| // Special case: `__dataclass_transform__` is recognized as `DataclassTransform` | ||
| // regardless of module, for backwards compatibility with pre-3.11 libraries | ||
| // like SQLModel. The name matches the attribute set at runtime by the decorator. | ||
| // See: https://typing.python.org/en/latest/spec/dataclasses.html#runtime-behavior |
There was a problem hiding this comment.
That section does mention __dataclass_transform__, but only the attribute on the dataclass-transformer. Not a special-cased function name. So maybe we should just link to https://github.com/microsoft/pyright/blob/321c1825ab6badb7c8b8ccfd12558910a6d75450/packages/pyright-internal/src/analyzer/decorators.ts#L167-L168 here? And maybe research if mypy has a similar special case.
crates/ty_python_semantic/resources/mdtest/external/sqlmodel.md
Outdated
Show resolved
Hide resolved
crates/ty_python_semantic/resources/mdtest/external/sqlmodel.md
Outdated
Show resolved
Hide resolved
crates/ty_python_semantic/resources/mdtest/dataclasses/dataclass_transform.md
Outdated
Show resolved
Hide resolved
crates/ty_python_semantic/resources/mdtest/dataclasses/dataclass_transform.md
Show resolved
Hide resolved
Typing conformance resultsNo changes detected ✅ |
|
|
The test failures seem to indicate that this fix doesn't really work? |
b65e269 to
c9a7f22
Compare
This changes how we extract parameters from `dataclass_transform()` calls from positional pattern matching to named parameter lookup. This allows custom `__dataclass_transform__` functions (like SQLModel's) with different signatures to work correctly. The previous code used `if let [6 params]` which silently failed for functions with fewer parameters. Named lookup with defaults is more robust and matches how Python interprets the keyword-only parameters. Also adds a fallback from `field_descriptors` to `field_specifiers` for SQLModel compatibility. Co-Authored-By: Claude Opus 4.5 <[email protected]>
c9a7f22 to
0bf0818
Compare
thanks for the review! i think the issue was that the original code used positional pattern matching expecting exactly 6 params, but SQLModel's signature only has 4...so it silently failed to match. tried to keep this minimal:
local tests pass but waiting on CI to confirm. open to more refactoring for code hygiene too, whatever conforms to the long term vision |
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
unsupported-operator |
0 | 79 | 0 |
invalid-parameter-default |
0 | 0 | 7 |
invalid-argument-type |
0 | 4 | 1 |
invalid-return-type |
0 | 4 | 0 |
possibly-missing-attribute |
0 | 4 | 0 |
too-many-positional-arguments |
3 | 0 | 1 |
unknown-argument |
0 | 1 | 2 |
invalid-assignment |
0 | 0 | 1 |
unresolved-attribute |
0 | 1 | 0 |
| Total | 3 | 93 | 12 |
| if to_bool(frozen_default, false) { | ||
| flags |= DataclassTransformerFlags::FROZEN_DEFAULT; | ||
| } | ||
| // Try both "field_specifiers" (typing spec) and "field_descriptors" (SQLModel) |
There was a problem hiding this comment.
and "field_descriptors" (SQLModel)
oh, that is unfortunate :-|. But I guess it's a small exception. Pyright also has this older name of the parameter hard-coded in their codebase.
__dataclass_transform__ as dataclass_transform__dataclass_transform__ to support SQLModel
Summary
For backwards compatibility with pre-3.11 Python, ty now recognizes any function named
__dataclass_transform__as equivalent totyping.dataclass_transform, regardless of which module it is defined in.This matches pyright's behavior and enables proper type checking for libraries like SQLModel that use this pattern to support older Python versions. The name matches the attribute set at runtime by the decorator.
Reference: https://typing.python.org/en/latest/spec/dataclasses.html#runtime-behavior
closes astral-sh/ty#1329
Test plan
__dataclass_transform__recognition indataclass_transform.mdsqlmodel.mdexternal tests to verify the fix works with real SQLModel patterns🤖 Generated with Claude Code