4 Summary: A lil' TOML parser
6 Author-email: Taneli Hukkinen <hukkin@users.noreply.github.com>
8 Description-Content-Type: text/markdown
9 Classifier: License :: OSI Approved :: MIT License
10 Classifier: Operating System :: MacOS
11 Classifier: Operating System :: Microsoft :: Windows
12 Classifier: Operating System :: POSIX :: Linux
13 Classifier: Programming Language :: Python :: 3 :: Only
14 Classifier: Programming Language :: Python :: 3.7
15 Classifier: Programming Language :: Python :: 3.8
16 Classifier: Programming Language :: Python :: 3.9
17 Classifier: Programming Language :: Python :: 3.10
18 Classifier: Programming Language :: Python :: Implementation :: CPython
19 Classifier: Programming Language :: Python :: Implementation :: PyPy
20 Classifier: Topic :: Software Development :: Libraries :: Python Modules
21 Classifier: Typing :: Typed
22 Project-URL: Changelog, https://github.com/hukkin/tomli/blob/master/CHANGELOG.md
23 Project-URL: Homepage, https://github.com/hukkin/tomli
25 [![Build Status](https://github.com/hukkin/tomli/workflows/Tests/badge.svg?branch=master)](https://github.com/hukkin/tomli/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush)
26 [![codecov.io](https://codecov.io/gh/hukkin/tomli/branch/master/graph/badge.svg)](https://codecov.io/gh/hukkin/tomli)
27 [![PyPI version](https://img.shields.io/pypi/v/tomli)](https://pypi.org/project/tomli)
33 **Table of Contents** *generated with [mdformat-toc](https://github.com/hukkin/mdformat-toc)*
35 <!-- mdformat-toc start --slug=github --maxlevel=6 --minlevel=2 -->
38 - [Installation](#installation)
40 - [Parse a TOML string](#parse-a-toml-string)
41 - [Parse a TOML file](#parse-a-toml-file)
42 - [Handle invalid TOML](#handle-invalid-toml)
43 - [Construct `decimal.Decimal`s from TOML floats](#construct-decimaldecimals-from-toml-floats)
45 - [Why this parser?](#why-this-parser)
46 - [Is comment preserving round-trip parsing supported?](#is-comment-preserving-round-trip-parsing-supported)
47 - [Is there a `dumps`, `write` or `encode` function?](#is-there-a-dumps-write-or-encode-function)
48 - [How do TOML types map into Python types?](#how-do-toml-types-map-into-python-types)
49 - [Performance](#performance)
51 <!-- mdformat-toc end -->
53 ## Intro<a name="intro"></a>
55 Tomli is a Python library for parsing [TOML](https://toml.io).
56 Tomli is fully compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0).
58 ## Installation<a name="installation"></a>
64 ## Usage<a name="usage"></a>
66 ### Parse a TOML string<a name="parse-a-toml-string"></a>
78 toml_dict = tomli.loads(toml_str)
79 assert toml_dict == {"gretzky": 99, "kurri": {"jari": 17}}
82 ### Parse a TOML file<a name="parse-a-toml-file"></a>
87 with open("path_to_file/conf.toml", "rb") as f:
88 toml_dict = tomli.load(f)
91 The file must be opened in binary mode (with the `"rb"` flag).
92 Binary mode will enforce decoding the file as UTF-8 with universal newlines disabled,
93 both of which are required to correctly parse TOML.
95 ### Handle invalid TOML<a name="handle-invalid-toml"></a>
101 toml_dict = tomli.loads("]] this is invalid TOML [[")
102 except tomli.TOMLDecodeError:
103 print("Yep, definitely not valid.")
106 Note that error messages are considered informational only.
107 They should not be assumed to stay constant across Tomli versions.
109 ### Construct `decimal.Decimal`s from TOML floats<a name="construct-decimaldecimals-from-toml-floats"></a>
112 from decimal import Decimal
115 toml_dict = tomli.loads("precision-matters = 0.982492", parse_float=Decimal)
116 assert toml_dict["precision-matters"] == Decimal("0.982492")
119 Note that `decimal.Decimal` can be replaced with another callable that converts a TOML float from string to a Python type.
120 The `decimal.Decimal` is, however, a practical choice for use cases where float inaccuracies can not be tolerated.
122 Illegal types are `dict` and `list`, and their subtypes.
123 A `ValueError` will be raised if `parse_float` produces illegal types.
125 ## FAQ<a name="faq"></a>
127 ### Why this parser?<a name="why-this-parser"></a>
130 - pure Python with zero dependencies
131 - the fastest pure Python parser [\*](#performance):
132 15x as fast as [tomlkit](https://pypi.org/project/tomlkit/),
133 2.4x as fast as [toml](https://pypi.org/project/toml/)
134 - outputs [basic data types](#how-do-toml-types-map-into-python-types) only
135 - 100% spec compliant: passes all tests in
136 [a test set](https://github.com/toml-lang/compliance/pull/8)
137 soon to be merged to the official
138 [compliance tests for TOML](https://github.com/toml-lang/compliance)
140 - thoroughly tested: 100% branch coverage
142 ### Is comment preserving round-trip parsing supported?<a name="is-comment-preserving-round-trip-parsing-supported"></a>
146 The `tomli.loads` function returns a plain `dict` that is populated with builtin types and types from the standard library only.
147 Preserving comments requires a custom type to be returned so will not be supported,
148 at least not by the `tomli.loads` and `tomli.load` functions.
150 Look into [TOML Kit](https://github.com/sdispater/tomlkit) if preservation of style is what you need.
152 ### Is there a `dumps`, `write` or `encode` function?<a name="is-there-a-dumps-write-or-encode-function"></a>
154 [Tomli-W](https://github.com/hukkin/tomli-w) is the write-only counterpart of Tomli, providing `dump` and `dumps` functions.
156 The core library does not include write capability, as most TOML use cases are read-only, and Tomli intends to be minimal.
158 ### How do TOML types map into Python types?<a name="how-do-toml-types-map-into-python-types"></a>
160 | TOML type | Python type | Details |
161 | ---------------- | ------------------- | ------------------------------------------------------------ |
162 | Document Root | `dict` | |
165 | Integer | `int` | |
166 | Float | `float` | |
167 | Boolean | `bool` | |
168 | Offset Date-Time | `datetime.datetime` | `tzinfo` attribute set to an instance of `datetime.timezone` |
169 | Local Date-Time | `datetime.datetime` | `tzinfo` attribute set to `None` |
170 | Local Date | `datetime.date` | |
171 | Local Time | `datetime.time` | |
174 | Inline Table | `dict` | |
176 ## Performance<a name="performance"></a>
178 The `benchmark/` folder in this repository contains a performance benchmark for comparing the various Python TOML parsers.
179 The benchmark can be run with `tox -e benchmark-pypi`.
180 Running the benchmark on my personal computer output the following:
183 foo@bar:~/dev/tomli$ tox -e benchmark-pypi
184 benchmark-pypi installed: attrs==19.3.0,click==7.1.2,pytomlpp==1.0.2,qtoml==0.3.0,rtoml==0.7.0,toml==0.10.2,tomli==1.1.0,tomlkit==0.7.2
185 benchmark-pypi run-test-pre: PYTHONHASHSEED='2658546909'
186 benchmark-pypi run-test: commands[0] | python -c 'import datetime; print(datetime.date.today())'
188 benchmark-pypi run-test: commands[1] | python --version
190 benchmark-pypi run-test: commands[2] | python benchmark/run.py
191 Parsing data.toml 5000 times:
192 ------------------------------------------------------
193 parser | exec time | performance (more is better)
194 -----------+------------+-----------------------------
195 rtoml | 0.901 s | baseline (100%)
196 pytomlpp | 1.08 s | 83.15%
197 tomli | 3.89 s | 23.15%
198 toml | 9.36 s | 9.63%
199 qtoml | 11.5 s | 7.82%
200 tomlkit | 56.8 s | 1.59%
203 The parsers are ordered from fastest to slowest, using the fastest parser as baseline.
204 Tomli performed the best out of all pure Python TOML parsers,
205 losing only to pytomlpp (wraps C++) and rtoml (wraps Rust).