Skip to content

Commit cabc624

Browse files
try orjson
1 parent b459a7c commit cabc624

File tree

7 files changed

+168
-13
lines changed

7 files changed

+168
-13
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ db = [
5757
"sqlmodel >=0.0.24,<0.1",
5858
]
5959
monitoring = ["pyleak >=0.1.14,<1.0"]
60+
orjson = ["orjson >=3.9"]
6061

6162
[project.urls]
6263
homepage = "https://reflex.dev"
@@ -75,6 +76,7 @@ dev = [
7576
"hatchling",
7677
"libsass",
7778
"numpy",
79+
"orjson >=3.9",
7880
"pandas",
7981
"pillow",
8082
"playwright",

reflex/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,8 @@ def _setup_state(self) -> None:
545545
ping_interval=environment.REFLEX_SOCKET_INTERVAL.get(),
546546
ping_timeout=environment.REFLEX_SOCKET_TIMEOUT.get(),
547547
json=SimpleNamespace(
548-
dumps=staticmethod(format.json_dumps),
549-
loads=staticmethod(json.loads),
548+
dumps=staticmethod(format.json_dumps_fast),
549+
loads=staticmethod(format.json_loads_fast),
550550
),
551551
allow_upgrades=False,
552552
transports=[config.transport],

reflex/utils/format.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,73 @@ def json_dumps(obj: Any, **kwargs) -> str:
686686
return json.dumps(obj, **kwargs)
687687

688688

689+
def _orjson_default(obj: Any) -> Any:
690+
"""Handle custom types for orjson serialization.
691+
692+
Args:
693+
obj: The object to serialize.
694+
695+
Returns:
696+
A JSON-serializable representation of the object.
697+
698+
Raises:
699+
TypeError: If the object is not JSON serializable.
700+
"""
701+
from reflex.utils import serializers
702+
703+
result = serializers.serialize(obj)
704+
if result is not None:
705+
return result
706+
msg = f"Object of type {type(obj).__name__} is not JSON serializable"
707+
raise TypeError(msg)
708+
709+
710+
def json_dumps_fast(obj: Any) -> str:
711+
"""Fast JSON serialization using orjson when available.
712+
713+
This function provides a faster alternative to json_dumps() by using
714+
the orjson library (written in Rust) when it's installed. Falls back
715+
to the standard json_dumps() if orjson is not available.
716+
717+
Args:
718+
obj: The object to serialize to JSON.
719+
720+
Returns:
721+
A JSON string representation of the object.
722+
"""
723+
try:
724+
import orjson
725+
726+
return orjson.dumps(
727+
obj,
728+
default=_orjson_default,
729+
option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY,
730+
).decode("utf-8")
731+
except ImportError:
732+
return json_dumps(obj)
733+
734+
735+
def json_loads_fast(data: str | bytes) -> Any:
736+
"""Fast JSON deserialization using orjson when available.
737+
738+
This function provides a faster alternative to json.loads() by using
739+
the orjson library (written in Rust) when it's installed. Falls back
740+
to the standard json.loads() if orjson is not available.
741+
742+
Args:
743+
data: The JSON string or bytes to deserialize.
744+
745+
Returns:
746+
The deserialized Python object.
747+
"""
748+
try:
749+
import orjson
750+
751+
return orjson.loads(data)
752+
except ImportError:
753+
return json.loads(data)
754+
755+
689756
def collect_form_dict_names(form_dict: dict[str, Any]) -> dict[str, Any]:
690757
"""Collapse keys with consecutive suffixes into a single list value.
691758

reflex/vars/base.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import datetime
99
import functools
1010
import inspect
11-
import json
1211
import re
1312
import string
1413
import uuid
@@ -52,7 +51,7 @@
5251
VarDependencyError,
5352
VarTypeError,
5453
)
55-
from reflex.utils.format import format_state_name
54+
from reflex.utils.format import format_state_name, json_loads_fast
5655
from reflex.utils.imports import (
5756
ImmutableImportDict,
5857
ImmutableParsedImportDict,
@@ -1179,7 +1178,7 @@ def _decode(self) -> Any:
11791178
if isinstance(self, LiteralVar):
11801179
return self._var_value
11811180
try:
1182-
return json.loads(str(self))
1181+
return json_loads_fast(str(self))
11831182
except ValueError:
11841183
return str(self)
11851184

reflex/vars/number.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import dataclasses
66
import decimal
7-
import json
87
import math
98
from collections.abc import Callable
109
from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, overload
@@ -17,6 +16,7 @@
1716
VarTypeError,
1817
VarValueError,
1918
)
19+
from reflex.utils.format import json_dumps_fast
2020
from reflex.utils.imports import ImportDict, ImportVar
2121
from reflex.utils.types import safe_issubclass
2222

@@ -959,11 +959,11 @@ def json(self) -> str:
959959
PrimitiveUnserializableToJSONError: If the var is unserializable to JSON.
960960
"""
961961
if isinstance(self._var_value, decimal.Decimal):
962-
return json.dumps(float(self._var_value))
962+
return json_dumps_fast(float(self._var_value))
963963
if math.isinf(self._var_value) or math.isnan(self._var_value):
964964
msg = f"No valid JSON representation for {self}"
965965
raise PrimitiveUnserializableToJSONError(msg)
966-
return json.dumps(self._var_value)
966+
return json_dumps_fast(self._var_value)
967967

968968
def __hash__(self) -> int:
969969
"""Calculate the hash value of the object.

reflex/vars/sequence.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import dataclasses
77
import decimal
88
import inspect
9-
import json
109
import re
1110
from collections.abc import Iterable, Mapping, Sequence
1211
from typing import TYPE_CHECKING, Any, Literal, TypeVar, get_args, overload
@@ -17,6 +16,7 @@
1716
from reflex.constants.base import REFLEX_VAR_OPENING_TAG
1817
from reflex.utils import types
1918
from reflex.utils.exceptions import VarTypeError
19+
from reflex.utils.format import json_dumps_fast
2020
from reflex.utils.types import GenericType, get_origin
2121

2222
from .base import (
@@ -1264,7 +1264,7 @@ def create(
12641264
)
12651265

12661266
return LiteralStringVar(
1267-
_js_expr=json.dumps(value),
1267+
_js_expr=json_dumps_fast(value),
12681268
_var_type=_var_type,
12691269
_var_data=_var_data,
12701270
_var_value=value,
@@ -1284,7 +1284,7 @@ def json(self) -> str:
12841284
Returns:
12851285
The JSON representation of the var.
12861286
"""
1287-
return json.dumps(self._var_value)
1287+
return json_dumps_fast(self._var_value)
12881288

12891289

12901290
@dataclasses.dataclass(
@@ -1842,6 +1842,6 @@ def json(self) -> str:
18421842
Returns:
18431843
The JSON representation of the var.
18441844
"""
1845-
return json.dumps(
1845+
return json_dumps_fast(
18461846
list(self._var_value),
18471847
)

0 commit comments

Comments
 (0)