🤖 AI text below 🤖
What
The dispatch() function emitted by tools/generate-dispatch.py (_core_dispatch_source) has no
terminal case, so an argument matching none of its arms falls through to a read of an unbound local:
def dispatch(num_modes: int) -> type[_SimulatorAdapter]:
match num_modes:
case n if n <= 0:
raise NumberOfModesInvalidError(errmsg)
case 1:
cls = MonomialPropagator001
...
case 250:
cls = MonomialPropagator250
case n if n > 250:
raise NumberOfModesInvalidError(errmsg)
return cls # <-- UnboundLocalError if nothing matched
Why this is a problem
The arms cover n <= 0, the integer literals 1..MAX, and n > MAX. Anything else — a non-integral
value, or None — reaches return cls with cls never assigned, and the user sees
UnboundLocalError: cannot access local variable 'cls' where it is not associated with a value
instead of the NumberOfModesInvalidError the module defines for exactly this purpose.
None is reachable in practice: MajoranaOperator._from_terms(..., num_modes=None)
(src/monoprop/majorana.py) leaves num_modes unset, and _init_simulator passes
majorana_operator.num_modes straight into dispatch()
(src/monoprop/monomial_propagator.py:105,121).
Suggested fix
Add a terminal arm that raises NumberOfModesInvalidError with the received value and its type.
Note this overlaps with the dispatch-module simplification (see the separate issue on collapsing the
generated _dispatch.py): that change replaces the match with an explicit guard, at which point
this becomes a plain if. If both land in the same pass, fix it there rather than twice.
Verification
pytest case asserting NumberOfModesInvalidError for dispatch(None) and for a non-integral value.
Found by a code-reading review of the repository at 29a8050. No build tree was available, so the
analysis is from source inspection and should be confirmed against a build.
🤖 AI text below 🤖
What
The
dispatch()function emitted bytools/generate-dispatch.py(_core_dispatch_source) has noterminal
case, so an argument matching none of its arms falls through to a read of an unbound local:Why this is a problem
The arms cover
n <= 0, the integer literals1..MAX, andn > MAX. Anything else — a non-integralvalue, or
None— reachesreturn clswithclsnever assigned, and the user seesinstead of the
NumberOfModesInvalidErrorthe module defines for exactly this purpose.Noneis reachable in practice:MajoranaOperator._from_terms(..., num_modes=None)(
src/monoprop/majorana.py) leavesnum_modesunset, and_init_simulatorpassesmajorana_operator.num_modesstraight intodispatch()(
src/monoprop/monomial_propagator.py:105,121).Suggested fix
Add a terminal arm that raises
NumberOfModesInvalidErrorwith the received value and its type.Note this overlaps with the dispatch-module simplification (see the separate issue on collapsing the
generated
_dispatch.py): that change replaces thematchwith an explicit guard, at which pointthis becomes a plain
if. If both land in the same pass, fix it there rather than twice.Verification
pytestcase assertingNumberOfModesInvalidErrorfordispatch(None)and for a non-integral value.Found by a code-reading review of the repository at
29a8050. No build tree was available, so theanalysis is from source inspection and should be confirmed against a build.