-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathruntime_persistent_variables.py
More file actions
139 lines (109 loc) · 4.66 KB
/
Copy pathruntime_persistent_variables.py
File metadata and controls
139 lines (109 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from __future__ import annotations
from typing import Any
RUNTIME_VARIABLE_SCOPES = ("save", "persistent")
PERSISTENT_VARIABLE_STORE_FORMAT_VERSION = 1
def get_safe_runtime_variable_scope(value: object) -> str:
return "persistent" if str(value or "").strip().lower() == "persistent" else "save"
def is_persistent_runtime_variable(variable: dict | None) -> bool:
return get_safe_runtime_variable_scope((variable or {}).get("scope")) == "persistent"
def get_persistent_runtime_variables(variables: list[dict] | None) -> list[dict]:
return [
variable
for variable in variables or []
if isinstance(variable, dict) and variable.get("id") and is_persistent_runtime_variable(variable)
]
def _safe_number(value: object, fallback: float = 0) -> float | int:
try:
parsed = float(value)
except (TypeError, ValueError):
parsed = float(fallback)
return int(parsed) if parsed.is_integer() else parsed
def _number_bound(value: object) -> float | None:
if value is None or isinstance(value, bool):
return None
try:
return float(value)
except (TypeError, ValueError):
return None
def coerce_persistent_runtime_variable_value(variable: dict, value: object) -> object:
variable_type = str(variable.get("type") or "string").strip().lower()
fallback = variable.get("defaultValue")
if variable_type == "number":
next_value = _safe_number(value, _safe_number(fallback, 0))
min_value = _number_bound(variable.get("min", variable.get("minValue")))
max_value = _number_bound(variable.get("max", variable.get("maxValue")))
if min_value is not None:
next_value = max(float(next_value), min_value)
if max_value is not None:
next_value = min(float(next_value), max_value)
return int(next_value) if float(next_value).is_integer() else next_value
if variable_type == "boolean":
if isinstance(value, bool):
return value
if isinstance(value, str):
normalized = value.strip().lower()
if normalized in {"true", "1", "yes", "on"}:
return True
if normalized in {"false", "0", "no", "off", ""}:
return False
return fallback if isinstance(fallback, bool) else bool(value)
if value is None:
return fallback if isinstance(fallback, str) else ""
return str(value)
def _persistent_value_source(value: object) -> dict:
if not isinstance(value, dict):
return {}
nested_values = value.get("values")
return nested_values if isinstance(nested_values, dict) else value
def sanitize_persistent_runtime_variable_state(
value: object,
variables: list[dict] | None,
) -> dict[str, object]:
source = _persistent_value_source(value)
result: dict[str, object] = {}
for variable in get_persistent_runtime_variables(variables):
variable_id = str(variable.get("id") or "")
raw_value = source.get(variable_id, variable.get("defaultValue"))
result[variable_id] = coerce_persistent_runtime_variable_value(variable, raw_value)
return result
def merge_persistent_runtime_variable_state(
variable_state: dict | None,
variables: list[dict] | None,
persistent_state: object,
) -> dict[str, object]:
merged = dict(variable_state) if isinstance(variable_state, dict) else {}
merged.update(sanitize_persistent_runtime_variable_state(persistent_state, variables))
return merged
def collect_persistent_runtime_variable_state(
variable_state: dict | None,
variables: list[dict] | None,
) -> dict[str, object]:
return sanitize_persistent_runtime_variable_state(variable_state or {}, variables)
def build_persistent_runtime_variable_store(
variable_state: dict | None,
variables: list[dict] | None,
*,
updated_at: str = "",
) -> dict[str, Any]:
return {
"formatVersion": PERSISTENT_VARIABLE_STORE_FORMAT_VERSION,
"updatedAt": str(updated_at or ""),
"values": collect_persistent_runtime_variable_state(variable_state, variables),
}
def get_persistent_runtime_variable_summary(
variable_state: dict | None,
variables: list[dict] | None,
) -> dict[str, Any]:
definitions = get_persistent_runtime_variables(variables)
values = sanitize_persistent_runtime_variable_state(variable_state or {}, variables)
changed_count = sum(
1
for variable in definitions
if values.get(str(variable.get("id") or ""))
!= coerce_persistent_runtime_variable_value(variable, variable.get("defaultValue"))
)
return {
"count": len(definitions),
"changedCount": changed_count,
"values": values,
}