A modern, high-performance TOML library for Python implemented in Rust.
This project is a maintained and enhanced fork of samuelcolvin/rtoml. The original project hasn't been updated in a while, and this fork continues development for the latest Python versions, with additional Rust tooling improvements.
- Python 3.14 Support: Full support for Python 3.14, including free-threaded mode (GIL-free)
- Modern Dependencies: Updated to latest Rust dependencies (PyO3 0.26, toml 0.9)
- Enhanced Error Handling: tomllib-compatible error messages with line/column information
- Comprehensive Docstrings: For improved developer experience and IDE support
- Custom Float Parsing: Support for
parse_floatparameter (e.g., for Decimal types) - Binary File Support: Read TOML from binary file handles
- Better Type Safety: Comprehensive type stubs and full mypy strict compatibility
- Modern Tooling: Built with uv, maturin, and modern Python packaging standards
Original project by Samuel Colvin. This fork maintained by Sean Lees.
Both projects are MIT licensed.
- Correctness: Built on the widely-used and stable toml-rs library. Passes all standard TOML tests with 100% test coverage on Python code.
- Performance: One of the fastest Python TOML libraries available.
- Flexible None handling: Configurable support for
Nonevalues with custom serialization/deserialization. - Type safe: Full type annotations with
py.typedmarker for excellent IDE support and type checking.
Requires python>=3.10, binaries are available from PyPI for Linux, macOS and Windows,
see here.
uv add rustoml
# or
pip install rustomlIf no binary is available on PyPI for your system configuration, you'll need Rust stable installed before you can install rustoml.
def load(toml: str | Path | TextIO, *, none_value: str | None = None) -> dict[str, Any]: ...Parse TOML via a string or file and return a python dictionary.
toml: astr,Pathor file object fromopen().none_value: controlling which value intomlis loaded asNonein python. By default,none_valueisNone, which means nothing is loaded asNone
def loads(toml: str, *, none_value: str | None = None) -> dict[str, Any]: ...Parse a TOML string and return a python dictionary. (provided to match the interface of json and similar libraries)
toml: astrcontaining TOML.none_value: controlling which value intomlis loaded asNonein python. By default,none_valueisNone, which means nothing is loaded asNone
def dumps(obj: Any, *, pretty: bool = False, none_value: str | None = "null") -> str: ...Serialize a python object to TOML.
obj: a python object to be serialized.pretty: ifTruethe output has a more "pretty" format.none_value: controlling howNonevalues inobjare serialized.none_value=NonemeansNonevalues are ignored.
def dump(
obj: Any, file: Path | TextIO, *, pretty: bool = False, none_value: str | None = "null"
) -> int: ...Serialize a python object to TOML and write it to a file.
obj: a python object to be serialized.file: aPathor file object fromopen().pretty: ifTruethe output has a more "pretty" format.none_value: controlling howNonevalues inobjare serialized.none_value=NonemeansNonevalues are ignored.
from datetime import datetime, timezone, timedelta
import rustoml
obj = {
'title': 'TOML Example',
'owner': {
'dob': datetime(1979, 5, 27, 7, 32, tzinfo=timezone(timedelta(hours=-8))),
'name': 'Tom Preston-Werner',
},
'database': {
'connection_max': 5000,
'enabled': True,
'ports': [8001, 8001, 8002],
'server': '192.168.1.1',
},
}
loaded_obj = rustoml.load("""\
# This is a TOML document.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [8001, 8001, 8002]
connection_max = 5000
enabled = true
""")
assert loaded_obj == obj
assert rustoml.dumps(obj) == """\
title = "TOML Example"
[owner]
dob = 1979-05-27T07:32:00-08:00
name = "Tom Preston-Werner"
[database]
connection_max = 5000
enabled = true
server = "192.168.1.1"
ports = [8001, 8001, 8002]
"""An example of None-value handling:
obj = {
'a': None,
'b': 1,
'c': [1, 2, None, 3],
}
# Ignore None values
assert rustoml.dumps(obj, none_value=None) == """\
b = 1
c = [1, 2, 3]
"""
# Serialize None values as '@None'
assert rustoml.dumps(obj, none_value='@None') == """\
a = "@None"
b = 1
c = [1, 2, "@None", 3]
"""
# Deserialize '@None' back to None
assert rustoml.load("""\
a = "@None"
b = 1
c = [1, 2, "@None", 3]
""", none_value='@None') == obj