Skip to content

Commit b78d5c7

Browse files
committed
applied requests
1 parent ab14e7c commit b78d5c7

File tree

3 files changed

+67
-60
lines changed

3 files changed

+67
-60
lines changed

src/fourc_webviewer/fourc_webserver.py

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
)
3030
from fourc_webviewer.python_utils import (
3131
convert_string2number,
32+
dict_leaves_to_number_if_schema,
3233
find_value_recursively,
34+
parse_validation_error_text,
3335
smart_string2number_cast,
3436
)
3537

@@ -75,7 +77,7 @@ def __init__(
7577
self._server_vars["temp_dir_object"] = tempfile.TemporaryDirectory()
7678

7779
# Register on_field_blur function, which is called when the user leaves a field
78-
self.server.controller.on_field_blur = self.on_field_blur
80+
self.server.controller.on_leave_edit_field = self.on_leave_edit_field
7981

8082
# initialize state variables for the different modes and
8183
# statuses of the client (e.g. view mode versus edit mode,
@@ -1116,81 +1118,25 @@ def click_save_button(self, **kwargs):
11161118
else:
11171119
self.state.export_status = self.state.all_export_statuses["error"]
11181120

1119-
def parse_validation_error_text(self, text):
1120-
"""Parse a ValidationError message string (with multiple "- Parameter
1121-
in [...]" blocks) into a nested dict."""
1122-
error_dict = {}
1123-
# Match "- Parameter in [...]" blocks up until the next one or end of string
1124-
block_re = re.compile(
1125-
r"- Parameter in (?P<path>(?:\[[^\]]+\])+)\n"
1126-
r"(?P<body>.*?)(?=(?:- Parameter in )|\Z)",
1127-
re.DOTALL,
1128-
)
1129-
for m in block_re.finditer(text):
1130-
path_str = m.group("path")
1131-
body = m.group("body")
1132-
1133-
# extract the Error: line
1134-
err_m = re.search(r"Error:\s*(.+)", body)
1135-
if not err_m:
1136-
continue
1137-
err_msg = err_m.group(1).strip()
1138-
1139-
keys = re.findall(r'\["([^"]+)"\]', path_str)
1140-
1141-
# walk/create nested dicts, then assign the message at the leaf
1142-
cur = error_dict
1143-
for key in keys[:-1]:
1144-
cur = cur.setdefault(key, {})
1145-
cur[keys[-1]] = err_msg
1146-
1147-
return error_dict
1148-
11491121
@change("general_sections")
11501122
def on_sections_change(self, general_sections, **kwargs):
11511123
"""Reaction to change of state.general_sections."""
11521124

11531125
self.sync_server_vars_from_state()
11541126
try:
11551127
fourcinput = FourCInput(self._server_vars["fourc_yaml_content"])
1156-
# print(CONFIG)
1157-
1158-
def get_by_path(dct, path):
1159-
"""Retrieve the value at the nested path from dct.
1160-
1161-
Raises KeyError if any key is missing.
1162-
"""
1163-
# print(f"get_by_path: {path}")
1164-
current = dct
1165-
for key in path:
1166-
current = current[key]
1167-
return current
1168-
1169-
def dict_leaves_to_number_if_schema(value, schema_path=[]):
1170-
"""Convert all leaves of a dict to numbers if possible."""
1171-
if isinstance(value, dict):
1172-
for k, v in value.items():
1173-
value[k] = dict_leaves_to_number_if_schema(
1174-
v, schema_path + ["properties", k]
1175-
)
1176-
return value
1177-
if isinstance(value, str) and get_by_path(
1178-
CONFIG["json_schema"], schema_path + ["type"]
1179-
) in ["number", "integer"]:
1180-
return smart_string2number_cast(value)
1181-
return value
11821128

11831129
dict_leaves_to_number_if_schema(fourcinput._sections)
11841130

11851131
fourcinput.validate()
11861132
self.state.input_error_dict = {}
11871133
except ValidationError as exc:
1188-
self.state.input_error_dict = self.parse_validation_error_text(
1134+
self.state.input_error_dict = parse_validation_error_text(
11891135
str(exc.args[0])
11901136
) # exc.args[0] is the error message
11911137
return False
11921138

1193-
def on_field_blur(self):
1139+
def on_leave_edit_field(self):
11941140
"""Reaction to user leaving the field."""
11951141
# also gets called when a new file is loaded
11961142
# basically just sets the state based on server_vars

src/fourc_webviewer/gui_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ def _prop_value_table(server):
502502
"|| json_schema['properties']?.[selected_section_name]?.['properties']?.[item_key]?.['type'] == 'integer')"
503503
"&& !json_schema['properties']?.[selected_section_name]?.['properties']?.[item_key]?.['enum']"
504504
),
505-
blur=server.controller.on_field_blur,
505+
blur=server.controller.on_leave_edit_field,
506506
update_modelValue="flushState('general_sections')", # this is required in order to flush the state changes correctly to the server, as our passed on v-model is a nested variable
507507
classes="w-80 pb-1",
508508
dense=True,

src/fourc_webviewer/python_utils.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""Module for python utils."""
22

3+
import re
4+
5+
from fourcipp import CONFIG
6+
37

48
def flatten_list(input_list):
59
"""Flattens a given (multi-level) list into a single list.
@@ -48,6 +52,63 @@ def find_value_recursively(input_dict, target_key):
4852
return None
4953

5054

55+
def get_by_path(dct, path):
56+
"""Retrieve the value at the nested path from dct.
57+
58+
Raises KeyError if any key is missing.
59+
"""
60+
current = dct
61+
for key in path:
62+
current = current[key]
63+
return current
64+
65+
66+
def dict_leaves_to_number_if_schema(value, schema_path=[]):
67+
"""Convert all leaves of a dict to numbers if possible."""
68+
if isinstance(value, dict):
69+
for k, v in value.items():
70+
value[k] = dict_leaves_to_number_if_schema(
71+
v, schema_path + ["properties", k]
72+
)
73+
return value
74+
if isinstance(value, str) and get_by_path(
75+
CONFIG["json_schema"], schema_path + ["type"]
76+
) in ["number", "integer"]:
77+
return smart_string2number_cast(value)
78+
return value
79+
80+
81+
def parse_validation_error_text(text):
82+
"""Parse a ValidationError message string (with multiple "- Parameter in
83+
[...]" blocks) into a nested dict."""
84+
error_dict = {}
85+
# Match "- Parameter in [...]" blocks up until the next one or end of string
86+
block_re = re.compile(
87+
r"- Parameter in (?P<path>(?:\[[^\]]+\])+)\n"
88+
r"(?P<body>.*?)(?=(?:- Parameter in )|\Z)",
89+
re.DOTALL,
90+
)
91+
for m in block_re.finditer(text):
92+
path_str = m.group("path")
93+
body = m.group("body")
94+
95+
# extract the Error: line
96+
err_m = re.search(r"Error:\s*(.+)", body)
97+
if not err_m:
98+
continue
99+
err_msg = err_m.group(1).strip()
100+
101+
keys = re.findall(r'\["([^"]+)"\]', path_str)
102+
103+
# walk/create nested dicts, then assign the message at the leaf
104+
cur = error_dict
105+
for key in keys[:-1]:
106+
cur = cur.setdefault(key, {})
107+
cur[keys[-1]] = err_msg
108+
109+
return error_dict
110+
111+
51112
def smart_string2number_cast(input_string):
52113
"""Casts an input_string to float / int if possible. Helpful when dealing
53114
with automatic to-string conversions from vuetify.VTextField input

0 commit comments

Comments
 (0)