Monty错误处理完全指南:5大异常类型、Traceback解析与display()格式
【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/monty
Monty 是一个用 Rust 编写的极简、安全 Python 解释器,专为 AI 场景设计。所有代码都在独立的沙箱子进程中执行,因此"如何优雅地接住沙箱抛出的错误"是每个使用者的必修课。本指南带你快速掌握 Monty 的 5 大异常类型、Traceback 帧解析,以及display()的三种输出格式,帮助你在生产环境中稳定捕获和展示沙箱错误。
Monty 异常体系:一张图看懂 5 大异常类型
Monty 的所有解释器错误都继承自同一个基类MontyError,只要except MontyError就能一网打尽。其完整层级定义在源码 crates/monty-python/src/exceptions.rs 中:
| 异常类 | 触发时机 | 典型应对 |
|---|---|---|
MontySyntaxError | Python 代码语法错误或无法被解析 | 提示用户修正代码 |
MontyRuntimeError | 代码执行期间失败(除零、KeyError 等) | 展示 Traceback,会话可继续 |
MontyTypingError | 开启类型检查后,检查器拒绝该代码片段 | 展示渲染好的诊断信息 |
MontyCrashedError | 沙箱进程死亡或超时被看门狗终止 | 捕获后重试或上报 |
MontyDisconnectError | 远程 Worker 连接中断(WebSocket 场景) | 在新会话中重试 |
💡 另有两位"近亲":
MontyShutdown(远程服务器正在关闭,请求未执行,可安全重跑)和MontyConversionError(宿主值无法转换进沙箱)。两者同样继承MontyError。
读懂 MontyRuntimeError:exception() 还原真实异常
这是最常用的一类错误。以1 / 0为例,沙箱内部抛出的是标准 Python 的ZeroDivisionError,它被 Monty 包装成MontyRuntimeError抛给宿主:
from pydantic_monty import Monty, MontyError with Monty() as pool: with pool.checkout() as session: try: session.feed_run('1 / 0') except MontyError as e: inner = e.exception() # 还原为原生 ZeroDivisionError print(inner) # division by zero print(type(inner).__name__) # ZeroDivisionErrorexception()方法会根据存储的类型和消息重建一个真实的 Python 异常对象,所以你可以直接用isinstance判断具体错误。例如沙箱里的json.loads失败会还原成带lineno、colno字段的json.JSONDecodeError;'café'.encode('ascii')则还原出带encoding、object、start、end结构化字段的UnicodeEncodeError。这些用例全部可以在 crates/monty-python/tests/test_exceptions.py 中查阅。
Traceback 解析:traceback() 返回的 Frame 结构
MontyRuntimeError和MontySyntaxError都提供traceback()方法,返回一个Frame对象列表。每个 Frame 包含以下属性:
filename:代码所在文件(如main.py)line/column:起始行、列(从 1 开始)end_line/end_column:结束位置function_name:函数名,模块级代码为Nonesource_line:可用于预览的源代码行
except MontyRuntimeError as e: for frame in e.traceback(): print(frame.filename, frame.line, frame.function_name, frame.source_line)两个设计细节值得一提:
- 惰性构建:帧列表在第一次调用
traceback()时才生成并缓存。深递归异常不会让宿主进程白白分配大量内存。 - 去重优化:递归场景中多个帧指向同一行源码时,只分配一份字符串对象。
display() 方法:3 种格式化输出的选型
不想自己拼接?display(format)直接返回格式化好的字符串,支持三种模式(实现见 crates/monty-types/src/exceptions.rs):
| 格式参数 | 输出内容 | 适用场景 |
|---|---|---|
"traceback"(默认) | 完整的 CPython 风格 Traceback + 异常行 | 日志记录、调试面板 |
"type-msg" | ZeroDivisionError: division by zero一行摘要 | 用户提示、告警消息 |
"msg" | 仅消息体division by zero | 嵌入已有错误模板 |
except MontyRuntimeError as e: print(e.display()) # 完整 Traceback print(e.display('type-msg')) # ZeroDivisionError: division by zero print(e.display('msg')) # division by zero传入其他参数会抛出ValueError,错误信息会明确告知三种合法取值。MontyTypingError的display()则不带参数,直接返回按会话配置(如full/concise)渲染好的类型检查诊断文本。
沙箱专属错误:MontyCrashedError 与 MontyShutdown
Monty 把执行放在子进程中,崩溃只损失 Worker,宿主进程毫发无伤——而这两类错误正是这种隔离的"回执":
MontyCrashedError:Worker 段错误、被外部杀死、触达request_timeout看门狗时限,或自行宣告致命错误后退出。用e.timed_out区分是否超时,e.exit_status查看退出码(信号死亡时为None)。捕获它,换一个新会话重试即可。MontyShutdown:仅出现在 WebSocket 远程场景,表示服务器正在优雅关闭。它是唯一不带Error后缀的异常——因为这不是你代码的错。e.dump携带关闭前抓取的会话快照,可交给新会话的load_session无缝续跑。
新手常见问题(FAQ)
Q:如何用一个except接住所有 Monty 错误?捕获基类MontyError即可,语法、运行时、类型检查、崩溃类错误全部覆盖。
Q:语法错误和运行时错误有什么本质区别?MontySyntaxError发生在代码解析阶段(feed_run时即抛出),MontyRuntimeError发生在执行阶段;两者都提供traceback()和display()。
Q:错误发生后会话还能用吗?MontyRuntimeError/MontySyntaxError/MontyTypingError不会破坏会话,可继续feed_run;而MontyCrashedError会丢失整个会话,需要重新 checkout。
Q:沙箱内部能自定义异常类吗?不能。沙箱中的类无法继承,raise MyClass()会触发TypeError: exceptions must derive from BaseException,与 CPython 行为一致。
总结
| 你的需求 | 该用什么 |
|---|---|
| 接住一切沙箱错误 | except MontyError |
| 判断具体错误类型 | e.exception()+isinstance |
| 拿到逐帧调用栈 | e.traceback()→Frame列表 |
| 生成用户友好的错误文本 | e.display('type-msg') |
| Worker 崩溃后恢复 | 捕获MontyCrashedError并重试 |
| 服务器关闭后续跑会话 | 用MontyShutdown.dump恢复 |
掌握这套"5 大异常 +exception()+traceback()+display()"的组合拳,你就能在任何 AI Agent 或代码执行服务中,把 Monty 沙箱的错误处理做得既安全又专业。
【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/monty
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考