diff --git a/pyproject.toml b/pyproject.toml index 8ec331d..b888d65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ namespaces = true # ----------------------------------------- Project Metadata ------------------------------------- # [project] -version = "0.0.0.dev48" +version = "0.0.0.dev49" name = "PySerials" dependencies = [ "jsonschema >= 4.21.0, < 5", @@ -26,8 +26,8 @@ dependencies = [ "ruamel.yaml >= 0.17.32, < 0.18", # https://yaml.readthedocs.io/en/stable/ "ruamel.yaml.string >= 0.1.1, < 1", "tomlkit >= 0.11.8, < 0.12", # https://tomlkit.readthedocs.io/en/stable/, - "MDit == 0.0.0.dev45", - "ExceptionMan == 0.0.0.dev45", + "MDit == 0.0.0.dev46", + "ExceptionMan == 0.0.0.dev46", "ProtocolMan == 0.0.0.dev2", ] requires-python = ">=3.10" diff --git a/requirements.txt b/requirements.txt index 405b89f..758e3e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,6 @@ jsonpath-ng >= 1.6.1, < 2 ruamel.yaml >= 0.17.32, < 0.18 ruamel.yaml.string >= 0.1.1, < 1 tomlkit >= 0.11.8, < 0.12 -MDit == 0.0.0.dev45 -ExceptionMan == 0.0.0.dev45 +MDit == 0.0.0.dev46 +ExceptionMan == 0.0.0.dev46 ProtocolMan == 0.0.0.dev2 \ No newline at end of file diff --git a/src/pyserials/exception/update.py b/src/pyserials/exception/update.py index ef7a0ed..a8b8b03 100644 --- a/src/pyserials/exception/update.py +++ b/src/pyserials/exception/update.py @@ -128,7 +128,8 @@ def __init__( self.template_start = template_start self.template_end = template_end parts = description_template.split("{path_invalid}") - parts.insert(1, _mdit.element.code_span(self.path_invalid)) + if len(parts) > 1: + parts.insert(1, _mdit.element.code_span(self.path_invalid)) super().__init__( path=path.replace("'", ""), data=data, diff --git a/src/pyserials/update.py b/src/pyserials/update.py index a0a59c0..678685a 100644 --- a/src/pyserials/update.py +++ b/src/pyserials/update.py @@ -152,6 +152,7 @@ def __init__( self._pattern_value: dict[int, _RegexPattern] = {} self._data = None + self._visited_paths = set() return def fill( @@ -161,6 +162,7 @@ def fill( current_path: str = "", ): self._data = data + self._visited_paths = set() path = (f"$.{current_path}" if self._add_prefix else current_path) if current_path else "$" return self._recursive_subst( templ=template or data, @@ -198,13 +200,15 @@ def getter_function(path: str, default: Any = None, search: bool = False): local_context = {} try: exec(code_str_full, global_context, local_context) - return local_context["__inline_code__"]() + output = local_context["__inline_code__"]() except Exception as e: raise_error( description_template=f"Code at {{path_invalid}} raised an exception: {e}\n{code_str_full}", path_invalid=current_path, exception=e, ) + self._visited_paths.add(self._normalize_path(current_path)) + return output def get_address_value(match: _re.Match | str, return_all_matches: bool = False, from_code: bool = False): raw_path = match if isinstance(match, str) else str(match.group(1)) @@ -238,6 +242,7 @@ def get_address_value(match: _re.Match | str, return_all_matches: bool = False, root_path_expr = root_path_expr.left path_expr = self._concat_json_paths(root_path_expr, path_expr) value, matched = get_value(path_expr, return_all_matches, from_code) + self._visited_paths.add(self._normalize_path(current_path)) if from_code: return value, matched if matched: @@ -337,6 +342,8 @@ def raise_error(path_invalid: str, description_template: str, exception: Excepti ) from exception self._check_endless_loop(templ, current_chain) + # if self._normalize_path(current_path) in self._visited_paths: + # return templ if isinstance(templ, str): # Handle value blocks @@ -393,9 +400,16 @@ def raise_error(path_invalid: str, description_template: str, exception: Excepti current_chain=current_chain + [new_path], ) if isinstance(elem, str) and self._pattern_unpack.fullmatch(elem): - out.extend(elem_filled) + try: + out.extend(elem_filled) + except TypeError as e: + raise_error( + path_invalid=current_path, + description_template=str(e) + ) else: out.append(elem_filled) + self._visited_paths.add(self._normalize_path(current_path)) return out if isinstance(templ, dict): @@ -422,6 +436,7 @@ def raise_error(path_invalid: str, description_template: str, exception: Excepti level=0, current_chain=current_chain + [new_path], ) + self._visited_paths.add(self._normalize_path(current_path)) return new_dict return templ @@ -480,6 +495,10 @@ def _recursive_extract(expr): _recursive_extract(jsonpath) return fields + @staticmethod + def _normalize_path(path: str) -> str: + return path.replace("'", "") + def _concat_json_paths(self, path1, path2): if not isinstance(path2, _jsonpath.Child): return _jsonpath.Child(path1, path2) diff --git a/src/pyserials/write.py b/src/pyserials/write.py index 2008bed..dd43ef1 100644 --- a/src/pyserials/write.py +++ b/src/pyserials/write.py @@ -2,6 +2,7 @@ from pathlib import Path as _Path import json as _json import ruamel.yaml as _yaml +from ruamel.yaml import scalarstring as _yaml_scalar_string import tomlkit as _tomlkit @@ -22,8 +23,16 @@ def to_string( def to_yaml_string( data: dict | list | str | int | float | bool | _yaml.CommentedMap | _yaml.CommentedSeq, end_of_file_newline: bool = True, + indent_mapping: int = 2, + indent_sequence: int = 4, + indent_sequence_offset: int = 2, + multiline_string_to_block: bool = True, ) -> str: - yaml_syntax = _yaml.YAML(typ=["rt", "string"]).dumps(data, add_final_eol=False).removesuffix("\n...") + yaml = _yaml.YAML(typ=["rt", "string"]) + yaml.indent(mapping=indent_mapping, sequence=indent_sequence, offset=indent_sequence_offset) + if multiline_string_to_block: + _yaml_scalar_string.walk_tree(data) + yaml_syntax = yaml.dumps(data, add_final_eol=False).removesuffix("\n...") return f"{yaml_syntax}\n" if end_of_file_newline else yaml_syntax @@ -46,9 +55,17 @@ def to_yaml_file( data: dict | list | str | int | float | bool | _yaml.CommentedMap | _yaml.CommentedSeq, path: str | _Path, make_dirs: bool = True, + indent_mapping: int = 2, + indent_sequence: int = 4, + indent_sequence_offset: int = 2, + multiline_string_to_block: bool = True, ): path = _Path(path).resolve() if make_dirs: path.parent.mkdir(parents=True, exist_ok=True) - _yaml.YAML().dump(data, path) + yaml = _yaml.YAML() + yaml.indent(mapping=indent_mapping, sequence=indent_sequence, offset=indent_sequence_offset) + if multiline_string_to_block: + _yaml_scalar_string.walk_tree(data) + yaml.dump(data, path) return