-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HH-205308 fix recursion in json encoder #680
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,53 @@ | ||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import TYPE_CHECKING, Callable, Optional, Union | ||
from typing import Any, Callable, Optional, Union | ||
|
||
import orjson | ||
from pydantic import BaseModel | ||
from tornado.concurrent import Future | ||
|
||
if TYPE_CHECKING: | ||
from typing import Any | ||
|
||
handler_logger = logging.getLogger('handler') | ||
|
||
|
||
FrontikJsonDecodeError = orjson.JSONDecodeError | ||
|
||
|
||
def _encode_value(value: Any) -> Any: | ||
def _deep_encode_value(value: Any) -> Any: | ||
""" | ||
This method partially duplicates ``_encode_value()``. | ||
It is only used by ``JsonBuilder.to_dict()`` | ||
which is only used by ``JsonProducer.get_jinja_context()``. | ||
""" | ||
|
||
if isinstance(value, dict): | ||
return {k: _encode_value(v) for k, v in value.items()} | ||
return {k: _deep_encode_value(v) for k, v in value.items()} | ||
|
||
elif isinstance(value, (set, frozenset, list, tuple)): | ||
return [_encode_value(v1) for v1 in value] | ||
return [_deep_encode_value(v1) for v1 in value] | ||
|
||
elif isinstance(value, Future): | ||
if value.done() and value.exception() is None: | ||
return _deep_encode_value(value.result()) | ||
|
||
return None | ||
|
||
elif isinstance(value, BaseModel): | ||
return _deep_encode_value(value.model_dump()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. тут добавил рекурсивный вызов |
||
|
||
elif hasattr(value, 'to_dict'): | ||
return _deep_encode_value(value.to_dict()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. и тут добавил рекурсивный вызов |
||
|
||
return value | ||
|
||
|
||
def _encode_value(value: Any) -> Any: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. этот метод теперь без рекурсии. также убрал обработку |
||
if isinstance(value, (set, frozenset)): | ||
return list(value) | ||
|
||
elif isinstance(value, Future): | ||
if value.done() and value.exception() is None: | ||
return _encode_value(value.result()) | ||
return value.result() | ||
|
||
return None | ||
|
||
|
@@ -35,7 +57,7 @@ def _encode_value(value: Any) -> Any: | |
elif hasattr(value, 'to_dict'): | ||
return value.to_dict() | ||
|
||
return value | ||
raise TypeError | ||
|
||
|
||
def json_encode(obj: Any, default: Callable = _encode_value) -> str: | ||
|
@@ -76,7 +98,7 @@ def replace(self, *args: Any, **kwargs: Any) -> None: | |
|
||
def to_dict(self) -> dict: | ||
"""Return plain dict from all data appended to JsonBuilder""" | ||
return _encode_value(self._concat_chunks()) | ||
return _deep_encode_value(self._concat_chunks()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. вот это одно место, где нужно преобразовывать в т.ч. вложенные объекты |
||
|
||
def _concat_chunks(self) -> dict: | ||
result = {} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
бывший рекурсивный
_encode_value
переименовал в_deep_encode_value
и в паре мест добавил ещё рекурсии (т.к. странно, что некоторые вложенные объекты преобразовывались, а некоторые нет, так что сделал все), см. комменты ниже