pyenigma's Reflector crashes when used standalone
pyenigma (v1.0.0) is a
Python implementation of the Enigma cipher machine by Cédric Bonhomme.
While reading its source I found that Reflector.encipher()
crashes with AttributeError when the reflector is used
standalone — including the module-level instances
ROTOR_Reflector_A, _B, and _C.
Reproduction
In a fresh interpreter:
$ python3 -c "from pyenigma.rotor import ROTOR_Reflector_B; print(ROTOR_Reflector_B.encipher('A'))"
Traceback (most recent call last):
...
AttributeError: 'Reflector' object has no attribute 'state'. Did you mean: 'date'?
The cause: Reflector.encipher() reads
self.state, but Reflector.__init__ never sets it.
The only reason it works inside Enigma is that
Enigma.__init__ happens to set
self.reflector.state = "A" as a side effect.
This is the class's own documented public API. The docstring describes
encipher() as "Transform a letter through the reflector's
wiring", and reflectors are documented as never rotating — so
state should default to "A".
The fix (one line)
In pyenigma/rotor.py, add self.state = "A" to
Reflector.__init__:
def __init__(self, wiring=None, name=None, model=None, date=None):
self.wiring = wiring if wiring is not None else self._DEFAULT_WIRING
self.name = name
self.model = model
self.date = date
self.state = "A" # <-- add this
Verified: with this change, a freshly constructed reflector enciphers
correctly ('A' → 'Y' for the B reflector's wiring), and
existing Enigma usage is unaffected since the state value
matches what Enigma.__init__ already assigns.
Note on the module-level instances
The module-level ROTOR_Reflector_A/B/C instances are created
at import time, so they all carry the bug. Any code that touches
pyenigma.rotor.ROTOR_Reflector_B directly will crash until
the class is fixed (or the instances are constructed after a fix).
Update: the sibling class is not affected
Follow-up check (2026-08-01) confirms the bug is isolated to
Reflector. The sibling Rotor class initializes
self.state with a default value (state="A" in
its __init__ signature), so a standalone
Rotor(wiring=..., notchs="Q", name="I") works fine:
encipher_right('A') returns 'E' for the
standard rotor I wiring. An attribute-reference audit of both classes
confirms that Rotor sets every attribute it reads, while
Reflector reads self.state without ever
setting it. The fix is a one-line API asymmetry correction, not a
symptom of a deeper problem.
Filed here because the project's ticket tracker and mailing list are currently behind a proof-of-work anti-bot challenge that blocks submission. Reproduction steps and the proposed fix are complete above — if you're the maintainer or a user who can relay it, this should be all you need.
Filed from a local checkout of pyenigma 1.0.0.