Skip to content

Commit 4104103

Browse files
authored
Fix handling of DOMAIN (#16)
* Fix UI editing of DOMAIN values * Unicode DOMAIN doesn't work * Add `odg cat` to odg as alias to `odg list` * Print string length on `odg list` output * Fixed encoding handling in nosis/XML * Test suite update to reflect changes
1 parent e7aeb5f commit 4104103

18 files changed

+1180
-306
lines changed

src/objdictgen/__main__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
201201
# -- LIST --
202202
subp = subparser.add_parser('list', help="""
203203
List
204-
""")
204+
""", aliases=['cat'])
205205
subp.add_argument('od', nargs="+", help="Object dictionary")
206206
subp.add_argument('-i', '--index', action="append", help="Specify parameter index to show")
207207
subp.add_argument('--all', action="store_true",
@@ -325,7 +325,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
325325

326326

327327
# -- LIST command --
328-
elif opts.command == "list":
328+
elif opts.command in ("list", "cat"):
329329

330330
for n, name in enumerate(opts.od):
331331

src/objdictgen/node.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,10 @@ def GetPrintParams(self, keys=None, short=False, compact=False, unused=False, ve
10941094

10951095
# Special formatting on value
10961096
if isinstance(value, str):
1097-
value = '"' + value + '"'
1097+
length = len(value)
1098+
if typename == 'DOMAIN':
1099+
value = value.encode('unicode_escape').decode()
1100+
value = '"' + value + f'" ({length})'
10981101
elif i and index_range and index_range.name in ('rpdom', 'tpdom'):
10991102
# FIXME: In PDO mappings, the value is ints
11001103
assert isinstance(value, int)

src/objdictgen/nodemanager.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,9 @@ def SetCurrentEntry(self, index: int, subindex: int, value: str, name: str, edit
697697
# Might fail with binascii.Error if hex is malformed
698698
if len(value) % 2 != 0:
699699
value = "0" + value
700-
bvalue = codecs.decode(value, 'hex_codec').decode()
700+
# The latin-1 encoding supports using 0x80-0xFF as values
701+
# FIXME: Doesn't work with unicode
702+
bvalue = codecs.decode(value, 'hex_codec').decode('latin-1')
701703
node.SetEntry(index, subindex, bvalue)
702704
elif editor == "dcf":
703705
node.SetEntry(index, subindex, value)
@@ -1047,7 +1049,9 @@ def GetNodeEntryValues(self, node: Node, index: int) -> tuple[list[dict], list[d
10471049
editor["value"] = "dcf"
10481050
else:
10491051
editor["value"] = "domain"
1050-
dic["value"] = codecs.encode(dic["value"].encode(), 'hex_codec').decode()
1052+
# The latin-1 encoding supports using 0x80-0xFF as values
1053+
# FIXME: Doesn't work with unicode
1054+
dic["value"] = codecs.encode(dic["value"].encode('latin-1'), 'hex_codec').decode().upper()
10511055
elif dic["type"] == "BOOLEAN":
10521056
editor["value"] = "bool"
10531057
dic["value"] = maps.BOOL_TYPE[dic["value"]]

src/objdictgen/nosis.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def safe_string(s: str, isattr: bool = True) -> str:
198198

199199
if isattr:
200200
# for others, use Python style escapes
201-
return repr(s)[1:-1] # without the extra single-quotes
201+
return s.encode('unicode_escape').decode('utf-8')
202202

203203
return s
204204

@@ -279,7 +279,7 @@ def xmldump(filehandle: io.TextIOWrapper|None, py_obj: object,
279279

280280
id_tag = f' id="{objid}"' if objid is not None else ""
281281

282-
fh.write(f"""<?xml version="1.0"?>
282+
fh.write(f"""<?xml version="1.0" encoding="utf-8"?>
283283
<!DOCTYPE PyObject SYSTEM "PyObjects.dtd">
284284
<PyObject module="{module}" class="{klass_tag}"{id_tag}>
285285
""")

tests/conftest.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@
2929
]
3030

3131
# Files to exclude from py2 legacy testing
32-
PY2_OD_EXCLUDE = [
33-
ODDIR / "unicode.json",
34-
ODDIR / "unicode.od",
32+
PY2_OD_EXCLUDE: list[Path] = [
3533
]
3634

3735
# Files to exclude in EDS testing
38-
PY2_EDS_EXCLUDE = [
39-
ODDIR / "legacy-strings.od", # The legacy tool silently crash on this input
36+
PY2_EDS_EXCLUDE: list[Path] = [
37+
]
38+
39+
# Files to exclude in pickle testing
40+
PY2_PICKLE_EXCLUDE: list[Path] = [
4041
]
4142

4243
# Equivalent files that should compare as equal
@@ -377,6 +378,9 @@ def py2_pickle(odfile, py2, wd_session):
377378
if not odfile.exists():
378379
pytest.skip(f"File not found: {odfile.rel_to_wd()}")
379380

381+
if odfile in PY2_PICKLE_EXCLUDE:
382+
pytest.skip(f"File {odfile.rel_to_wd()} is excluded from py2 testing")
383+
380384
tmpod = odfile.stem
381385

382386
shutil.copy(odfile, tmpod + '.od')
@@ -398,7 +402,9 @@ def py2_pickle(odfile, py2, wd_session):
398402

399403
# Load the pickled data
400404
with open(tmpod + '.pickle', 'rb') as f:
401-
data = pickle.load(f, encoding='utf-8')
405+
# It seems unicode_escape is needed to be able to encode low and high
406+
# ascii characters as well as unicode characters
407+
data = pickle.load(f, encoding='unicode_escape')
402408

403409
return odfile, data
404410

tests/od/domain.json

+52-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"$version": "1",
44
"$description": "Canfestival object dictionary data",
55
"$tool": "odg 3.4",
6-
"$date": "2024-04-10T22:48:13.333406",
6+
"$date": "2024-04-13T23:37:31.909712",
77
"name": "domain",
88
"description": "",
99
"type": "master",
@@ -12,17 +12,65 @@
1212
"dictionary": [
1313
{
1414
"index": "0x2000", // 8192
15-
"name": "Domain",
15+
"name": "Extended",
1616
"struct": "var",
1717
"group": "user",
1818
"mandatory": false,
1919
"sub": [
2020
{
21-
"name": "Domain",
21+
"name": "Extended",
2222
"type": "DOMAIN", // 15
2323
"access": "rw",
2424
"pdo": true,
25-
"value": "\u0002@ABC\u0001"
25+
"value": "\u0000\u0011\"3DUfw\u0088\u0099\u00aa\u00bb\u00cc\u00dd\u00ee\u00ff"
26+
}
27+
]
28+
},
29+
{
30+
"index": "0x2001", // 8193
31+
"name": "Bytes",
32+
"struct": "var",
33+
"group": "user",
34+
"mandatory": false,
35+
"sub": [
36+
{
37+
"name": "Bytes",
38+
"type": "DOMAIN", // 15
39+
"access": "rw",
40+
"pdo": true,
41+
"value": "\u00e2\u009c\u0093"
42+
}
43+
]
44+
},
45+
{
46+
"index": "0x2002", // 8194
47+
"name": "Utf8",
48+
"struct": "var",
49+
"group": "user",
50+
"mandatory": false,
51+
"sub": [
52+
{
53+
"name": "Utf8",
54+
"type": "DOMAIN", // 15
55+
"access": "rw",
56+
"pdo": true,
57+
"value": ""
58+
}
59+
]
60+
},
61+
{
62+
"index": "0x2003", // 8195
63+
"name": "Unicode",
64+
"struct": "var",
65+
"group": "user",
66+
"mandatory": false,
67+
"sub": [
68+
{
69+
"name": "Unicode",
70+
"type": "DOMAIN", // 15
71+
"access": "rw",
72+
"pdo": true,
73+
"value": "\u2713"
2674
}
2775
]
2876
}

tests/od/domain.od

+146-14
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,83 @@
1-
<?xml version="1.0"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<!DOCTYPE PyObject SYSTEM "PyObjects.dtd">
3-
<PyObject module="node" class="Node" id="2217354715472">
4-
<attr name="Profile" type="dict" id="2217369299472">
3+
<PyObject module="node" class="Node" id="2273352183440">
4+
<attr name="Profile" type="dict" id="2273365816464">
55
</attr>
66
<attr name="Description" type="string" value="" />
7-
<attr name="Dictionary" type="dict" id="2217369505408">
7+
<attr name="Dictionary" type="dict" id="2273373045312">
88
<entry>
99
<key type="numeric" value="8192" />
10-
<val type="string" value="\x02@ABC\x01" />
10+
<val type="string" value="\x00\x11&quot;3DUfw\x88\x99\xaa\xbb\xcc\xdd\xee\xff" />
11+
</entry>
12+
<entry>
13+
<key type="numeric" value="8193" />
14+
<val type="string" value="\xe2\x9c\x93" />
15+
</entry>
16+
<entry>
17+
<key type="numeric" value="8194" />
18+
<val type="string" value="" />
19+
</entry>
20+
<entry>
21+
<key type="numeric" value="8195" />
22+
<val type="string" value="\u2713" />
1123
</entry>
1224
</attr>
13-
<attr name="SpecificMenu" type="list" id="2217369263296">
25+
<attr name="SpecificMenu" type="list" id="2273373059712">
1426
</attr>
15-
<attr name="ParamsDictionary" type="dict" id="2217369504960">
27+
<attr name="ParamsDictionary" type="dict" id="2273373045248">
1628
</attr>
17-
<attr name="UserMapping" type="dict" id="2217355415632">
29+
<attr name="UserMapping" type="dict" id="2273373059408">
1830
<entry>
1931
<key type="numeric" value="8192" />
20-
<val type="dict" id="2217369504832">
32+
<val type="dict" id="2273373010688">
33+
<entry>
34+
<key type="string" value="need" />
35+
<val type="False" value="" />
36+
</entry>
37+
<entry>
38+
<key type="string" value="values" />
39+
<val type="list" id="2273373059456">
40+
<item type="dict" id="2273373010624">
41+
<entry>
42+
<key type="string" value="access" />
43+
<val type="string" value="rw" />
44+
</entry>
45+
<entry>
46+
<key type="string" value="pdo" />
47+
<val type="True" value="" />
48+
</entry>
49+
<entry>
50+
<key type="string" value="type" />
51+
<val type="numeric" value="15" />
52+
</entry>
53+
<entry>
54+
<key type="string" value="name" />
55+
<val type="string" value="Extended" />
56+
</entry>
57+
</item>
58+
</val>
59+
</entry>
60+
<entry>
61+
<key type="string" value="name" />
62+
<val type="string" value="Extended" />
63+
</entry>
64+
<entry>
65+
<key type="string" value="struct" />
66+
<val type="numeric" value="1" />
67+
</entry>
68+
</val>
69+
</entry>
70+
<entry>
71+
<key type="numeric" value="8193" />
72+
<val type="dict" id="2273373009792">
2173
<entry>
2274
<key type="string" value="need" />
2375
<val type="False" value="" />
2476
</entry>
2577
<entry>
2678
<key type="string" value="values" />
27-
<val type="list" id="2217369261952">
28-
<item type="dict" id="2217352937216">
79+
<val type="list" id="2273373059520">
80+
<item type="dict" id="2273373009728">
2981
<entry>
3082
<key type="string" value="access" />
3183
<val type="string" value="rw" />
@@ -40,23 +92,103 @@
4092
</entry>
4193
<entry>
4294
<key type="string" value="name" />
43-
<val type="string" value="Domain" />
95+
<val type="string" value="Bytes" />
96+
</entry>
97+
</item>
98+
</val>
99+
</entry>
100+
<entry>
101+
<key type="string" value="name" />
102+
<val type="string" value="Bytes" />
103+
</entry>
104+
<entry>
105+
<key type="string" value="struct" />
106+
<val type="numeric" value="1" />
107+
</entry>
108+
</val>
109+
</entry>
110+
<entry>
111+
<key type="numeric" value="8194" />
112+
<val type="dict" id="2273373009152">
113+
<entry>
114+
<key type="string" value="need" />
115+
<val type="False" value="" />
116+
</entry>
117+
<entry>
118+
<key type="string" value="name" />
119+
<val type="string" value="Utf8" />
120+
</entry>
121+
<entry>
122+
<key type="string" value="struct" />
123+
<val type="numeric" value="1" />
124+
</entry>
125+
<entry>
126+
<key type="string" value="values" />
127+
<val type="list" id="2273373060800">
128+
<item type="dict" id="2273373009088">
129+
<entry>
130+
<key type="string" value="name" />
131+
<val type="string" value="Utf8" />
132+
</entry>
133+
<entry>
134+
<key type="string" value="type" />
135+
<val type="numeric" value="15" />
136+
</entry>
137+
<entry>
138+
<key type="string" value="access" />
139+
<val type="string" value="rw" />
140+
</entry>
141+
<entry>
142+
<key type="string" value="pdo" />
143+
<val type="True" value="" />
44144
</entry>
45145
</item>
46146
</val>
47147
</entry>
148+
</val>
149+
</entry>
150+
<entry>
151+
<key type="numeric" value="8195" />
152+
<val type="dict" id="2273373049792">
153+
<entry>
154+
<key type="string" value="need" />
155+
<val type="False" value="" />
156+
</entry>
48157
<entry>
49158
<key type="string" value="name" />
50-
<val type="string" value="Domain" />
159+
<val type="string" value="Unicode" />
51160
</entry>
52161
<entry>
53162
<key type="string" value="struct" />
54163
<val type="numeric" value="1" />
55164
</entry>
165+
<entry>
166+
<key type="string" value="values" />
167+
<val type="list" id="2273373156800">
168+
<item type="dict" id="2273373048448">
169+
<entry>
170+
<key type="string" value="name" />
171+
<val type="string" value="Unicode" />
172+
</entry>
173+
<entry>
174+
<key type="string" value="type" />
175+
<val type="numeric" value="15" />
176+
</entry>
177+
<entry>
178+
<key type="string" value="access" />
179+
<val type="string" value="rw" />
180+
</entry>
181+
<entry>
182+
<key type="string" value="pdo" />
183+
<val type="True" value="" />
184+
</entry>
185+
</item>
186+
</val>
187+
</entry>
56188
</val>
57189
</entry>
58190
</attr>
59-
<attr name="DS302" type="dict" id="2217369297168">
191+
<attr name="DS302" type="dict" id="2273373058960">
60192
</attr>
61193
<attr name="ProfileName" type="string" value="None" />
62194
<attr name="Type" type="string" value="master" />

0 commit comments

Comments
 (0)