Skip to content

Commit c0c29ca

Browse files
committed
Enable using OD files with validation error
1 parent 107782c commit c0c29ca

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

src/objdictgen/__main__.py

+8-10
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@
3030

3131
import objdictgen
3232
from objdictgen import jsonod
33+
from objdictgen.node import Node
3334
from objdictgen.printing import format_node
3435
from objdictgen.typing import TDiffEntries, TDiffNodes, TPath
3536

3637
T = TypeVar('T')
3738

38-
if TYPE_CHECKING:
39-
from objdictgen.node import Node
40-
4139
# Initalize the python logger to simply output to stdout
4240
log = logging.getLogger()
4341
log.setLevel(logging.INFO)
@@ -79,7 +77,7 @@ def open_od(fname: TPath|str, validate=True, fix=False) -> "Node":
7977
""" Open and validate the OD file"""
8078

8179
try:
82-
od = objdictgen.LoadFile(fname)
80+
od = Node.LoadFile(fname, validate=validate)
8381

8482
if validate:
8583
od.Validate(fix=fix)
@@ -145,6 +143,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
145143
# -- COMMON --
146144
opt_debug = dict(action='store_true', help="Debug: enable tracebacks on errors")
147145
opt_od = dict(metavar='od', default=None, help="Object dictionary")
146+
opt_novalidate = dict(action='store_true', help="Don't validate input files")
148147

149148
parser.add_argument('--version', action='version', version='%(prog)s ' + objdictgen.__version__)
150149
parser.add_argument('--no-color', action='store_true', help="Disable colored output")
@@ -175,8 +174,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
175174
help="Store in internal format (json only)")
176175
subp.add_argument('--no-sort', action="store_true",
177176
help="Don't order of parameters in output OD")
178-
subp.add_argument('--novalidate', action="store_true",
179-
help="Don't validate files before conversion")
177+
subp.add_argument('--novalidate', **opt_novalidate) # type: ignore[arg-type]
180178
subp.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type]
181179

182180
# -- DIFF --
@@ -186,8 +184,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
186184
subp.add_argument('od1', **opt_od) # type: ignore[arg-type]
187185
subp.add_argument('od2', **opt_od) # type: ignore[arg-type]
188186
subp.add_argument('--internal', action="store_true", help="Diff internal object")
189-
subp.add_argument('--novalidate', action="store_true",
190-
help="Don't validate input files before diff")
187+
subp.add_argument('--novalidate', **opt_novalidate) # type: ignore[arg-type]
191188
subp.add_argument('--show', action="store_true", help="Show difference data")
192189
subp.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type]
193190
subp.add_argument('--no-color', action='store_true', help="Disable colored output")
@@ -214,6 +211,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
214211
subp.add_argument('--unused', action="store_true", help="Include unused profile parameters")
215212
subp.add_argument('--internal', action="store_true", help="Show internal data")
216213
subp.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type]
214+
subp.add_argument('--novalidate', **opt_novalidate) # type: ignore[arg-type]
217215
subp.add_argument('--no-color', action='store_true', help="Disable colored output")
218216

219217
# -- NETWORK --
@@ -270,7 +268,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
270268
# -- CONVERT command --
271269
elif opts.command in ("convert", "conv", "gen"):
272270

273-
od = open_od(opts.od, fix=opts.fix)
271+
od = open_od(opts.od, fix=opts.fix, validate=not opts.novalidate)
274272

275273
to_remove: set[int] = set()
276274

@@ -347,7 +345,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
347345
if len(opts.od) > 1:
348346
print(Fore.LIGHTBLUE_EX + name + '\n' + "=" * len(name) + Style.RESET_ALL)
349347

350-
od = open_od(name)
348+
od = open_od(name, validate=not opts.novalidate)
351349
for line in format_node(od, name, index=opts.index, opts=opts):
352350
print(line)
353351

src/objdictgen/jsonod.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ def generate_jsonc(node: "Node", compact=False, sort=False, internal=False,
366366
return text
367367

368368

369-
def generate_node(contents: str|TODJson) -> "Node":
369+
def generate_node(contents: str|TODJson, validate: bool = True) -> "Node":
370370
""" Import from JSON string or objects """
371371

372372
if isinstance(contents, str):
@@ -394,14 +394,15 @@ def generate_node(contents: str|TODJson) -> "Node":
394394
with open(objdictgen.JSON_SCHEMA, 'r', encoding="utf-8") as f:
395395
SCHEMA = json.loads(remove_jsonc(f.read()))
396396

397-
if SCHEMA and jd.get('$version') == JSON_VERSION:
397+
if validate and SCHEMA and jd.get('$version') == JSON_VERSION:
398398
jsonschema.validate(jd, schema=SCHEMA)
399399

400400
# Get the object type mappings forwards (int to str) and backwards (str to int)
401401
objtypes_i2s, objtypes_s2i = get_object_types(dictionary=jd.get("dictionary", []))
402402

403403
# Validate the input json against for the OD format specifics
404-
validate_fromdict(jd, objtypes_i2s, objtypes_s2i)
404+
if validate:
405+
validate_fromdict(jd, objtypes_i2s, objtypes_s2i)
405406

406407
return node_fromdict(jd, objtypes_s2i)
407408

src/objdictgen/node.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def isEds(filepath: TPath) -> bool:
171171
return header == "[FileInfo]"
172172

173173
@staticmethod
174-
def LoadFile(filepath: TPath) -> "Node":
174+
def LoadFile(filepath: TPath, **kwargs) -> "Node":
175175
""" Open a file and create a new node """
176176
if Node.isXml(filepath):
177177
log.debug("Loading XML OD '%s'", filepath)
@@ -184,12 +184,12 @@ def LoadFile(filepath: TPath) -> "Node":
184184

185185
log.debug("Loading JSON OD '%s'", filepath)
186186
with open(filepath, "r", encoding="utf-8") as f:
187-
return Node.LoadJson(f.read())
187+
return Node.LoadJson(f.read(), **kwargs)
188188

189189
@staticmethod
190-
def LoadJson(contents: str) -> "Node":
190+
def LoadJson(contents: str, validate=True) -> "Node":
191191
""" Import a new Node from a JSON string """
192-
return jsonod.generate_node(contents)
192+
return jsonod.generate_node(contents, validate=validate)
193193

194194
def DumpFile(self, filepath: TPath, filetype: str|None = "jsonc", **kwargs):
195195
""" Save node into file """

tests/conftest.py

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
# Files to exclude from testing all ODs
3232
OD_EXCLUDE: list[Path] = [
3333
ODDIR / 'fail-validation.od',
34+
ODDIR / 'schema-error.json',
3435
]
3536

3637
# Files to exclude from py2 legacy testing

tests/od/schema-error.json

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{
2+
"$id": "od data",
3+
"$version": "1",
4+
"$description": "Canfestival object dictionary data",
5+
"$tool": "odg 3.4",
6+
"$dates": "2024-02-27T00:27:21.144432",
7+
"name": "master",
8+
"description": "Empty master OD",
9+
"type": "master",
10+
"id": 0,
11+
"profile": "None",
12+
"dictionary": [
13+
{
14+
"index": "0x1000", // 4096
15+
"name": "Device Type",
16+
"struct": "var",
17+
"group": "built-in",
18+
"mandatory": true,
19+
"sub": [
20+
{
21+
"name": "Device Type",
22+
"type": "UNSIGNED32", // 7
23+
"access": "ro",
24+
"pdo": false,
25+
"value": 0
26+
}
27+
]
28+
},
29+
{
30+
"index": "0x1001", // 4097
31+
"name": "Error Register",
32+
"struct": "var",
33+
"group": "built-in",
34+
"mandatory": true,
35+
"sub": [
36+
{
37+
"name": "Error Register",
38+
"type": "UNSIGNED8", // 5
39+
"access": "ro",
40+
"pdo": true,
41+
"value": 0
42+
}
43+
]
44+
},
45+
{
46+
"index": "0x1018", // 4120
47+
"name": "Identity",
48+
"struct": "record",
49+
"group": "built-in",
50+
"mandatory": true,
51+
"sub": [
52+
{
53+
"name": "Number of Entries",
54+
"type": "UNSIGNED8", // 5
55+
"access": "ro",
56+
"pdo": false
57+
},
58+
{
59+
"name": "Vendor ID",
60+
"type": "UNSIGNED32", // 7
61+
"access": "ro",
62+
"pdo": false,
63+
"value": 0
64+
},
65+
{
66+
"name": "Product Code",
67+
"type": "UNSIGNED32", // 7
68+
"access": "ro",
69+
"pdo": false,
70+
"value": 0
71+
},
72+
{
73+
"name": "Revision Number",
74+
"type": "UNSIGNED32", // 7
75+
"access": "ro",
76+
"pdo": false,
77+
"value": 0
78+
},
79+
{
80+
"name": "Serial Number",
81+
"type": "UNSIGNED32", // 7
82+
"access": "ro",
83+
"pdo": false,
84+
"value": 0
85+
}
86+
]
87+
}
88+
]
89+
}

0 commit comments

Comments
 (0)