Skip to content
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

Merged
merged 1 commit into from
Feb 1, 2024
Merged
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
44 changes: 33 additions & 11 deletions frontik/json_builder.py
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:
Copy link
Member Author

@Powerrr Powerrr Feb 1, 2024

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 и в паре мест добавил ещё рекурсии (т.к. странно, что некоторые вложенные объекты преобразовывались, а некоторые нет, так что сделал все), см. комменты ниже

"""
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())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут добавил рекурсивный вызов


elif hasattr(value, 'to_dict'):
return _deep_encode_value(value.to_dict())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

и тут добавил рекурсивный вызов


return value


def _encode_value(value: Any) -> Any:
Copy link
Member Author

@Powerrr Powerrr Feb 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

этот метод теперь без рекурсии. также убрал обработку dict, list, tuple, т.к. json-сериализатор сам их умеет

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

Expand All @@ -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:
Expand Down Expand Up @@ -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())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вот это одно место, где нужно преобразовывать в т.ч. вложенные объекты


def _concat_chunks(self) -> dict:
result = {}
Expand Down
Loading