Fix Python 3.11+ incompatibility: size int-like instruction args as one byte#151
Fix Python 3.11+ incompatibility: size int-like instruction args as one byte#151HansGR wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates memory/space.py to ensure compatibility with Python 3.11+, where IntFlag objects implement len() to return a popcount. By introducing explicit isinstance(value, int) checks, the code avoids incorrect length calculations for integer-like values. The review feedback recommends replacing a bare except: clause in the clear method with specific exception handling (TypeError and ZeroDivisionError) to prevent catching system-interrupting exceptions.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| try: | ||
| values = [value] * (len(self) // len(value)) | ||
| except: | ||
| values = [value] * len(self) |
There was a problem hiding this comment.
Avoid using a bare except: clause as it can catch unexpected exceptions like SystemExit or KeyboardInterrupt, making debugging harder and preventing proper program interruption. Since len(value) can raise a TypeError (if the object has no length) or ZeroDivisionError (if the length is zero), it is better to catch these specific exceptions explicitly.
| try: | |
| values = [value] * (len(self) // len(value)) | |
| except: | |
| values = [value] * len(self) | |
| try: | |
| values = [value] * (len(self) // len(value)) | |
| except (TypeError, ZeroDivisionError): | |
| values = [value] * len(self) |
References
- PEP 8 recommends avoiding bare except clauses because they catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C. (link)
On Python 3.11+,
-ruin/door-rando seeds (and any build whose eventlayout places a multi-bit IntFlag arg before a forward label) can fail at
the final ROM write with:
Root cause: Python 3.11 added
__len__toenum.IntFlag, which returnsthe number of set flags (popcount) instead of raising
TypeError. Thebyte-counting helpers in memory/space.py size flattened values with
try: n += len(value) except: n += 1, relying onlen()raising forscalar byte values. Instruction args that are
IntFlagmembers are intsubclasses representing a single byte, but on 3.11+
len()now returnstheir popcount, e.g.:
Flashis anIntFlagand is passed straight through to FlashScreen, sofield.FlashScreen(field.Flash.WHITE)makes_parse_labelsover-count thebyte offset by 2. Every subsequent label pointer in that block is then
written two bytes past its placeholder, leaving unresolved
Nonebytes inthe ROM data that surface at
bytearray(self.data). (IntEnum, e.g.Status, is unaffected -- onlyIntFlaggained__len__.)Fix: treat
intinstances (which includeIntEnum/IntFlag) as a singlebyte in the three byte-counting sites --
_parse_labels,clear, and theWritesize pre-pass -- so counts match the bytes actually emitted on everyinterpreter. No behavior change on 3.10; 3.11 and 3.12 now produce output
identical to each other.
Repro of the underlying enum change (no game data needed):
https://claude.ai/code/session_01Tvbr7PfXazsR3SAPXUMKmc