The TOML (Tom’s Obvious Minimal Language) format came out in 2013, so it’s been around for more than a decade. Python added support for TOML in Python 3.11 with its tomllib
module in the standard library. However, unlike some of Python’s other standard libraries, such as json
or its XML-related libraries, the tomllib
library is only for reading, not writing. To create TOML documents in Python, you will need a third-party TOML package, such as tomlkit or toml.
Many Python developers use TOML as their configuration format of choice. In fact, you will find that most popular Python packages use a file called pyproject.toml for configuration. You can even use that file as a replacement for requirements.txt. Mypy, Flake8, and other tools can also be configured using pyproject.toml. You can learn more about that file and how it is formatted in the Python packaging guide.
In this tutorial, you will focus only on what Python itself provides for TOML support.
Let’s get started!
Getting Started
Python’s tomllib
is based on the tomli package. You can read all about the implementation details and why TOML support was added to Python in PEP 680.
The nice thing about having TOML support built-in to Python is that you do not need to install anything other than Python itself. However, if you need to be able to create or edit a TOML document, then you will need a third-party package as tomllib
is read-only.
Reading TOML with Python
To really understand what happens when you use the tomllib
module, you need a TOML file. You can pick your favorite Python package and grab a TOML file from it. For the purposes of this tutorial, you can use the Squall package’s TOML file. Squall is a TUI for viewing and editing SQLite databases.
Here’s what the TOML looks like:
[project] name = "squall_sql" dynamic = [ "version", ] description = "Squall - SQLite Editor" readme = "README.md" requires-python = ">=3.11" authors = [ { name = "Mike Driscoll", email = "mike@nlah.org" }, ] maintainers = [ { name = "Mike Driscoll", email = "mike@nlah.org" }, ] classifiers = [ "License :: OSI Approved :: MIT License", "Environment :: Console", "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Other Audience", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows :: Windows 10", "Operating System :: Microsoft :: Windows :: Windows 11", "Operating System :: POSIX :: Linux", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed", ] keywords = [ "tui", "sql", "sqlite", "terminal", ] dependencies = [ "rich>=13.9.4", "SQLAlchemy>=2.0.38", "textual>=2.1.1", ] packages = [ "src/squall", ] [project.license] file = "LICENSE" [project.urls] Homepage = "https://github.com/driscollis/squall" Documentation = "https://github.com/driscollis/squall/blob/main/README.md" Repository = "https://github.com/driscollis/squall" Issues = "https://github.com/driscollis/squall/issues" Discussions = "https://github.com/driscollis/squall/discussions" Wiki = "https://github.com/driscollis/squall/wiki" [project.scripts] squall = "squall.squall:main" [build-system] requires = [ "hatchling", "wheel", ] build-backend = "hatchling.build" [dependency-groups] dev = [ "build>=1.2.1", "ruff>=0.9.3", "pyinstrument>=5.0.1", "textual-dev>=1.7.0", ] [tool.hatch.version] path = "src/squall/__init__.py" [tool.hatch.build.targets.wheel] packages = [ "src/squall", ] include = [ "py.typed", "**/*.py", "**/*.html", "**/*.gif", "**/*.jpg", "**/*.png", "**/*.md", "**/*.tcss", ] [tool.hatch.build.targets.sdist] include = [ "src/squall", "LICENSE", "README.md", "pyproject.toml", ] exclude = [ "*.pyc", "__pycache__", "*.so", "*.dylib", ] [tool.pytest.ini_options] pythonpath = [ "src" ]
The next step is to write some Python code to attempt to read in the TOML file above. Open up your favorite Python IDE and create a file. You can call it something like pyproject_parser.py
if you want.
Then enter the following code into it:
import tomllib from pathlib import Path from pprint import pprint pyproject = Path("pyproject.toml") with pyproject.open("rb") as config: data = tomllib.load(config) pprint(data)
Here you open the TOML file from Squall and load it using the tomllib
module. You use Python’s pprint
module to print it out. The nice thing about the tomllib
module is that it returns a dictionary.
Of course, the dictionary doesn’t print nicely without using pretty print, which is why you use the pprint
module here.
The following is the output you will get if you run this code:
{'build-system': {'build-backend': 'hatchling.build', 'requires': ['hatchling', 'wheel']}, 'dependency-groups': {'dev': ['build>=1.2.1', 'ruff>=0.9.3', 'pyinstrument>=5.0.1', 'textual-dev>=1.7.0']}, 'project': {'authors': [{'email': 'mike@pythonlibrary.org', 'name': 'Mike Driscoll'}], 'classifiers': ['License :: OSI Approved :: MIT License', 'Environment :: Console', 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: Other Audience', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Operating System :: MacOS', 'Operating System :: Microsoft :: Windows :: ' 'Windows 10', 'Operating System :: Microsoft :: Windows :: ' 'Windows 11', 'Operating System :: POSIX :: Linux', 'Topic :: Software Development :: Libraries :: ' 'Python Modules', 'Typing :: Typed'], 'dependencies': ['rich>=13.9.4', 'SQLAlchemy>=2.0.38', 'textual>=2.1.1'], 'description': 'Squall - SQLite Editor', 'dynamic': ['version'], 'keywords': ['tui', 'sql', 'sqlite', 'terminal'], 'license': {'file': 'LICENSE'}, 'maintainers': [{'email': 'mike@pythonlibrary.org', 'name': 'Mike Driscoll'}], 'name': 'squall_sql', 'packages': ['src/squall'], 'readme': 'README.md', 'requires-python': '>=3.11', 'scripts': {'squall': 'squall.squall:main'}, 'urls': {'Discussions': 'https://github.com/driscollis/squall/discussions', 'Documentation': 'https://github.com/driscollis/squall/blob/main/README.md', 'Homepage': 'https://github.com/driscollis/squall', 'Issues': 'https://github.com/driscollis/squall/issues', 'Repository': 'https://github.com/driscollis/squall', 'Wiki': 'https://github.com/driscollis/squall/wiki'}}, 'tool': {'hatch': {'build': {'targets': {'sdist': {'exclude': ['*.pyc', '__pycache__', '*.so', '*.dylib'], 'include': ['src/squall', 'LICENSE', 'README.md', 'pyproject.toml']}, 'wheel': {'include': ['py.typed', '**/*.py', '**/*.html', '**/*.gif', '**/*.jpg', '**/*.png', '**/*.md', '**/*.tcss'], 'packages': ['src/squall']}}}, 'version': {'path': 'src/squall/__init__.py'}}, 'pytest': {'ini_options': {'pythonpath': ['src']}}}}
Awesome! You can now read a TOML file with Python and you get a nicely formatted dictionary!
Wrapping Up
The TOML format is great and well established, especially in the Python world. If you ever plan to create a package of your own, you will probably need to create a TOML file. If you work in dev/ops or as a system administrator, you may need to configure tools for CI/CD in the pyproject.toml file for Mypy, Flake8, Ruff, or some other tool.
Knowing how to read, write and edit a TOML file is a good tool to have in your kit. Check out Python’s tomllib
module for reading or if you need more power, check out tomlkit or toml.
Related Reading
- Python and TOML: New Best Friends – Real Python
- PEP 680 – tomllib: Support for Parsing TOML in the Standard Library