Skip to content

Commit 10ab189

Browse files
committed
Enable using OD files with validation error
1 parent 609ae6a commit 10ab189

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

src/objdictgen/__main__.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,11 @@
3030

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

3536
T = TypeVar('T')
3637

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

8078
try:
81-
od = objdictgen.LoadFile(fname)
79+
od = Node.LoadFile(fname, validate=validate)
8280

8381
if validate:
8482
od.Validate(fix=fix)
@@ -197,6 +195,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
197195
# -- COMMON --
198196
opt_debug = dict(action='store_true', help="Debug: enable tracebacks on errors")
199197
opt_od = dict(metavar='od', default=None, help="Object dictionary")
198+
opt_novalidate = dict(action='store_true', help="Don't validate input files")
200199

201200
parser.add_argument('--version', action='version', version='%(prog)s ' + objdictgen.__version__)
202201
parser.add_argument('--no-color', action='store_true', help="Disable colored output")
@@ -227,8 +226,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
227226
help="Store in internal format (json only)")
228227
subp.add_argument('--no-sort', action="store_true",
229228
help="Don't order of parameters in output OD")
230-
subp.add_argument('--novalidate', action="store_true",
231-
help="Don't validate files before conversion")
229+
subp.add_argument('--novalidate', **opt_novalidate) # type: ignore[arg-type]
232230
subp.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type]
233231

234232
# -- DIFF --
@@ -238,8 +236,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
238236
subp.add_argument('od1', **opt_od) # type: ignore[arg-type]
239237
subp.add_argument('od2', **opt_od) # type: ignore[arg-type]
240238
subp.add_argument('--internal', action="store_true", help="Diff internal object")
241-
subp.add_argument('--novalidate', action="store_true",
242-
help="Don't validate input files before diff")
239+
subp.add_argument('--novalidate', **opt_novalidate) # type: ignore[arg-type]
243240
subp.add_argument('--show', action="store_true", help="Show difference data")
244241
subp.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type]
245242
subp.add_argument('--no-color', action='store_true', help="Disable colored output")
@@ -265,6 +262,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
265262
subp.add_argument('--short', action="store_true", help="Do not list sub-index")
266263
subp.add_argument('--unused', action="store_true", help="Include unused profile parameters")
267264
subp.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type]
265+
subp.add_argument('--novalidate', **opt_novalidate) # type: ignore[arg-type]
268266
subp.add_argument('--no-color', action='store_true', help="Disable colored output")
269267

270268
# -- NETWORK --
@@ -321,7 +319,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
321319
# -- CONVERT command --
322320
elif opts.command in ("convert", "conv", "gen"):
323321

324-
od = open_od(opts.od, fix=opts.fix)
322+
od = open_od(opts.od, fix=opts.fix, validate=not opts.novalidate)
325323

326324
to_remove: set[int] = set()
327325

@@ -398,7 +396,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
398396
if len(opts.od) > 1:
399397
print(Fore.LIGHTBLUE_EX + name + '\n' + "=" * len(name) + Style.RESET_ALL)
400398

401-
od = open_od(name)
399+
od = open_od(name, validate=not opts.novalidate)
402400
for line in list_od(od, name, opts):
403401
print(line)
404402

src/objdictgen/jsonod.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ def generate_jsonc(node: "Node", compact=False, sort=False, internal=False,
411411
return text
412412

413413

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

417417
if isinstance(contents, str):
@@ -439,14 +439,15 @@ def generate_node(contents: str|TODJson) -> "Node":
439439
with open(objdictgen.JSON_SCHEMA, 'r', encoding="utf-8") as f:
440440
SCHEMA = json.loads(remove_jsonc(f.read()))
441441

442-
if SCHEMA and jd.get('$version') == JSON_VERSION:
442+
if validate and SCHEMA and jd.get('$version') == JSON_VERSION:
443443
jsonschema.validate(jd, schema=SCHEMA)
444444

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

448448
# Validate the input json against for the OD format specifics
449-
validate_fromdict(jd, objtypes_i2s, objtypes_s2i)
449+
if validate:
450+
validate_fromdict(jd, objtypes_i2s, objtypes_s2i)
450451

451452
return node_fromdict(jd, objtypes_s2i)
452453

src/objdictgen/node.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def isEds(filepath: TPath) -> bool:
176176
return header == "[FileInfo]"
177177

178178
@staticmethod
179-
def LoadFile(filepath: TPath) -> "Node":
179+
def LoadFile(filepath: TPath, **kwargs) -> "Node":
180180
""" Open a file and create a new node """
181181
if Node.isXml(filepath):
182182
log.debug("Loading XML OD '%s'", filepath)
@@ -189,12 +189,12 @@ def LoadFile(filepath: TPath) -> "Node":
189189

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

194194
@staticmethod
195-
def LoadJson(contents: str) -> "Node":
195+
def LoadJson(contents: str, validate=True) -> "Node":
196196
""" Import a new Node from a JSON string """
197-
return jsonod.generate_node(contents)
197+
return jsonod.generate_node(contents, validate=validate)
198198

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

tests/conftest.py

Lines changed: 1 addition & 0 deletions
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

Lines changed: 89 additions & 0 deletions
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)