Skip to Content
Course content

262: The tomllib Module for TOML Config Files

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've spent any time managing project settings, you know the struggle. JSON is great for machines but a nightmare for humans to edit manually because of those trailing commas. YAML is visually clean, but one accidental space in your indentation can break your entire deployment. That's why I've shifted most of my configuration files to TOML (Tom's Obvious, Minimal Language).

Since Python 3.11, we have the tomllib module built right into the standard library. It's fast and follows the spec strictly. Today, we're going to build a small configuration loader for a hypothetical "Web Scraper" tool that needs to handle different environment settings and API keys.

Defining our Scraper Settings

First, let's create a configuration file. I prefer TOML because it handles sections (tables) beautifully. I'll create a file named settings.toml. Notice how I can group my scraping targets separately from my global app settings.

# settings.toml
[app]
debug = true
timeout = 30
log_level = "INFO"

[sources.tech_crunch]
url = "https://techcrunch.com"
max_articles = 10

[sources.wired]
url = "https://wired.com"
max_articles = 5

Pulling the Data into Python

Now, let's get this into our code. The tomllib module provides load() for file streams and loads() for strings. Since we have a file, we'll use load(). One thing to keep in mind: tomllib requires the file to be opened in binary mode ("rb"), not text mode. I've tripped over this more than once.

import tomllib

try:
    with open("settings.toml", "rb") as f:
        config = tomllib.load(f)
except FileNotFoundError:
    print("Config file missing!")
    config = {}

print(f"Debugging enabled: {config['app']['debug']}")
print(f"Wired URL: {config['sources']['wired']['url']}")

The "Write-Only" Trap

Here is where I usually hit a wall when I first start a project. I'll try to write a "reset to defaults" feature where the script updates the TOML file programmatically. I'll instinctively try something like this:

# This will fail!
import tomllib

config = {"app": {"debug": False}}
with open("settings.toml", "wb") as f:
    tomllib.dump(config, f) # AttributeError: module 'tomllib' has no attribute 'dump'

I forgot that tomllib is a read-only parser. The Python maintainers decided not to include a writer in the standard library to keep the module lean. If you actually need to write TOML files, you'll have to install a third-party library like tomli-w. For this lesson, we'll stick to reading, which is 95% of what you'll do with config files anyway.

Using the Loaded Config

Now that we know we can't write back to the file, let's actually use the data to drive some logic. I like to wrap the config access in a way that provides defaults, just in case a user deletes a line from the TOML file.

import tomllib

def run_scraper(config):
    # Using .get() helps avoid KeyError if the TOML is malformed
    app_settings = config.get("app", {})
    timeout = app_settings.get("timeout", 10) # Default to 10 seconds
    
    sources = config.get("sources", {})
    for name, data in sources.items():
        print(f"Scraping {name} at {data['url']} (Max: {data['max_articles']})")
        print(f"Applying timeout of {timeout}s...")

with open("settings.toml", "rb") as f:
    config_data = tomllib.load(f)

run_scraper(config_data)



📋 Practical Task

Build a Multi-Environment Database Config Loader

Your task is to create a Python script that simulates loading different database credentials based on an environment variable.

  • Create a file named db_config.toml with two sections: [development] and [production]. Each section should have a host, port (integer), and enabled (boolean).
  • Write a Python script that imports tomllib.
  • The script should define a variable env = "development" (you can manually change this to "production" to test).
  • Load the TOML file and use the env variable to access the correct section.
  • Print a formatted string: "Connecting to {env} database at {host}:{port}...", but only if enabled is True. If enabled is False, print "Database for {env} is currently disabled."
Rating
0 0

There are no comments for now.

to be the first to leave a comment.