PySerials 0.0.0.dev3__tar.gz → 0.0.0.dev4__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.dev3 → pyserials-0.0.0.dev4}/PKG-INFO +4 -1
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/pyproject.toml +4 -1
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/PySerials.egg-info/PKG-INFO +4 -1
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/PySerials.egg-info/SOURCES.txt +2 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/PySerials.egg-info/requires.txt +3 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/pyserials/__init__.py +2 -1
- pyserials-0.0.0.dev4/src/pyserials/compare.py +29 -0
- pyserials-0.0.0.dev4/src/pyserials/exception/_base.py +58 -0
- pyserials-0.0.0.dev4/src/pyserials/exception/read.py +211 -0
- pyserials-0.0.0.dev4/src/pyserials/exception/update.py +139 -0
- pyserials-0.0.0.dev4/src/pyserials/exception/validate.py +243 -0
- pyserials-0.0.0.dev4/src/pyserials/nested_dict.py +124 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/pyserials/read.py +53 -16
- pyserials-0.0.0.dev4/src/pyserials/update.py +243 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/pyserials/validate.py +22 -11
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/pyserials/write.py +27 -11
- pyserials-0.0.0.dev3/src/pyserials/exception/_base.py +0 -10
- pyserials-0.0.0.dev3/src/pyserials/exception/read.py +0 -119
- pyserials-0.0.0.dev3/src/pyserials/exception/update.py +0 -131
- pyserials-0.0.0.dev3/src/pyserials/exception/validate.py +0 -73
- pyserials-0.0.0.dev3/src/pyserials/update.py +0 -157
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/README.md +0 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/setup.cfg +0 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/PySerials.egg-info/dependency_links.txt +0 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/PySerials.egg-info/not-zip-safe +0 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/PySerials.egg-info/top_level.txt +0 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/pyserials/exception/__init__.py +0 -0
- {pyserials-0.0.0.dev3 → pyserials-0.0.0.dev4}/src/pyserials/format.py +0 -0
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PySerials
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev4
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: jsonschema<5,>=4.21.0
|
|
6
6
|
Requires-Dist: ruamel.yaml<0.18,>=0.17.32
|
|
7
7
|
Requires-Dist: ruamel.yaml.string<1,>=0.1.1
|
|
8
8
|
Requires-Dist: tomlkit<0.12,>=0.11.8
|
|
9
|
+
Requires-Dist: markitup
|
|
10
|
+
Requires-Dist: ansi-sgr
|
|
11
|
+
Requires-Dist: ExceptionMan
|
|
@@ -17,12 +17,15 @@ namespaces = true
|
|
|
17
17
|
# ----------------------------------------- Project Metadata -------------------------------------
|
|
18
18
|
#
|
|
19
19
|
[project]
|
|
20
|
-
version = "0.0.0.
|
|
20
|
+
version = "0.0.0.dev4"
|
|
21
21
|
name = "PySerials"
|
|
22
22
|
dependencies = [
|
|
23
23
|
"jsonschema >= 4.21.0, < 5",
|
|
24
24
|
"ruamel.yaml >= 0.17.32, < 0.18", # https://yaml.readthedocs.io/en/stable/
|
|
25
25
|
"ruamel.yaml.string >= 0.1.1, < 1",
|
|
26
26
|
"tomlkit >= 0.11.8, < 0.12", # https://tomlkit.readthedocs.io/en/stable/,
|
|
27
|
+
"markitup",
|
|
28
|
+
"ansi-sgr",
|
|
29
|
+
"ExceptionMan"
|
|
27
30
|
]
|
|
28
31
|
requires-python = ">=3.10"
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PySerials
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev4
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: jsonschema<5,>=4.21.0
|
|
6
6
|
Requires-Dist: ruamel.yaml<0.18,>=0.17.32
|
|
7
7
|
Requires-Dist: ruamel.yaml.string<1,>=0.1.1
|
|
8
8
|
Requires-Dist: tomlkit<0.12,>=0.11.8
|
|
9
|
+
Requires-Dist: markitup
|
|
10
|
+
Requires-Dist: ansi-sgr
|
|
11
|
+
Requires-Dist: ExceptionMan
|
|
@@ -7,7 +7,9 @@ src/PySerials.egg-info/not-zip-safe
|
|
|
7
7
|
src/PySerials.egg-info/requires.txt
|
|
8
8
|
src/PySerials.egg-info/top_level.txt
|
|
9
9
|
src/pyserials/__init__.py
|
|
10
|
+
src/pyserials/compare.py
|
|
10
11
|
src/pyserials/format.py
|
|
12
|
+
src/pyserials/nested_dict.py
|
|
11
13
|
src/pyserials/read.py
|
|
12
14
|
src/pyserials/update.py
|
|
13
15
|
src/pyserials/validate.py
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
def items(source, target, path: str = "$"):
|
|
2
|
+
def recursive_compare(src, trg, curr_path):
|
|
3
|
+
if type(src) is not type(trg):
|
|
4
|
+
comp["modified"].append(curr_path)
|
|
5
|
+
return
|
|
6
|
+
if isinstance(src, dict):
|
|
7
|
+
for key in src:
|
|
8
|
+
if key not in trg:
|
|
9
|
+
comp["added"].append(f"{curr_path}.{key}")
|
|
10
|
+
continue
|
|
11
|
+
recursive_compare(src[key], trg[key], f"{curr_path}.{key}")
|
|
12
|
+
for key in trg:
|
|
13
|
+
if key not in src:
|
|
14
|
+
comp["removed"].append(f"{curr_path}.{key}")
|
|
15
|
+
return
|
|
16
|
+
if isinstance(src, (list, tuple)):
|
|
17
|
+
len_src = len(src)
|
|
18
|
+
len_trg = len(trg)
|
|
19
|
+
min_len = min(len_src, len_trg)
|
|
20
|
+
for i in range(min_len):
|
|
21
|
+
recursive_compare(src[i], trg[i], f"{curr_path}[{i}]")
|
|
22
|
+
for i in range(min_len, max(len_src, len_trg)):
|
|
23
|
+
comp["added" if len_src > len_trg else "removed"].append(f"{curr_path}[{i}]")
|
|
24
|
+
return
|
|
25
|
+
comp["unchanged" if src == trg else "modified"].append(curr_path)
|
|
26
|
+
return
|
|
27
|
+
comp = {"added": [], "removed": [], "modified": [], "unchanged": []}
|
|
28
|
+
recursive_compare(source, target, path)
|
|
29
|
+
return {key: sorted(comp[key]) for key in comp}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""PySerials base Exception class."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Literal as _Literal
|
|
5
|
+
import ansi_sgr as _sgr
|
|
6
|
+
from markitup import html as _html, doc as _doc
|
|
7
|
+
from exceptionman import ReporterException as _ReporterException
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_ANSI_HEADING_STYLE = {
|
|
11
|
+
1: _sgr.style(text_styles="bold", background_color="red"),
|
|
12
|
+
2: _sgr.style(text_styles="bold", background_color="yellow"),
|
|
13
|
+
3: _sgr.style(text_styles="bold", background_color="green"),
|
|
14
|
+
4: _sgr.style(text_styles="bold", background_color="blue"),
|
|
15
|
+
5: _sgr.style(text_styles="bold", background_color="magenta"),
|
|
16
|
+
6: _sgr.style(text_styles="bold", background_color="cyan"),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PySerialsException(_ReporterException):
|
|
21
|
+
"""Base class for all exceptions raised by PySerials."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
message: str,
|
|
26
|
+
description: str | None = None,
|
|
27
|
+
message_html: str | _html.Element | None = None,
|
|
28
|
+
description_html: str | _html.Element | None = None,
|
|
29
|
+
report_heading: str = "PySerials Error Report",
|
|
30
|
+
):
|
|
31
|
+
super().__init__(
|
|
32
|
+
message=message,
|
|
33
|
+
description=description,
|
|
34
|
+
message_html=message_html,
|
|
35
|
+
description_html=description_html,
|
|
36
|
+
report_heading=report_heading,
|
|
37
|
+
)
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def ansi_heading(section: list[int], title: str) -> str:
|
|
42
|
+
"""Get an ANSI SGR formatted heading."""
|
|
43
|
+
sec = ".".join(str(n) for n in section)
|
|
44
|
+
sec_level = min(len(section), 6)
|
|
45
|
+
heading = f" {sec}. {title} "
|
|
46
|
+
return _sgr.format(heading, control_sequence=_ANSI_HEADING_STYLE[sec_level])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def ansi_bold(text: str) -> str:
|
|
50
|
+
return _sgr.format(text, control_sequence=_sgr.style(text_styles="bold"))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def format_code(code: str) -> tuple[str, str]:
|
|
54
|
+
console = _sgr.format(
|
|
55
|
+
code, control_sequence=_sgr.style(text_color=(220, 220, 220), background_color=(20, 20, 20))
|
|
56
|
+
)
|
|
57
|
+
html = str(_html.elem.code(code))
|
|
58
|
+
return console, html
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""Exceptions raised by `pyserials.read` module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Literal as _Literal
|
|
5
|
+
from pathlib import Path as _Path
|
|
6
|
+
|
|
7
|
+
import ruamel.yaml as _yaml
|
|
8
|
+
import json as _json
|
|
9
|
+
|
|
10
|
+
from markitup import html as _html, md as _md
|
|
11
|
+
from tomlkit.exceptions import TOMLKitError as _TOMLKitError
|
|
12
|
+
|
|
13
|
+
from pyserials.exception._base import PySerialsException as _PySerialsException
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PySerialsReadException(_PySerialsException):
|
|
17
|
+
"""Base class for all exceptions raised by `pyserials.read` module.
|
|
18
|
+
|
|
19
|
+
Attributes
|
|
20
|
+
----------
|
|
21
|
+
source_type : {"file", "string"}
|
|
22
|
+
Type of source from which data was read.
|
|
23
|
+
data_type : {"json", "yaml", "toml"} or None
|
|
24
|
+
Type of input data, if known.
|
|
25
|
+
filepath : pathlib.Path or None
|
|
26
|
+
Path to the input datafile, if data was read from a file.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
source_type: _Literal["file", "string"],
|
|
32
|
+
description: str,
|
|
33
|
+
description_html: str | _html.Element | None = None,
|
|
34
|
+
data_type: _Literal["json", "yaml", "toml"] | None = None,
|
|
35
|
+
filepath: _Path | None = None,
|
|
36
|
+
):
|
|
37
|
+
if source_type == "string":
|
|
38
|
+
source = source_html = "string"
|
|
39
|
+
else:
|
|
40
|
+
source = f"file at '{filepath}'"
|
|
41
|
+
source_html = f"file at <code>{filepath}</code>"
|
|
42
|
+
data_ = f"{data_type.upper()} data" if data_type else "data"
|
|
43
|
+
message_template = f"Failed to read {data_} from input {{source}}."
|
|
44
|
+
super().__init__(
|
|
45
|
+
message=message_template.format(source=source),
|
|
46
|
+
message_html=message_template.format(source=source_html),
|
|
47
|
+
description=description,
|
|
48
|
+
description_html=description_html,
|
|
49
|
+
report_heading="PySerials Read Error Report",
|
|
50
|
+
)
|
|
51
|
+
self.source_type: _Literal["file", "string"] = source_type
|
|
52
|
+
self.data_type: _Literal["json", "yaml", "toml"] | None = data_type
|
|
53
|
+
self.filepath: _Path | None = filepath
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class PySerialsEmptyStringError(PySerialsReadException):
|
|
58
|
+
"""Exception raised when a string to be read is empty."""
|
|
59
|
+
|
|
60
|
+
def __init__(self, data_type: _Literal["json", "yaml", "toml"]):
|
|
61
|
+
description = f"The string is empty."
|
|
62
|
+
super().__init__(description=description, source_type="string", data_type=data_type)
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PySerialsInvalidFileExtensionError(PySerialsReadException):
|
|
67
|
+
"""Exception raised when a file to be read has an unrecognized extension."""
|
|
68
|
+
|
|
69
|
+
def __init__(self, filepath: _Path):
|
|
70
|
+
description = (
|
|
71
|
+
f"The file extension must be one of 'json', 'yaml', 'yml', or '.toml', "
|
|
72
|
+
f"but got '{filepath.suffix.removeprefix('.')}'. "
|
|
73
|
+
"Please provide the extension explicitly, or rename the file to have a valid extension."
|
|
74
|
+
)
|
|
75
|
+
super().__init__(description=description, source_type="file", filepath=filepath)
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class PySerialsMissingFileError(PySerialsReadException):
|
|
80
|
+
"""Exception raised when a file to be read does not exist."""
|
|
81
|
+
|
|
82
|
+
def __init__(self, data_type: _Literal["json", "yaml", "toml"], filepath: _Path):
|
|
83
|
+
description = f"The file does not exist."
|
|
84
|
+
super().__init__(description=description, source_type="file", data_type=data_type, filepath=filepath)
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class PySerialsEmptyFileError(PySerialsReadException):
|
|
89
|
+
"""Exception raised when a file to be read is empty."""
|
|
90
|
+
|
|
91
|
+
def __init__(self, data_type: _Literal["json", "yaml", "toml"], filepath: _Path):
|
|
92
|
+
description = f"The file is empty."
|
|
93
|
+
super().__init__(description=description, source_type="file", data_type=data_type, filepath=filepath)
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class PySerialsInvalidDataError(PySerialsReadException):
|
|
98
|
+
"""Exception raised when the data is invalid.
|
|
99
|
+
|
|
100
|
+
Attributes
|
|
101
|
+
----------
|
|
102
|
+
data : str
|
|
103
|
+
The input data that was supposed to be read.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
def __init__(
|
|
107
|
+
self,
|
|
108
|
+
source_type: _Literal["file", "string"],
|
|
109
|
+
data_type: _Literal["json", "yaml", "toml"],
|
|
110
|
+
data: str,
|
|
111
|
+
cause: Exception,
|
|
112
|
+
filepath: _Path | None = None,
|
|
113
|
+
):
|
|
114
|
+
self.data = data
|
|
115
|
+
self.cause = cause
|
|
116
|
+
self.problem: str = str(cause)
|
|
117
|
+
self.problem_line: int | None = None
|
|
118
|
+
self.problem_column: int | None = None
|
|
119
|
+
self.problem_data_type: str | None = None
|
|
120
|
+
self.context: str | None = None
|
|
121
|
+
self.context_line: int | None = None
|
|
122
|
+
self.context_column: int | None = None
|
|
123
|
+
self.context_data_type: str | None = None
|
|
124
|
+
|
|
125
|
+
if isinstance(cause, _yaml.YAMLError):
|
|
126
|
+
self.problem_line = cause.problem_mark.line + 1
|
|
127
|
+
self.problem_column = cause.problem_mark.column + 1
|
|
128
|
+
self.problem_data_type = cause.problem_mark.name
|
|
129
|
+
self.problem = cause.problem.strip()
|
|
130
|
+
if cause.context:
|
|
131
|
+
self.context = cause.context.strip()
|
|
132
|
+
self.context_line = cause.context_mark.line + 1
|
|
133
|
+
self.context_column = cause.context_mark.column + 1
|
|
134
|
+
self.context_data_type = cause.context_mark.name
|
|
135
|
+
elif isinstance(cause, _json.JSONDecodeError):
|
|
136
|
+
self.problem = cause.msg
|
|
137
|
+
self.problem_line = cause.lineno
|
|
138
|
+
self.problem_column = cause.colno
|
|
139
|
+
elif isinstance(cause, _TOMLKitError):
|
|
140
|
+
self.problem_line = cause.line
|
|
141
|
+
self.problem_column = cause.col
|
|
142
|
+
self.problem = cause.args[0].removesuffix(f" at line {self.problem_line} col {self.problem_column}")
|
|
143
|
+
self.problem = self.problem.strip().capitalize().removesuffix(".")
|
|
144
|
+
description = "The data is not valid"
|
|
145
|
+
if self.problem_line:
|
|
146
|
+
description += f" at line {self.problem_line}, column {self.problem_column}"
|
|
147
|
+
description += f": {self.problem}."
|
|
148
|
+
super().__init__(description=description, source_type=source_type, data_type=data_type, filepath=filepath)
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
def _report_content(self, mode: _Literal["full", "short"], md: bool) -> _html.elem.Ul:
|
|
152
|
+
|
|
153
|
+
def make_tabel(problem, line, column, data_type):
|
|
154
|
+
rows = [
|
|
155
|
+
[title, value] for title, value in [
|
|
156
|
+
["Description", problem],
|
|
157
|
+
["Line Number", line],
|
|
158
|
+
["Column Number", column],
|
|
159
|
+
["Data Type", data_type],
|
|
160
|
+
] if value is not None
|
|
161
|
+
]
|
|
162
|
+
return _html.elem.table_from_rows(rows_body=rows)
|
|
163
|
+
|
|
164
|
+
content_list = [
|
|
165
|
+
_html.elem.details(
|
|
166
|
+
[
|
|
167
|
+
_html.elem.summary("❌ Problem"),
|
|
168
|
+
make_tabel(self.problem, self.problem_line, self.problem_column, self.problem_data_type)
|
|
169
|
+
]
|
|
170
|
+
),
|
|
171
|
+
]
|
|
172
|
+
if self.context:
|
|
173
|
+
content_list.append(
|
|
174
|
+
_html.elem.details(
|
|
175
|
+
[
|
|
176
|
+
_html.elem.summary("🔍 Context"),
|
|
177
|
+
make_tabel(self.context, self.context_line, self.context_column, self.context_data_type)
|
|
178
|
+
]
|
|
179
|
+
),
|
|
180
|
+
)
|
|
181
|
+
data_lines = self.data.splitlines()
|
|
182
|
+
if self.problem_line:
|
|
183
|
+
line_idx = self.problem_line - 1
|
|
184
|
+
problem_line = data_lines[line_idx]
|
|
185
|
+
if md:
|
|
186
|
+
problem_line = f"- {problem_line}"
|
|
187
|
+
else:
|
|
188
|
+
if self.problem_column:
|
|
189
|
+
col_idx = self.problem_column - 1
|
|
190
|
+
prob_col = problem_line[col_idx]
|
|
191
|
+
prob_col_highlight = _html.elem.span(prob_col, {"class": "highlight-char"})
|
|
192
|
+
problem_line = f"{problem_line[:col_idx]}{prob_col_highlight}{problem_line[col_idx+1:]}"
|
|
193
|
+
problem_line = str(_html.elem.span(problem_line, {"class": "highlight-line"}))
|
|
194
|
+
data_lines[line_idx] = problem_line
|
|
195
|
+
if mode == "short":
|
|
196
|
+
if self.problem_line is not None:
|
|
197
|
+
problem_line_idx = self.problem_line - 1
|
|
198
|
+
start_line = max(0, problem_line_idx)
|
|
199
|
+
end_line = min(len(data_lines), problem_line_idx + 1)
|
|
200
|
+
if self.context_line is not None:
|
|
201
|
+
context_line_idx = self.context_line - 1
|
|
202
|
+
start_line = max(0, context_line_idx, problem_line_idx)
|
|
203
|
+
end_line = min(len(data_lines), context_line_idx + 1, problem_line_idx + 1)
|
|
204
|
+
data_lines = data_lines[start_line:end_line]
|
|
205
|
+
data = "\n".join(data_lines)
|
|
206
|
+
if md:
|
|
207
|
+
code_block = _md.elem.code_fence(data, info="diff")
|
|
208
|
+
else:
|
|
209
|
+
code_block = _html.elem.pre(_html.elem.code(data, {"class": f"language-{self.data_type}"}))
|
|
210
|
+
content_list.append(_html.elem.details([_html.elem.summary("📄 Data"), code_block]))
|
|
211
|
+
return _html.elem.ul([_html.elem.li(content) for content in content_list])
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Exceptions raised by `pyserials.update` module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Any as _Any, Literal as _Literal
|
|
5
|
+
|
|
6
|
+
from markitup.html import elem as _html
|
|
7
|
+
|
|
8
|
+
from pyserials.exception import _base
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PySerialsUpdateException(_base.PySerialsException):
|
|
12
|
+
"""Base class for all exceptions raised by `pyserials.update` module.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
path : str
|
|
17
|
+
JSONPath to where the update failed.
|
|
18
|
+
data : dict | list | str | int | float | bool
|
|
19
|
+
Data that failed to update.
|
|
20
|
+
data_full : dict | list | str | int | float | bool
|
|
21
|
+
Full data input.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
path: str,
|
|
27
|
+
data: dict | list | str | int | float | bool,
|
|
28
|
+
data_full: dict | list | str | int | float | bool,
|
|
29
|
+
description: str,
|
|
30
|
+
description_html: str | _html.Element | None = None,
|
|
31
|
+
):
|
|
32
|
+
message_template = "Failed to update data at {path}."
|
|
33
|
+
path_console, path_html = _base.format_code(path)
|
|
34
|
+
super().__init__(
|
|
35
|
+
message=message_template.format(path=path_console),
|
|
36
|
+
message_html=message_template.format(path=path_html),
|
|
37
|
+
description=description,
|
|
38
|
+
description_html=description_html,
|
|
39
|
+
report_heading="PySerials Update Error Report",
|
|
40
|
+
)
|
|
41
|
+
self.path = path
|
|
42
|
+
self.data = data
|
|
43
|
+
self.data_full = data_full
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PySerialsUpdateDictFromAddonError(PySerialsUpdateException):
|
|
48
|
+
"""Base class for all exceptions raised by `pyserials.update.dict_from_addon`.
|
|
49
|
+
|
|
50
|
+
Attributes
|
|
51
|
+
----------
|
|
52
|
+
data_addon : Any
|
|
53
|
+
Value of the failed data in the addon dictionary.
|
|
54
|
+
data_addon_full : dictionary
|
|
55
|
+
Full addon input.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
problem_type: _Literal["duplicate", "type_mismatch"],
|
|
61
|
+
path: str,
|
|
62
|
+
data: _Any,
|
|
63
|
+
data_full: dict,
|
|
64
|
+
data_addon: _Any,
|
|
65
|
+
data_addon_full: dict,
|
|
66
|
+
):
|
|
67
|
+
self.type_data = type(data)
|
|
68
|
+
self.type_data_addon = type(data_addon)
|
|
69
|
+
type_data_console, type_data_html = _base.format_code(self.type_data.__name__)
|
|
70
|
+
type_data_addon_console, type_data_addon_html = _base.format_code(self.type_data_addon.__name__)
|
|
71
|
+
path_console, path_html = _base.format_code(path)
|
|
72
|
+
kwargs_console, kwargs_html = (
|
|
73
|
+
{"path": path, "type_data": type_data, "type_data_addon": type_data_addon}
|
|
74
|
+
for path, type_data, type_data_addon in zip(
|
|
75
|
+
(path_console, path_html),
|
|
76
|
+
(type_data_console, type_data_html),
|
|
77
|
+
(type_data_addon_console, type_data_addon_html),
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
description_template = (
|
|
81
|
+
"There was a duplicate in the addon dictionary; "
|
|
82
|
+
"the value of type {type_data_addon} already exists in the source data."
|
|
83
|
+
) if problem_type == "duplicate" else (
|
|
84
|
+
"There was a type mismatch between the source and addon dictionary values; "
|
|
85
|
+
"the value is of type {type_data} in the source data, "
|
|
86
|
+
"but of type {type_data_addon} in the addon data."
|
|
87
|
+
)
|
|
88
|
+
super().__init__(
|
|
89
|
+
description=description_template.format(**kwargs_console),
|
|
90
|
+
description_html=description_template.format(**kwargs_html),
|
|
91
|
+
path=path,
|
|
92
|
+
data=data,
|
|
93
|
+
data_full=data_full,
|
|
94
|
+
)
|
|
95
|
+
self.problem_type: _Literal["duplicate", "type_mismatch"] = problem_type
|
|
96
|
+
self.data_addon = data_addon
|
|
97
|
+
self.data_addon_full = data_addon_full
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class PySerialsUpdateTemplatedDataError(PySerialsUpdateException):
|
|
102
|
+
"""Exception raised when updating templated data fails.
|
|
103
|
+
|
|
104
|
+
Attributes
|
|
105
|
+
----------
|
|
106
|
+
path_invalid : str
|
|
107
|
+
JSONPath that caused the update to fail.
|
|
108
|
+
data_source : dict
|
|
109
|
+
Source data that was used to update the template.
|
|
110
|
+
template_start : str
|
|
111
|
+
The start marker of the template.
|
|
112
|
+
template_end : str
|
|
113
|
+
The end marker of the template.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def __init__(
|
|
117
|
+
self,
|
|
118
|
+
description_template: str,
|
|
119
|
+
path_invalid: str,
|
|
120
|
+
path: str,
|
|
121
|
+
data: str,
|
|
122
|
+
data_full: dict | list | str | int | float | bool,
|
|
123
|
+
data_source: dict,
|
|
124
|
+
template_start: str,
|
|
125
|
+
template_end: str,
|
|
126
|
+
):
|
|
127
|
+
path_invalid_console, path_invalid_html = _base.format_code(path_invalid.replace("'", ""))
|
|
128
|
+
super().__init__(
|
|
129
|
+
description=description_template.format(path_invalid=path_invalid_console),
|
|
130
|
+
description_html=description_template.format(path_invalid=path_invalid_html),
|
|
131
|
+
path=path.replace("'", ""),
|
|
132
|
+
data=data,
|
|
133
|
+
data_full=data_full,
|
|
134
|
+
)
|
|
135
|
+
self.path_invalid = path_invalid
|
|
136
|
+
self.data_source = data_source
|
|
137
|
+
self.template_start = template_start
|
|
138
|
+
self.template_end = template_end
|
|
139
|
+
return
|