Tighten JSON path helper performance

This commit is contained in:
2026-07-21 11:19:37 +00:00
parent 4ad9e93b63
commit 0fae1f5f20

View File

@@ -28,9 +28,9 @@ def _parse_json_path(path):
return tuple(segments)
def _get_json_path_value(data, path):
def _get_json_path_value_segments(data, segments):
current = data
for segment in _parse_json_path(path):
for segment in segments:
if isinstance(segment, int):
if not isinstance(current, list) or segment >= len(current):
return None
@@ -43,9 +43,13 @@ def _get_json_path_value(data, path):
return current
def _has_json_path(data, path):
def _get_json_path_value(data, path):
return _get_json_path_value_segments(data, _parse_json_path(path))
def _has_json_path_segments(data, segments):
current = data
for segment in _parse_json_path(path):
for segment in segments:
if isinstance(segment, int):
if not isinstance(current, list) or segment >= len(current):
return False
@@ -58,16 +62,20 @@ def _has_json_path(data, path):
return True
def _has_json_path(data, path):
return _has_json_path_segments(data, _parse_json_path(path))
def _build_missing_container(next_segment):
return [] if isinstance(next_segment, int) else {}
def _set_json_path_value_recursive(current, segments, value):
if not segments:
def _set_json_path_value_recursive(current, segments, position, value):
if position >= len(segments):
return value
segment = segments[0]
is_last = len(segments) == 1
segment = segments[position]
is_last = position == len(segments) - 1
if isinstance(segment, int):
if not isinstance(current, list):
@@ -83,8 +91,8 @@ def _set_json_path_value_recursive(current, segments, value):
next_current = result[segment]
if not isinstance(next_current, (dict, list)):
next_current = _build_missing_container(segments[1])
updated = _set_json_path_value_recursive(next_current, segments[1:], value)
next_current = _build_missing_container(segments[position + 1])
updated = _set_json_path_value_recursive(next_current, segments, position + 1, value)
if updated is None:
return None
result[segment] = updated
@@ -100,31 +108,34 @@ def _set_json_path_value_recursive(current, segments, value):
next_current = result.get(segment)
if not isinstance(next_current, (dict, list)):
next_current = _build_missing_container(segments[1])
updated = _set_json_path_value_recursive(next_current, segments[1:], value)
next_current = _build_missing_container(segments[position + 1])
updated = _set_json_path_value_recursive(next_current, segments, position + 1, value)
if updated is None:
return None
result[segment] = updated
return result
def _set_json_path_value(data, path, value):
def _set_json_path_value_segments(data, segments, value):
if not isinstance(data, dict):
return None
segments = _parse_json_path(path)
if not segments:
return value
return _set_json_path_value_recursive(data, segments, value)
return _set_json_path_value_recursive(data, segments, 0, value)
def _remove_json_path_value_recursive(current, segments):
if not segments:
def _set_json_path_value(data, path, value):
return _set_json_path_value_segments(data, _parse_json_path(path), value)
def _remove_json_path_value_recursive(current, segments, position):
if position >= len(segments):
return _clone_container(current)
segment = segments[0]
is_last = len(segments) == 1
segment = segments[position]
is_last = position == len(segments) - 1
if isinstance(segment, int):
if not isinstance(current, list) or segment >= len(current):
@@ -135,7 +146,7 @@ def _remove_json_path_value_recursive(current, segments):
del result[segment]
return result
updated = _remove_json_path_value_recursive(result[segment], segments[1:])
updated = _remove_json_path_value_recursive(result[segment], segments, position + 1)
if updated is None:
return None
result[segment] = updated
@@ -149,18 +160,21 @@ def _remove_json_path_value_recursive(current, segments):
del result[segment]
return result
updated = _remove_json_path_value_recursive(result[segment], segments[1:])
updated = _remove_json_path_value_recursive(result[segment], segments, position + 1)
if updated is None:
return None
result[segment] = updated
return result
def _remove_json_path_value(data, path):
segments = _parse_json_path(path)
def _remove_json_path_value_segments(data, segments):
if not segments:
return _clone_container(data)
return _remove_json_path_value_recursive(data, segments)
return _remove_json_path_value_recursive(data, segments, 0)
def _remove_json_path_value(data, path):
return _remove_json_path_value_segments(data, _parse_json_path(path))
def _merge_json_objects(base_object, overlay_object):
@@ -211,7 +225,7 @@ def _unflatten_json_object(flat_object):
for path, value in flat_object.items():
if not isinstance(path, str):
return None
result = _set_json_path_value(result, path, value)
result = _set_json_path_value_segments(result, _parse_json_path(path), value)
if result is None:
return None
return result
@@ -369,10 +383,13 @@ class DumasJSONPickFieldsNode:
result = {}
for raw_path in paths.splitlines():
path = raw_path.strip()
if not path or not _has_json_path(json_object, path):
if not path:
continue
value = _get_json_path_value(json_object, path)
result = _set_json_path_value(result, path, value)
segments = _parse_json_path(path)
if not _has_json_path_segments(json_object, segments):
continue
value = _get_json_path_value_segments(json_object, segments)
result = _set_json_path_value_segments(result, segments, value)
if result is None:
return (None,)
return (result,)