Skip to content

Support TypedDict form data in on_submit#6301

Open
GautamBytes wants to merge 2 commits intoreflex-dev:mainfrom
GautamBytes:feat/support-typeddict-forms
Open

Support TypedDict form data in on_submit#6301
GautamBytes wants to merge 2 commits intoreflex-dev:mainfrom
GautamBytes:feat/support-typeddict-forms

Conversation

@GautamBytes
Copy link
Copy Markdown
Contributor

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

New Feature Submission:

  • Does your submission pass the tests?
  • Have you linted your code locally prior to submission?

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Description

This PR adds TypedDict support for on_submit form data handlers while keeping existing dict[str, Any] and dict[str, str] handlers working as before.

What changed:

  • allows on_submit handlers annotated with a concrete TypedDict
  • validates required TypedDict keys against statically knowable form fields at form construction time
  • includes both literal name fields and existing id-backed form refs in the validation set
  • skips strict validation when field identifiers are dynamic or the submit chain is opaque, to avoid false positives
  • continues to allow extra form fields
  • keeps the runtime payload shape unchanged

This improves:

  • IDE autocomplete and handler authoring
  • static typing for form payload keys
  • compile-time feedback when a form is missing required fields expected by the handler

closes #6264

Signed-off-by: Gautam Manchandani <gautammanch@Gautams-MacBook-Air.local>
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 8, 2026

Merging this PR will not alter performance

✅ 9 untouched benchmarks


Comparing GautamBytes:feat/support-typeddict-forms (eb8b5fe) with main (2f8b816)

Open in CodSpeed

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

Greptile Summary

This PR adds TypedDict support for on_submit form data handlers in Reflex forms. Two complementary changes enable this:

  1. Type-checking relaxation (event/__init__.py): A new helper _is_mapping_style_event_arg_compatible_with_typed_dict lets any Mapping-typed event arg satisfy a TypedDict-annotated callback parameter, bypassing the stricter typehint_issubclass check. A new on_submit_mapping_event overload on Form.on_submit exposes a generic Mapping type for the submission payload.
  2. Compile-time field validation (forms.py): _validate_on_submit_typed_dict_fields is invoked at form construction time. It resolves required keys from the TypedDict annotation, collects static form field identifiers (both name props and id-backed refs), and raises EventHandlerValueError if any required keys are absent — unless dynamic Var identifiers are present, in which case validation is skipped.

Key changes:

  • Form.on_submit gains a on_submit_mapping_event overload to support generic Mapping payloads
  • _is_mapping_style_event_arg_compatible_with_typed_dict globally relaxes Mapping→TypedDict compatibility across all event handlers
  • BASE_STATE TypeVar is moved from the bottom TYPE_CHECKING block to the top one, leaving a now-redundant import at line ~2593
  • Comprehensive test suite covers acceptance, optional fields, extra fields, bound-arg resolution, missing-field errors, and dynamic-name bypass

Confidence Score: 5/5

Safe to merge — all remaining findings are non-blocking style and defensive-coding suggestions with no impact on correctness or existing behaviour

The implementation is well-structured and thoroughly tested. The four findings are all P2: a redundant dead-code import block, a narrow exception catch that could be broadened for defensive safety, a deliberate (though undocumented) global relaxation of Mapping→TypedDict compatibility, and a minor double traversal of form refs. None of these affect runtime correctness or existing users. The runtime payload shape is explicitly unchanged, backward compatibility is preserved, and the new validation only fires at construction time with a clear error message.

packages/reflex-base/src/reflex_base/event/init.py — redundant TYPE_CHECKING block at the bottom and the global scope of the Mapping relaxation are worth a second look before merge

Vulnerabilities

No security concerns identified. The new TypedDict validation runs at Python import/construction time using only type introspection (get_type_hints, is_typeddict, __required_keys__). No user-supplied data reaches the validation path, and the runtime payload shape is explicitly unchanged.

Important Files Changed

Filename Overview
packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py Core change: adds TypedDict field validation at form construction time, new mapping submit event overload, and several helper functions for static field discovery — well-structured but has a subtle gap where get_type_hints only catches NameError
packages/reflex-base/src/reflex_base/event/init.py Adds _is_mapping_style_event_arg_compatible_with_typed_dict to relax type checks globally for Mapping→TypedDict compatibility; moves BASE_STATE TypeVar to top but leaves a now-redundant if TYPE_CHECKING import block at the bottom
tests/units/components/forms/test_form.py Comprehensive new test suite covering acceptance, optional fields, extra fields, bound-arg resolution, missing-field errors, and dynamic-name bypass — good coverage of the happy and error paths
pyi_hashes.json Hash update for the changed forms.py stub — routine maintenance change

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Form.create"] --> B{on_submit in props?}
    B -- No --> C[Assign prevent_default]
    B -- Yes --> D[Build form component]
    C --> D
    D --> E[_validate_on_submit_typed_dict_fields]
    E --> F{on_submit is EventChain?}
    F -- No --> Z[Skip validation]
    F -- Yes --> G{Any non-EventSpec events?}
    G -- Yes --> Z
    G -- No --> H[_resolve_on_submit_typed_dict_contract]
    H --> I{form_data arg found?}
    I -- No --> Z
    I -- Yes --> J[get_type_hints on handler func]
    J --> K{annotation is TypedDict?}
    K -- No --> Z
    K -- Yes --> L[_get_static_form_field_keys]
    L --> M[Collect id-backed refs]
    M --> N[Scan children for static name props]
    N --> O{Any dynamic Var identifiers?}
    O -- Yes --> Z
    O -- No --> P{Missing required keys?}
    P -- No --> Z[Validation passes]
    P -- Yes --> Q[Raise EventHandlerValueError]
Loading

Reviews (1): Last reviewed commit: "Support TypedDict form submit data" | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

on_submit should support TypedDict for form data

1 participant