Handle edge cases in utils helpers

TL;DR

  • An empty attribute dtype such as [] or ((),) now reaches the error explaining the expected spelling, instead of raising IndexError.
  • tango.utils.get_attrs no longer writes to standard output, and raises the TypeError it intends to.
  • tango.utils.EventCallback renders an unrecognised event type instead of printing None, and accepts max_buf=0.
  • __build_to_tango_type no longer rebuilds part of its map once per CmdArgType attribute.

Reported in #789.

Key Facts

  • is_devstate_seq unwrapped nested sequences without checking anything was left. It matters because get_attribute_type_format calls it before the code that raises "Spectrum attribute type must be specified as (,)", so a user who wrote the dtype wrongly got an IndexError instead of the message telling them how to write it. is_enum_seq already carried the guard; this makes the pair symmetric.
  • get_attrs had a second defect beyond the stray print: its message interpolated obj.__name__, which only exists on classes, so for an instance the intended TypeError was replaced by an AttributeError raised while formatting it. The message now reports the type of the bad mapping.
  • _append compared buffer length with ==, so max_buf=0 popped from an empty list on the first event. Now it trims with a loop and only stores when the buffer has room, which is also robust if the buffer ever exceeds its bound.
  • __build_to_tango_type is behaviour-preserving. The inner loop sat inside the dir(CmdArgType) loop and reused both loop variables, so it rebuilt the numpy half of the map on every iteration and produced the same dict at the end. Ruff flags the variable reuse as PLW2901. Existing coverage of TO_TANGO_TYPE guards the result.

Caveats

  • The first commit adds the tests and fails on its own; the second makes them pass.
  • The get_attrs test needs an object whose __dict__ is not a mapping, which takes a metaclass with a __dict__ property. That is contrived, but it is the only way to reach the branch.
  • EventCallback._get_value and _append are marked "Internal usage only" and are tested directly. The public push_event swallows exceptions, so a test through it could not distinguish these fixes from the existing error handling.
  • Builds on !1074 (merged) and targets its branch. Retarget as the chain merges.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading