Bir Rust projesi açtıysanız, TOML ile tanışmışsınızdır. pyproject.toml kullanan bir Python paketi
dokunduysanız, onu kullandınız. TOML — Tom's Obvious Minimal Language (Tom'un Açık Minimal Dili) —
YAML'ın boşluk tuzaklarından ve JSON'un yorumlara izin vermeye yanaşmamasından bıkan geliştiricileri
sessiz sedasız fethetmeye devam eden yapılandırma dosyası formatıdır. GitHub'ın kurucu ortaklarından
Tom Preston-Werner tarafından oluşturulan TOML, tek bir fikir etrafında tasarlandı: bir yapılandırma formatı,
spesifikasyona bakmadan okuyabilecek kadar açık olmalıdır. Bu vaadi yerine getirip getirmediğine bakalım.
TOML Tam Olarak Nedir?
TOML, resmi spesifikasyonun hemen başında belirtilen üç açık tasarım hedefiyle bir yapılandırma dosyası formatıdır: okunması açık, karmaşıklıkta minimal ve bir hash tablosuna (çoğu dilde sözlük/map) kesin olmayan biçimde eşlenmeli. O üçüncü hedef kilit olandır — her geçerli TOML dosyasının tam olarak bir doğru ayrıştırma sonucu vardır. Sürpriz tip zorlaması yok, YAML tarzı boolean tuzakları yok, bir değerin dize mi yoksa sayı mı olduğu konusunda belirsizlik yok.
Format, eski INI dosyalarından bölüm başlığı stilini ödünç alır ancak üstüne uygun tipler, diziler ve iç içe tablolar ekler. Sonuç, daha önce yapılandırma dosyası düzenlemiş herkesin tanıdık bulacağı bir şeydir, ancak bir ayrıştırıcının gerçek bir tiplendirilmiş veri modeli çıkarabileceği kadar yapıya sahiptir. Spesifikasyonun 1.0.0 sürümü, yıllarca süren iyileştirmelerden sonra Ocak 2021'de yayınlandı — kenar durumlarını incelemek istiyorsanız TOML spesifikasyonuna GitHub'da göz atabilirsiniz.
Temel Bilgiler: Anahtar-Değer Çiftleri ve Yorumlar
Bir TOML dosyası anahtar-değer çiftlerinden oluşur. Anahtarlar ve değerler = ile ayrılır
ve yorumlar # ile başlar. Basit.
# 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 = falseÇoğu anahtarda tırnak gerekmez. Değerler tiplendirilmiştir — 8 bir tam sayı, 0.85
bir ondalıklı, false bir boolean. Tahmin yok, değerin nasıl göründüğüne göre örtük
zorlama yok. Bu, zamanın %90'ında yazacağınız gündelik TOML'dur.
Dize Tipleri: Temel, Literal ve Çok Satırlı
TOML'un dört dize tipi vardır. Bu, her gerçek dünya durumunu temiz biçimde kapsar:
# 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/
'''Literal dize tipi ('tek tırnaklar'), insanların var olduğunu unuttuğu türdendir, ancak
gerçekten kullanışlıdır — regex desenleri ve Windows yolları, kaçış katlamadan çok daha temizdir.
Daha az ters eğik çizgi yazmanızı sağlayan hangi tırnak stilini tercih ederseniz onu seçin.
Sayılar, Boolean'lar ve Tarih/Saatler
TOML'un yerel tipleri, bir yapılandırma dosyasına gerçekten koyacağınız her şeyi kapsar. Özellikle, birinci sınıf tarih/saat desteği vardır — YAML'ın teknik olarak sahip olduğu ancak ayrıştırıcılar arasında tutarsız biçimde işlediği bir şey.
# 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 ve false —
YAML 1.1'in kabul ettiği True, TRUE, yes, on veya
diğer varyantlar değil. Bu kasıtlıdır. "true" dizesine ihtiyacınız varsa, tırnak içine alın.Tablolar: INI Tarzı Bölüm Başlıkları
TOML'daki tablolar, [başlık] sözdizimi ile tanımlanır. Bir başlığın altındaki her şey,
bir sonraki başlık görünene kadar o tabloya aittir. Bu, TOML'u tanıdık kılan özelliktir —
esasen INI dosyalarıdır ama tiplerle.
[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"[database.credentials] gibi noktalı başlıklar, iç içe tablolar oluşturur. Ayrıştırma sonucu
tam olarak beklediğiniz gibidir: iç içe bir credentials nesnesine sahip bir database nesnesi.
Basit durumlar için satır içi tablolar da yazabilirsiniz — aşağıda daha fazlası.
Diziler ve Tablo Dizileri
TOML'daki diziler köşeli parantez kullanır ve birden fazla satıra yayılabilir. Gerçekten ayırt edici
TOML özelliği Tablo Dizisidir — çift parantezlerle tanımlanır [[başlık]]. Bu,
TOML'un "JSON gibi görünmeden bir nesne listesini nasıl ifade ederim?" sorusuna verdiği yanıttır.
# 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"]Bu [[servers]] sözdizimi, üç nesnenin bir dizisine ayrıştırılır — JSON'da
"servers": [{...}, {...}, {...}]'ye eşdeğer. JSON nesne dizilerine kıyasla ayrıntılıdır,
ancak her öğenin çok sayıda alanı olduğunda okunabilirlik avantajı sağlar. Bu kalıbı, birden fazla
ikili hedef, örnek ve kıyaslama girişleri tanımlamak için
Cargo.toml manifestlerinde
yoğun biçimde görebilirsiniz.
Satır İçi Tablolar: Kompakt Tek Satırlıklar
Bir tablonun yalnızca birkaç alanı varsa ve bunun için tüm bir bölüm başlığı istemiyorsanız, satır içi tablolar tek bir satırda yazmanıza olanak tanır:
[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 }Satır içi tablolar tek bir satırda kalmalı ve daha sonra bir [başlık] ile genişletilemez.
Bunları küçük, bütünleşik değer grupları için kullanın — koordinat çiftleri, derleme hedefleri veya
basit bayrak yapılandırmaları için mükemmeldirler. Üç veya dört alanın üzerinde olduklarında kullanmayın;
o noktada düzenli bir tablo daha iyi okunur.
TOML Gerçek Dünyada
TOML, Rust ve Python ekosistemlerinde güçlü bir niş edinmiş ve başka yerlerde de zemin kazanıyor. Günlük hayatınızda bununla nerede karşılaşacağınız:
- Rust — Cargo.toml: Her Rust projesinde biri var. Paket meta verilerini, bağımlılıkları, özellikleri ve derleme hedeflerini tanımlar. Cargo manifest referansı, bulabileceğiniz en ayrıntılı gerçek dünya TOML kullanım kılavuzudur.
- Python — pyproject.toml: PEP 518 ve PEP 621, TOML'u Python proje meta veri formatı olarak standartlaştırdı. Poetry, Hatch, PDM ve setuptools hepsini oradan okur.
- Deno: Deno yapılandırma dosyası, JSON'a ek olarak TOML'u da destekler.
- Hugo: Hugo statik site üreticisi, yapılandırma ve ön içerik formatı olarak TOML'u kabul eder — Markdown dosyalarının başında
+++sınırlayıcıları arasında görürsünüz. - uv: Astral'ın hızlı Python paket yöneticisi, tüm yapılandırma için pyproject.toml kullanır, bu da TOML'u yeni Python araçları için fiilen standart haline getirir.
Mevcut bir yapılandırmayı formatlar arasında dönüştürmeniz gerekiyorsa, TOML'dan JSON'a ve JSON'dan TOML'a dönüştürücüler yapısal eşlemeyi sizin için halleder. Ya da mevcut bir dosyadaki tutarsız boşlukları temizlemek için TOML Biçimleyiciyi, sözdizimi hatalarını üretimde yüzeye çıkmadan önce yakalamak için TOML Doğrulayıcısını kullanın.
Python'da TOML Ayrıştırma
Python 3.11'den itibaren standart kütüphane
tomllib'i içeriyor
— harici bağımlılık gerekmez. Python 3.9 ve 3.10 için
tomli geri dönüşümünün
özdeş bir API'si var, bu nedenle tek bir içe aktarma takma adıyla aralarında geçiş yapabilirsiniz.
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")tomllib.load()'un ikili modu ("rb") gerektirdiğini unutmayın. Bu kasıtlıdır —
TOML, UTF-8 kodlaması gerektirir ve ikili modda açmak, ayrıştırıcının kodlama denetimini kendisi
yapmasına olanak tanır. İlk seferinde insanları yakalayan küçük bir tuhaflık.
Rust'ta TOML Ayrıştırma
Rust'ta toml sandığı
standart seçimdir. serde ile sıkıca entegre olur, bu nedenle minimum şablonla doğrudan
kendi yapılarınıza seri çıkarabilirsiniz:
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(())
}Cargo.toml'daki [dependencies]'e toml = "0.8" ve
serde = { version = "1", features = ["derive"] } ekleyin ve hazırsınız. Serde türet makroları
tüm alan eşlemesini halleder. Yapı alan adlarınız snake_case kullanıyorsa ancak TOML anahtarları
kebab-case kullanıyorsa, yapı düzeyinde #[serde(rename_all = "kebab-case")] ekleyin
ve her şey otomatik olarak eşlenir.
TOML vs YAML vs JSON — Hangisi Ne Zaman Seçilir
Bu soru her yeni projede gündeme gelir. İşte dürüst özet:
- TOML: İnsanların yazdığı ve sürdürdüğü yapılandırma dosyaları için en iyi seçimdir; tipli değerlerin önemli olduğu ve iç içe geçmenin sığ-orta düzeyde olduğu durumlar. En uygun nokta: uygulama yapılandırmaları, derleme manifestleri, araç ayarları. Derin iç içe geçmede çöker — 4+ düzey, tekrarlanan bölüm başlıklarıyla garip hale gelir.
- YAML: Çok sayıda nesne listesiyle yapılandırılmış veri yazarken en iyidir (Kubernetes manifestleri, GitHub Actions iş akışları). Çok satırlı dize desteği TOML'dan gerçekten daha iyidir. Dezavantajı: boşluk duyarlılığı ve YAML 1.1 tip zorlaması gerçek dünyada gerçek hatalar oluşturur.
- JSON: Makine-makine veri alışverişi, API'ler ve mümkün olan en geniş araç zinciri desteğine ihtiyaç duyduğunuzda en iyidir. İnsan tarafından sürdürülen yapılandırma için pek iyi değil — yorum yok, dize kaçışı sıkıcı.
Gerçek bir pyproject.toml
Her şeyi bir araya getirmek için, bir Python kütüphanesi için gerçekçi bir pyproject.toml —
modern bir açık kaynak projesinde bulacağınız türden. Formatın çok sayıda yapılandırılmış
bilgi taşırken taramayı ne kadar kolaylaştırdığına dikkat edin:
[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 = 90Bu gerçek iş yapan gerçek TOML. Her [tool.x] bölümü, farklı bir araç için ayrı bir ad alanıdır
— ruff, mypy, coverage — hepsi birbirine basmadan tek bir dosyada yaşıyor.
Derin iç içe geçme gerekmez, her şey bir bakışta okunabilir.
Sonuç
TOML vaadini yerine getirir: okunabilir, belirsizliksiz ve temiz biçimde tiplendirilmiş. Rust, Python veya Go'da yeni bir proje başlıyorsanız, özellikle kaynak kontrolüne dahil edilecek ve birden fazla kişi tarafından düzenlenecek dosyalar için yapılandırma dosyalarında TOML'a varsayılan olarak başvurmaya değer. Yalnızca boşluk duyarsızlığı, YAML'a kıyasla bir rahatlama. TOML dosyalarıyla doğrudan tarayıcınızda çalışmak için TOML Biçimleyici ve TOML Doğrulayıcı en yaygın görevleri halleder. Ve mevcut bir projeyi JSON'dan taşıyorsanız veya TOML'u JSON tabanlı bir boru hattına köprülemeniz gerekiyorsa, TOML'dan JSON'a ve JSON'dan TOML'a dönüştürücüler ihtiyacınızı karşılar.