Skip to content

eds: fix LowLimit/HighLimit parsing for all signed integer types#658

Open
friederschueler wants to merge 2 commits intocanopen-python:masterfrom
friederschueler:fix/eds-limit-parsing
Open

eds: fix LowLimit/HighLimit parsing for all signed integer types#658
friederschueler wants to merge 2 commits intocanopen-python:masterfrom
friederschueler:fix/eds-limit-parsing

Conversation

@friederschueler
Copy link
Copy Markdown
Collaborator

Fixes incomplete signed integer handling for LowLimit/HighLimit in EDS parsing, as noted in #352.

Changes

  • Replace _calc_bit_length() (only handled INTEGER8/16/32/64) with a lookup dict _SIGNED_BIT_LENGTHS covering all 8 SIGNED_TYPES (INTEGER8/16/24/32/40/48/56/64)
  • Log a warning instead of silently ignoring invalid limit values (except ValueError: pass)
  • Add EDS test entries in sample.eds for INTEGER24/40/48/56 with hex-encoded negative limits
  • Extend test_record_with_limits and add test_invalid_limit_logs_warning

Note on formatting

eds.py and test_eds.py were reformatted with black. If a purely functional diff is preferred, the formatting commits can be dropped — the functional changes are small and easy to separate.

Closes part of #352.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@acolomb
Copy link
Copy Markdown
Member

acolomb commented May 7, 2026

Please always separate style changes from functional changes. Except of course fixing in the immediate vicinity of the functional changes.

Comment on lines +207 to +216
_SIGNED_BIT_LENGTHS = {
datatypes.INTEGER8: 8,
datatypes.INTEGER16: 16,
datatypes.INTEGER24: 24,
datatypes.INTEGER32: 32,
datatypes.INTEGER40: 40,
datatypes.INTEGER48: 48,
datatypes.INTEGER56: 56,
datatypes.INTEGER64: 64,
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to hard-code these at all:

Suggested change
_SIGNED_BIT_LENGTHS = {
datatypes.INTEGER8: 8,
datatypes.INTEGER16: 16,
datatypes.INTEGER24: 24,
datatypes.INTEGER32: 32,
datatypes.INTEGER40: 40,
datatypes.INTEGER48: 48,
datatypes.INTEGER56: 56,
datatypes.INTEGER64: 64,
}
def _calc_bit_length(data_type: int) -> int:
if data_type in datatypes.SIGNED_TYPES:
st = ODVariable.STRUCT_TYPES[data_type]
if isinstance(st, datatypes.IntegerN):
return st.width
return st.size * 8
else:
raise ValueError(
f"Invalid data_type '{data_type}', expecting a signed integer data_type."
)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of the function, following the zen of python:

simple is better than complex
explicit is better than implicit

a lookup dict is the way to go. one could argue to put it into datatypes.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I'm more convinced by the "Don't Repeat Yourself" principle. Listing combinations of numbers and a symbol including the same number, sounds pretty useless. As the data is already there, I prefer a helper function in the object_dictionary module, instead of duplicating it here. A dict can be generated as well from the existing data, but it is really a waste of memory 99.9 % of the time.

What makes this function a bit complicated is the fact that the dict in class ODVariable uses two different approaches for different bit widths. But that is really material for another round of cleanup, maybe changing the way we generate that dict instead of re-using it elsewhere.

Please go with the function to not add technical debt here.

Comment thread canopen/objectdictionary/eds.py Outdated
var.min = int(min_string, 0)
except ValueError:
pass
logger.warning("Failed to parse LowLimit for %s: %r", name, min_string)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging is better than not logging, of course. But this whole treatment looks suspicious:

  1. How does the outside code even notice that the EDS partly failed to parse? Informing the user for troubleshooting is not enough IMHO, but raising would be a massive API break, causing potential errors with previously "working" EDS files.
  2. AFAICT the _signed_int_from_hex() helper does not even fully check whether the value is representable in the given bit width. That's another class of EDS errors we could easily catch and report here, but don't.
  3. Ignoring ValueError seems like a pattern blindly applied to every option. Even for Description and Unit below, which are strings and there is not even a chance of a ValueError from ConfigParser.get().

When we touch / fix this code, let's put some more thought into what really makes sense. Especially point 1 is not solved by logging alone. Being stricter in parsing EDS files might be beneficial.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I get the point and tend to agree to just don't touch it at this point.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I really meant was to fix it now. But of course it can be another PR, to keep this focused. You up to it, or should I?

Comment thread test/test_eds.py Outdated
- Replace _calc_bit_length() (only handled INTEGER8/16/32/64) with a
  lookup dict _SIGNED_BIT_LENGTHS covering all 8 SIGNED_TYPES
  (INTEGER8/16/24/32/40/48/56/64)
- Log a warning instead of silently ignoring invalid limit values
  (except ValueError: pass)
- Add EDS test entries in sample.eds for INTEGER24/40/48/56 with
  hex-encoded negative limits
- Extend test_record_with_limits and add test_invalid_limit_logs_warning

Closes part of canopen-python#352.
@friederschueler friederschueler force-pushed the fix/eds-limit-parsing branch from 27e94d8 to f65a1fb Compare May 7, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants