Hvis du har åbnet et Rust-projekt, har du mødt TOML. Hvis du har rørt ved en Python-pakke der bruger
pyproject.toml, har du også brugt det. TOML — Tom's Obvious Minimal Language —
er konfigurationsfilformatet der stille og roligt vinder over udviklere der er trætte af YAMLs mellemrum-faldgruber
og JSONs afvisning af at tillade kommentarer. Skabt af Tom Preston-Werner, medstifter af GitHub, blev TOML
designet omkring én idé: et konfigurationsformat skal være så oplagt at du kan læse det uden en specifikation.
Lad os se om det lever op til det løfte.
Hvad er TOML præcis?
TOML er et konfigurationsfilformat med tre eksplicitte designmål, angivet direkte øverst i den officielle specifikation: det skal være oplagt at læse, minimalt i kompleksitet og mappe entydigt til en hashtabel (et dictionary/map i de fleste sprog). Det tredje mål er det vigtigste — enhver gyldig TOML-fil har præcis ét korrekt parsingresultat. Ingen overraskende typetvang, ingen YAML-booleske faldgruber, ingen tvetydighed om hvorvidt en værdi er en streng eller et tal.
Formatet låner sektionsoverskriftsstilen fra gamle INI-filer men tilføjer ordentlige typer, arrays og indlejrede tabeller ovenpå. Resultatet er noget der føles bekendt for enhver der har redigeret en konfigurationsfil, men med tilstrækkelig struktur til at en parser kan give dig en reel typed datamodel ud af det. Version 1.0.0 af specifikationen blev udgivet i januar 2021 efter år med forfining — du kan gennemse hele TOML-specifikationen på GitHub hvis du vil grave i kanttilfælde.
Grundlaget: nøgle-værdi-par og kommentarer
En TOML-fil er opbygget af nøgle-værdi-par. Nøgler og værdier er adskilt af =,
og kommentarer starter med #. Enkelt.
# Cargo.toml — Rust package manifest
[package]
name = "image-resizer"
version = "0.4.2"
edition = "2021"
authors = ["Ada Lovelace <[email protected]>"]
description = "Fast image resizing with Lanczos3 resampling"
license = "MIT"
repository = "https://github.com/example/image-resizer"
# Integers, floats, booleans — all native types
max_threads = 8
quality_default = 0.85
verbose_logging = falseIngen anførselstegn krævet på de fleste nøgler. Værdier er typede — 8 er et heltal, 0.85
er et flyttal, false er en boolean. Ingen gætning, ingen implicit tvang baseret på hvordan værdien ser ud.
Det er den hverdagslige TOML du vil skrive 90% af tiden.
Strengtyper: grundlæggende, literale og flerlinjer
TOML har fire strengtyper. Det dækker alle virkelige tilfælde rent:
# Basic strings — double quotes, support escape sequences
greeting = "Hello, \nworld!"
path = "C:\\Users\\ada\\Documents"
# Literal strings — single quotes, no escape processing at all
regex_pattern = '\d{4}-\d{2}-\d{2}'
windows_path = 'C:\Users\ada'
# Multiline basic string — triple double quotes
sql_query = """
SELECT user_id, email, created_at
FROM users
WHERE active = true
AND created_at > '2024-01-01'
ORDER BY created_at DESC
"""
# Multiline literal string — triple single quotes, no escapes
shell_script = '''
#!/bin/bash
echo "Deploying $APP_NAME to $ENV"
kubectl apply -f k8s/
'''Den literale strengtype ('enkle anførselstegn') er den som folk glemmer eksisterer, og den er
genuint nyttig — regex-mønstre og Windows-stier er meget renere uden escape-fordobling. Vælg den anførselstegns-stil
der betyder at du skriver færre backslashes.
Tal, booleaner og datoer/tider
TOMLs native typer dækker alt du faktisk ville lægge i en konfigurationsfil. Bemærkelsesværdigt har det førsteklasses understøttelse af dato/tid — noget YAML teknisk set har men håndterer inkonsekvent på tværs af parsere.
# Integers — underscores allowed as separators (like numeric literals in code)
max_connections = 1_000_000
port = 5432
hex_color = 0xFF6B6B # hex prefix supported
octal_permissions = 0o755 # octal prefix supported
# Floats
pi = 3.14159265
compression_ratio = 1.5e-3
infinity_val = inf # special values: inf, -inf, nan
# Booleans — lowercase only (not True, TRUE, yes, on)
ssl_enabled = true
dry_run = false
# Datetimes — RFC 3339 format
created_at = 2024-03-15T09:30:00Z
updated_at = 2024-03-15T14:22:10+05:30
log_date = 2024-03-15 # local date (no time)
backup_time = 03:00:00 # local time (no date)true og false —
ikke True, TRUE, yes, on eller nogen af de andre varianter
YAML 1.1 accepterer. Det er bevidst. Hvis du har brug for strengen "true", citér den.Tabeller: INI-stilede sektionsoverskrifter
Tabeller i TOML defineres med [overskrift]-syntaks. Alt under en overskrift tilhører
den tabel indtil næste overskrift vises. Det er den funktion der gør TOML bekendt — det er
i bund og grund INI-filer men med typer.
[database]
host = "db.internal"
port = 5432
name = "app_production"
pool_size = 20
[database.credentials]
username = "app_user"
# Don't put real passwords here — use env vars or a secrets manager
password_env = "DB_PASSWORD"
[server]
host = "0.0.0.0"
port = 8080
workers = 4
[server.tls]
enabled = true
cert_file = "/etc/ssl/certs/app.crt"
key_file = "/etc/ssl/private/app.key"Prikkede overskrifter som [database.credentials] opretter indlejrede tabeller. Det parsede resultat
er præcis hvad du ville forvente: et database-objekt med et indlejret credentials-objekt.
Du kan også skrive inline-tabeller til simple tilfælde — mere om det nedenfor.
Arrays og arrays af tabeller
Arrays i TOML bruger firkantede parenteser og kan strække sig over flere linjer. Den virkelig karakteristiske
TOML-funktion er Array of Tables — defineret med dobbelte parenteser [[overskrift]].
Det er TOMLs svar på "hvordan udtrykker jeg en liste af objekter?" uden at det ser ud som JSON.
# Regular arrays — can be split across lines, trailing comma is fine
allowed_origins = [
"https://app.example.com",
"https://admin.example.com",
"http://localhost:3000",
]
supported_formats = ["jpeg", "png", "webp", "avif"]
retry_delays_ms = [100, 250, 500, 1000, 2000]
# Array of Tables — [[double brackets]]
# Each [[servers]] header appends a new object to the servers array
[[servers]]
name = "web-01"
ip = "10.0.1.10"
role = "primary"
tags = ["web", "prod"]
[[servers]]
name = "web-02"
ip = "10.0.1.11"
role = "replica"
tags = ["web", "prod"]
[[servers]]
name = "db-01"
ip = "10.0.2.10"
role = "primary"
tags = ["database", "prod"]Den [[servers]]-syntaks parser til et array af tre objekter — svarende til
"servers": [{...}, {...}, {...}] i JSON. Det er mere omstændeligt sammenlignet med JSON-arrays af objekter,
men fordelen er læsbarhed når hvert element har mange felter. Du kan se dette mønster flittigt i
Cargo.toml-manifester
til definition af flere binære mål, eksempler og benchmark-poster.
Inline-tabeller: kompakte enkeltlinjer
Når en tabel kun har et par felter og du ikke ønsker en hel sektionsoverskrift til den, lader inline-tabeller dig skrive det på en enkelt linje:
[build]
# Inline table — must stay on one line
target = { arch = "x86_64", os = "linux", libc = "musl" }
# Equivalent to writing:
# [build.target]
# arch = "x86_64"
# os = "linux"
# libc = "musl"
[feature_flags]
auth = { enabled = true, rollout_pct = 100 }
search = { enabled = true, rollout_pct = 50 }
beta = { enabled = false, rollout_pct = 0 }Inline-tabeller skal forblive på en enkelt linje og kan ikke udvides senere med en [overskrift].
Brug dem til små, sammenhængende værdigrupper — de er fremragende til ting som koordinatpar, byggmål
eller simple flagkonfigurationer. Brug dem ikke når du har mere end tre eller fire felter; på det tidspunkt
læser en normal tabel bedre.
TOML i den virkelige verden
TOML har udskåret sig en stærk niche i Rust- og Python-økosystemerne og vinder indpas andetsteds. Her er hvor du støder på det dagligt:
- Rust — Cargo.toml: Hvert Rust-projekt har en. Definerer pakke-metadata, afhængigheder, funktioner og byggmål. Cargo-manifest-referencen er den mest detaljerede virkelige TOML-brugsguide du finder.
- Python — pyproject.toml: PEP 518 og PEP 621 standardiserede TOML som Python-projektmetadataformatet. Poetry, Hatch, PDM og setuptools læser alle fra det.
- Deno: Denos konfigurationsfil understøtter TOML ud over JSON.
- Hugo: Den statiske website-generator Hugo accepterer TOML som konfiguration og front-matter-format — du ser det mellem
+++-afgrænsere øverst i Markdown-filer. - uv: Den hurtige Python-pakkeadministrator fra Astral bruger pyproject.toml til al konfiguration, hvilket gør TOML til de facto-standard for nye Python-værktøjer.
Hvis du skal konvertere en eksisterende konfiguration mellem formater, håndterer TOML til JSON og JSON til TOML-konverterne den strukturelle mapping for dig. Eller brug TOML Formatter til at rydde op i inkonsekvent afstand i en eksisterende fil og TOML Validator til at fange syntaksfejl inden de dukker op i produktion.
Parsing af TOML i Python
Siden Python 3.11 inkluderer standardbiblioteket
tomllib
— ingen ekstern afhængighed nødvendig. Til Python 3.9 og 3.10 har backporten
tomli
et identisk API, så du kan skifte mellem dem med et enkelt importalias.
import sys
if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib # pip install tomli
# tomllib only reads binary mode — open with "rb"
with open("pyproject.toml", "rb") as f:
config = tomllib.load(f)
# Types match TOML exactly: str, int, float, bool, datetime, list, dict
project_name = config["project"]["name"] # str
python_requires = config["project"]["requires-python"] # str
dependencies = config["project"]["dependencies"] # list[str]
print(f"Project: {project_name}")
print(f"Requires Python: {python_requires}")
print(f"Dependencies ({len(dependencies)}):")
for dep in dependencies:
print(f" {dep}")
# Parse from a string with tomllib.loads()
raw = """
[server]
host = "localhost"
port = 8080
debug = true
"""
server_config = tomllib.loads(raw)
print(server_config["server"]["port"]) # 8080 (int, not "8080")Bemærk at tomllib.load() kræver binær tilstand ("rb"). Det er bevidst —
TOML kræver UTF-8-kodning, og at åbne i binær tilstand lader parseren selv håndtere kodningskontrol.
Det er en lille faldgrube der fanger folk første gang.
Parsing af TOML i Rust
I Rust er craten toml
standardvalget. Den integrerer tæt med serde, så du kan deserialisere direkte til
dine egne structs med minimal standardkode:
use serde::Deserialize;
use std::fs;
#[derive(Debug, Deserialize)]
struct AppConfig {
server: ServerConfig,
database: DatabaseConfig,
feature_flags: FeatureFlags,
}
#[derive(Debug, Deserialize)]
struct ServerConfig {
host: String,
port: u16,
workers: usize,
}
#[derive(Debug, Deserialize)]
struct DatabaseConfig {
host: String,
port: u16,
name: String,
pool_size: u32,
}
#[derive(Debug, Deserialize)]
struct FeatureFlags {
enable_beta: bool,
max_upload_mb: u32,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let raw = fs::read_to_string("config.toml")?;
let config: AppConfig = toml::from_str(&raw)?;
println!("Server: {}:{}", config.server.host, config.server.port);
println!("DB pool size: {}", config.database.pool_size);
println!("Beta enabled: {}", config.feature_flags.enable_beta);
Ok(())
}Tilføj toml = "0.8" og serde = { version = "1", features = ["derive"] }
til din [dependencies] i Cargo.toml og du er klar. Serde derive-makroerne håndterer al
feltmapping. Hvis dine struct-feltnavne bruger snake_case men TOML-nøglerne bruger kebab-case, tilføj
#[serde(rename_all = "kebab-case")] på struct-niveau og alt mapper automatisk.
TOML vs YAML vs JSON — hvornår man skal vælge hvad
Dette spørgsmål dukker op i hvert nyt projekt. Her er den ærlige opdeling:
- TOML: Bedst til konfigurationsfiler som mennesker skriver og vedligeholder, hvor typede værdier er vigtige og indlejring er lav til moderat. Styrke: appkonfigurationer, byggmanifester, værktøjsindstillinger. Bryder ned ved dyb indlejring — 4+ niveauer bliver besværlige med gentagne sektionsoverskrifter.
- YAML: Bedst når du skriver strukturerede data med masser af lister-af-objekter (Kubernetes-manifester, GitHub Actions-arbejdsflows). Understøttelse af flerlinjestrenge er genuint bedre end TOMLs. Ulempen: mellemrum-følsomhed og YAML 1.1-typetvang skaber reelle fejl i praksis.
- JSON: Bedst til maskine-til-maskine-dataudveksling, API'er og når du har brug for den bredest mulige værktøjsunderstøttelse. Ikke godt til menneskelig konfiguration — ingen kommentarer, og strengescaping er besværlig.
En rigtig pyproject.toml
For at sætte det hele sammen, her er en realistisk pyproject.toml for et Python-bibliotek —
den slags du finder i et moderne open source-projekt. Bemærk hvordan formatet bærer en masse struktureret
information mens det stadig er let at skanne:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "httpx-cache"
version = "1.2.0"
description = "Transparent HTTP caching layer for httpx"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.9"
authors = [
{ name = "Ada Lovelace", email = "[email protected]" },
]
keywords = ["http", "cache", "httpx", "async"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = [
"httpx>=0.25.0",
"anyio>=4.0.0",
]
[project.optional-dependencies]
redis = ["redis>=5.0.0"]
dev = [
"pytest>=7.4.0",
"pytest-asyncio>=0.23.0",
"coverage[toml]>=7.3.0",
"ruff>=0.1.0",
"mypy>=1.7.0",
]
[project.urls]
Homepage = "https://github.com/example/httpx-cache"
Changelog = "https://github.com/example/httpx-cache/blob/main/CHANGELOG.md"
[tool.ruff]
line-length = 100
target-version = "py39"
[tool.ruff.lint]
select = ["E", "F", "I", "UP"]
[tool.mypy]
strict = true
python_version = "3.9"
[tool.coverage.run]
source = ["httpx_cache"]
branch = true
[tool.coverage.report]
fail_under = 90Det er rigtig TOML der udfører rigtigt arbejde. Hvert [tool.x]-afsnit er et separat navnerum
for et andet værktøj — ruff, mypy, coverage — alle lever i én fil uden at træde på hinandens tæer.
Ingen dyb indlejring nødvendig, alt er læsbart med et blik.
Opsummering
TOML leverer på sit løfte: læsbart, entydigt og rent typet. Hvis du starter et nyt projekt i Rust, Python eller Go er TOML værd at vælge som standard til konfigurationsfiler — særligt filer der vil blive committed til kildekontrol og redigeret af flere personer. Manglen på mellemrum-følsomhed alene er en lettelse sammenlignet med YAML. Til at arbejde med TOML-filer direkte i din browser, håndterer TOML Formatter og TOML Validator de mest almindelige opgaver. Og hvis du migrerer et eksisterende projekt fra JSON eller skal bygge bro over TOML til en JSON-baseret pipeline, har konverterne TOML til JSON og JSON til TOML dig dækket.