PySerials 0.0.0.dev28__py3-none-any.whl → 0.0.0.dev30__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PySerials-0.0.0.dev28.dist-info → PySerials-0.0.0.dev30.dist-info}/METADATA +3 -3
- {PySerials-0.0.0.dev28.dist-info → PySerials-0.0.0.dev30.dist-info}/RECORD +6 -6
- pyserials/nested_dict.py +3 -3
- pyserials/update.py +86 -15
- {PySerials-0.0.0.dev28.dist-info → PySerials-0.0.0.dev30.dist-info}/WHEEL +0 -0
- {PySerials-0.0.0.dev28.dist-info → PySerials-0.0.0.dev30.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PySerials
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev30
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: jsonschema <5,>=4.21.0
|
|
6
6
|
Requires-Dist: referencing >=0.35.1
|
|
@@ -8,7 +8,7 @@ Requires-Dist: jsonpath-ng <2,>=1.6.1
|
|
|
8
8
|
Requires-Dist: ruamel.yaml <0.18,>=0.17.32
|
|
9
9
|
Requires-Dist: ruamel.yaml.string <1,>=0.1.1
|
|
10
10
|
Requires-Dist: tomlkit <0.12,>=0.11.8
|
|
11
|
-
Requires-Dist: MDit ==0.0.0.
|
|
12
|
-
Requires-Dist: ExceptionMan ==0.0.0.
|
|
11
|
+
Requires-Dist: MDit ==0.0.0.dev27
|
|
12
|
+
Requires-Dist: ExceptionMan ==0.0.0.dev27
|
|
13
13
|
Requires-Dist: ProtocolMan ==0.0.0.dev2
|
|
14
14
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
pyserials/__init__.py,sha256=-ySdqDuoUXdi2Pa8uuFa5m1CTAtbZS3SWc5qzaOdR5o,142
|
|
2
2
|
pyserials/compare.py,sha256=j62A1UIiAm08_xONlbZmU2EcH1GMEpDyEQH66dZ2YMM,1297
|
|
3
3
|
pyserials/format.py,sha256=dTukpab6WHSyVRQ9SteY5fhr3GFjWFboEl-1cw_udVY,1729
|
|
4
|
-
pyserials/nested_dict.py,sha256=
|
|
4
|
+
pyserials/nested_dict.py,sha256=FfdFDoVPGKsKp_Yhh0a4DN-YveTgNvremaan73rw5Po,4038
|
|
5
5
|
pyserials/read.py,sha256=uucYQH1V4GStwRgRZ2eQIXkH4ukB5qz0EA885grwi68,6592
|
|
6
|
-
pyserials/update.py,sha256=
|
|
6
|
+
pyserials/update.py,sha256=Y4C4YxKQNiX27ymxpKqWNK-PZT5YZUA_0k4TzKSiaIE,13221
|
|
7
7
|
pyserials/validate.py,sha256=ti0D_yLzB_HELvf1d5qrarx1Ac-opBMN1Xh5lADRAQU,3664
|
|
8
8
|
pyserials/write.py,sha256=pN8w78qVsKJjZd_jvPUcZjYp_RJkP7uQzpiXvPOv4lM,1776
|
|
9
9
|
pyserials/exception/__init__.py,sha256=ZhbggwJUMlTyBhifAivC8ZQxP1Na6lJAwzZs7_YjOSU,151
|
|
@@ -11,7 +11,7 @@ pyserials/exception/_base.py,sha256=IdaZwBPBYgiUaWnvN0eMXvQQBqLbN1t766034CK7Hlc,
|
|
|
11
11
|
pyserials/exception/read.py,sha256=QyG6ulExXH9u8oDRjUfter70SMDVQqL4nig5s-JzWN4,9252
|
|
12
12
|
pyserials/exception/update.py,sha256=P0js2-iY2fgO_KLdqedgWE3TTS5Xz15cusZY_wuKIW4,4222
|
|
13
13
|
pyserials/exception/validate.py,sha256=7UkQEEqCa8HJ20gpTFnLDhT3P5OPLD2oD9fUK2Jcuns,7466
|
|
14
|
-
PySerials-0.0.0.
|
|
15
|
-
PySerials-0.0.0.
|
|
16
|
-
PySerials-0.0.0.
|
|
17
|
-
PySerials-0.0.0.
|
|
14
|
+
PySerials-0.0.0.dev30.dist-info/METADATA,sha256=NW75-UoA0NqjlI_psM1Cp8gQ_mPvKpZwkF-j6JqNQa0,438
|
|
15
|
+
PySerials-0.0.0.dev30.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
16
|
+
PySerials-0.0.0.dev30.dist-info/top_level.txt,sha256=SAks7WjSjdkv3i9Hvt4gY_P7VQbhhYJN5mf5dqx1aao,10
|
|
17
|
+
PySerials-0.0.0.dev30.dist-info/RECORD,,
|
pyserials/nested_dict.py
CHANGED
|
@@ -19,7 +19,7 @@ class NestedDict:
|
|
|
19
19
|
template_marker_unpack_end: str = "}}",
|
|
20
20
|
template_implicit_root: bool = True,
|
|
21
21
|
template_stringer: Callable[[str], str] = str,
|
|
22
|
-
|
|
22
|
+
relative_template_keys: list[str] | None = None,
|
|
23
23
|
):
|
|
24
24
|
self._data = data or {}
|
|
25
25
|
self._templater = _ps.update.TemplateFiller(
|
|
@@ -30,7 +30,7 @@ class NestedDict:
|
|
|
30
30
|
implicit_root=template_implicit_root,
|
|
31
31
|
stringer=template_stringer,
|
|
32
32
|
)
|
|
33
|
-
self.
|
|
33
|
+
self._relative_template_keys = relative_template_keys
|
|
34
34
|
return
|
|
35
35
|
|
|
36
36
|
def fill(
|
|
@@ -67,7 +67,7 @@ class NestedDict:
|
|
|
67
67
|
current_path=current_path,
|
|
68
68
|
always_list=always_list,
|
|
69
69
|
recursive=recursive,
|
|
70
|
-
|
|
70
|
+
relative_template_keys=self._relative_template_keys,
|
|
71
71
|
)
|
|
72
72
|
|
|
73
73
|
def __call__(self):
|
pyserials/update.py
CHANGED
|
@@ -8,7 +8,7 @@ from jsonpath_ng import exceptions as _jsonpath_exceptions
|
|
|
8
8
|
import pyserials.exception as _exception
|
|
9
9
|
|
|
10
10
|
if _TYPE_CHECKING:
|
|
11
|
-
from typing import Literal, Callable
|
|
11
|
+
from typing import Literal, Callable, Sequence
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def dict_from_addon(
|
|
@@ -87,6 +87,18 @@ def data_from_jsonschema(data: dict | list, schema: dict) -> None:
|
|
|
87
87
|
return
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def remove_keys(data: dict | list, keys: str | Sequence[str]):
|
|
91
|
+
def recursive_pop(d):
|
|
92
|
+
if isinstance(d, dict):
|
|
93
|
+
return {k: recursive_pop(v) for k, v in d.items() if k not in keys}
|
|
94
|
+
if isinstance(d, list):
|
|
95
|
+
return [recursive_pop(v) for v in d]
|
|
96
|
+
return d
|
|
97
|
+
if isinstance(keys, str):
|
|
98
|
+
keys = [keys]
|
|
99
|
+
return recursive_pop(data)
|
|
100
|
+
|
|
101
|
+
|
|
90
102
|
class TemplateFiller:
|
|
91
103
|
|
|
92
104
|
def __init__(
|
|
@@ -115,7 +127,8 @@ class TemplateFiller:
|
|
|
115
127
|
self._recursive = None
|
|
116
128
|
self._path = None
|
|
117
129
|
self._raise_no_match = None
|
|
118
|
-
self.
|
|
130
|
+
self._template_keys = None
|
|
131
|
+
self._ignore_templates = True
|
|
119
132
|
return
|
|
120
133
|
|
|
121
134
|
def fill(
|
|
@@ -126,20 +139,41 @@ class TemplateFiller:
|
|
|
126
139
|
always_list: bool = True,
|
|
127
140
|
recursive: bool = True,
|
|
128
141
|
raise_no_match: bool = True,
|
|
129
|
-
|
|
142
|
+
relative_template_keys: list[str] | None = None,
|
|
130
143
|
):
|
|
131
144
|
self._data = templated_data
|
|
132
145
|
self._source = source_data
|
|
133
146
|
self._recursive = recursive
|
|
134
147
|
self._raise_no_match = raise_no_match
|
|
135
|
-
self.
|
|
148
|
+
self._template_keys = relative_template_keys or []
|
|
149
|
+
path = (f"$.{current_path}" if self._add_prefix else current_path) if current_path else "$"
|
|
150
|
+
if not relative_template_keys:
|
|
151
|
+
self._ignore_templates = False
|
|
152
|
+
return self._recursive_subst(
|
|
153
|
+
templ=self._data,
|
|
154
|
+
current_path=path,
|
|
155
|
+
always_list=always_list,
|
|
156
|
+
relative_path_anchor=path,
|
|
157
|
+
)
|
|
158
|
+
self._ignore_templates = True
|
|
159
|
+
first_pass = self._recursive_subst(
|
|
160
|
+
templ=self._data,
|
|
161
|
+
current_path=path,
|
|
162
|
+
always_list=always_list,
|
|
163
|
+
relative_path_anchor=path,
|
|
164
|
+
)
|
|
165
|
+
if self._data is self._source:
|
|
166
|
+
self._source = first_pass
|
|
167
|
+
self._data = first_pass
|
|
168
|
+
self._ignore_templates = False
|
|
136
169
|
return self._recursive_subst(
|
|
137
170
|
templ=self._data,
|
|
138
|
-
current_path=
|
|
139
|
-
always_list=always_list
|
|
171
|
+
current_path=path,
|
|
172
|
+
always_list=always_list,
|
|
173
|
+
relative_path_anchor=path,
|
|
140
174
|
)
|
|
141
175
|
|
|
142
|
-
def _recursive_subst(self, templ, current_path: str, always_list: bool):
|
|
176
|
+
def _recursive_subst(self, templ, current_path: str, always_list: bool, relative_path_anchor: str):
|
|
143
177
|
|
|
144
178
|
def raise_error(
|
|
145
179
|
path_invalid: str,
|
|
@@ -173,7 +207,7 @@ class TemplateFiller:
|
|
|
173
207
|
left_matches = _rec_match(expr.left)
|
|
174
208
|
for left_match in left_matches:
|
|
175
209
|
left_match_filled = self._recursive_subst(
|
|
176
|
-
left_match.value, current_path=str(expr.left), always_list=False
|
|
210
|
+
left_match.value, current_path=str(expr.left), always_list=False, relative_path_anchor=str(expr.left)
|
|
177
211
|
) if isinstance(left_match.value, str) else left_match.value
|
|
178
212
|
right_matches = expr.right.find(left_match_filled)
|
|
179
213
|
whole_matches.extend(right_matches)
|
|
@@ -192,8 +226,13 @@ class TemplateFiller:
|
|
|
192
226
|
path_invalid=path,
|
|
193
227
|
description_template="JSONPath expression {path_invalid} is invalid.",
|
|
194
228
|
)
|
|
229
|
+
if self._ignore_templates:
|
|
230
|
+
path_fields = self._extract_fields(path_expr)
|
|
231
|
+
has_template_key = any(field in self._template_keys for field in path_fields)
|
|
232
|
+
if has_template_key:
|
|
233
|
+
return re_match.string
|
|
195
234
|
if num_periods:
|
|
196
|
-
root_path_expr = _jsonpath.parse(
|
|
235
|
+
root_path_expr = _jsonpath.parse(relative_path_anchor)
|
|
197
236
|
for period in range(num_periods):
|
|
198
237
|
if isinstance(root_path_expr, _jsonpath.Root):
|
|
199
238
|
raise_error(
|
|
@@ -219,10 +258,24 @@ class TemplateFiller:
|
|
|
219
258
|
output = values[0] if single else values
|
|
220
259
|
if not self._recursive:
|
|
221
260
|
return output
|
|
222
|
-
|
|
261
|
+
if relative_path_anchor == current_path:
|
|
262
|
+
path_fields = self._extract_fields(jsonpath)
|
|
263
|
+
has_template_key = any(field in self._template_keys for field in path_fields)
|
|
264
|
+
_rel_path_anchor = current_path if has_template_key else str(jsonpath)
|
|
265
|
+
else:
|
|
266
|
+
_rel_path_anchor = relative_path_anchor
|
|
267
|
+
return self._recursive_subst(
|
|
268
|
+
output,
|
|
269
|
+
current_path=str(jsonpath),
|
|
270
|
+
always_list=always_list,
|
|
271
|
+
relative_path_anchor=_rel_path_anchor
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
def get_relative_path(new_path):
|
|
275
|
+
return new_path if current_path == relative_path_anchor else relative_path_anchor
|
|
223
276
|
|
|
224
277
|
if isinstance(templ, str):
|
|
225
|
-
match_whole_str = self._pattern_template.fullmatch(templ)
|
|
278
|
+
match_whole_str = self._pattern_template.fullmatch(templ) or self._pattern_template_unpack.fullmatch(templ)
|
|
226
279
|
if match_whole_str:
|
|
227
280
|
return get_address_value(match_whole_str)
|
|
228
281
|
return self._pattern_template.sub(
|
|
@@ -232,8 +285,9 @@ class TemplateFiller:
|
|
|
232
285
|
if isinstance(templ, list):
|
|
233
286
|
out = []
|
|
234
287
|
for idx, elem in enumerate(templ):
|
|
288
|
+
new_path = f"{current_path}[{idx}]"
|
|
235
289
|
elem_filled = self._recursive_subst(
|
|
236
|
-
elem,
|
|
290
|
+
templ=elem, current_path=new_path, always_list=always_list, relative_path_anchor=get_relative_path(new_path),
|
|
237
291
|
)
|
|
238
292
|
if isinstance(elem, str) and self._pattern_template_unpack.fullmatch(elem):
|
|
239
293
|
out.extend(elem_filled)
|
|
@@ -243,12 +297,15 @@ class TemplateFiller:
|
|
|
243
297
|
if isinstance(templ, dict):
|
|
244
298
|
new_dict = {}
|
|
245
299
|
for key, val in templ.items():
|
|
246
|
-
key_filled = self._recursive_subst(
|
|
247
|
-
|
|
300
|
+
key_filled = self._recursive_subst(
|
|
301
|
+
templ=key, current_path=current_path, always_list=False, relative_path_anchor=relative_path_anchor,
|
|
302
|
+
)
|
|
303
|
+
if key_filled in self._template_keys:
|
|
248
304
|
new_dict[key_filled] = val
|
|
249
305
|
continue
|
|
306
|
+
new_path = f"{current_path}.'{key_filled}'"
|
|
250
307
|
new_dict[key_filled] = self._recursive_subst(
|
|
251
|
-
val,
|
|
308
|
+
templ=val, current_path=new_path, always_list=always_list, relative_path_anchor=get_relative_path(new_path),
|
|
252
309
|
)
|
|
253
310
|
return new_dict
|
|
254
311
|
return templ
|
|
@@ -264,3 +321,17 @@ class TemplateFiller:
|
|
|
264
321
|
num_periods = 0
|
|
265
322
|
rest_of_string = s
|
|
266
323
|
return rest_of_string, num_periods
|
|
324
|
+
|
|
325
|
+
@staticmethod
|
|
326
|
+
def _extract_fields(jsonpath):
|
|
327
|
+
def _recursive_extract(expr):
|
|
328
|
+
if hasattr(expr, "fields"):
|
|
329
|
+
fields.extend(expr.fields)
|
|
330
|
+
if hasattr(expr, "right"):
|
|
331
|
+
_recursive_extract(expr.right)
|
|
332
|
+
if hasattr(expr, "left"):
|
|
333
|
+
_recursive_extract(expr.left)
|
|
334
|
+
return
|
|
335
|
+
fields = []
|
|
336
|
+
_recursive_extract(jsonpath)
|
|
337
|
+
return fields
|
|
File without changes
|
|
File without changes
|