PySerials 0.0.0.dev49__tar.gz → 0.0.0.dev50__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.
Files changed (24) hide show
  1. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/PKG-INFO +3 -3
  2. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/pyproject.toml +3 -3
  3. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/PySerials.egg-info/PKG-INFO +3 -3
  4. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/PySerials.egg-info/requires.txt +2 -2
  5. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/exception/update.py +3 -3
  6. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/update.py +35 -33
  7. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/README.md +0 -0
  8. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/setup.cfg +0 -0
  9. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/PySerials.egg-info/SOURCES.txt +0 -0
  10. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/PySerials.egg-info/dependency_links.txt +0 -0
  11. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/PySerials.egg-info/not-zip-safe +0 -0
  12. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/PySerials.egg-info/top_level.txt +0 -0
  13. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/__init__.py +0 -0
  14. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/compare.py +0 -0
  15. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/exception/__init__.py +0 -0
  16. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/exception/_base.py +0 -0
  17. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/exception/read.py +0 -0
  18. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/exception/validate.py +0 -0
  19. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/format.py +0 -0
  20. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/nested_dict.py +0 -0
  21. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/property_dict.py +0 -0
  22. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/read.py +0 -0
  23. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/src/pyserials/validate.py +0 -0
  24. {pyserials-0.0.0.dev49 → pyserials-0.0.0.dev50}/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.dev49
3
+ Version: 0.0.0.dev50
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.dev46
12
- Requires-Dist: ExceptionMan==0.0.0.dev46
11
+ Requires-Dist: MDit==0.0.0.dev47
12
+ Requires-Dist: ExceptionMan==0.0.0.dev47
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.dev49"
20
+ version = "0.0.0.dev50"
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.dev46",
30
- "ExceptionMan == 0.0.0.dev46",
29
+ "MDit == 0.0.0.dev47",
30
+ "ExceptionMan == 0.0.0.dev47",
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.dev49
3
+ Version: 0.0.0.dev50
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.dev46
12
- Requires-Dist: ExceptionMan==0.0.0.dev46
11
+ Requires-Dist: MDit==0.0.0.dev47
12
+ Requires-Dist: ExceptionMan==0.0.0.dev47
13
13
  Requires-Dist: ProtocolMan==0.0.0.dev2
@@ -4,6 +4,6 @@ jsonpath-ng<2,>=1.6.1
4
4
  ruamel.yaml<0.18,>=0.17.32
5
5
  ruamel.yaml.string<1,>=0.1.1
6
6
  tomlkit<0.12,>=0.11.8
7
- MDit==0.0.0.dev46
8
- ExceptionMan==0.0.0.dev46
7
+ MDit==0.0.0.dev47
8
+ ExceptionMan==0.0.0.dev47
9
9
  ProtocolMan==0.0.0.dev2
@@ -123,15 +123,15 @@ class PySerialsUpdateTemplatedDataError(PySerialsUpdateException):
123
123
  template_start: str,
124
124
  template_end: str,
125
125
  ):
126
- self.path_invalid = path_invalid.replace("'", "")
126
+ self.path_invalid = path_invalid
127
127
  self.data_source = data_source
128
128
  self.template_start = template_start
129
129
  self.template_end = template_end
130
130
  parts = description_template.split("{path_invalid}")
131
131
  if len(parts) > 1:
132
- parts.insert(1, _mdit.element.code_span(self.path_invalid))
132
+ parts.insert(1, _mdit.element.code_span(str(self.path_invalid)))
133
133
  super().__init__(
134
- path=path.replace("'", ""),
134
+ path=str(path),
135
135
  data=data,
136
136
  data_full=data_full,
137
137
  problem=_mdit.inline_container(*parts),
@@ -152,7 +152,7 @@ class TemplateFiller:
152
152
 
153
153
  self._pattern_value: dict[int, _RegexPattern] = {}
154
154
  self._data = None
155
- self._visited_paths = set()
155
+ self._visited_paths = {}
156
156
  return
157
157
 
158
158
  def fill(
@@ -162,17 +162,17 @@ class TemplateFiller:
162
162
  current_path: str = "",
163
163
  ):
164
164
  self._data = data
165
- self._visited_paths = set()
166
- path = (f"$.{current_path}" if self._add_prefix else current_path) if current_path else "$"
165
+ self._visited_paths = {}
166
+ path = _jsonpath.parse((f"$.{current_path}" if self._add_prefix else current_path) if current_path else "$")
167
167
  return self._recursive_subst(
168
168
  templ=template or data,
169
169
  current_path=path,
170
170
  relative_path_anchor=path,
171
171
  level=0,
172
- current_chain=[path],
172
+ current_chain=(path,),
173
173
  )
174
174
 
175
- def _recursive_subst(self, templ, current_path: str, relative_path_anchor: str, level: int, current_chain: list[str]):
175
+ def _recursive_subst(self, templ, current_path: str, relative_path_anchor: str, level: int, current_chain: tuple[str, ...]):
176
176
 
177
177
  def get_code_value(match: _re.Match | str):
178
178
 
@@ -207,7 +207,7 @@ class TemplateFiller:
207
207
  path_invalid=current_path,
208
208
  exception=e,
209
209
  )
210
- self._visited_paths.add(self._normalize_path(current_path))
210
+ self._visited_paths[current_path] = (output, True)
211
211
  return output
212
212
 
213
213
  def get_address_value(match: _re.Match | str, return_all_matches: bool = False, from_code: bool = False):
@@ -219,21 +219,21 @@ class TemplateFiller:
219
219
  path_expr = _jsonpath.parse(path)
220
220
  except _jsonpath_exceptions.JSONPathError:
221
221
  raise_error(
222
- path_invalid=path,
222
+ path_invalid=path_expr,
223
223
  description_template="JSONPath expression {path_invalid} is invalid.",
224
224
  )
225
225
  if num_periods:
226
226
  if relative_path_anchor != current_path:
227
- path_fields = self._extract_fields(_jsonpath.parse(current_path))
227
+ path_fields = self._extract_fields(current_path)
228
228
  has_template_key = any(field in self._template_keys for field in path_fields)
229
229
  anchor_path = relative_path_anchor if has_template_key else current_path
230
230
  else:
231
231
  anchor_path = current_path
232
- root_path_expr = _jsonpath.parse(anchor_path)
232
+ root_path_expr = anchor_path
233
233
  for period in range(num_periods):
234
234
  if isinstance(root_path_expr, _jsonpath.Root):
235
235
  raise_error(
236
- path_invalid=path,
236
+ path_invalid=path_expr,
237
237
  description_template=(
238
238
  "Relative path {path_invalid} is invalid; "
239
239
  f"reached root but still {num_periods - period} levels remaining."
@@ -241,8 +241,8 @@ class TemplateFiller:
241
241
  )
242
242
  root_path_expr = root_path_expr.left
243
243
  path_expr = self._concat_json_paths(root_path_expr, path_expr)
244
- value, matched = get_value(path_expr, return_all_matches, from_code)
245
- self._visited_paths.add(self._normalize_path(current_path))
244
+ value, matched = self._visited_paths.get(path_expr) or get_value(path_expr, return_all_matches, from_code)
245
+ self._visited_paths[path_expr] = (value, matched)
246
246
  if from_code:
247
247
  return value, matched
248
248
  if matched:
@@ -260,7 +260,7 @@ class TemplateFiller:
260
260
  return [], True
261
261
  if self._raise_no_match:
262
262
  raise_error(
263
- path_invalid=str(jsonpath),
263
+ path_invalid=jsonpath,
264
264
  description_template="JSONPath expression {path_invalid} did not match any data.",
265
265
  )
266
266
  return None, False
@@ -274,10 +274,10 @@ class TemplateFiller:
274
274
  _rel_path_anchor = relative_path_anchor
275
275
  return self._recursive_subst(
276
276
  output,
277
- current_path=str(jsonpath),
277
+ current_path=jsonpath,
278
278
  relative_path_anchor=_rel_path_anchor,
279
279
  level=0,
280
- current_chain=current_chain + [str(jsonpath)],
280
+ current_chain=current_chain + (jsonpath,),
281
281
  ), True
282
282
 
283
283
  def _rec_match(expr) -> list:
@@ -291,10 +291,10 @@ class TemplateFiller:
291
291
  for left_match in left_matches:
292
292
  left_match_filled = self._recursive_subst(
293
293
  templ=left_match.value,
294
- current_path=str(expr.left),
295
- relative_path_anchor=str(expr.left),
294
+ current_path=expr.left,
295
+ relative_path_anchor=expr.left,
296
296
  level=0,
297
- current_chain=current_chain + [str(expr.left)],
297
+ current_chain=current_chain + (expr.left,),
298
298
  ) if isinstance(left_match.value, str) else left_match.value
299
299
  right_matches = expr.right.find(left_match_filled)
300
300
  whole_matches.extend(right_matches)
@@ -341,9 +341,10 @@ class TemplateFiller:
341
341
  template_end=self._marker_end_value,
342
342
  ) from exception
343
343
 
344
+ if current_path in self._visited_paths:
345
+ return self._visited_paths[current_path][0]
346
+
344
347
  self._check_endless_loop(templ, current_chain)
345
- # if self._normalize_path(current_path) in self._visited_paths:
346
- # return templ
347
348
 
348
349
  if isinstance(templ, str):
349
350
  # Handle value blocks
@@ -391,13 +392,13 @@ class TemplateFiller:
391
392
  if isinstance(templ, list):
392
393
  out = []
393
394
  for idx, elem in enumerate(templ):
394
- new_path = f"{current_path}[{idx}]"
395
+ new_path = _jsonpath.Child(current_path, _jsonpath.Index(idx))
395
396
  elem_filled = self._recursive_subst(
396
397
  templ=elem,
397
398
  current_path=new_path,
398
399
  relative_path_anchor=get_relative_path(new_path),
399
400
  level=0,
400
- current_chain=current_chain + [new_path],
401
+ current_chain=current_chain + (new_path,),
401
402
  )
402
403
  if isinstance(elem, str) and self._pattern_unpack.fullmatch(elem):
403
404
  try:
@@ -409,7 +410,7 @@ class TemplateFiller:
409
410
  )
410
411
  else:
411
412
  out.append(elem_filled)
412
- self._visited_paths.add(self._normalize_path(current_path))
413
+ self._visited_paths[current_path] = (out, True)
413
414
  return out
414
415
 
415
416
  if isinstance(templ, dict):
@@ -428,29 +429,30 @@ class TemplateFiller:
428
429
  if key_filled in self._template_keys:
429
430
  new_dict[key_filled] = val
430
431
  continue
431
- new_path = f"{current_path}.'{key_filled}'"
432
+ new_path = _jsonpath.Child(current_path, _jsonpath.Fields(key_filled))
432
433
  new_dict[key_filled] = self._recursive_subst(
433
434
  templ=val,
434
435
  current_path=new_path,
435
436
  relative_path_anchor=get_relative_path(new_path),
436
437
  level=0,
437
- current_chain=current_chain + [new_path],
438
+ current_chain=current_chain + (new_path,),
438
439
  )
439
- self._visited_paths.add(self._normalize_path(current_path))
440
+ self._visited_paths[current_path] = (new_dict, True)
440
441
  return new_dict
441
442
  return templ
442
443
 
443
- def _check_endless_loop(self,templ, chain: list[str]):
444
- last_idx = len(chain) -1
444
+ def _check_endless_loop(self,templ, chain: tuple[str, ...]):
445
+ last_idx = len(chain) - 1
445
446
  first_idx = chain.index(chain[-1])
446
447
  if first_idx == last_idx:
447
448
  return
448
- loop = chain[first_idx - 1: -1]
449
- loop_str = "\n".join([f"- {path.replace("'", "")}" for path in loop])
449
+ loop = [chain[-2], *chain[first_idx: -2]]
450
+ loop_str = "\n".join([f"- {path}" for path in loop])
451
+ history_str = "\n".join([f"- {path}" for path in chain])
450
452
  raise _exception.update.PySerialsUpdateTemplatedDataError(
451
- description_template=f"Path {{path_invalid}} starts a loop:\n{loop_str}",
452
- path_invalid=loop[0],
453
- path=chain[-1],
453
+ description_template=f"Path {{path_invalid}} starts a loop:\n{loop_str}\nHistory:\n{history_str}",
454
+ path_invalid=chain[-2],
455
+ path=chain[0],
454
456
  data=templ,
455
457
  data_full=self._data,
456
458
  data_source=self._data,