Skip to content

Commit

Permalink
Enable using OD files with validation error
Browse files Browse the repository at this point in the history
  • Loading branch information
sveinse committed Dec 3, 2024
1 parent b1f4cec commit 77351bd
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 17 deletions.
18 changes: 8 additions & 10 deletions src/objdictgen/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,12 @@

import objdictgen
from objdictgen import jsonod
from objdictgen.node import Node
from objdictgen.printing import format_node
from objdictgen.typing import TDiffEntries, TDiffNodes, TPath

T = TypeVar('T')

if TYPE_CHECKING:
from objdictgen.node import Node

# Initalize the python logger to simply output to stdout
log = logging.getLogger()
log.setLevel(logging.INFO)
Expand Down Expand Up @@ -79,7 +77,7 @@ def open_od(fname: TPath|str, validate=True, fix=False) -> "Node":
""" Open and validate the OD file"""

try:
od = objdictgen.LoadFile(fname)
od = Node.LoadFile(fname, validate=validate)

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

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

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

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

od = open_od(opts.od, fix=opts.fix)
od = open_od(opts.od, fix=opts.fix, validate=not opts.novalidate)

to_remove: set[int] = set()

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

od = open_od(name)
od = open_od(name, validate=not opts.novalidate)
for line in format_node(od, name, index=opts.index, opts=opts):
print(line)

Expand Down
7 changes: 4 additions & 3 deletions src/objdictgen/jsonod.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def generate_jsonc(node: "Node", compact=False, sort=False, internal=False,
return text


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

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

if SCHEMA and jd.get('$version') == JSON_VERSION:
if validate and SCHEMA and jd.get('$version') == JSON_VERSION:
jsonschema.validate(jd, schema=SCHEMA)

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

# Validate the input json against for the OD format specifics
validate_fromdict(jd, objtypes_i2s, objtypes_s2i)
if validate:
validate_fromdict(jd, objtypes_i2s, objtypes_s2i)

return node_fromdict(jd, objtypes_s2i)

Expand Down
8 changes: 4 additions & 4 deletions src/objdictgen/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def isEds(filepath: TPath) -> bool:
return header == "[FileInfo]"

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

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

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

def DumpFile(self, filepath: TPath, filetype: str|None = "jsonc", **kwargs):
""" Save node into file """
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
# Files to exclude from testing all ODs
OD_EXCLUDE: list[Path] = [
ODDIR / 'fail-validation.od',
ODDIR / 'schema-error.json',
]

# Files to exclude from py2 legacy testing
Expand Down
89 changes: 89 additions & 0 deletions tests/od/schema-error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"$id": "od data",
"$version": "1",
"$description": "Canfestival object dictionary data",
"$tool": "odg 3.4",
"$dates": "2024-02-27T00:27:21.144432",
"name": "master",
"description": "Empty master OD",
"type": "master",
"id": 0,
"profile": "None",
"dictionary": [
{
"index": "0x1000", // 4096
"name": "Device Type",
"struct": "var",
"group": "built-in",
"mandatory": true,
"sub": [
{
"name": "Device Type",
"type": "UNSIGNED32", // 7
"access": "ro",
"pdo": false,
"value": 0
}
]
},
{
"index": "0x1001", // 4097
"name": "Error Register",
"struct": "var",
"group": "built-in",
"mandatory": true,
"sub": [
{
"name": "Error Register",
"type": "UNSIGNED8", // 5
"access": "ro",
"pdo": true,
"value": 0
}
]
},
{
"index": "0x1018", // 4120
"name": "Identity",
"struct": "record",
"group": "built-in",
"mandatory": true,
"sub": [
{
"name": "Number of Entries",
"type": "UNSIGNED8", // 5
"access": "ro",
"pdo": false
},
{
"name": "Vendor ID",
"type": "UNSIGNED32", // 7
"access": "ro",
"pdo": false,
"value": 0
},
{
"name": "Product Code",
"type": "UNSIGNED32", // 7
"access": "ro",
"pdo": false,
"value": 0
},
{
"name": "Revision Number",
"type": "UNSIGNED32", // 7
"access": "ro",
"pdo": false,
"value": 0
},
{
"name": "Serial Number",
"type": "UNSIGNED32", // 7
"access": "ro",
"pdo": false,
"value": 0
}
]
}
]
}

0 comments on commit 77351bd

Please sign in to comment.