PySerials 0.0.0.dev32__tar.gz → 0.0.0.dev33__tar.gz
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.dev32 → pyserials-0.0.0.dev33}/PKG-INFO +3 -3
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/pyproject.toml +3 -3
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/PySerials.egg-info/PKG-INFO +3 -3
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/PySerials.egg-info/requires.txt +2 -2
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/nested_dict.py +18 -52
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/update.py +169 -160
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/README.md +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/setup.cfg +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/PySerials.egg-info/SOURCES.txt +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/PySerials.egg-info/dependency_links.txt +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/PySerials.egg-info/not-zip-safe +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/PySerials.egg-info/top_level.txt +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/__init__.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/compare.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/exception/__init__.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/exception/_base.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/exception/read.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/exception/update.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/exception/validate.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/format.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/read.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/validate.py +0 -0
- {pyserials-0.0.0.dev32 → pyserials-0.0.0.dev33}/src/pyserials/write.py +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.dev33
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: jsonschema<5,>=4.21.0
|
|
6
6
|
Requires-Dist: referencing>=0.35.1
|
|
@@ -8,6 +8,6 @@ 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.dev30
|
|
12
|
+
Requires-Dist: ExceptionMan==0.0.0.dev30
|
|
13
13
|
Requires-Dist: ProtocolMan==0.0.0.dev2
|
|
@@ -17,7 +17,7 @@ namespaces = true
|
|
|
17
17
|
# ----------------------------------------- Project Metadata -------------------------------------
|
|
18
18
|
#
|
|
19
19
|
[project]
|
|
20
|
-
version = "0.0.0.
|
|
20
|
+
version = "0.0.0.dev33"
|
|
21
21
|
name = "PySerials"
|
|
22
22
|
dependencies = [
|
|
23
23
|
"jsonschema >= 4.21.0, < 5",
|
|
@@ -26,8 +26,8 @@ dependencies = [
|
|
|
26
26
|
"ruamel.yaml >= 0.17.32, < 0.18", # https://yaml.readthedocs.io/en/stable/
|
|
27
27
|
"ruamel.yaml.string >= 0.1.1, < 1",
|
|
28
28
|
"tomlkit >= 0.11.8, < 0.12", # https://tomlkit.readthedocs.io/en/stable/,
|
|
29
|
-
"MDit == 0.0.0.
|
|
30
|
-
"ExceptionMan == 0.0.0.
|
|
29
|
+
"MDit == 0.0.0.dev30",
|
|
30
|
+
"ExceptionMan == 0.0.0.dev30",
|
|
31
31
|
"ProtocolMan == 0.0.0.dev2",
|
|
32
32
|
]
|
|
33
33
|
requires-python = ">=3.10"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PySerials
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev33
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: jsonschema<5,>=4.21.0
|
|
6
6
|
Requires-Dist: referencing>=0.35.1
|
|
@@ -8,6 +8,6 @@ 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.dev30
|
|
12
|
+
Requires-Dist: ExceptionMan==0.0.0.dev30
|
|
13
13
|
Requires-Dist: ProtocolMan==0.0.0.dev2
|
|
@@ -24,15 +24,17 @@ class NestedDict:
|
|
|
24
24
|
end_list: str = "]]$",
|
|
25
25
|
end_unpack: str = "}}*",
|
|
26
26
|
end_code: str = "}}#",
|
|
27
|
-
recursive: bool = True,
|
|
28
27
|
raise_no_match: bool = True,
|
|
29
28
|
leave_no_match: bool = False,
|
|
30
29
|
no_match_value: Any = None,
|
|
31
30
|
code_context: dict[str, Any] | None = None,
|
|
31
|
+
code_context_partial: dict[str, Callable | tuple[Callable, str]] | None = None,
|
|
32
|
+
code_context_call: dict[str, Callable[[Callable], Any]] | None = None,
|
|
32
33
|
stringer: Callable[[str], str] = str,
|
|
33
34
|
unpack_string_joiner: str = ", ",
|
|
34
35
|
relative_template_keys: list[str] | None = None,
|
|
35
36
|
implicit_root: bool = True,
|
|
37
|
+
getter_function_name: str = "get",
|
|
36
38
|
):
|
|
37
39
|
self._data = data or {}
|
|
38
40
|
self._templater = _ps.update.TemplateFiller(
|
|
@@ -47,29 +49,21 @@ class NestedDict:
|
|
|
47
49
|
end_list=end_list,
|
|
48
50
|
end_unpack=end_unpack,
|
|
49
51
|
end_code=end_code,
|
|
52
|
+
raise_no_match=raise_no_match,
|
|
53
|
+
leave_no_match=leave_no_match,
|
|
54
|
+
no_match_value=no_match_value,
|
|
55
|
+
code_context=code_context,
|
|
56
|
+
code_context_partial=code_context_partial,
|
|
57
|
+
code_context_call=code_context_call,
|
|
58
|
+
stringer=stringer,
|
|
59
|
+
unpack_string_joiner=unpack_string_joiner,
|
|
60
|
+
relative_template_keys=relative_template_keys,
|
|
61
|
+
implicit_root=implicit_root,
|
|
62
|
+
getter_function_name=getter_function_name,
|
|
50
63
|
)
|
|
51
|
-
self._recursive = recursive
|
|
52
|
-
self._raise_no_match = raise_no_match
|
|
53
|
-
self._leave_no_match = leave_no_match
|
|
54
|
-
self._no_match_value = no_match_value
|
|
55
|
-
self._code_context = code_context or {}
|
|
56
|
-
self._stringer = stringer
|
|
57
|
-
self._unpack_string_joiner = unpack_string_joiner
|
|
58
|
-
self._relative_template_keys = relative_template_keys or []
|
|
59
|
-
self._implicit_root = implicit_root
|
|
60
64
|
return
|
|
61
65
|
|
|
62
|
-
def fill(
|
|
63
|
-
self,
|
|
64
|
-
path: str = "",
|
|
65
|
-
recursive: bool | None = None,
|
|
66
|
-
raise_no_match: bool | None = None,
|
|
67
|
-
leave_no_match: bool | None = None,
|
|
68
|
-
code_context: dict[str, Any] | None = None,
|
|
69
|
-
stringer: Callable[[str], str] | None = None,
|
|
70
|
-
unpack_string_joiner: str | None = None,
|
|
71
|
-
level: int = 0,
|
|
72
|
-
):
|
|
66
|
+
def fill(self, path: str = ""):
|
|
73
67
|
if not path:
|
|
74
68
|
value = self._data
|
|
75
69
|
else:
|
|
@@ -79,13 +73,6 @@ class NestedDict:
|
|
|
79
73
|
filled_value = self.fill_data(
|
|
80
74
|
data=value,
|
|
81
75
|
current_path=path,
|
|
82
|
-
recursive=recursive,
|
|
83
|
-
raise_no_match=raise_no_match,
|
|
84
|
-
leave_no_match=leave_no_match,
|
|
85
|
-
code_context=code_context,
|
|
86
|
-
stringer=stringer,
|
|
87
|
-
unpack_string_joiner=unpack_string_joiner,
|
|
88
|
-
level=level,
|
|
89
76
|
)
|
|
90
77
|
if not path:
|
|
91
78
|
self._data = filled_value
|
|
@@ -93,32 +80,11 @@ class NestedDict:
|
|
|
93
80
|
self.__setitem__(path, filled_value)
|
|
94
81
|
return filled_value
|
|
95
82
|
|
|
96
|
-
def fill_data(
|
|
97
|
-
self,
|
|
98
|
-
data,
|
|
99
|
-
current_path: str = "",
|
|
100
|
-
recursive: bool | None = None,
|
|
101
|
-
raise_no_match: bool | None = None,
|
|
102
|
-
leave_no_match: bool | None = None,
|
|
103
|
-
stringer: Callable[[str], str] | None = None,
|
|
104
|
-
code_context: dict[str, Any] | None = None,
|
|
105
|
-
unpack_string_joiner: str | None = None,
|
|
106
|
-
level: int = 0,
|
|
107
|
-
):
|
|
83
|
+
def fill_data(self, data, current_path: str = ""):
|
|
108
84
|
return self._templater.fill(
|
|
109
|
-
|
|
110
|
-
|
|
85
|
+
data=self._data,
|
|
86
|
+
template=data,
|
|
111
87
|
current_path=current_path,
|
|
112
|
-
recursive=recursive if recursive is not None else self._recursive,
|
|
113
|
-
raise_no_match=raise_no_match if raise_no_match is not None else self._raise_no_match,
|
|
114
|
-
leave_no_match=leave_no_match if leave_no_match is not None else self._leave_no_match,
|
|
115
|
-
no_match_value=self._no_match_value,
|
|
116
|
-
code_context=code_context if code_context is not None else self._code_context,
|
|
117
|
-
stringer=stringer if stringer is not None else self._stringer,
|
|
118
|
-
unpack_string_joiner=unpack_string_joiner if unpack_string_joiner is not None else self._unpack_string_joiner,
|
|
119
|
-
relative_template_keys=self._relative_template_keys,
|
|
120
|
-
implicit_root=self._implicit_root,
|
|
121
|
-
level=level,
|
|
122
88
|
)
|
|
123
89
|
|
|
124
90
|
def __call__(self):
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations as _annotations
|
|
|
3
3
|
import re
|
|
4
4
|
from typing import TYPE_CHECKING as _TYPE_CHECKING
|
|
5
5
|
import re as _re
|
|
6
|
+
from functools import partial as _partial
|
|
6
7
|
|
|
7
8
|
import jsonpath_ng as _jsonpath
|
|
8
9
|
from jsonpath_ng import exceptions as _jsonpath_exceptions
|
|
@@ -116,6 +117,17 @@ class TemplateFiller:
|
|
|
116
117
|
end_list: str = "]]$",
|
|
117
118
|
end_unpack: str = "}}*",
|
|
118
119
|
end_code: str = "}}#",
|
|
120
|
+
raise_no_match: bool = True,
|
|
121
|
+
leave_no_match: bool = False,
|
|
122
|
+
no_match_value: Any = None,
|
|
123
|
+
code_context: dict[str, Any] | None = None,
|
|
124
|
+
code_context_partial: dict[str, Callable | tuple[Callable, str]] | None = None,
|
|
125
|
+
code_context_call: dict[str, Callable[[Callable], Any]] | None = None,
|
|
126
|
+
stringer: Callable[[str], str] = str,
|
|
127
|
+
unpack_string_joiner: str = ", ",
|
|
128
|
+
relative_template_keys: list[str] | None = None,
|
|
129
|
+
implicit_root: bool = True,
|
|
130
|
+
getter_function_name: str = "get",
|
|
119
131
|
):
|
|
120
132
|
self._marker_start_value = marker_start_value
|
|
121
133
|
self._marker_end_value = marker_end_value
|
|
@@ -125,99 +137,64 @@ class TemplateFiller:
|
|
|
125
137
|
self._pattern_list = _RegexPattern(start=start_list, end=end_list)
|
|
126
138
|
self._pattern_unpack = _RegexPattern(start=start_unpack, end=end_unpack)
|
|
127
139
|
self._pattern_code = _RegexPattern(start=start_code, end=end_code)
|
|
128
|
-
self._add_prefix = True
|
|
129
|
-
|
|
130
|
-
self._pattern_value: dict[int, _RegexPattern] = {}
|
|
131
|
-
self._data = None
|
|
132
|
-
self._source = None
|
|
133
|
-
self._recursive = None
|
|
134
|
-
self._path = None
|
|
135
|
-
self._raise_no_match = None
|
|
136
|
-
self._template_keys = None
|
|
137
|
-
self._ignore_templates = True
|
|
138
|
-
self._leave_no_match = False
|
|
139
|
-
self._no_match_value = None
|
|
140
|
-
self._code_context = {}
|
|
141
|
-
self._stringer = str
|
|
142
|
-
self._unpack_string_joiner = ", "
|
|
143
|
-
self._path_history = []
|
|
144
|
-
return
|
|
145
|
-
|
|
146
|
-
def _get_value_regex_pattern(self, level: int = 0) -> _RegexPattern:
|
|
147
|
-
level_patterns = self._pattern_value.setdefault(level, {})
|
|
148
|
-
if level in level_patterns:
|
|
149
|
-
return level_patterns[level]
|
|
150
|
-
count = self._repeater_count_value + level
|
|
151
|
-
pattern = _RegexPattern(
|
|
152
|
-
start=f"{self._marker_start_value}{self._repeater_start_value * count} ",
|
|
153
|
-
end=f" {self._repeater_end_value * count}{self._marker_end_value}",
|
|
154
|
-
)
|
|
155
|
-
level_patterns[level] = pattern
|
|
156
|
-
return pattern
|
|
157
140
|
|
|
158
|
-
def fill(
|
|
159
|
-
self,
|
|
160
|
-
templated_data: dict | list | str,
|
|
161
|
-
source_data: dict | list,
|
|
162
|
-
current_path: str = "",
|
|
163
|
-
recursive: bool = True,
|
|
164
|
-
raise_no_match: bool = True,
|
|
165
|
-
leave_no_match: bool = False,
|
|
166
|
-
no_match_value: Any = None,
|
|
167
|
-
code_context: dict[str, Any] | None = None,
|
|
168
|
-
stringer: Callable[[str], str] = str,
|
|
169
|
-
unpack_string_joiner: str = ", ",
|
|
170
|
-
relative_template_keys: list[str] | None = None,
|
|
171
|
-
implicit_root: bool = True,
|
|
172
|
-
level: int = 0,
|
|
173
|
-
):
|
|
174
|
-
self._data = templated_data
|
|
175
|
-
self._source = source_data
|
|
176
|
-
self._recursive = recursive
|
|
177
141
|
self._raise_no_match = raise_no_match
|
|
178
142
|
self._leave_no_match = leave_no_match
|
|
179
143
|
self._no_match_value = no_match_value
|
|
180
144
|
self._code_context = code_context or {}
|
|
145
|
+
self._code_context_partial = code_context_partial or {}
|
|
146
|
+
self._code_context_call = code_context_call or {}
|
|
181
147
|
self._stringer = stringer
|
|
182
148
|
self._unpack_string_joiner = unpack_string_joiner
|
|
183
149
|
self._add_prefix = implicit_root
|
|
184
150
|
self._template_keys = relative_template_keys or []
|
|
185
|
-
self.
|
|
151
|
+
self._getter_function_name = getter_function_name
|
|
152
|
+
|
|
153
|
+
self._pattern_value: dict[int, _RegexPattern] = {}
|
|
154
|
+
self._data = None
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
def fill(
|
|
158
|
+
self,
|
|
159
|
+
data: dict | list,
|
|
160
|
+
template: dict | list | str | None = None,
|
|
161
|
+
current_path: str = "",
|
|
162
|
+
):
|
|
163
|
+
self._data = data
|
|
186
164
|
path = (f"$.{current_path}" if self._add_prefix else current_path) if current_path else "$"
|
|
187
|
-
if not relative_template_keys:
|
|
188
|
-
self._ignore_templates = False
|
|
189
|
-
return self._recursive_subst(
|
|
190
|
-
templ=self._data,
|
|
191
|
-
current_path=path,
|
|
192
|
-
relative_path_anchor=path,
|
|
193
|
-
level=level,
|
|
194
|
-
)
|
|
195
|
-
self._ignore_templates = True
|
|
196
|
-
first_pass = self._recursive_subst(
|
|
197
|
-
templ=self._data,
|
|
198
|
-
current_path=path,
|
|
199
|
-
relative_path_anchor=path,
|
|
200
|
-
level=level,
|
|
201
|
-
)
|
|
202
|
-
if self._data is self._source:
|
|
203
|
-
self._source = first_pass
|
|
204
|
-
self._data = first_pass
|
|
205
|
-
self._ignore_templates = False
|
|
206
|
-
self._path_history = []
|
|
207
165
|
return self._recursive_subst(
|
|
208
|
-
templ=
|
|
166
|
+
templ=template or data,
|
|
209
167
|
current_path=path,
|
|
210
168
|
relative_path_anchor=path,
|
|
211
|
-
level=
|
|
169
|
+
level=0,
|
|
170
|
+
current_chain=[path],
|
|
212
171
|
)
|
|
213
172
|
|
|
214
|
-
def _recursive_subst(self, templ, current_path: str, relative_path_anchor: str, level: int,
|
|
173
|
+
def _recursive_subst(self, templ, current_path: str, relative_path_anchor: str, level: int, current_chain: list[str]):
|
|
174
|
+
|
|
175
|
+
def get_code_value(match: _re.Match | str):
|
|
176
|
+
|
|
177
|
+
def getter_function(path: str, default: Any = None, search: bool = False):
|
|
178
|
+
value, matched = get_address_value(path, return_all_matches=search, from_code=True)
|
|
179
|
+
if matched:
|
|
180
|
+
return value
|
|
181
|
+
if search:
|
|
182
|
+
return []
|
|
183
|
+
return default
|
|
215
184
|
|
|
216
|
-
|
|
185
|
+
code_str = match if isinstance(match, str) else match.group(1)
|
|
217
186
|
code_lines = ["def __inline_code__():"]
|
|
218
187
|
code_lines.extend([f" {line}" for line in code_str.strip("\n").splitlines()])
|
|
219
188
|
code_str_full = "\n".join(code_lines)
|
|
220
|
-
global_context = self._code_context.copy()
|
|
189
|
+
global_context = self._code_context.copy() | {self._getter_function_name: getter_function}
|
|
190
|
+
for name, partial_func_data in self._code_context_partial.items():
|
|
191
|
+
if isinstance(partial_func_data, tuple):
|
|
192
|
+
func, arg_name = partial_func_data
|
|
193
|
+
global_context[name] = _partial(func, **{arg_name: getter_function})
|
|
194
|
+
else:
|
|
195
|
+
global_context[name] = _partial(partial_func_data, getter_function)
|
|
196
|
+
for name, call_func in self._code_context_call.items():
|
|
197
|
+
global_context[name] = call_func(getter_function)
|
|
221
198
|
local_context = {}
|
|
222
199
|
try:
|
|
223
200
|
exec(code_str_full, global_context, local_context)
|
|
@@ -228,8 +205,9 @@ class TemplateFiller:
|
|
|
228
205
|
path_invalid=current_path,
|
|
229
206
|
)
|
|
230
207
|
|
|
231
|
-
def get_address_value(
|
|
232
|
-
|
|
208
|
+
def get_address_value(match: _re.Match | str, return_all_matches: bool = False, from_code: bool = False):
|
|
209
|
+
raw_path = match if isinstance(match, str) else str(match.group(1))
|
|
210
|
+
path, num_periods = self._remove_leading_periods(raw_path.strip())
|
|
233
211
|
if num_periods == 0:
|
|
234
212
|
path = f"$.{path}" if self._add_prefix else path
|
|
235
213
|
try:
|
|
@@ -239,13 +217,14 @@ class TemplateFiller:
|
|
|
239
217
|
path_invalid=path,
|
|
240
218
|
description_template="JSONPath expression {path_invalid} is invalid.",
|
|
241
219
|
)
|
|
242
|
-
if self._ignore_templates:
|
|
243
|
-
path_fields = self._extract_fields(path_expr)
|
|
244
|
-
has_template_key = any(field in self._template_keys for field in path_fields)
|
|
245
|
-
if has_template_key:
|
|
246
|
-
return re_match.string
|
|
247
220
|
if num_periods:
|
|
248
|
-
|
|
221
|
+
if relative_path_anchor != current_path:
|
|
222
|
+
path_fields = self._extract_fields(_jsonpath.parse(current_path))
|
|
223
|
+
has_template_key = any(field in self._template_keys for field in path_fields)
|
|
224
|
+
anchor_path = relative_path_anchor if has_template_key else current_path
|
|
225
|
+
else:
|
|
226
|
+
anchor_path = current_path
|
|
227
|
+
root_path_expr = _jsonpath.parse(anchor_path)
|
|
249
228
|
for period in range(num_periods):
|
|
250
229
|
if isinstance(root_path_expr, _jsonpath.Root):
|
|
251
230
|
raise_error(
|
|
@@ -256,17 +235,21 @@ class TemplateFiller:
|
|
|
256
235
|
),
|
|
257
236
|
)
|
|
258
237
|
root_path_expr = root_path_expr.left
|
|
259
|
-
path_expr =
|
|
260
|
-
value, matched = get_value(path_expr, return_all_matches)
|
|
238
|
+
path_expr = self._concat_json_paths(root_path_expr, path_expr)
|
|
239
|
+
value, matched = get_value(path_expr, return_all_matches, from_code)
|
|
240
|
+
if from_code:
|
|
241
|
+
return value, matched
|
|
261
242
|
if matched:
|
|
262
243
|
return value
|
|
263
244
|
if self._leave_no_match:
|
|
264
|
-
return
|
|
245
|
+
return match.group()
|
|
265
246
|
return self._no_match_value
|
|
266
247
|
|
|
267
|
-
def get_value(jsonpath, return_all_matches: bool) -> tuple[Any, bool]:
|
|
248
|
+
def get_value(jsonpath, return_all_matches: bool, from_code: bool) -> tuple[Any, bool]:
|
|
268
249
|
matches = _rec_match(jsonpath)
|
|
269
250
|
if not matches:
|
|
251
|
+
if from_code:
|
|
252
|
+
return None, False
|
|
270
253
|
if return_all_matches:
|
|
271
254
|
return [], True
|
|
272
255
|
if self._raise_no_match:
|
|
@@ -277,8 +260,6 @@ class TemplateFiller:
|
|
|
277
260
|
return None, False
|
|
278
261
|
values = [m.value for m in matches]
|
|
279
262
|
output = values if return_all_matches or len(values) > 1 else values[0]
|
|
280
|
-
if not self._recursive:
|
|
281
|
-
return output, True
|
|
282
263
|
if relative_path_anchor == current_path:
|
|
283
264
|
path_fields = self._extract_fields(jsonpath)
|
|
284
265
|
has_template_key = any(field in self._template_keys for field in path_fields)
|
|
@@ -290,10 +271,11 @@ class TemplateFiller:
|
|
|
290
271
|
current_path=str(jsonpath),
|
|
291
272
|
relative_path_anchor=_rel_path_anchor,
|
|
292
273
|
level=0,
|
|
274
|
+
current_chain=current_chain + [str(jsonpath)],
|
|
293
275
|
), True
|
|
294
276
|
|
|
295
277
|
def _rec_match(expr) -> list:
|
|
296
|
-
matches = expr.find(self.
|
|
278
|
+
matches = expr.find(self._data)
|
|
297
279
|
if matches:
|
|
298
280
|
return matches
|
|
299
281
|
if isinstance(expr.left, _jsonpath.Root):
|
|
@@ -306,6 +288,7 @@ class TemplateFiller:
|
|
|
306
288
|
current_path=str(expr.left),
|
|
307
289
|
relative_path_anchor=str(expr.left),
|
|
308
290
|
level=0,
|
|
291
|
+
current_chain=current_chain + [str(expr.left)],
|
|
309
292
|
) if isinstance(left_match.value, str) else left_match.value
|
|
310
293
|
right_matches = expr.right.find(left_match_filled)
|
|
311
294
|
whole_matches.extend(right_matches)
|
|
@@ -314,33 +297,44 @@ class TemplateFiller:
|
|
|
314
297
|
def get_relative_path(new_path):
|
|
315
298
|
return new_path if current_path == relative_path_anchor else relative_path_anchor
|
|
316
299
|
|
|
317
|
-
def
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
template_start=self._marker_start_value,
|
|
329
|
-
template_end=self._marker_end_value,
|
|
300
|
+
def fill_nested_values(match: _re.Match | str):
|
|
301
|
+
pattern_nested = self._get_value_regex_pattern(level=level + 1)
|
|
302
|
+
return pattern_nested.sub(
|
|
303
|
+
lambda x: self._recursive_subst(
|
|
304
|
+
templ=x.group(),
|
|
305
|
+
current_path=current_path,
|
|
306
|
+
relative_path_anchor=get_relative_path(current_path),
|
|
307
|
+
level=level + 1,
|
|
308
|
+
current_chain=current_chain,
|
|
309
|
+
),
|
|
310
|
+
match if isinstance(match, str) else match.group(1),
|
|
330
311
|
)
|
|
331
312
|
|
|
332
313
|
def string_filler_unpack(match: _re.Match):
|
|
333
|
-
|
|
314
|
+
path = str(match.group(1)).strip()
|
|
315
|
+
match_list = self._pattern_list.fullmatch(path)
|
|
334
316
|
if match_list:
|
|
335
317
|
values = get_address_value(match_list, return_all_matches=True)
|
|
336
318
|
else:
|
|
337
|
-
match_code = self._pattern_code.fullmatch(
|
|
319
|
+
match_code = self._pattern_code.fullmatch(path)
|
|
338
320
|
if match_code:
|
|
339
|
-
values = get_code_value(match_code
|
|
321
|
+
values = get_code_value(match_code)
|
|
340
322
|
else:
|
|
341
|
-
values = get_address_value(
|
|
323
|
+
values = get_address_value(path)
|
|
342
324
|
return self._unpack_string_joiner.join([self._stringer(val) for val in values])
|
|
343
325
|
|
|
326
|
+
def raise_error(path_invalid: str, description_template: str):
|
|
327
|
+
raise _exception.update.PySerialsUpdateTemplatedDataError(
|
|
328
|
+
description_template=description_template,
|
|
329
|
+
path_invalid=path_invalid,
|
|
330
|
+
path=current_path,
|
|
331
|
+
data=templ,
|
|
332
|
+
data_full=self._data,
|
|
333
|
+
data_source=self._data,
|
|
334
|
+
template_start=self._marker_start_value,
|
|
335
|
+
template_end=self._marker_end_value,
|
|
336
|
+
)
|
|
337
|
+
|
|
344
338
|
# if not internal:
|
|
345
339
|
# self._path_history.append(current_path)
|
|
346
340
|
# loop = self._find_loop()
|
|
@@ -358,49 +352,47 @@ class TemplateFiller:
|
|
|
358
352
|
# )
|
|
359
353
|
|
|
360
354
|
if isinstance(templ, str):
|
|
361
|
-
|
|
362
|
-
templ_nested_filled = pattern_nested.sub(
|
|
363
|
-
lambda x: self._recursive_subst(
|
|
364
|
-
templ=x.group(),
|
|
365
|
-
current_path=current_path,
|
|
366
|
-
relative_path_anchor=get_relative_path(current_path),
|
|
367
|
-
level=level+1,
|
|
368
|
-
internal=True,
|
|
369
|
-
),
|
|
370
|
-
templ
|
|
371
|
-
)
|
|
355
|
+
# Handle value blocks
|
|
372
356
|
pattern_value = self._get_value_regex_pattern(level=level)
|
|
373
|
-
|
|
374
|
-
if
|
|
375
|
-
return get_address_value(
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
submatch_code = self._pattern_code.fullmatch(
|
|
357
|
+
match_value = pattern_value.fullmatch(templ)
|
|
358
|
+
if match_value:
|
|
359
|
+
return get_address_value(fill_nested_values(match_value))
|
|
360
|
+
# Handle list blocks
|
|
361
|
+
match_list = self._pattern_list.fullmatch(templ)
|
|
362
|
+
if match_list:
|
|
363
|
+
return get_address_value(fill_nested_values(match_list), return_all_matches=True)
|
|
364
|
+
# Handle code blocks
|
|
365
|
+
match_code = self._pattern_code.fullmatch(templ)
|
|
366
|
+
if match_code:
|
|
367
|
+
return get_code_value(match_code)
|
|
368
|
+
# Handle unpack blocks
|
|
369
|
+
match_unpack = self._pattern_unpack.fullmatch(templ)
|
|
370
|
+
if match_unpack:
|
|
371
|
+
unpack_value = match_unpack.group(1)
|
|
372
|
+
submatch_code = self._pattern_code.fullmatch(unpack_value)
|
|
389
373
|
if submatch_code:
|
|
390
|
-
return get_code_value(submatch_code
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
374
|
+
return get_code_value(submatch_code)
|
|
375
|
+
unpack_value = fill_nested_values(unpack_value)
|
|
376
|
+
submatch_list = self._pattern_list.fullmatch(unpack_value)
|
|
377
|
+
if submatch_list:
|
|
378
|
+
return get_address_value(unpack_value, return_all_matches=True)
|
|
379
|
+
return get_address_value(unpack_value)
|
|
380
|
+
# Handle strings
|
|
381
|
+
code_blocks_filled = self._pattern_code.sub(
|
|
382
|
+
lambda x: self._stringer(get_code_value(x)),
|
|
383
|
+
templ
|
|
384
|
+
)
|
|
385
|
+
nested_values_filled = fill_nested_values(code_blocks_filled)
|
|
386
|
+
unpacked_filled = self._pattern_unpack.sub(string_filler_unpack, nested_values_filled)
|
|
387
|
+
lists_filled = self._pattern_list.sub(
|
|
388
|
+
lambda x: self._stringer(get_address_value(x)),
|
|
402
389
|
unpacked_filled
|
|
403
390
|
)
|
|
391
|
+
templ_values_filled = pattern_value.sub(
|
|
392
|
+
lambda x: self._stringer(get_address_value(x)),
|
|
393
|
+
lists_filled
|
|
394
|
+
)
|
|
395
|
+
return templ_values_filled
|
|
404
396
|
|
|
405
397
|
if isinstance(templ, list):
|
|
406
398
|
out = []
|
|
@@ -411,8 +403,9 @@ class TemplateFiller:
|
|
|
411
403
|
current_path=new_path,
|
|
412
404
|
relative_path_anchor=get_relative_path(new_path),
|
|
413
405
|
level=0,
|
|
406
|
+
current_chain=current_chain + [new_path],
|
|
414
407
|
)
|
|
415
|
-
if isinstance(elem, str) and self._pattern_unpack.fullmatch(elem
|
|
408
|
+
if isinstance(elem, str) and self._pattern_unpack.fullmatch(elem):
|
|
416
409
|
out.extend(elem_filled)
|
|
417
410
|
else:
|
|
418
411
|
out.append(elem_filled)
|
|
@@ -426,9 +419,9 @@ class TemplateFiller:
|
|
|
426
419
|
current_path=current_path,
|
|
427
420
|
relative_path_anchor=relative_path_anchor,
|
|
428
421
|
level=0,
|
|
429
|
-
|
|
422
|
+
current_chain=current_chain,
|
|
430
423
|
)
|
|
431
|
-
if isinstance(key, str) and self._pattern_unpack.fullmatch(key
|
|
424
|
+
if isinstance(key, str) and self._pattern_unpack.fullmatch(key):
|
|
432
425
|
new_dict.update(key_filled)
|
|
433
426
|
continue
|
|
434
427
|
if key_filled in self._template_keys:
|
|
@@ -440,20 +433,32 @@ class TemplateFiller:
|
|
|
440
433
|
current_path=new_path,
|
|
441
434
|
relative_path_anchor=get_relative_path(new_path),
|
|
442
435
|
level=0,
|
|
436
|
+
current_chain=current_chain + [new_path],
|
|
443
437
|
)
|
|
444
438
|
return new_dict
|
|
445
439
|
return templ
|
|
446
440
|
|
|
447
|
-
def _find_loop(self):
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
441
|
+
# def _find_loop(self):
|
|
442
|
+
# for pattern_length in range(1, len(self._path_history) // 2 + 1):
|
|
443
|
+
# # Slice the end of the list into two consecutive patterns
|
|
444
|
+
# pattern = self._path_history[-pattern_length:]
|
|
445
|
+
# previous_pattern = self._path_history[-2 * pattern_length:-pattern_length]
|
|
446
|
+
# # Check if the two patterns are the same
|
|
447
|
+
# if pattern == previous_pattern:
|
|
448
|
+
# pattern.insert(0, pattern[-1])
|
|
449
|
+
# return pattern
|
|
450
|
+
# return
|
|
451
|
+
|
|
452
|
+
def _get_value_regex_pattern(self, level: int = 0) -> _RegexPattern:
|
|
453
|
+
if level in self._pattern_value:
|
|
454
|
+
return self._pattern_value[level]
|
|
455
|
+
count = self._repeater_count_value + level
|
|
456
|
+
pattern = _RegexPattern(
|
|
457
|
+
start=f"{self._marker_start_value}{self._repeater_start_value * count} ",
|
|
458
|
+
end=f" {self._repeater_end_value * count}{self._marker_end_value}",
|
|
459
|
+
)
|
|
460
|
+
self._pattern_value[level] = pattern
|
|
461
|
+
return pattern
|
|
457
462
|
|
|
458
463
|
@staticmethod
|
|
459
464
|
def _remove_leading_periods(s: str) -> (str, int):
|
|
@@ -481,6 +486,10 @@ class TemplateFiller:
|
|
|
481
486
|
_recursive_extract(jsonpath)
|
|
482
487
|
return fields
|
|
483
488
|
|
|
489
|
+
def _concat_json_paths(self, path1, path2):
|
|
490
|
+
if not isinstance(path2, _jsonpath.Child):
|
|
491
|
+
return _jsonpath.Child(path1, path2)
|
|
492
|
+
return _jsonpath.Child(self._concat_json_paths(path1, path2.left), path2.right)
|
|
484
493
|
|
|
485
494
|
class _RegexPattern:
|
|
486
495
|
|
|
@@ -495,8 +504,8 @@ class _RegexPattern:
|
|
|
495
504
|
matches = self.pattern.findall(string)
|
|
496
505
|
if len(matches) == 1:
|
|
497
506
|
# Verify the match spans the entire string
|
|
498
|
-
return self.pattern.fullmatch(string)
|
|
507
|
+
return self.pattern.fullmatch(string.strip())
|
|
499
508
|
return None
|
|
500
509
|
|
|
501
510
|
def sub(self, repl, string: str) -> str:
|
|
502
|
-
return self.pattern.sub(repl, string)
|
|
511
|
+
return self.pattern.sub(repl, string)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|