eds: Support custom_options for unknown EDS fields#653
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds support for round-tripping vendor-specific (non-CiA-306) EDS/DCF keys by collecting them into a new custom_options dict on object dictionary objects and exporting them back out.
Changes:
- Introduces
custom_optionsonODVariable,ODRecord, andODArrayto store unknown EDS keys. - Updates EDS import/export to populate and persist
custom_optionsusing a_STANDARD_OPTIONSallowlist and_get_custom_options()helper. - Adds tests and sample EDS entries covering read + export/import round-trip behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
canopen/objectdictionary/eds.py |
Collects unknown keys into custom_options during import and writes them back during export. |
canopen/objectdictionary/__init__.py |
Adds custom_options attribute to OD object types. |
test/test_eds.py |
Adds unit tests for reading and round-tripping custom_options. |
test/sample.eds |
Adds sample objects containing vendor-specific keys to validate behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
064b334 to
11da53a
Compare
11da53a to
1f1cb14
Compare
1f1cb14 to
8c780ba
Compare
When importing an EDS/DCF file, any key that is not part of the CiA 306 standard field set is now collected into a custom_options dict on the object. This allows applications to round-trip vendor-specific metadata without losing it. Co-authored-by: FedericoSpada <FedericoSpada@users.noreply.github.com>
8c780ba to
66544de
Compare
|
With all the AI output in between, it's hard to keep track of what changed. I'd really prefer not force-pushing additional fixes (or even merging the master branch). Much easier to see what's going on with simple commits on top, ideally with a one-line mention what was touched. Will be squashed away when merging. Thanks! |
acolomb
left a comment
There was a problem hiding this comment.
Looks great overall, but one question about the shared mutable dicts, see below.
| "bit_definitions", "storage_location"): | ||
| if attr in template.__dict__: | ||
| var.__dict__[attr] = template.__dict__[attr] | ||
| var.custom_options = getattr(template, "custom_options", {}) |
There was a problem hiding this comment.
On second thought, this attribute always exists. Let's avoid the potential creation of non-shared dicts here as well.
| var.custom_options = getattr(template, "custom_options", {}) | |
| var.custom_options = template.custom_options |
There was a problem hiding this comment.
Or handle it as part of the enumerated attributes? The existence check is not really needed in this specific case, but still simpler to use a common code path. If you decide to do that, please switch to getattr / setattr in the process.
There was a problem hiding this comment.
This is what I had in mind: (GutHub won't render it correctly as a suggestion)
for attr in ("data_type", "unit", "factor", "min", "max", "default",
"access_type", "description", "value_descriptions",
"bit_definitions", "storage_location", "custom_options"):
if (template_value := getattr(template, attr)) is not None:
setattr(var, attr, template_value)|
The two remaining "partial" lines from the Codecov report can be ignored IMHO, that's only the safety check to not rewrite standard options. |
From review, direct access to the template, we know this attribute exists. Co-authored-by: André Colomb <github.com@andre.colomb.de>
Supersedes #615.
When importing an EDS/DCF file, any key that is not part of the CiA 306 standard field set is now collected into a
custom_optionsdict on the object. This allows applications to round-trip vendor-specific metadata without losing it.Changes
ODVariable,ODRecordandODArraygain acustom_options: dict[str, str]attribute (default{})._STANDARD_OPTIONSset ineds.pylists all keys that are parsed explicitly.ObjFlagsandDenotationare intentionally not in this set — they flow throughcustom_optionsand survive round-trips until first-class support is added in eds: Add first-class support for CiA 306 ObjFlags and Denotation #654._get_custom_options(eds, section)helper collects every key not in_STANDARD_OPTIONS.custom_optionsis populated for top-level VAR/DOMAIN, ARRAY and RECORD objects as well as for sub-variables viabuild_variable().copy_variable()now gives each copied variable its owncustom_optionsdict to avoid shared-state mutations between shallow-copy clones.export_variable()andexport_record()writecustom_optionsback to the EDS file, guarded by a_STANDARD_OPTIONScheck to prevent user-supplied keys from clobbering standard fields.Tests
test_reading_custom_options— VAR withCategory=Motor,Offset=100test_custom_options_standard_keys_excluded— standard keys absent fromcustom_optionstest_custom_options_empty_for_standard_object— heartbeat time has{}test_custom_options_record— RECORD-levelcustom_optionstest_roundtrip_custom_options— full EDS export/import cycle preserves valuestest_roundtrip_custom_options_not_duplicated_as_standard— standard keys stay out after round-trip