PEP 680: tomllib
省流:
tomllib .load( )
tomllib .loads( )
用法类似于 json.load 和 json.loads 。
EOF.
好吧,开个玩笑。
[ T ] oml
[Tom's Obvious Minimal Language]
[Tom 的(语义)明显、(配置)最小化的语言]
为人而生的配置文件格式。
以其创造者 Tom Preston-Werner 的名字谦逊地命名。
它:
-
语义明显 易于阅读
-
能 无歧义 地映射为哈希表
-
易于解析 成各种语言中的数据结构
与 Python 相近的语法和设计理念,使它迅速成为 Python 社区的首选配置文件格式。它还被指定为项目元数据存储格式:
pyproject.toml
,详见
PEP 621
和
Declaring project metadata — Python Packaging User Guide
(当然这些也有可能与 PyPA 成员,PSF 元老,TOML 核心成员 Pradyun Gedam 在 2018 年成为
toml-lang/toml
标准的主要维护者有关系)
。
因此,有人说
Python 和 TOML 是新的最好的朋友
,这也是一篇很好的 TOML 配合 Python 使用的英文教程。
但是,TOML 在很长一段时间里缺席标准库。因此,社区中出现了这些
第三方库
toml
最早且最广泛使用的 TOML 读写库之一。
toml
.load(
)
f
可以是文件路径,文件路径的列表(将被合并为一个对象)或者文件描述符。返回一个
_dict
的实例。
例如可以传入
_dict=collections.OrderedDict
来保持键的顺序。
对无效的 TOML 文档将引发
TomlDecodeError
。
toml
.loads(
)
类似于
toml.load
,但是接受一个字符串。
toml
.dump(
)
将
o
转换为 TOML 格式的字符串,写入
f
。
encoder
是一个
TomlEncoder
的实例。返回 TOML 格式的字符串。
toml
.dumps(
)
类似于
toml.dump
,但是只返回 TOML 格式的字符串。
t
oml
i
简洁(只有约 800 行代码),快速(速度是
tomlkit
的 16 倍,
toml
的 2.3 倍)且测试完备(100% 测试覆盖率)的 TOML 读取库。
tomli
.load(
)
第一个参数应是一个可读二进制文件对象。返回一个
dict
。会通过 [转换表](#转换表)将 TOML 类型转换为 Python 类型。
对每一个 TOML 浮点数都会以字符串形式调用
parse_float
。默认情况下,这相当于
float(num_str)
。这可以用于为 TOML 浮点数使用另一种数据类型或解析器(如
decimal.Decimal
)。
可调用对象不能返回
dict
或
list
,否则将引发
ValueError
。
对无效的 TOML 文档将引发
TOMLDecodeError
。
tomli
.loads(
)
类似于
tomli.load
,但是接受一个
str
。
tomli
.TOMLDecodeError
ValueError
的子类。
转换表
tomli-w
由
tomli
作者
Taneli Hukkinen
开发的 TOML 写入库。非常简洁(只有一个不到 200 行的代码文件)
tomli_w
.dump(
)
将
obj
转换为 TOML 格式的字符串,写入
fp
。
multiline_strings
为
True
时,将使用多行字符串。
注意
:输出的字符串不保证是有效的 TOML 文档。如果输入数据可能是错误的而且有校验输出是否有效的需要,请使用
tomli.loads()
解析一次字符串以确保是有效的 TOML 文档。
tomli_w
.dumps(
)
类似于
tomli_w.dump
,但是只返回 TOML 格式的字符串。
tomlkit
保留注释和样式的 TOML 读写库。支持 TOML 1.0.0。
tomlkit
.load(
)
fp
是一个可读字符串文件对象。返回一个
TOMLDocument
实例。
tomlkit
.loads(
)
类似于
tomlkit.load
,但是接受一个
str
。
tomlkit
.dump(
)
将
data
转换为 TOML 格式的字符串,写入
fp
。如果
sort_keys
为
True
,则将键按字母顺序排序。
tomlkit
.dumps(
)
类似于
tomlkit.dump
,但是只返回 TOML 格式的字符串。
tomlkit
.TOMLDocument
可以通过
tomlkit.document()
创建。是一个对底层数据对象的映射,并且保留了样式信息。可以使用
tomlkit.items
系列 API 从零开始创建
TOMLDocument
。
可以看出:
-
toml 过于老旧。
为了提供对过往 Python 版本的支持,提供了
_dict
以支持
OrderedDict
。这在 Python 3.7+ 毫无必要,因为
dict
是有序的。除此之外,对于时区,它使用自定义的
toml.tz.TomlTz
而不是
datetime.timezone
;对于无效的 TOML 文档,它引发
toml.TomlDecodeError
而不是符合 PEP 8 的命名
TOMLDecodeError
。最重要的是,它有复杂但效果不尽如人意的写入 API。
这些问题使它没有成为
tomllib
的参考实现,也使
toml
不能成为新的标准库的名字(因为这会带来破坏性更改)。无论如何,都不推荐使用这一过时而缺乏维护的库。
-
tomli 提供了类似于内置库 marshal 和 pickle 的读取 API, 简洁而易于维护 。
你可能注意到了,它的 API 和
tomllib
一致。实际上它就是
tomllib
的参考实现,而且
tomllib
就是它的一个版本。即使在它成为标准库之后,它也会继续作为第三方库存在,为 Python 3.11- 提供向后移植。
你可以如此指定依赖:
然后在代码如此使用:
-
tomli-w 提供了类似于内置库 marshal 和 pickle 的写入 API, 简洁而易于维护 。
它不保留注释和样式,而且也无法保证生成有效的 TOML 文档。不过,因为简单且统一的 API,它依然是官方文档中推荐使用的写入库。推荐在写入没有注释或样式的简单 TOML 文档时搭配
tomli
或
tomllib
使用。
-
tomlkit 提供强大的保留注释和格式的读写功能 ,被许多知名包管理工具(大多有 TOML 保留格式写入需求)使用,如 hatch、poetry 和 pdm, 但是 API 复杂,不易维护和使用 。
它的读取速度非常慢,而且类型提示和代码补全也很糟糕,所以非常不建议使用它读取 TOML 文档,除非需要修改文档。不过,因为是(据我所知的)唯一的保留注释和格式的库,它也是官方文档推荐使用的读写库。推荐只使用它创建或修改文档。
其他第三方库
-
rtoml 基于 toml-rs 的 Rust 扩展实现。由 pydantic 作者 Samuel Colvin 开发。性能优异,但对 TOML 主要使用场景(配置文件)而言可有可无,且不支持 TOML 1.0.0,安装困难,不推荐使用。
-
pytomlpp 基于 toml++ 的 C++ 扩展实现。性能优异,但对 TOML 主要使用场景(配置文件)而言可有可无,不推荐使用。
-
qtoml 仅支持 TOML 0.5.0,缺乏维护,不推荐使用。
性能
以下测试均在 Raspberry Pi 4 Model B Rev 1.4 + Ubuntu 22.04.1 LTS (Linux-5.15.0-1017-raspi-aarch64-with-glibc2.35) + GCC 11.3.0 + CPython 3.11.0 上进行。
读取(
tomli benchmark
):
写入(
tomli-w benchmark
):
PEP 680: tomllib
PEP 680: tomllib
动机
根据
PEP 571
、
PEP 518
和
PEP621
,TOML 是 Python 打包的首选格式。Python 构建工具为了能够自举(在没有其他构建工具的情况下安装自身,此时无法下载安装其他第三方库),必须内置 TOML 解析库或者使用其他变通方法解析 TOML 文档。这给重打包者(如 Debian 系的 apt)和下游使用者带来了严重的问题。
此外,许多 Python 工具使用 TOML 作为配置文件格式,例如 black、mypy、pytest、tox、pylint、isort 和 flake8(可以发现其中不少是 Python 核心开发者维护的库)。
选择
tomli
的理由
-
纯 Python 实现:TOML 解析不太可能成为项目瓶颈,并且需要更高性能的用户可以选择第三方库(就像 JSON,即使 CPython 提供了一个标准 C 扩展库);可以避免许多 C 特有的安全问题,例如缓冲区溢出。
-
便于维护: 作者愿意帮助它融入标准库并维护它 , Python 核心开发者 Petr Viktorin 也愿意维护读取 API 。相较之下, tomlkit 的作者都认为这个库不适合成为标准库,没有 Python 核心开发者表示愿意维护写入 API。
未来
虽然当下
tomllib
没有写入 API,但是如果有更好的 API 和相关的使用用例,以后可能会有新的 PEP 引入它们。为了性能,以后也可能会使用 C 扩展重新实现
tomllib
。
不过,考虑到大多数使用场景只是读取 TOML 文档,现在的
tomllib
已经足够了。
-
TOML:Tom 的(语义)明显、(配置)最小 化的语言 ( https://toml.io/cn/)
-
Tom Preston-Werner (https://tom.preston-werner.com/)
-
PEP 621 – Storing project metadata in pyproject.toml | peps.python.org (https://www.python.org/dev/peps/pep-0621/)
-
Declaring project metadata — Python Packaging User Guide (https://packaging.python.org/en/latest/specifications/declaring-project-metadata/)
-
toml-lang/toml: Tom's Obvious, Minimal Language ( https://github.com/toml-lang/toml )
-
Python and TOML: New Best Friends – Real Python (https://realpython.com/python-toml/)
-
uiri/toml: Python lib for TOML (https://github.com/uiri/toml)
-
hukkin/tomli: A lil' TOML parser (https://github.com/hukkin/tomli)
-
hukkin/tomli-w: A lil' TOML writer (counterpart to https://github.com/hukkin/tomli) (https://github.com/hukkin/tomli-w)
-
hukkin (Taneli Hukkinen) (https://github.com/hukkin)
-
sdispater/tomlkit: Style-preserving TOML library for Python (https://github.com/sdispater/tomlkit)
-
samuelcolvin/rtoml: A fast TOML library for python implemented in rust. (https://github.com/samuelcolvin/rtoml)
-
toml-rs/toml-rs: A TOML encoding/decoding library for Rust (https://github.com/alexcrichton/toml-rs)
-
bobfang1992/pytomlpp: A python wrapper for tomlplusplus (https://github.com/bobfang1992/pytomlpp)
-
toml++ TOML for C++ (https://marzer.github.io/tomlplusplus/)
-
alethiophile/qtoml: Another Python TOML encoder/decoder (https://github.com/alethiophile/qtoml)
-
tomli/benchmark at master · hukkin/tomli (https://github.com/hukkin/tomli/tree/master/benchmark)
-
tomli-w/benchmark at master · hukkin/tomli-w (https://github.com/hukkin/tomli-w/tree/master/benchmark)
-
PEP 680 – tomllib: Support for Parsing TOML in the Standard Library | peps.python.org (https://peps.python.org/pep-0680/)
-
Please consider pushing tomli into stdlib · Issue #141 · hukkin/tomli (https://github.com/hukkin/tomli/issues/141#issuecomment-998018972)
-
Adopting/recommending a toml parser? - #88 by encukou - Packaging - Discussions on Python.org (https://discuss.python.org/t/adopting-recommending-a-toml-parser/4068/88)