298. 手动 main 错误报告
为 main_only_background.py 添加有用的模拟错误报告。
第 298 / 356 · tests/chapter_08_manual_main/test_298_manual_main_error_reporting.py
需要更新的文件
main_only_background.py为什么需要这一步
main_only_background.py 使用 pygame 运行真实的手动 ROM 循环。当真实 ROM 执行遇到模拟器尚未实现的行为时,用户需要在 Python 回溯信息之前看到上下文。
如果没有上下文,错误可能只显示
ValueError: Unsupported CPU bus read: 4020有了上下文,main_only_background.py 还应打印有用的模拟器状态:
Emulation Error:
type=ValueError
message=Unsupported CPU bus read: 4020
pc=$812A
ppu_frame=123
ppu_scanline=241
ppu_cycle=10这不会替代回溯信息。原始异常仍应被重新抛出,以便开发者正常调试。
建议的实现示例
def print_emulation_error(error: Exception, console: Console) -> None:
print("Emulation Error:")
print(f" type={type(error).__name__}")
print(f" message={error}")
print(f" pc=${console.cpu.pc:04X}")
print(f" ppu_frame={console.ppu.frame}")
print(f" ppu_scanline={console.ppu.scanline}")
print(f" ppu_cycle={console.ppu.cycle}")
def main() -> None:
...
pygame.init()
try:
window = pygame.display.set_mode(...)
running = True
while running:
...
executed = console.step_until_next_frame()
framebuffer = console.render_background_framebuffer()
draw_framebuffer(window, framebuffer, SCALE)
pygame.display.flip()
except KeyboardInterrupt:
print("Stopped by user.")
except Exception as error:
print_emulation_error(error, console)
raise
finally:
pygame.quit()为什么要单独捕获 KeyboardInterrupt?Ctrl+C 是用户有意的停止操作,而非模拟器故障。它应打印友好的停止消息,且不应打印模拟错误报告。
为什么要重新抛出非预期异常?错误报告提供模拟器上下文,但回溯信息仍然重要。重新抛出可保持原始故障对调试可见。
超出本步骤范围
- 更改 CPU 操作码诊断
- 捕获并隐藏所有错误
- 将日志写入文件
- 从 pytest 调用 main()
运行本课
uv run pytest tests/chapter_08_manual_main/test_298_manual_main_error_reporting.py -v