70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
from typing import Any, Optional
|
|
|
|
import orjson
|
|
from django.conf import settings
|
|
from drf_orjson_renderer.parsers import ORJSONParser
|
|
from rest_framework.exceptions import ParseError
|
|
|
|
|
|
def _underscoreize_key(key: str, no_underscore_before_number: bool = False) -> str:
|
|
if not isinstance(key, str) or not key:
|
|
return key
|
|
out = []
|
|
prev_lower = False
|
|
for ch in key:
|
|
if ch.isupper():
|
|
if out and (
|
|
prev_lower or (not no_underscore_before_number and out[-1].isdigit())
|
|
):
|
|
out.append("_")
|
|
out.append(ch.lower())
|
|
prev_lower = False
|
|
elif ch.isdigit():
|
|
if out and not no_underscore_before_number and not out[-1].isdigit():
|
|
out.append("_")
|
|
out.append(ch)
|
|
prev_lower = False
|
|
else:
|
|
out.append(ch)
|
|
prev_lower = True
|
|
return "".join(out)
|
|
|
|
|
|
def underscoreize(obj: Any, no_underscore_before_number: bool = False) -> Any:
|
|
if isinstance(obj, dict):
|
|
return {
|
|
(
|
|
_underscoreize_key(k, no_underscore_before_number)
|
|
if isinstance(k, str)
|
|
else k
|
|
): underscoreize(v, no_underscore_before_number)
|
|
for k, v in obj.items()
|
|
}
|
|
if isinstance(obj, (list, tuple)):
|
|
t = type(obj)
|
|
return t(underscoreize(v, no_underscore_before_number) for v in obj)
|
|
return obj
|
|
|
|
|
|
class CamelCaseParser(ORJSONParser):
|
|
def parse(
|
|
self, stream, media_type: Optional[Any] = None, parser_context: Any = None
|
|
) -> Any:
|
|
parser_context = parser_context or {}
|
|
encoding: str = parser_context.get("encoding", settings.DEFAULT_CHARSET)
|
|
|
|
try:
|
|
raw = stream.read().decode(encoding)
|
|
data = orjson.loads(raw)
|
|
except ValueError as exc:
|
|
raise ParseError(f"JSON parse error - {exc}") from exc
|
|
|
|
no_us_before_number = (
|
|
getattr(settings, "REST_FRAMEWORK", {})
|
|
.get("JSON_UNDERSCOREIZE", {})
|
|
.get("no_underscore_before_number", False)
|
|
)
|
|
return underscoreize(data, no_underscore_before_number=no_us_before_number)
|
|
|
|
|
|
__all__ = ["CamelCaseParser", "underscoreize"]
|