Skip to content

Fix RecursionError when serializing Enum/IntFlag parameter values#140

Merged
marcosfrenkel merged 2 commits into
toolsforexperiments:masterfrom
marcosfrenkel:fixing_serialization_bug
Jun 11, 2026
Merged

Fix RecursionError when serializing Enum/IntFlag parameter values#140
marcosfrenkel merged 2 commits into
toolsforexperiments:masterfrom
marcosfrenkel:fixing_serialization_bug

Conversation

@marcosfrenkel

@marcosfrenkel marcosfrenkel commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Station snapshots (and parameter gets) containing IntFlag/Enum values crashed
the server with RecursionError: maximum recursion depth exceeded on the send
path. This happens with real drivers such as the Yokogawa GS200, whose
status/event-register parameters return IntFlag instances.

Root cause

Starting with Python 3.11, Flag/IntFlag members are iterable, and a
single-bit member iterates to a one-element sequence containing itself:

>>> list(StatusByte.EAV)
[<StatusByte.EAV: 4>]
>>> list(StatusByte.EAV)[0] is StatusByte.EAV
True

The serializers (dict_to_serialized_dict / iterable_to_serialized_dict)
recurse into anything that is a non-str Iterable. A flag value matched that
check and recursed into itself forever, raising RecursionError from encode()
on the server's send path — so the client never got a response.

Fix

blueprints.py:

  • Treat any Enum as a scalar in dict_to_serialized_dict and
    iterable_to_serialized_dict (serialize its .value), placed before the
    generic Iterable check so flag members never recurse.
  • For a top-level Enum/IntFlag message (the return of a parameter get),
    serialize it with its _class_type via the new _convert_enum_to_dict helper
    so the client reconstructs the actual enum instance — not just a bare int.

Tests

New test/pytest/test_enum_serialization.py:

  • Unit coverage that single-bit, multi-bit, and plain enums serialize to their
    value without recursion.
  • encode(ServerResponse(...)) over a snapshot reproduces the original failing
    path and asserts valid JSON.
  • Round-trip tests that a top-level enum message reconstructs back to the real
    enum type.
  • End-to-end client/server tests (get, instrument snapshot, full station
    snapshot) using a new DummyInstrumentWithFlags dummy instrument that mirrors
    the GS200 status registers.

Notes

A nested flag inside a snapshot is serialized lossily to its integer value
(snapshots are display-oriented), whereas a parameter get round-trips back to
the actual enum type via _class_type.

Comment thread src/instrumentserver/testing/dummy_instruments/generic.py Outdated
@marcosfrenkel marcosfrenkel changed the title fix bug for when EnumFlag type is serialized Fix RecursionError when serializing Enum/IntFlag parameter values Jun 11, 2026
@marcosfrenkel marcosfrenkel merged commit e48cafb into toolsforexperiments:master Jun 11, 2026
7 checks passed
@marcosfrenkel marcosfrenkel deleted the fixing_serialization_bug branch June 11, 2026 23:11
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.

1 participant