Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ db = [
"sqlmodel >=0.0.24,<0.1",
]
monitoring = ["pyleak >=0.1.14,<1.0"]
orjson = ["orjson >=3.9"]

[project.urls]
homepage = "https://reflex.dev"
Expand All @@ -75,6 +76,7 @@ dev = [
"hatchling",
"libsass",
"numpy",
"orjson >=3.9",
"pandas",
"pillow",
"playwright",
Expand Down
4 changes: 2 additions & 2 deletions reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,8 @@ def _setup_state(self) -> None:
ping_interval=environment.REFLEX_SOCKET_INTERVAL.get(),
ping_timeout=environment.REFLEX_SOCKET_TIMEOUT.get(),
json=SimpleNamespace(
dumps=staticmethod(format.json_dumps),
loads=staticmethod(json.loads),
dumps=staticmethod(format.json_dumps_fast),
loads=staticmethod(format.json_loads_fast),
),
allow_upgrades=False,
transports=[config.transport],
Expand Down
67 changes: 67 additions & 0 deletions reflex/utils/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,73 @@ def json_dumps(obj: Any, **kwargs) -> str:
return json.dumps(obj, **kwargs)


def _orjson_default(obj: Any) -> Any:
"""Handle custom types for orjson serialization.

Args:
obj: The object to serialize.

Returns:
A JSON-serializable representation of the object.

Raises:
TypeError: If the object is not JSON serializable.
"""
from reflex.utils import serializers

result = serializers.serialize(obj)
if result is not None:
return result
msg = f"Object of type {type(obj).__name__} is not JSON serializable"
raise TypeError(msg)


def json_dumps_fast(obj: Any) -> str:
"""Fast JSON serialization using orjson when available.

This function provides a faster alternative to json_dumps() by using
the orjson library (written in Rust) when it's installed. Falls back
to the standard json_dumps() if orjson is not available.

Args:
obj: The object to serialize to JSON.

Returns:
A JSON string representation of the object.
"""
try:
import orjson

return orjson.dumps(
obj,
default=_orjson_default,
option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY,
).decode("utf-8")
except ImportError:
return json_dumps(obj)


def json_loads_fast(data: str | bytes) -> Any:
"""Fast JSON deserialization using orjson when available.

This function provides a faster alternative to json.loads() by using
the orjson library (written in Rust) when it's installed. Falls back
to the standard json.loads() if orjson is not available.

Args:
data: The JSON string or bytes to deserialize.

Returns:
The deserialized Python object.
"""
try:
import orjson

return orjson.loads(data)
except ImportError:
return json.loads(data)


def collect_form_dict_names(form_dict: dict[str, Any]) -> dict[str, Any]:
"""Collapse keys with consecutive suffixes into a single list value.

Expand Down
5 changes: 2 additions & 3 deletions reflex/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import datetime
import functools
import inspect
import json
import re
import string
import uuid
Expand Down Expand Up @@ -52,7 +51,7 @@
VarDependencyError,
VarTypeError,
)
from reflex.utils.format import format_state_name
from reflex.utils.format import format_state_name, json_loads_fast
from reflex.utils.imports import (
ImmutableImportDict,
ImmutableParsedImportDict,
Expand Down Expand Up @@ -1179,7 +1178,7 @@ def _decode(self) -> Any:
if isinstance(self, LiteralVar):
return self._var_value
try:
return json.loads(str(self))
return json_loads_fast(str(self))
except ValueError:
return str(self)

Expand Down
6 changes: 3 additions & 3 deletions reflex/vars/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import dataclasses
import decimal
import json
import math
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, overload
Expand All @@ -17,6 +16,7 @@
VarTypeError,
VarValueError,
)
from reflex.utils.format import json_dumps_fast
from reflex.utils.imports import ImportDict, ImportVar
from reflex.utils.types import safe_issubclass

Expand Down Expand Up @@ -959,11 +959,11 @@ def json(self) -> str:
PrimitiveUnserializableToJSONError: If the var is unserializable to JSON.
"""
if isinstance(self._var_value, decimal.Decimal):
return json.dumps(float(self._var_value))
return json_dumps_fast(float(self._var_value))
if math.isinf(self._var_value) or math.isnan(self._var_value):
msg = f"No valid JSON representation for {self}"
raise PrimitiveUnserializableToJSONError(msg)
return json.dumps(self._var_value)
return json_dumps_fast(self._var_value)

def __hash__(self) -> int:
"""Calculate the hash value of the object.
Expand Down
8 changes: 4 additions & 4 deletions reflex/vars/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import dataclasses
import decimal
import inspect
import json
import re
from collections.abc import Iterable, Mapping, Sequence
from typing import TYPE_CHECKING, Any, Literal, TypeVar, get_args, overload
Expand All @@ -17,6 +16,7 @@
from reflex.constants.base import REFLEX_VAR_OPENING_TAG
from reflex.utils import types
from reflex.utils.exceptions import VarTypeError
from reflex.utils.format import json_dumps_fast
from reflex.utils.types import GenericType, get_origin

from .base import (
Expand Down Expand Up @@ -1264,7 +1264,7 @@ def create(
)

return LiteralStringVar(
_js_expr=json.dumps(value),
_js_expr=json_dumps_fast(value),
_var_type=_var_type,
_var_data=_var_data,
_var_value=value,
Expand All @@ -1284,7 +1284,7 @@ def json(self) -> str:
Returns:
The JSON representation of the var.
"""
return json.dumps(self._var_value)
return json_dumps_fast(self._var_value)


@dataclasses.dataclass(
Expand Down Expand Up @@ -1842,6 +1842,6 @@ def json(self) -> str:
Returns:
The JSON representation of the var.
"""
return json.dumps(
return json_dumps_fast(
list(self._var_value),
)
Loading
Loading