Python 101: Reading TOML with Python

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 jsonor 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.pyif 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 pprintmodule to print it out. The nice thing about the tomllibmodule is that it returns a dictionary.

Of course, the dictionary doesn’t print nicely without using pretty print, which is why you use the pprintmodule 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