Override JSONEncoder.default instead of json.dumps

Many libraries (like httpx, used by openai), will use `from json import dumps`,
and if they do that before `reflex.state` gets imported, then they will get the
original dumps function instead of our patched one.

To workaround this, monkeypatch the `JSONEncoder.default` function instead.

This is also nicer behavior for custom subclasses of JSONEncoder; if someone
wants to opt-out of our monkeypatching, they can simply not call
`super().default(o)` in their subclass, which by default only raises a
TypeError.
This commit is contained in:
Masen Furer 2024-10-31 14:08:46 -07:00
parent 6f3b550e88
commit 1a1fff07e9
No known key found for this signature in database
GPG Key ID: 2AE2BD5531FF94F4

View File

@ -3716,40 +3716,27 @@ def serialize_mutable_proxy(mp: MutableProxy):
return mp.__wrapped__ return mp.__wrapped__
_orig_json_dumps = json.dumps _orig_json_JSONEncoder_default = json.JSONEncoder.default
def _json_dumps_wrapper(*args, **kwargs): def _json_JSONEncoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any:
"""Wrap json.dumps to handle MutableProxy objects. """Wrap JSONEncoder.default to handle MutableProxy objects.
Args: Args:
*args: args for json.dumps. self: the JSONEncoder instance.
**kwargs: kwargs for json.dumps. o: the object to serialize.
Returns: Returns:
The JSON string. A JSON-able object.
""" """
if "cls" not in kwargs:
_orig_default = kwargs.pop("default", None)
def _default(obj):
if _orig_default is not None:
try: try:
return _orig_default(obj) return o.__wrapped__
except TypeError:
pass
try:
return obj.__wrapped__
except AttributeError: except AttributeError:
pass pass
raise TypeError() return _orig_json_JSONEncoder_default(self, o)
if "cls" not in kwargs:
kwargs["default"] = _default
return _orig_json_dumps(*args, **kwargs)
json.dumps = _json_dumps_wrapper json.JSONEncoder.default = _json_JSONEncoder_default_wrapper
class ImmutableMutableProxy(MutableProxy): class ImmutableMutableProxy(MutableProxy):