diff --git a/packages/reflex-base/news/+model-event-arg-fields.bugfix.md b/packages/reflex-base/news/+model-event-arg-fields.bugfix.md new file mode 100644 index 00000000000..d8a48c53411 --- /dev/null +++ b/packages/reflex-base/news/+model-event-arg-fields.bugfix.md @@ -0,0 +1 @@ +Event handler arguments hinted as an `rx.Model` no longer emit a `PydanticDeprecatedSince20` warning for every key of the payload. diff --git a/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py b/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py index 876f35e2d2f..ff079d4b2fd 100644 --- a/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py +++ b/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py @@ -135,10 +135,9 @@ def _transform_event_arg(value: Any, hinted_args: Any) -> Any: if issubclass(hinted_args, Model): # Remove non-fields from the payload + model_fields = hinted_args.model_fields return hinted_args(**{ - key: value - for key, value in value.items() - if key in hinted_args.__fields__ + key: value for key, value in value.items() if key in model_fields }) if dataclasses.is_dataclass(hinted_args): return hinted_args(**value) diff --git a/tests/units/reflex_base/event/processor/test_base_state_processor.py b/tests/units/reflex_base/event/processor/test_base_state_processor.py index b1613881257..a1c8d745278 100644 --- a/tests/units/reflex_base/event/processor/test_base_state_processor.py +++ b/tests/units/reflex_base/event/processor/test_base_state_processor.py @@ -8,6 +8,7 @@ import inspect import logging import traceback +import warnings import weakref from collections.abc import Mapping from pathlib import Path @@ -24,6 +25,7 @@ from reflex_base.event.processor import BaseStateEventProcessor from reflex_base.event.processor.base_state_processor import ( _prepare_event_payload, + _transform_event_arg, _transform_event_payload, ) from reflex_base.registry import RegistrationContext @@ -1975,6 +1977,31 @@ def test_transform_event_payload_passes_form_data_on_as_dict(hint, expected): assert type(payload["data"]) is type(expected) +def test_transform_event_arg_model_drops_non_fields_without_deprecation(): + """Filtering a Model payload to its fields emits no Pydantic deprecation.""" + pydantic_warnings = pytest.importorskip("pydantic.warnings") + pytest.importorskip("sqlmodel") + + class Post(rx.Model): + title: str + likes: int = 0 + + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + post = _transform_event_arg( + {"title": "hi", "likes": 2, "extra": 1, "other": 2}, Post + ) + + assert [ + w + for w in caught + if issubclass(w.category, pydantic_warnings.PydanticDeprecatedSince20) + ] == [] + assert isinstance(post, Post) + assert (post.title, post.likes) == ("hi", 2) + assert not post.model_extra + + def test_prepare_event_payload_transforms_form_data(): """A payload is transformed for the handler's annotations."""