Skip to content

Conversation

@sharkdp
Copy link
Contributor

@sharkdp sharkdp commented Oct 15, 2025

Summary

Add support for the field_specifiers parameter on dataclass_transform decorator calls.

closes astral-sh/ty#1068

Conformance test results

All true positives ✔️

Ecosystem analysis

  • trio: this is the kind of change that I would expect from this PR. The code makes use of a dataclass Outcome with a _unwrapped: bool = attr.ib(default=False, eq=False, init=False) field that is excluded from the __init__ signature, so we now see a bunch of constructor-call-related errors going away.
  • home-assistant/core: They have a domain: str = attr.ib(init=False, repr=False) field and then use
      @domain.default
      def _domain_default(self) -> str:
          # …
    This accesses the default attribute on dataclasses.Field[…] with a type of default: _T | Literal[_MISSING_TYPE.MISSING], so we get those "Object of type _MISSING_TYPE is not callable" errors. I don't really understand how that is supposed to work. Even if _MISSING_TYPE would be absent from that union, what does this try to call? pyright also issues an error and it doesn't seem to work at runtime? So this looks like a true positive?
  • attrs: Similar here. There are some new diagnostics on code that tries to access .validator on a field. This does work at runtime, but I'm not sure how that is supposed to type-check (without a custom plugin). pyright errors on this as well.
  • A handful of new false positives because we don't support alias yet

Test Plan

Updated tests.

@sharkdp sharkdp added the ty Multi-file analysis & type inference label Oct 15, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 15, 2025

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-10-16 13:58:15.685593376 +0000
+++ new-output.txt	2025-10-16 13:58:19.040608580 +0000
@@ -1,5 +1,5 @@
 fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/ef9f932/src/function/execute.rs:402:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_type_statement.py`: `PEP695TypeAliasType < 'db >::value_type_(Id(d417)): execute: too many cycle iterations`
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/ef9f932/src/function/execute.rs:402:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(16c43)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/ef9f932/src/function/execute.rs:402:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(17443)): 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__`
@@ -279,6 +279,8 @@
 dataclasses_transform_converter.py:121:11: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 7
 dataclasses_transform_converter.py:130:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Literal[1], /) -> int`, found `def converter_simple(s: str) -> int`
 dataclasses_transform_field.py:49:43: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> @Todo(unsupported type[X] special form)`
+dataclasses_transform_field.py:64:16: error[unknown-argument] Argument `id` does not match any known parameter
+dataclasses_transform_field.py:75:1: error[missing-argument] No argument provided for required parameter `name`
 dataclasses_transform_field.py:75:16: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
 dataclasses_transform_func.py:57:1: error[invalid-assignment] Object of type `Literal[3]` is not assignable to attribute `name` of type `str`
 dataclasses_transform_func.py:61:6: error[unsupported-operator] Operator `<` is not supported for types `Customer1` and `Customer1`
@@ -288,6 +290,7 @@
 dataclasses_transform_func.py:77:36: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@create_model_frozen`
 dataclasses_transform_func.py:97:1: error[invalid-assignment] Property `id` defined in `Customer3` is read-only
 dataclasses_transform_meta.py:60:36: error[unknown-argument] Argument `other_name` does not match any known parameter
+dataclasses_transform_meta.py:66:8: error[missing-argument] No arguments provided for required parameters `id`, `name`
 dataclasses_transform_meta.py:66:18: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 2
 dataclasses_transform_meta.py:73:6: error[unsupported-operator] Operator `<` is not supported for types `Customer1` and `Customer1`
 dataclasses_transform_meta.py:79:6: error[unsupported-operator] Operator `<` is not supported for types `Customer2` and `Customer2`
@@ -898,5 +901,5 @@
 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] Invalid key access on 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. Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?
-Found 900 diagnostics
+Found 903 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 Oct 15, 2025

mypy_primer results

Changes were detected when running on open source projects
attrs (https://github.com/python-attrs/attrs)
- tests/dataclass_transform_example.py:21:13: info[revealed-type] Revealed type: `(self: DefineConverter, with_converter: int = int) -> None`
+ tests/dataclass_transform_example.py:21:13: info[revealed-type] Revealed type: `(self: DefineConverter, with_converter: int) -> None`
- tests/dataclass_transform_example.py:56:13: info[revealed-type] Revealed type: `(_a: int = Any) -> None`
+ tests/dataclass_transform_example.py:56:13: info[revealed-type] Revealed type: `(_a: int) -> None`
+ tests/test_hooks.py:154:48: error[missing-argument] No argument provided for required parameter `y`
+ tests/test_next_gen.py:142:14: error[unresolved-attribute] Type `dataclasses.Field` has no attribute `validator`
- tests/test_next_gen.py:380:14: error[unresolved-attribute] Type `int` has no attribute `validator`
+ tests/test_next_gen.py:380:14: error[unresolved-attribute] Type `dataclasses.Field` has no attribute `validator`
- Found 559 diagnostics
+ Found 561 diagnostics

artigraph (https://github.com/artigraph/artigraph)
- src/arti/internal/mappings.py:124:24: error[missing-argument] No argument provided for required parameter `root`
- src/arti/internal/mappings.py:124:34: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Literal["open"]`
- tests/arti/types/test_types.py:146:73: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | tuple[str]`
- tests/arti/types/test_types.py:146:73: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `Unknown | tuple[str]`
- tests/arti/types/test_types.py:146:73: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | tuple[str]`
- tests/arti/types/test_types.py:150:36: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | tuple[str]`
- tests/arti/types/test_types.py:150:36: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `Unknown | tuple[str]`
- tests/arti/types/test_types.py:150:36: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | tuple[str]`
- Found 146 diagnostics
+ Found 138 diagnostics

Tanjun (https://github.com/FasterSpeeding/Tanjun)
+ tanjun/commands/menu.py:608:19: error[missing-argument] No arguments provided for required parameters `_name`, `_type`
+ tanjun/context/autocomplete.py:236:13: error[missing-argument] No arguments provided for required parameters `_name`, `_value`
- Found 113 diagnostics
+ Found 115 diagnostics

trio (https://github.com/python-trio/trio)
- src/trio/_channel.py:203:50: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `SendType@MemorySendChannel`
- src/trio/_channel.py:295:50: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ClosedResourceError`
- src/trio/_channel.py:303:54: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `EndOfChannel`
- src/trio/_channel.py:447:50: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ClosedResourceError`
- src/trio/_channel.py:455:54: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `BrokenResourceError`
- src/trio/_core/_io_common.py:28:54: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `BaseException`
- src/trio/_core/_io_kqueue.py:287:58: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ClosedResourceError`
- src/trio/_core/_parking_lot.py:303:21: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `BrokenResourceError`
+ src/trio/_core/_run.py:628:35: error[missing-argument] No argument provided for required parameter `_scope`
- src/trio/_core/_run.py:1760:38: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `TrioInternalError`
+ src/trio/_core/_run.py:1749:80: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- src/trio/_core/_run.py:1925:31: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `None`
- src/trio/_core/_run.py:2055:33: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `RuntimeError`
- src/trio/_core/_run.py:2071:33: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `None`
- src/trio/_core/_run.py:2169:56: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `BaseException`
- src/trio/_core/_run.py:2705:48: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `@Todo | list[Unknown]`
- src/trio/_core/_run.py:2884:43: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `BaseException`
- src/trio/_core/_run.py:2963:46: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `KeyboardInterrupt`
- src/trio/_core/_tests/test_ki.py:406:50: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Literal[1]`
- src/trio/_core/_tests/test_run.py:246:54: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ValueError`
- src/trio/_core/_tests/test_run.py:253:54: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Literal[0]`
- src/trio/_core/_tests/test_run.py:1030:65: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Literal[1]`
- src/trio/_core/_tests/test_run.py:1287:66: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ValueError`
- src/trio/_core/_tests/test_run.py:1321:31: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ValueError`
- src/trio/_core/_tests/test_run.py:1352:66: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ValueError`
- src/trio/_core/_tests/test_run.py:1391:31: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ValueError`
- src/trio/_core/_tests/test_run.py:2431:64: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `None`
- src/trio/_core/_tests/test_run.py:2439:42: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Literal["be free!"]`
- src/trio/_core/_tests/test_run.py:2448:68: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `KeyError`
- src/trio/_core/_tests/test_run.py:2452:42: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `ValueError`
- src/trio/_core/_tests/test_run.py:2459:79: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `None`
- src/trio/_core/_traps.py:308:41: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Literal["reattaching"]`
- src/trio/_core/_traps.py:310:35: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Literal["reattaching"]`
- src/trio/_tests/test_timeouts.py:100:54: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `None`
- src/trio/_threads.py:205:35: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `RunFinishedError`
- src/trio/_threads.py:379:70: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Value[Unknown] | Error`
- Found 645 diagnostics
+ Found 613 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
- src/integrations/prefect-docker/prefect_docker/worker.py:950:35: error[missing-argument] No argument provided for required parameter `root`
- src/integrations/prefect-docker/tests/test_worker.py:1187:9: error[missing-argument] No argument provided for required parameter `root`
- src/integrations/prefect-kubernetes/tests/test_observer.py:78:42: error[missing-argument] No argument provided for required parameter `root`
- src/integrations/prefect-kubernetes/tests/test_observer.py:155:42: error[missing-argument] No argument provided for required parameter `root`
- src/integrations/prefect-redis/tests/test_messaging.py:452:30: error[missing-argument] No argument provided for required parameter `root`
- src/integrations/prefect-redis/tests/test_ordering.py:23:12: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/cli/variable.py:163:57: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | str | int | ... omitted 5 union elements`
- src/prefect/cli/variable.py:163:57: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `Unknown | str | int | ... omitted 5 union elements`
- src/prefect/cli/variable.py:163:57: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | str | int | ... omitted 5 union elements`
- src/prefect/cli/variable.py:165:57: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | str | int | ... omitted 5 union elements`
- src/prefect/cli/variable.py:165:57: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `Unknown | str | int | ... omitted 5 union elements`
- src/prefect/cli/variable.py:165:57: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Unknown | str | int | ... omitted 5 union elements`
- src/prefect/client/schemas/responses.py:469:16: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/events/related.py:36:9: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/events/related.py:51:12: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/events/utilities.py:96:27: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Any | str | dict[str, str] | dict[str, Any] | None`
- src/prefect/events/utilities.py:96:27: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `Any | str | dict[str, str] | dict[str, Any] | None`
- src/prefect/events/utilities.py:96:27: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Any] | None`, found `Any | str | dict[str, str] | dict[str, Any] | None`
- src/prefect/runner/runner.py:1052:17: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/runner/runner.py:1068:26: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/runner/runner.py:1101:17: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/runner/runner.py:1110:13: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/runner/runner.py:1126:26: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/events/actions.py:143:20: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/events/actions.py:201:20: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/events/actions.py:217:30: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/events/actions.py:233:30: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/events/schemas/automations.py:432:25: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/events/schemas/automations.py:448:21: error[missing-argument] No argument provided for required parameter `root`
- src/prefect/server/models/work_queues.py:397:17: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `dict[str, Unknown] | dict[str, Unknown | bool]`
- src/prefect/server/models/work_queues.py:415:13: error[invalid-argument-type] Argument is incorrect: Expected `set[str]`, found `dict[str, Unknown] | dict[str, Unknown | bool]`
- Found 3173 diagnostics
+ Found 3142 diagnostics

core (https://github.com/home-assistant/core)
+ homeassistant/components/device_tracker/legacy.py:409:12: error[missing-argument] No argument provided for required parameter `config`
+ homeassistant/helpers/entity_registry.py:218:5: error[call-non-callable] Object of type `_MISSING_TYPE` is not callable
+ homeassistant/helpers/entity_registry.py:443:5: error[call-non-callable] Object of type `_MISSING_TYPE` is not callable
- Found 13758 diagnostics
+ Found 13761 diagnostics
Memory usage changes were detected when running on open source projects
prefect (https://github.com/PrefectHQ/prefect)
-     struct fields = ~35MB
+     struct fields = ~36MB
-     memo metadata = ~98MB
+     memo metadata = ~103MB

@github-actions
Copy link
Contributor

github-actions bot commented Oct 15, 2025

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 0 52 0
missing-argument 5 21 0
call-non-callable 2 0 0
unresolved-attribute 1 0 1
unused-ignore-comment 1 0 0
Total 9 73 1

Full report with detailed diff (timing results)

@sharkdp sharkdp force-pushed the david/field-specifiers branch 2 times, most recently from f2dca71 to ef11297 Compare October 15, 2025 14:23
@sharkdp sharkdp force-pushed the david/field-specifiers branch from ef11297 to 2354319 Compare October 15, 2025 14:39
@sharkdp sharkdp marked this pull request as ready for review October 15, 2025 14:43
@sharkdp

This comment was marked as resolved.

@sharkdp sharkdp marked this pull request as draft October 15, 2025 15:43
@sharkdp sharkdp marked this pull request as ready for review October 16, 2025 13:56
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Thank you!

reveal_type(alice.age) # revealed: int | None
```

### For base-class-based transformers
Copy link
Member

Choose a reason for hiding this comment

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

[insert "all your base are belong to us" joke]

Comment on lines +695 to +702
fn from_flags(db: &'db dyn Db, flags: DataclassFlags) -> Self {
let dataclasses_field = known_module_symbol(db, KnownModule::Dataclasses, "field")
.place
.ignore_possibly_undefined()
.unwrap_or_else(Type::unknown);

Self::new(db, flags, vec![dataclasses_field].into_boxed_slice())
}
Copy link
Member

Choose a reason for hiding this comment

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

I am sort-of morbidly curious about what does happen to our inference if you try to define a dataclass, with dataclasses.field for one of the fields, and you're using a custom typeshed that doesn't have dataclasses.field in it. That might be an interesting test, but it's almost certainly not worth spending time on it right now 😄

@sharkdp sharkdp merged commit 8dad58d into main Oct 16, 2025
41 checks passed
@sharkdp sharkdp deleted the david/field-specifiers branch October 16, 2025 18:49
dcreager added a commit that referenced this pull request Oct 16, 2025
…rable

* origin/main:
  [ty] Support dataclass-transform `field_specifiers` (#20888)
  Bump 0.14.1 (#20925)
  Standardize syntax error construction (#20903)
  [`pydoclint`] Implement `docstring-extraneous-parameter` (`DOC102`) (#20376)
  [ty] Fix panic 'missing root' when handling completion request (#20917)
  [ty] Run file watching tests serial when using nextest (#20918)
  [ty] Add version hint for failed stdlib attribute accesses (#20909)
  More CI improvements (#20920)
  [ty] Check typeshed VERSIONS for parent modules when reporting failed stdlib imports (#20908)
dcreager added a commit that referenced this pull request Oct 17, 2025
* main:
  [ty] Prefer declared type for invariant collection literals (#20927)
  [ty] Don't track inferability via different `Type` variants (#20677)
  [ty] Use declared variable types as bidirectional type context (#20796)
  [ty] Avoid unnecessarily widening generic specializations (#20875)
  [ty] Support dataclass-transform `field_specifiers` (#20888)
  Bump 0.14.1 (#20925)
  Standardize syntax error construction (#20903)
  [`pydoclint`] Implement `docstring-extraneous-parameter` (`DOC102`) (#20376)
  [ty] Fix panic 'missing root' when handling completion request (#20917)
  [ty] Run file watching tests serial when using nextest (#20918)
  [ty] Add version hint for failed stdlib attribute accesses (#20909)
  More CI improvements (#20920)
  [ty] Check typeshed VERSIONS for parent modules when reporting failed stdlib imports (#20908)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support field_specifiers in dataclass_transform

2 participants