Skip to content

Commit 8fd5c9f

Browse files
improve typing for serializer decorator (#4317)
* improve typing for serializer decorator * use wrapped logic * dang it darglint --------- Co-authored-by: Khaleel Al-Adhami <[email protected]>
1 parent 0c482bd commit 8fd5c9f

File tree

1 file changed

+58
-40
lines changed

1 file changed

+58
-40
lines changed

reflex/utils/serializers.py

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
Set,
1919
Tuple,
2020
Type,
21+
TypeVar,
2122
Union,
2223
get_type_hints,
2324
overload,
@@ -32,17 +33,33 @@
3233
SerializedType = Union[str, bool, int, float, list, dict, None]
3334

3435

35-
Serializer = Callable[[Type], SerializedType]
36+
Serializer = Callable[[Any], SerializedType]
3637

3738

3839
SERIALIZERS: dict[Type, Serializer] = {}
3940
SERIALIZER_TYPES: dict[Type, Type] = {}
4041

42+
SERIALIZED_FUNCTION = TypeVar("SERIALIZED_FUNCTION", bound=Serializer)
4143

44+
45+
@overload
46+
def serializer(
47+
fn: None = None,
48+
to: Type[SerializedType] | None = None,
49+
) -> Callable[[SERIALIZED_FUNCTION], SERIALIZED_FUNCTION]: ...
50+
51+
52+
@overload
4253
def serializer(
43-
fn: Serializer | None = None,
44-
to: Type | None = None,
45-
) -> Serializer:
54+
fn: SERIALIZED_FUNCTION,
55+
to: Type[SerializedType] | None = None,
56+
) -> SERIALIZED_FUNCTION: ...
57+
58+
59+
def serializer(
60+
fn: SERIALIZED_FUNCTION | None = None,
61+
to: Any = None,
62+
) -> SERIALIZED_FUNCTION | Callable[[SERIALIZED_FUNCTION], SERIALIZED_FUNCTION]:
4663
"""Decorator to add a serializer for a given type.
4764
4865
Args:
@@ -51,43 +68,44 @@ def serializer(
5168
5269
Returns:
5370
The decorated function.
54-
55-
Raises:
56-
ValueError: If the function does not take a single argument.
5771
"""
58-
if fn is None:
59-
# If the function is not provided, return a partial that acts as a decorator.
60-
return functools.partial(serializer, to=to) # type: ignore
61-
62-
# Check the type hints to get the type of the argument.
63-
type_hints = get_type_hints(fn)
64-
args = [arg for arg in type_hints if arg != "return"]
65-
66-
# Make sure the function takes a single argument.
67-
if len(args) != 1:
68-
raise ValueError("Serializer must take a single argument.")
69-
70-
# Get the type of the argument.
71-
type_ = type_hints[args[0]]
72-
73-
# Make sure the type is not already registered.
74-
registered_fn = SERIALIZERS.get(type_)
75-
if registered_fn is not None and registered_fn != fn:
76-
raise ValueError(
77-
f"Serializer for type {type_} is already registered as {registered_fn.__qualname__}."
78-
)
79-
80-
# Apply type transformation if requested
81-
if to is not None or ((to := type_hints.get("return")) is not None):
82-
SERIALIZER_TYPES[type_] = to
83-
get_serializer_type.cache_clear()
84-
85-
# Register the serializer.
86-
SERIALIZERS[type_] = fn
87-
get_serializer.cache_clear()
88-
89-
# Return the function.
90-
return fn
72+
73+
def wrapper(fn: SERIALIZED_FUNCTION) -> SERIALIZED_FUNCTION:
74+
# Check the type hints to get the type of the argument.
75+
type_hints = get_type_hints(fn)
76+
args = [arg for arg in type_hints if arg != "return"]
77+
78+
# Make sure the function takes a single argument.
79+
if len(args) != 1:
80+
raise ValueError("Serializer must take a single argument.")
81+
82+
# Get the type of the argument.
83+
type_ = type_hints[args[0]]
84+
85+
# Make sure the type is not already registered.
86+
registered_fn = SERIALIZERS.get(type_)
87+
if registered_fn is not None and registered_fn != fn:
88+
raise ValueError(
89+
f"Serializer for type {type_} is already registered as {registered_fn.__qualname__}."
90+
)
91+
92+
to_type = to or type_hints.get("return")
93+
94+
# Apply type transformation if requested
95+
if to_type:
96+
SERIALIZER_TYPES[type_] = to_type
97+
get_serializer_type.cache_clear()
98+
99+
# Register the serializer.
100+
SERIALIZERS[type_] = fn
101+
get_serializer.cache_clear()
102+
103+
# Return the function.
104+
return fn
105+
106+
if fn is not None:
107+
return wrapper(fn)
108+
return wrapper
91109

92110

93111
@overload

0 commit comments

Comments
 (0)