objdictgen 3.5__tar.gz → 3.5.2__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.
Files changed (54) hide show
  1. {objdictgen-3.5/src/objdictgen.egg-info → objdictgen-3.5.2}/PKG-INFO +19 -11
  2. {objdictgen-3.5 → objdictgen-3.5.2}/README.md +18 -10
  3. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/__init__.py +8 -2
  4. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/__main__.py +4 -3
  5. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/jsonod.py +29 -6
  6. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/node.py +8 -6
  7. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/schema/od.schema.json +5 -1
  8. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/networkedit.py +7 -0
  9. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/objdictedit.py +15 -6
  10. {objdictgen-3.5 → objdictgen-3.5.2/src/objdictgen.egg-info}/PKG-INFO +19 -11
  11. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen.egg-info/SOURCES.txt +1 -0
  12. objdictgen-3.5.2/tests/test_installer.py +38 -0
  13. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_jsonod.py +30 -0
  14. {objdictgen-3.5 → objdictgen-3.5.2}/LICENSE +0 -0
  15. {objdictgen-3.5 → objdictgen-3.5.2}/pyproject.toml +0 -0
  16. {objdictgen-3.5 → objdictgen-3.5.2}/setup.cfg +0 -0
  17. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-302.prf +0 -0
  18. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-401.prf +0 -0
  19. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-402.prf +0 -0
  20. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-404.prf +0 -0
  21. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-406.prf +0 -0
  22. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-408.prf +0 -0
  23. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-410.prf +0 -0
  24. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-418.prf +0 -0
  25. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/config/DS-419.prf +0 -0
  26. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/eds_utils.py +0 -0
  27. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/gen_cfile.py +0 -0
  28. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/img/networkedit.ico +0 -0
  29. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/img/networkedit.png +0 -0
  30. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/maps.py +0 -0
  31. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/nodelist.py +0 -0
  32. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/nodemanager.py +0 -0
  33. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/nosis.py +0 -0
  34. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/py.typed +0 -0
  35. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/typing.py +0 -0
  36. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/__init__.py +0 -0
  37. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/commondialogs.py +0 -0
  38. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/exception.py +0 -0
  39. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/networkeditortemplate.py +0 -0
  40. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/nodeeditortemplate.py +0 -0
  41. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen/ui/subindextable.py +0 -0
  42. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen.egg-info/dependency_links.txt +0 -0
  43. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen.egg-info/entry_points.txt +0 -0
  44. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen.egg-info/requires.txt +0 -0
  45. {objdictgen-3.5 → objdictgen-3.5.2}/src/objdictgen.egg-info/top_level.txt +0 -0
  46. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_imports.py +0 -0
  47. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_knownfailures.py +0 -0
  48. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_main.py +0 -0
  49. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_maps.py +0 -0
  50. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_node.py +0 -0
  51. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_nodelist.py +0 -0
  52. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_nodemanager.py +0 -0
  53. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_nosis.py +0 -0
  54. {objdictgen-3.5 → objdictgen-3.5.2}/tests/test_odcompare.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: objdictgen
3
- Version: 3.5
3
+ Version: 3.5.2
4
4
  Summary: CanFestival Object Dictionary tool
5
5
  Home-page: https://github.com/Laerdal/python-objdictgen
6
6
  Author: Svein Seldal
@@ -61,8 +61,8 @@ Laerdal Medical fork for the canfestival library:
61
61
  objdictgen is a tool to parse, view and manipulate files containing object
62
62
  dictionary (OD). An object dictionary is entries with data and configuration
63
63
  in CANopen devices. The `odg` executable is installed. It supports
64
- reading and writing OD files in `.json` format, in legacy XML `.od` and `.eds`
65
- files. It can generate c code for use with the canfestival library.
64
+ reading and writing OD files in `.json`/`.jsonc` format, in legacy XML `.od`
65
+ and `.eds` files. It can generate c code for use with the canfestival library.
66
66
 
67
67
 
68
68
  ## Install
@@ -119,14 +119,11 @@ descriptions, help with values and validate the file.
119
119
  "json.schemas": [
120
120
  {
121
121
  "fileMatch": [
122
- "**.json"
122
+ "**.jsonc"
123
123
  ],
124
124
  "url": "./src/objdictgen/schema/od.schema.json"
125
125
  }
126
126
  ],
127
- "files.associations": {
128
- "*.json": "jsonc"
129
- }
130
127
  ```
131
128
 
132
129
  ## Conversion
@@ -134,7 +131,7 @@ descriptions, help with values and validate the file.
134
131
  The recommended way to convert existing/legacy `.od` files to the new JSON
135
132
  format is:
136
133
 
137
- $ odg generate <file.od> <file.json> --fix --drop-unused [--nosort]
134
+ $ odg generate <file.od> <file.jsonc> --fix --drop-unused [--nosort]
138
135
 
139
136
  The `--fix` option might be necessary if the OD-file contains internal
140
137
  inconsistencies. It is safe to run this option as it will not delete any active
@@ -145,10 +142,10 @@ parameter that might be used in the file.
145
142
  ## Motivation
146
143
 
147
144
  The biggest improvement with the new tool over the original implementation is
148
- the introduction of a new `.json` based format to store the object dictionary.
149
- The JSON format is well-known and easy to read. The tool supports jsonc,
145
+ the introduction of a new `.jsonc` based format to store the object dictionary.
146
+ The JSON format is well-known and easy to read. The tool use jsonc,
150
147
  allowing comments in the json file. `odg` will process the file in a repeatable
151
- manner, making it possible support diffing of the `.json` file output. `odg`
148
+ manner, making it possible support diffing of the `.jsonc` file output. `odg`
152
149
  remains 100% compatible with the legacy `.od` format on both input and output.
153
150
 
154
151
  The original objdictedit and objdictgen tool were written in legacy python 2 and
@@ -159,6 +156,17 @@ This tool is a fork from upstream canfestival-3-asc repo:
159
156
  > https://github.com/Laerdal/canfestival-3-asc
160
157
 
161
158
 
159
+ ## Making objdictedit excutable
160
+
161
+ To be able build an executable that can be run from anywhere:
162
+
163
+ $ pip install pyinstaller
164
+ $ pyinstaller packaging/objdictedit.spec
165
+
166
+ The file `dist/objdictedit.exe` can now be used anywhere. It does not need any
167
+ pre-installed software.
168
+
169
+
162
170
  ## License
163
171
 
164
172
  Objdictgen has been based on the python tool included in CanFestival. This
@@ -18,8 +18,8 @@ Laerdal Medical fork for the canfestival library:
18
18
  objdictgen is a tool to parse, view and manipulate files containing object
19
19
  dictionary (OD). An object dictionary is entries with data and configuration
20
20
  in CANopen devices. The `odg` executable is installed. It supports
21
- reading and writing OD files in `.json` format, in legacy XML `.od` and `.eds`
22
- files. It can generate c code for use with the canfestival library.
21
+ reading and writing OD files in `.json`/`.jsonc` format, in legacy XML `.od`
22
+ and `.eds` files. It can generate c code for use with the canfestival library.
23
23
 
24
24
 
25
25
  ## Install
@@ -76,14 +76,11 @@ descriptions, help with values and validate the file.
76
76
  "json.schemas": [
77
77
  {
78
78
  "fileMatch": [
79
- "**.json"
79
+ "**.jsonc"
80
80
  ],
81
81
  "url": "./src/objdictgen/schema/od.schema.json"
82
82
  }
83
83
  ],
84
- "files.associations": {
85
- "*.json": "jsonc"
86
- }
87
84
  ```
88
85
 
89
86
  ## Conversion
@@ -91,7 +88,7 @@ descriptions, help with values and validate the file.
91
88
  The recommended way to convert existing/legacy `.od` files to the new JSON
92
89
  format is:
93
90
 
94
- $ odg generate <file.od> <file.json> --fix --drop-unused [--nosort]
91
+ $ odg generate <file.od> <file.jsonc> --fix --drop-unused [--nosort]
95
92
 
96
93
  The `--fix` option might be necessary if the OD-file contains internal
97
94
  inconsistencies. It is safe to run this option as it will not delete any active
@@ -102,10 +99,10 @@ parameter that might be used in the file.
102
99
  ## Motivation
103
100
 
104
101
  The biggest improvement with the new tool over the original implementation is
105
- the introduction of a new `.json` based format to store the object dictionary.
106
- The JSON format is well-known and easy to read. The tool supports jsonc,
102
+ the introduction of a new `.jsonc` based format to store the object dictionary.
103
+ The JSON format is well-known and easy to read. The tool use jsonc,
107
104
  allowing comments in the json file. `odg` will process the file in a repeatable
108
- manner, making it possible support diffing of the `.json` file output. `odg`
105
+ manner, making it possible support diffing of the `.jsonc` file output. `odg`
109
106
  remains 100% compatible with the legacy `.od` format on both input and output.
110
107
 
111
108
  The original objdictedit and objdictgen tool were written in legacy python 2 and
@@ -116,6 +113,17 @@ This tool is a fork from upstream canfestival-3-asc repo:
116
113
  > https://github.com/Laerdal/canfestival-3-asc
117
114
 
118
115
 
116
+ ## Making objdictedit excutable
117
+
118
+ To be able build an executable that can be run from anywhere:
119
+
120
+ $ pip install pyinstaller
121
+ $ pyinstaller packaging/objdictedit.spec
122
+
123
+ The file `dist/objdictedit.exe` can now be used anywhere. It does not need any
124
+ pre-installed software.
125
+
126
+
119
127
  ## License
120
128
 
121
129
  Objdictgen has been based on the python tool included in CanFestival. This
@@ -18,12 +18,15 @@
18
18
  # USA
19
19
 
20
20
  import os
21
+ import sys
21
22
  from pathlib import Path
22
23
 
23
24
  from objdictgen.node import Node
24
25
  from objdictgen.nodemanager import NodeManager
25
26
 
26
- __version__ = "3.5"
27
+ __version__ = "3.5.2"
28
+ __version_tuple__ = (3, 5, 2, 0)
29
+ __copyright__ = "(c) 2024 Svein Seldal, Laerdal Medical AS, and several. Licensed under GPLv2.1."
27
30
 
28
31
  # Shortcuts
29
32
  LoadFile = Node.LoadFile
@@ -31,7 +34,10 @@ LoadJson = Node.LoadJson
31
34
 
32
35
  ODG_PROGRAM = "odg"
33
36
 
34
- SCRIPT_DIRECTORY = Path(__file__).parent
37
+ if hasattr(sys, '_MEIPASS'):
38
+ SCRIPT_DIRECTORY = Path(sys._MEIPASS) / 'objdictgen'
39
+ else:
40
+ SCRIPT_DIRECTORY = Path(__file__).resolve().parent
35
41
 
36
42
  PROFILE_DIRECTORIES: list[Path] = [
37
43
  SCRIPT_DIRECTORY / 'config'
@@ -220,7 +220,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
220
220
  subp.add_argument('-x', '--exclude', action="append", help="OD Index to exclude.")
221
221
  subp.add_argument('-f', '--fix', action="store_true",
222
222
  help="Fix any inconsistency errors in OD before generate output")
223
- subp.add_argument('-t', '--type', choices=['od', 'eds', 'json', 'c'],
223
+ subp.add_argument('-t', '--type', choices=['od', 'eds', 'json', 'jsonc', 'c'],
224
224
  help="Select output file type")
225
225
  subp.add_argument('--drop-unused', action="store_true", help="Remove unused parameters")
226
226
  subp.add_argument('--internal', action="store_true",
@@ -351,8 +351,9 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None):
351
351
 
352
352
  # Write the data
353
353
  od.DumpFile(opts.out,
354
- filetype=opts.type, sort=not opts.no_sort,
355
- internal=opts.internal, validate=not opts.novalidate
354
+ filetype=opts.type,
355
+ # These additional options are only used for JSON output
356
+ sort=not opts.no_sort, internal=opts.internal, validate=not opts.novalidate
356
357
  )
357
358
 
358
359
 
@@ -58,12 +58,13 @@ class ValidationError(Exception):
58
58
  # 1 - Default JSON format
59
59
  JSON_ID = "od data"
60
60
  JSON_DESCRIPTION = "Canfestival object dictionary data"
61
+ JSON_SCHEMA = "https://raw.githubusercontent.com/Laerdal/python-objdictgen/main/src/objdictgen/schema/od.schema.json"
61
62
  JSON_INTERNAL_VERSION = "0"
62
63
  JSON_VERSION = "1"
63
64
 
64
65
  # Output order in JSON file
65
66
  JSON_TOP_ORDER = (
66
- "$id", "$version", "$description", "$tool", "$date", "$schema",
67
+ "$id", "$version", "$description", "$schema", "$tool", "$date", "$schema",
67
68
  "name", "description", "type", "id", "profile",
68
69
  "default_string_size", "dictionary",
69
70
  )
@@ -117,6 +118,7 @@ FIELDS_DATA_MUST = {
117
118
  }
118
119
  FIELDS_DATA_OPT = {
119
120
  '$description', # info only
121
+ '$schema', # info only
120
122
  '$tool', # info only
121
123
  '$date', # info only
122
124
  'id', # default 0
@@ -357,7 +359,8 @@ def compare_profile(profilename: TPath, params: ODMapping, menu: TProfileMenu|No
357
359
  return False, False
358
360
 
359
361
 
360
- def generate_jsonc(node: "Node", compact=False, sort=False, internal=False, validate=True) -> str:
362
+ def generate_jsonc(node: "Node", compact=False, sort=False, internal=False,
363
+ validate=True, jsonc=True) -> str:
361
364
  """ Export a JSONC string representation of the node """
362
365
 
363
366
  # Get the dict representation
@@ -374,20 +377,37 @@ def generate_jsonc(node: "Node", compact=False, sort=False, internal=False, vali
374
377
  text = json.dumps(jd, separators=(',', ': '), indent=2)
375
378
 
376
379
  # Convert the special __ fields to jsonc comments
380
+ # Syntax: "__<field>: <value>"
377
381
  text = re.sub(
378
382
  r'^(\s*)"__(\w+)": "(.*)",?$',
379
- r'\1// "\2": "\3"',
383
+ # In regular json files, __* fields are omitted from output
384
+ # In jsonc files, the __* entry is converted to a comment:
385
+ # "// <field>: <value>"
386
+ r'\1// "\2": "\3"' if jsonc else '',
380
387
  text,
381
388
  flags=re.MULTILINE,
382
389
  )
383
390
 
391
+ if jsonc:
392
+ # In jsonc the field is converted to "<field>, // <comment>"
393
+ repl = lambda m: m[1].replace('\\"', '"') + m[3] + m[2]
394
+ else:
395
+ # In json the field is converted to "<field>,"
396
+ repl = lambda m: m[1].replace('\\"', '"') + m[3]
397
+
384
398
  # Convert the special @@ fields to jsonc comments
399
+ # Syntax: "@@<field>, // <comment>@@"
385
400
  text = re.sub(
386
401
  r'"@@(.*?)(\s*//.*?)?@@"(.*)$',
387
- lambda m: m[1].replace('\\"', '"') + m[3] + m[2],
402
+ repl,
388
403
  text,
389
404
  flags=re.MULTILINE,
390
405
  )
406
+
407
+ # In case the json contains empty lines, remove them
408
+ if not jsonc:
409
+ text = "\n".join(line for line in text.splitlines() if line.strip())
410
+
391
411
  return text
392
412
 
393
413
 
@@ -501,6 +521,7 @@ def node_todict(node: "Node", sort=False, rich=True, internal=False, validate=Tr
501
521
  '$id': JSON_ID,
502
522
  '$version': JSON_INTERNAL_VERSION if internal else JSON_VERSION,
503
523
  '$description': JSON_DESCRIPTION,
524
+ '$schema': JSON_SCHEMA,
504
525
  '$tool': str(objdictgen.ODG_PROGRAM) + ' ' + str(objdictgen.__version__),
505
526
  '$date': datetime.now().astimezone().isoformat(),
506
527
  'name': node.Name,
@@ -722,7 +743,7 @@ def rearrage_for_json(obj: TODObjJson, node: "Node", objtypes_i2s: dict[int, str
722
743
 
723
744
  # Add __type when rich format
724
745
  if info and "type" not in sub:
725
- sub["__type"] = objtypes_i2s.get(info["type"], info["type"])
746
+ sub["__type"] = f'@@"{objtypes_i2s.get(info["type"], info["type"])}" // {info["type"]}@@'
726
747
 
727
748
  # Replace value
728
749
  if rich and "value" in sub:
@@ -744,7 +765,8 @@ def rearrage_for_json(obj: TODObjJson, node: "Node", objtypes_i2s: dict[int, str
744
765
  # Replace numeric type with string value
745
766
  if rich and "type" in each:
746
767
  # FIXME: The cast is to ensure mypy is able keep track
747
- each["type"] = objtypes_i2s.get(cast(int, each["type"]), each["type"])
768
+ n = objtypes_i2s.get(cast(int, each["type"]), each["type"])
769
+ each["type"] = f'@@"{n}" // {each["type"]}@@'
748
770
 
749
771
  # Rearrage order of 'sub' and 'each'
750
772
  obj["sub"] = [
@@ -1148,6 +1170,7 @@ def validate_fromdict(jsonobj: TODJson, objtypes_i2s: dict[int, str], objtypes_s
1148
1170
  # "type" (must)
1149
1171
  # Y "dictionary" (must)
1150
1172
  # "$description" (optional)
1173
+ # "$schema" (optional)
1151
1174
  # "$tool" (optional)
1152
1175
  # "$date" (optional)
1153
1176
  # "id" (optional, default 0)
@@ -196,14 +196,14 @@ class Node(NodeProtocol):
196
196
  """ Import a new Node from a JSON string """
197
197
  return jsonod.generate_node(contents)
198
198
 
199
- def DumpFile(self, filepath: TPath, filetype: str|None = "json", **kwargs):
199
+ def DumpFile(self, filepath: TPath, filetype: str|None = "jsonc", **kwargs):
200
200
  """ Save node into file """
201
201
 
202
202
  # Attempt to determine the filetype from the filepath
203
203
  if not filetype:
204
204
  filetype = Path(filepath).suffix[1:]
205
205
  if not filetype:
206
- filetype = "json"
206
+ filetype = "jsonc"
207
207
 
208
208
  if filetype == 'od':
209
209
  log.debug("Writing XML OD '%s'", filepath)
@@ -219,9 +219,11 @@ class Node(NodeProtocol):
219
219
  f.write(content)
220
220
  return
221
221
 
222
- if filetype == 'json':
222
+ if filetype in ('json', 'jsonc'):
223
223
  log.debug("Writing JSON OD '%s'", filepath)
224
- jdata = self.DumpJson(**kwargs)
224
+ kw = kwargs.copy()
225
+ kw['jsonc'] = filetype == 'jsonc'
226
+ jdata = self.DumpJson(**kw)
225
227
  with open(filepath, "w", encoding="utf-8") as f:
226
228
  f.write(jdata)
227
229
  return
@@ -234,10 +236,10 @@ class Node(NodeProtocol):
234
236
 
235
237
  raise ValueError("Unknown file suffix, unable to write file")
236
238
 
237
- def DumpJson(self, compact=False, sort=False, internal=False, validate=True) -> str:
239
+ def DumpJson(self, compact=False, sort=False, internal=False, validate=True, jsonc=True) -> str:
238
240
  """ Dump the node into a JSON string """
239
241
  return jsonod.generate_jsonc(
240
- self, compact=compact, sort=sort, internal=internal, validate=validate
242
+ self, compact=compact, sort=sort, internal=internal, validate=validate, jsonc=jsonc
241
243
  )
242
244
 
243
245
  def asdict(self) -> dict[str, Any]:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema",
3
- "$id": "https://raw.githubusercontent.com/laerdal-svg/python-objdictgen/main/src/objdictgen/schema/od.schema.json",
3
+ "$id": "https://raw.githubusercontent.com/Laerdal/python-objdictgen/main/src/objdictgen/schema/od.schema.json",
4
4
  "title": "Object Dictionary",
5
5
  "description": "A Object Dictionary description for canfestival",
6
6
  "type": "object",
@@ -21,6 +21,10 @@
21
21
  "description": "Description about the file",
22
22
  "type": "string"
23
23
  },
24
+ "$schema": {
25
+ "description": "The schema that this file is based on",
26
+ "type": "string"
27
+ },
24
28
  "$tool": {
25
29
  "description": "Tool that generated this file (optional)",
26
30
  "type": "string"
@@ -18,6 +18,7 @@
18
18
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19
19
  # USA
20
20
 
21
+ import ctypes
21
22
  import getopt
22
23
  import logging
23
24
  import os
@@ -415,6 +416,12 @@ class NetworkEdit(NetworkEditorTemplate):
415
416
 
416
417
 
417
418
  def uimain(project):
419
+
420
+ # Set the application ID for Windows taskbar
421
+ if sys.platform == "win32":
422
+ myappid = 'objdictgen.objdictedit.' + objdictgen.__version__
423
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
424
+
418
425
  app = wx.PySimpleApp()
419
426
 
420
427
  wx.InitAllImageHandlers()
@@ -18,6 +18,7 @@
18
18
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19
19
  # USA
20
20
 
21
+ import ctypes
21
22
  import getopt
22
23
  import logging
23
24
  import os
@@ -196,9 +197,9 @@ class ObjdictEdit(NodeEditorTemplate):
196
197
 
197
198
  def _init_ctrls(self, parent):
198
199
  wx.Frame.__init__(
199
- self, id=ID_OBJDICTEDIT, name='objdictedit',
200
+ self, id=ID_OBJDICTEDIT, name=self.title,
200
201
  parent=parent, pos=wx.Point(149, 178), size=wx.Size(1000, 700),
201
- style=wx.DEFAULT_FRAME_STYLE, title='Objdictedit',
202
+ style=wx.DEFAULT_FRAME_STYLE, title=self.title,
202
203
  )
203
204
  self._init_utils()
204
205
  self.SetClientSize(wx.Size(1000, 700))
@@ -228,6 +229,8 @@ class ObjdictEdit(NodeEditorTemplate):
228
229
  self.SetStatusBar(self.HelpBar)
229
230
 
230
231
  def __init__(self, parent, manager: NodeManager|None = None, filesopen: list[TPath]|None = None):
232
+ self.title = f"Object dictionary editor v{objdictgen.__version__}"
233
+
231
234
  filesopen = filesopen or []
232
235
  if manager is None:
233
236
  NodeEditorTemplate.__init__(self, NodeManager(), True)
@@ -322,9 +325,9 @@ class ObjdictEdit(NodeEditorTemplate):
322
325
 
323
326
  def RefreshTitle(self):
324
327
  if self.FileOpened.GetPageCount() > 0:
325
- self.SetTitle(f"Objdictedit - {self.Manager.GetCurrentFilename()}")
328
+ self.SetTitle(self.title + f" - {self.Manager.GetCurrentFilename()}")
326
329
  else:
327
- self.SetTitle("Objdictedit")
330
+ self.SetTitle(self.title)
328
331
 
329
332
  def RefreshCurrentIndexList(self):
330
333
  selected = self.FileOpened.GetSelection()
@@ -424,7 +427,7 @@ class ObjdictEdit(NodeEditorTemplate):
424
427
 
425
428
  with wx.FileDialog(
426
429
  self, "Choose a file", directory, "",
427
- "OD files (*.json;*.od;*.eds)|*.json;*.od;*.eds|All files|*.*",
430
+ wildcard="OD JSON file (*.jsonc;*.json)|*.jsonc;*.json|Legacy OD file (*.od)|*.od|EDS file (*.eds)|*.eds|All files|*.*",
428
431
  style=wx.FD_OPEN | wx.FD_CHANGE_DIR,
429
432
  ) as dialog:
430
433
  if dialog.ShowModal() != wx.ID_OK:
@@ -475,7 +478,7 @@ class ObjdictEdit(NodeEditorTemplate):
475
478
 
476
479
  with wx.FileDialog(
477
480
  self, "Choose a file", directory, filename,
478
- wildcard="OD JSON file (*.json)|*.json;|OD file (*.od)|*.od;|EDS file (*.eds)|*.eds",
481
+ wildcard="OD JSON file (*.jsonc;*.json)|*.jsonc;*.json|Legacy OD file (*.od)|*.od|EDS file (*.eds)|*.eds",
479
482
  style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR,
480
483
  ) as dialog:
481
484
  if dialog.ShowModal() != wx.ID_OK:
@@ -608,6 +611,12 @@ class ObjdictEdit(NodeEditorTemplate):
608
611
 
609
612
 
610
613
  def uimain(args):
614
+
615
+ # Set the application ID for Windows taskbar
616
+ if sys.platform == "win32":
617
+ myappid = 'objdictgen.objdictedit.' + objdictgen.__version__
618
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
619
+
611
620
  app = wx.App()
612
621
 
613
622
  wx.InitAllImageHandlers()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: objdictgen
3
- Version: 3.5
3
+ Version: 3.5.2
4
4
  Summary: CanFestival Object Dictionary tool
5
5
  Home-page: https://github.com/Laerdal/python-objdictgen
6
6
  Author: Svein Seldal
@@ -61,8 +61,8 @@ Laerdal Medical fork for the canfestival library:
61
61
  objdictgen is a tool to parse, view and manipulate files containing object
62
62
  dictionary (OD). An object dictionary is entries with data and configuration
63
63
  in CANopen devices. The `odg` executable is installed. It supports
64
- reading and writing OD files in `.json` format, in legacy XML `.od` and `.eds`
65
- files. It can generate c code for use with the canfestival library.
64
+ reading and writing OD files in `.json`/`.jsonc` format, in legacy XML `.od`
65
+ and `.eds` files. It can generate c code for use with the canfestival library.
66
66
 
67
67
 
68
68
  ## Install
@@ -119,14 +119,11 @@ descriptions, help with values and validate the file.
119
119
  "json.schemas": [
120
120
  {
121
121
  "fileMatch": [
122
- "**.json"
122
+ "**.jsonc"
123
123
  ],
124
124
  "url": "./src/objdictgen/schema/od.schema.json"
125
125
  }
126
126
  ],
127
- "files.associations": {
128
- "*.json": "jsonc"
129
- }
130
127
  ```
131
128
 
132
129
  ## Conversion
@@ -134,7 +131,7 @@ descriptions, help with values and validate the file.
134
131
  The recommended way to convert existing/legacy `.od` files to the new JSON
135
132
  format is:
136
133
 
137
- $ odg generate <file.od> <file.json> --fix --drop-unused [--nosort]
134
+ $ odg generate <file.od> <file.jsonc> --fix --drop-unused [--nosort]
138
135
 
139
136
  The `--fix` option might be necessary if the OD-file contains internal
140
137
  inconsistencies. It is safe to run this option as it will not delete any active
@@ -145,10 +142,10 @@ parameter that might be used in the file.
145
142
  ## Motivation
146
143
 
147
144
  The biggest improvement with the new tool over the original implementation is
148
- the introduction of a new `.json` based format to store the object dictionary.
149
- The JSON format is well-known and easy to read. The tool supports jsonc,
145
+ the introduction of a new `.jsonc` based format to store the object dictionary.
146
+ The JSON format is well-known and easy to read. The tool use jsonc,
150
147
  allowing comments in the json file. `odg` will process the file in a repeatable
151
- manner, making it possible support diffing of the `.json` file output. `odg`
148
+ manner, making it possible support diffing of the `.jsonc` file output. `odg`
152
149
  remains 100% compatible with the legacy `.od` format on both input and output.
153
150
 
154
151
  The original objdictedit and objdictgen tool were written in legacy python 2 and
@@ -159,6 +156,17 @@ This tool is a fork from upstream canfestival-3-asc repo:
159
156
  > https://github.com/Laerdal/canfestival-3-asc
160
157
 
161
158
 
159
+ ## Making objdictedit excutable
160
+
161
+ To be able build an executable that can be run from anywhere:
162
+
163
+ $ pip install pyinstaller
164
+ $ pyinstaller packaging/objdictedit.spec
165
+
166
+ The file `dist/objdictedit.exe` can now be used anywhere. It does not need any
167
+ pre-installed software.
168
+
169
+
162
170
  ## License
163
171
 
164
172
  Objdictgen has been based on the python tool included in CanFestival. This
@@ -41,6 +41,7 @@ src/objdictgen/ui/nodeeditortemplate.py
41
41
  src/objdictgen/ui/objdictedit.py
42
42
  src/objdictgen/ui/subindextable.py
43
43
  tests/test_imports.py
44
+ tests/test_installer.py
44
45
  tests/test_jsonod.py
45
46
  tests/test_knownfailures.py
46
47
  tests/test_main.py
@@ -0,0 +1,38 @@
1
+
2
+ import pytest
3
+ from unittest import mock
4
+ import os
5
+ import sys
6
+
7
+ @pytest.fixture
8
+ def setenvvar(monkeypatch):
9
+ with mock.patch.dict(os.environ, {"TEST": "foobar"}):
10
+ yield
11
+
12
+
13
+ def test_filereplacer(basepath, wd, setenvvar):
14
+
15
+ sys.path.append(str(basepath / "packaging"))
16
+ os.chdir(basepath)
17
+ from filereplacer import convert
18
+
19
+ tests = [
20
+ (1, "Test data", "Test data"),
21
+ (2, "@@{name}", "objdictgen"),
22
+ (3, "@@{TEST}", "foobar"), # Read from the mocked environment variable
23
+ (4, "@@{nonexisting}", "non-existing"),
24
+ ]
25
+
26
+ for i, data, result in tests:
27
+ infile = wd / "test.txt"
28
+ outfile = wd / "out.txt"
29
+ with open(infile, "w", encoding="utf-8") as f:
30
+ f.write(data)
31
+ if i == 4:
32
+ with pytest.raises(KeyError):
33
+ convert(infile, outfile)
34
+ continue
35
+ else:
36
+ convert(infile, outfile)
37
+ with open(outfile, "r", encoding="utf-8") as f:
38
+ assert f.read() == result
@@ -130,3 +130,33 @@ def test_jsonod_timezone():
130
130
  if m:
131
131
  print(m[1])
132
132
  assert m[1] == cmp + "+" + tz
133
+
134
+
135
+ def test_jsonod_comments(odpath):
136
+ """ Test that the json file exports comments correctly. """
137
+
138
+ fname_jsonc = odpath / "jsonod-comments.jsonc"
139
+ fname_json = odpath / "jsonod-comments.json"
140
+
141
+ m1 = Node.LoadFile(fname_jsonc)
142
+
143
+ with open(fname_jsonc, "r") as f:
144
+ jsonc_data = f.read()
145
+ with open(fname_json, "r") as f:
146
+ json_data = f.read()
147
+
148
+ out = generate_jsonc(m1, compact=False, sort=False, internal=False, validate=True, jsonc=True)
149
+
150
+ # Compare the jsonc data with the generated data
151
+ for a, b in zip(jsonc_data.splitlines(), out.splitlines()):
152
+ if '"$date"' in a or '"$tool"' in a:
153
+ continue
154
+ assert a == b
155
+
156
+ out = generate_jsonc(m1, compact=False, sort=False, internal=False, validate=True, jsonc=False)
157
+
158
+ # Compare the json data with the generated data
159
+ for a, b in zip(json_data.splitlines(), out.splitlines()):
160
+ if '"$date"' in a or '"$tool"' in a:
161
+ continue
162
+ assert a == b
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes