Monty中如何使用datetime与json?常用内置能力与边界限制实测
2026/8/30 11:29:07 网站建设 项目流程

Monty中如何使用datetime与json?常用内置能力与边界限制实测

【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/monty

Monty 是一个用 Rust 编写的极简安全 Python 3.14 解释器,专为安全执行 AI 生成的代码而设计。本文实测它内置的 datetime 与 json 两个模块:常用能力怎么用、和 CPython 相比有哪些边界限制,帮你写出不会踩坑的沙箱代码。

为什么要在 Monty 里关注 datetime 和 json?

Monty 不是完整的 Python 环境——它刻意只提供一小块标准库子集asynciojsondatetimemathrepathlib等),并把文件系统、网络、环境变量全部隔离成宿主可控的外部调用。这意味着两个高频模块的行为和 CPython 存在微妙但关键的差异:

  • 沙箱里能获取真实时间吗?
  • json.dumps还能用default回调兜底吗?
  • 深度嵌套的 JSON 会不会被直接拒绝?

以下结论均来自仓库中的限制文档 limitations/datetime.md、limitations/json.md 与配套测试用例,属于"实测口径"。

datetime 模块:四个类,先记住能用什么

Monty 的 datetime 模块提供四个类:datedatetimetimedeltatimezone。模块级的timetzinfoMINYEAR/MAXYEAR不暴露。

构造与常用方法

核心用法和 CPython 基本一致,测试用例 datetime__core.py 覆盖了绝大多数常规场景:

import datetime d = datetime.date(2024, 6, 15) dt = datetime.datetime(2024, 6, 15, 10, 30, 45, tzinfo=datetime.timezone.utc) dt + datetime.timedelta(hours=5) # 时间加减 (dt - dt.replace(hour=8)).total_seconds() # timedelta 算术 dt.isoformat() # '2024-06-15T10:30:00+00:00'

几个和 CPython 不一致的细节,写代码前值得记住:

  • now()是唯一能拿到宿主机时间的入口。它会产生一次外部调用;date.today()utcnow()fromtimestamp()fromordinal()combine()均未实现,timezone(tz)传入后返回的tzinfo满足==不是同一个对象is为 False)。
  • replace()只接受关键字参数。CPython 允许d.replace(2025)这样按位置传参,Monty 会抛TypeError
  • timedeltahours/minutes/milliseconds/weeks是关键字参数,不能按位置传。
  • 两个timedelta之间的除法和整除未实现(乘、加、减、比较都支持)。
  • 年份超出 64 位整数范围时抛OverflowError: Python int too large to convert to C long,所有平台口径一致。

格式化:strftime 与 f-string 的三个坑

strftime走的是 Rust 的chrono格式化,大部分指令正常,但有三类边界行为(详见 datetime__format.py):

场景Monty 行为CPython 行为
无法识别的指令(如%Q原样保留Linux 原样保留、macOS 去掉%
date上用时间指令(%H等)ValueError: Invalid format string补零填充'00'
naive 值上用%z/%ZValueError输出空字符串

f-string 格式化日期与 CPython 的__format__对齐:f'{dt:%Y-%m-%d}'等价于dt.strftime('%Y-%m-%d'),空规格则回退到str(dt)

json 模块:loads / dumps 能力清单

Monty 的 json 模块由手写的编码器与jiter解析器组成,对支持的关键词组合做到与 CPython 逐字节一致。模块内只有三样东西:loadsdumpsJSONDecodeError

json.loads:无参数解析,但有硬上限

  • 输入只接受strbytes(传别的类型抛TypeError)。
  • 不接受任何关键字参数parse_floatobject_hookcls等一律TypeError
  • NaN/Infinity/-Infinity总是被接受,没有关闭开关。
  • 嵌套深度上限200 层,超了抛JSONDecodeError——这对防御恶意深层嵌套 JSON 是天然的资源保护。
  • 超大的 JSON 整数按int_max_str_digits语义抛ValueError(而非JSONDecodeError),与 CPython 一致。

json.dumps:支持 6 个关键词,拒绝 3 个

支持的关键词及 CPython 语义:indentsort_keysensure_asciiallow_nanseparatorsskipkeys

import json json.dumps({'b': 1, 'a': 2}, sort_keys=True) # '{"a": 2, "b": 1}' json.dumps('☃', ensure_ascii=False) # '"☃"'

而以下调用方式会直接TypeError

  • cls=:不支持自定义编码器类;
  • default=:没有兜底回调,不可序列化的对象(如set)抛TypeError: Object of type set is not JSON serializable
  • check_circular=循环引用检测恒为开启,自引用结构抛ValueError: Circular reference detected(见 json__dumps_errors.py)。

另外两个实用特性:dumps会把 dict 中bool/None/int/float类型的键自动转换成 JSON 允许的字符串键;tuple 会输出为数组。json.load(fp)/json.dump(obj, fp)未实现——沙箱里没有文件对象协议。

JSONDecodeError 的两个细节

  • 它继承自ValueError,可以用except ValueError:捕获。
  • 沙箱内部它是只有消息的异常,没有msg/doc/pos/lineno/colno属性;但当它通过宿主 API(如pydantic_monty)抛回宿主侧时,会被重建为带全部五个属性的真实json.JSONDecodeError(超过 64 KiB 的文档除外,此时doc为空字符串)。

速查:Monty 里最容易被 CPython 习惯坑到的点

  1. 想取当前日期 → 只能datetime.datetime.now(tz),没有date.today()
  2. replace()timedelta大单位参数 → 必须写关键字形式;
  3. strftime里别对纯date用时间指令,也别对 naive 值用%z
  4. json.loads一个参数都加不了,深度别超 200 层;
  5. json.dumps想自定义序列化 → 先在宿主侧把对象转成基础类型,沙箱内没有default兜底;
  6. 类继承不可用,所以datetime无法被子类化。

延伸阅读

  • datetime 差异全文:limitations/datetime.md
  • json 差异全文:limitations/json.md
  • 模块实现:crates/monty/src/modules/datetime.rs、crates/monty/src/modules/json/
  • 实测用例:crates/monty/test_cases/datetime__core.py、crates/monty/test_cases/json__module.py
  • 沙箱资源限制说明:docs/resource-limits.md

【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/monty

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询