perf: use orjson for faster request processing
This commit is contained in:
parent
1a1dc0a62c
commit
b857a4099a
4 changed files with 27 additions and 15 deletions
|
|
@ -34,6 +34,7 @@ from typing import (
|
|||
)
|
||||
|
||||
import click
|
||||
import orjson
|
||||
from werkzeug.datastructures import Headers
|
||||
|
||||
import frappe
|
||||
|
|
@ -1265,7 +1266,7 @@ def get_installed_apps(*, _ensure_on_bench: bool = False) -> list[str]:
|
|||
if not db:
|
||||
connect()
|
||||
|
||||
installed = json.loads(db.get_global("installed_apps") or "[]")
|
||||
installed = orjson.loads(db.get_global("installed_apps") or "[]")
|
||||
|
||||
if _ensure_on_bench:
|
||||
all_apps = cache.get_value("all_apps", get_all_apps)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import functools
|
|||
import logging
|
||||
import os
|
||||
|
||||
import orjson
|
||||
from werkzeug.exceptions import HTTPException, NotFound
|
||||
from werkzeug.middleware.profiler import ProfilerMiddleware
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
|
@ -297,11 +298,9 @@ def set_cors_headers(response):
|
|||
|
||||
|
||||
def make_form_dict(request: Request):
|
||||
import json
|
||||
|
||||
request_data = request.get_data(as_text=True)
|
||||
if request_data and request.is_json:
|
||||
args = json.loads(request_data)
|
||||
args = orjson.loads(request_data)
|
||||
else:
|
||||
args = {}
|
||||
args.update(request.args or {})
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@
|
|||
# License: MIT. See LICENSE
|
||||
|
||||
import datetime
|
||||
import decimal
|
||||
import json
|
||||
import functools
|
||||
import mimetypes
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
from collections.abc import Iterable
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
from re import Match
|
||||
from typing import TYPE_CHECKING
|
||||
from urllib.parse import quote
|
||||
from uuid import UUID
|
||||
|
||||
import orjson
|
||||
import werkzeug.utils
|
||||
from werkzeug.exceptions import Forbidden, NotFound
|
||||
from werkzeug.local import LocalProxy
|
||||
|
|
@ -32,6 +33,7 @@ if TYPE_CHECKING:
|
|||
from frappe.core.doctype.file.file import File
|
||||
|
||||
DateOrTimeTypes = datetime.date | datetime.datetime | datetime.time
|
||||
timedelta = datetime.timedelta
|
||||
|
||||
|
||||
def report_error(status_code):
|
||||
|
|
@ -148,7 +150,7 @@ def as_json():
|
|||
del frappe.local.response["http_status_code"]
|
||||
|
||||
response.mimetype = "application/json"
|
||||
response.data = json.dumps(frappe.local.response, default=json_handler, separators=(",", ":"))
|
||||
response.data = dump_response(frappe.local.response)
|
||||
return response
|
||||
|
||||
|
||||
|
|
@ -191,13 +193,15 @@ def _make_logs_v1():
|
|||
if frappe.error_log and is_traceback_allowed():
|
||||
if source := guess_exception_source(frappe.local.error_log and frappe.local.error_log[0]["exc"]):
|
||||
response["_exc_source"] = source
|
||||
response["exc"] = json.dumps([frappe.utils.cstr(d["exc"]) for d in frappe.local.error_log])
|
||||
response["exc"] = orjson.dumps([frappe.utils.cstr(d["exc"]) for d in frappe.local.error_log]).decode()
|
||||
|
||||
if frappe.local.message_log:
|
||||
response["_server_messages"] = json.dumps([json.dumps(d) for d in frappe.local.message_log])
|
||||
response["_server_messages"] = orjson.dumps(
|
||||
[orjson.dumps(d).decode() for d in frappe.local.message_log]
|
||||
).decode()
|
||||
|
||||
if frappe.debug_log:
|
||||
response["_debug_messages"] = json.dumps(frappe.local.debug_log)
|
||||
response["_debug_messages"] = orjson.dumps(frappe.local.debug_log).decode()
|
||||
|
||||
if frappe.flags.error_message:
|
||||
response["_error_message"] = frappe.flags.error_message
|
||||
|
|
@ -219,7 +223,7 @@ def json_handler(obj):
|
|||
if isinstance(obj, DateOrTimeTypes):
|
||||
return str(obj)
|
||||
|
||||
elif isinstance(obj, datetime.timedelta):
|
||||
elif isinstance(obj, timedelta):
|
||||
return format_timedelta(obj)
|
||||
|
||||
elif isinstance(obj, LocalProxy):
|
||||
|
|
@ -231,7 +235,7 @@ def json_handler(obj):
|
|||
elif isinstance(obj, Iterable):
|
||||
return list(obj)
|
||||
|
||||
elif isinstance(obj, decimal.Decimal):
|
||||
elif isinstance(obj, Decimal):
|
||||
return float(obj)
|
||||
|
||||
elif isinstance(obj, Match):
|
||||
|
|
@ -243,16 +247,23 @@ def json_handler(obj):
|
|||
elif callable(obj):
|
||||
return repr(obj)
|
||||
|
||||
elif isinstance(obj, uuid.UUID):
|
||||
elif isinstance(obj, Path):
|
||||
return str(obj)
|
||||
|
||||
elif isinstance(obj, Path):
|
||||
# orjson does this already
|
||||
# but json_handler needs to be compatible with built-in json module also
|
||||
elif isinstance(obj, UUID):
|
||||
return str(obj)
|
||||
|
||||
else:
|
||||
raise TypeError(f"""Object of type {type(obj)} with value of {obj!r} is not JSON serializable""")
|
||||
|
||||
|
||||
dump_response = functools.partial(
|
||||
orjson.dumps, default=json_handler, option=orjson.OPT_PASSTHROUGH_DATETIME | orjson.OPT_NON_STR_KEYS
|
||||
)
|
||||
|
||||
|
||||
def as_page():
|
||||
"""print web page"""
|
||||
from frappe.website.serve import get_response
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ dependencies = [
|
|||
"num2words~=0.5.14",
|
||||
"oauthlib~=3.2.2",
|
||||
"openpyxl~=3.1.5",
|
||||
"orjson~=3.10.18",
|
||||
"passlib~=1.7.4",
|
||||
"pdfkit~=1.0.0",
|
||||
"phonenumbers~=9.0.7",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue