Merge pull request #33391 from ankush/perf/safe_exec
perf: ~10x faster server script execution
This commit is contained in:
commit
996843f11b
1 changed files with 22 additions and 23 deletions
|
|
@ -31,6 +31,7 @@ from frappe.model.mapper import get_mapped_doc
|
|||
from frappe.model.rename_doc import rename_doc
|
||||
from frappe.modules import scrub
|
||||
from frappe.utils.background_jobs import enqueue, get_jobs
|
||||
from frappe.utils.caching import site_cache
|
||||
from frappe.utils.number_format import NumberFormat
|
||||
from frappe.utils.response import json_handler
|
||||
from frappe.website.utils import get_next_link, get_toc
|
||||
|
|
@ -81,7 +82,7 @@ class FrappePrintCollector(PrintCollector):
|
|||
|
||||
def is_safe_exec_enabled() -> bool:
|
||||
# server scripts can only be enabled via common_site_config.json
|
||||
return bool(frappe.get_common_site_config(cached=bool(frappe.request)).get(SAFE_EXEC_CONFIG_KEY))
|
||||
return bool(frappe.get_common_site_config(cached=True).get(SAFE_EXEC_CONFIG_KEY))
|
||||
|
||||
|
||||
def safe_exec(
|
||||
|
|
@ -115,15 +116,16 @@ def safe_exec(
|
|||
|
||||
with safe_exec_flags(), patched_qb():
|
||||
# execute script compiled by RestrictedPython
|
||||
exec(
|
||||
compile_restricted(script, filename=filename, policy=FrappeTransformer),
|
||||
exec_globals,
|
||||
_locals,
|
||||
)
|
||||
exec(_compile_code(script, filename=filename), exec_globals, _locals)
|
||||
|
||||
return exec_globals, _locals
|
||||
|
||||
|
||||
@site_cache(maxsize=32)
|
||||
def _compile_code(script: str, filename: str, mode: str = "exec"):
|
||||
return compile_restricted(script, filename=filename, policy=FrappeTransformer, mode=mode)
|
||||
|
||||
|
||||
def safe_eval(code, eval_globals=None, eval_locals=None):
|
||||
import unicodedata
|
||||
|
||||
|
|
@ -137,11 +139,7 @@ def safe_eval(code, eval_globals=None, eval_locals=None):
|
|||
eval_globals["__builtins__"] = {}
|
||||
eval_globals.update(WHITELISTED_SAFE_EVAL_GLOBALS)
|
||||
|
||||
return eval(
|
||||
compile_restricted(code, filename="<safe_eval>", policy=FrappeTransformer, mode="eval"),
|
||||
eval_globals,
|
||||
eval_locals,
|
||||
)
|
||||
return eval(_compile_code(code, filename="<safe_eval>", mode="eval"), eval_globals, eval_locals)
|
||||
|
||||
|
||||
def _validate_safe_eval_syntax(code):
|
||||
|
|
@ -179,7 +177,7 @@ def get_safe_globals():
|
|||
time_format = "HH:mm:ss"
|
||||
number_format = NumberFormat.from_string("#,###.##")
|
||||
|
||||
add_data_utils(datautils)
|
||||
datautils.update(SAFE_DATA_UTILS)
|
||||
|
||||
form_dict = getattr(frappe.local, "form_dict", frappe._dict())
|
||||
|
||||
|
|
@ -297,9 +295,7 @@ def get_safe_globals():
|
|||
get_visible_columns=get_visible_columns,
|
||||
)
|
||||
|
||||
add_module_properties(
|
||||
frappe.exceptions, out.frappe, lambda obj: inspect.isclass(obj) and issubclass(obj, Exception)
|
||||
)
|
||||
out.frappe.update(SAFE_EXCEPTIONS)
|
||||
|
||||
if frappe.response:
|
||||
out.frappe.response = frappe.response
|
||||
|
|
@ -567,7 +563,7 @@ def _validate_attribute_read(object, name):
|
|||
raise SyntaxError(f"Reading {object} attributes is not allowed")
|
||||
|
||||
if name.startswith("_"):
|
||||
raise AttributeError(f'"{name}" is an invalid attribute name because it ' 'starts with "_"')
|
||||
raise AttributeError(f'"{name}" is an invalid attribute name because it starts with "_"')
|
||||
|
||||
|
||||
def _write(obj):
|
||||
|
|
@ -587,13 +583,8 @@ def _write(obj):
|
|||
return obj
|
||||
|
||||
|
||||
def add_data_utils(data):
|
||||
for key, obj in frappe.utils.data.__dict__.items():
|
||||
if key in VALID_UTILS:
|
||||
data[key] = obj
|
||||
|
||||
|
||||
def add_module_properties(module, data, filter_method):
|
||||
def get_module_properties(module, filter_method):
|
||||
data = {}
|
||||
for key, obj in module.__dict__.items():
|
||||
if key.startswith("_"):
|
||||
# ignore
|
||||
|
|
@ -602,6 +593,7 @@ def add_module_properties(module, data, filter_method):
|
|||
if filter_method(obj):
|
||||
# only allow functions
|
||||
data[key] = obj
|
||||
return data
|
||||
|
||||
|
||||
VALID_UTILS = (
|
||||
|
|
@ -724,6 +716,9 @@ VALID_UTILS = (
|
|||
)
|
||||
|
||||
|
||||
SAFE_DATA_UTILS = {key: frappe.utils.data.__dict__[key] for key in VALID_UTILS}
|
||||
|
||||
|
||||
WHITELISTED_SAFE_EVAL_GLOBALS = {
|
||||
"int": int,
|
||||
"float": float,
|
||||
|
|
@ -740,3 +735,7 @@ SAFE_ORJSON = NamespaceDict(loads=orjson.loads, dumps=orjson.dumps)
|
|||
for key, val in vars(orjson).items():
|
||||
if key.startswith("OPT_"):
|
||||
SAFE_ORJSON[key] = val
|
||||
|
||||
SAFE_EXCEPTIONS = get_module_properties(
|
||||
frappe.exceptions, lambda obj: inspect.isclass(obj) and issubclass(obj, Exception)
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue