Skip to content

stubgen: emit synthesized __init__ for dataclass / Pydantic models#3306

Draft
tobyh-canva wants to merge 1 commit intofacebook:mainfrom
tobyh-canva:stubgen/synthesized-class-init
Draft

stubgen: emit synthesized __init__ for dataclass / Pydantic models#3306
tobyh-canva wants to merge 1 commit intofacebook:mainfrom
tobyh-canva:stubgen/synthesized-class-init

Conversation

@tobyh-canva
Copy link
Copy Markdown

Context

As in #3221 / #3223, stub output for dataclass and Pydantic models needs to reflect how instances are constructed (defaults, kw_only, validation aliases, etc.) without turning .pyi files into a dump of field() / Field() kwargs.

Intent

Alternative to #3223. Rather than primarily re-emitting a reduced field() / Field() on the class line, this approach injects a synthesized __init__ derived from the checker’s existing dataclass / Pydantic init plumbing, then aligns annotations with the authored class body where parameter names match (including alias-only init).

Changes

  • extract.rs: Resolve synthesized __init__ from ClassSynthesizedFields, map ParamStubParam, merge AST annotation text for init params (skipping InitVar), drop **kwargs from emitted synthetic inits, preserve / improve class-body ordering and field / Field elision behavior, import pruning for unused Pydantic helpers.
  • emit.rs: Multiline def __init__ when the stub has many parameters.
  • dataclass.rs: Validation-alias-only init parameters are keyword-only (*, id: ...), matching runtime and stub tests.
  • pydantic.rs / class_field.rs: Treat pydantic.BaseModel re-exports like other BaseModel bases; expose ClassField::dataclass_flags_of to stubgen.
  • mod.rs tests: Minimal on-disk pydantic shim + glob only input.py so temp package imports do not overwrite stubgen output.

Testing

  • cargo test -p pyrefly stubgen::tests::

Made with Cursor

Pydantic models default to lax init parameter types and extra **kwargs, which
made .pyi stubs noisy and unlike the source annotations. Stub extraction now
reuses the checker's synthesized __init__, overlays class-body annotation text
on matching parameters (including validation aliases), omits **kwargs from the
stub, and forces alias-only init parameters to be keyword-only.

Exposes ClassField::dataclass_flags_of to stubgen and treats re-exported
BaseModel as a Pydantic model for metadata.

Alternative to trimming field()/Field() on the class body (facebook#3223).

Co-authored-by: Cursor <cursoragent@cursor.com>
@tobyh-canva tobyh-canva force-pushed the stubgen/synthesized-class-init branch from a48a83e to 69dd83e Compare May 7, 2026 05:16
@github-actions github-actions Bot added size/xl and removed size/xl labels May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant