The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Read a TOML file | with path.open('rb') as file: config = tomllib.load(file) | View examples |
| Read a TOML string | config = tomllib.loads(source) | View examples |
| Support older Python | tomllib = importlib.import_module('tomllib' if sys.version_info >= (3, 11) else 'tomli') | View examples |
| Parse exact decimal values | config = tomllib.loads(source, parse_float=Decimal) | View examples |
| Read TOML date-time values | released = config['package']['released'] | View examples |
| Catch invalid TOML | except tomllib.TOMLDecodeError as error: report(error) | View examples |
| Bound untrusted input | if path.stat().st_size > MAX_CONFIG_BYTES: raise ValueError('configuration too large') | View examples |
| Validate a required value | port = require_port(config['server'].get('port')) | View examples |
| Read available INI files | loaded = parser.read(['defaults.ini', 'local.ini'], encoding='utf-8') | View examples |
| Read INI text | parser.read_string(source) | View examples |
| Convert an INI integer | workers = parser.getint('service', 'workers') | View examples |
| Convert an INI boolean | debug = parser.getboolean('service', 'debug') | View examples |
| Provide a missing-option fallback | timeout = parser.getfloat('service', 'timeout', fallback=5.0) | View examples |
| Define shared defaults | parser['DEFAULT'] = {'timeout': '5', 'retries': '2'} | View examples |
| Layer configuration files | parser.read(['base.ini', 'deployment.ini', 'local.ini'], encoding='utf-8') | View examples |
| Disable interpolation | parser = ConfigParser(interpolation=None) | View examples |
| Use cross-section interpolation | parser = ConfigParser(interpolation=ExtendedInterpolation()) | View examples |
| Preserve option-name case | parser.optionxform = str | View examples |
| Serialize INI configuration | parser.write(file, space_around_delimiters=True) | View examples |
Configuration is an input boundary, not an untyped global dictionary. Use tomllib when you want the well-defined TOML 1.0 format and native scalar types, or configparser when compatibility with INI-style files matters. Parse bounded input, merge layers in a documented order, convert and validate every required setting, and keep credentials outside files committed to source control. tomllib was added in Python 3.11 and intentionally reads but does not write TOML.
Step by step
Detailed examples
Read TOML through the correct text or binary boundary
tomllib.loads accepts str, while tomllib.load requires a readable binary file object so the parser controls TOML's required UTF-8 decoding. The module implements TOML 1.0, returns ordinary Python containers, and was added in Python 3.11 by PEP 680. For Python 3.10 and earlier, declare the compatible tomli backport rather than hiding an optional dependency. The standard library has no tomllib.dump or dumps API; use a dedicated writer when generation or comment-preserving edits are required.
import tomllib
source = '''
title = "Command Memo"
[server]
host = "127.0.0.1"
ports = [8000, 8001]
'''
config = tomllib.loads(source)
print(config['title'])
print(config['server']['host'])
print(config['server']['ports']) Command Memo
127.0.0.1
[8000, 8001]Understand TOML's typed conversion rules
TOML strings, integers, floats, booleans, arrays, and tables become the corresponding Python primitives and containers. Offset date-times become aware datetime objects with a fixed datetime.timezone offset, while local date-times remain naive; dates and times use their matching datetime types. parse_float receives the original float token and can construct Decimal for exact decimal input. Its result cannot be a dict or list. Conversion supplies representation, not business validation, so ranges and relationships still need explicit checks.
from decimal import Decimal
from datetime import date, datetime
import tomllib
source = '''
price = 19.95
released = 2026-08-12
generated = 2026-08-12T15:30:00Z
'''
config = tomllib.loads(source, parse_float=Decimal)
print(config['price'], type(config['price']).__name__)
print(config['released'].isoformat(), isinstance(config['released'], date))
print(config['generated'].isoformat(), isinstance(config['generated'], datetime)) 19.95 Decimal
2026-08-12 True
2026-08-12T15:30:00+00:00 TrueTreat parsed configuration as untrusted input
Parsing confirms format, not application correctness. Catch TOMLDecodeError at the configuration boundary, attach the source name to diagnostics, then validate required keys, types, ranges, mutually exclusive options, and unknown fields before starting dependent services. Python 3.14 added documented msg, doc, pos, lineno, and colno attributes to TOMLDecodeError; do not rely on those attributes when supporting older runtimes. The Python documentation also recommends limiting the size of untrusted TOML because malicious input can consume considerable CPU or memory.
import tomllib
def require_port(value):
if isinstance(value, bool) or not isinstance(value, int):
raise TypeError('server.port must be an integer')
if not 1 <= value <= 65535:
raise ValueError('server.port must be between 1 and 65535')
return value
for source in ('[server]\nport = 8443', '[server]\nport = 70000'):
try:
port = require_port(tomllib.loads(source)['server']['port'])
print(f'accepted {port}')
except (KeyError, TypeError, ValueError, tomllib.TOMLDecodeError) as error:
print(type(error).__name__, str(error)) accepted 8443
ValueError server.port must be between 1 and 65535Use explicit converters for INI values
configparser supports a family of INI-like dialects rather than one universal INI standard. It stores values as strings and lowercases option names by default; section names remain case-sensitive. Use getint, getfloat, and getboolean instead of ad hoc casts, especially because bool('false') is true. A ConfigParser is strict by default, rejecting duplicate sections or options within one source. read silently skips unavailable files and reports those it loaded, whereas read_file and read_string surface their input directly.
from configparser import ConfigParser
source = '''
[service]
workers = 4
debug = no
ratio = 0.75
'''
parser = ConfigParser()
parser.read_string(source)
print(parser.getint('service', 'workers') + 1)
print(parser.getboolean('service', 'debug'))
print(parser.getfloat('service', 'ratio'))
print(list(parser['service'])) 5
False
0.75
['workers', 'debug', 'ratio']Define deterministic precedence for defaults and overrides
Values in the special DEFAULT section are visible from every ordinary section and have precedence over a fallback argument. Reading multiple sources merges them in order: a later value replaces an earlier conflict, while unrelated earlier settings remain. This is useful for a documented chain such as built-in defaults, system file, deployment file, then an explicitly selected local file. Avoid silently reading an unbounded working-directory file, and distinguish an absent option from an invalid present option because fallback does not suppress conversion errors.
from configparser import ConfigParser
base = '''
[DEFAULT]
timeout = 5
[service]
host = api.internal
workers = 2
'''
override = '''
[service]
workers = 6
'''
parser = ConfigParser()
parser.read_string(base, source='base.ini')
parser.read_string(override, source='deployment.ini')
print(parser['service']['host'])
print(parser.getint('service', 'workers'))
print(parser.getint('service', 'timeout', fallback=30))
print(parser.get('service', 'region', fallback='local')) api.internal
6
5
localChoose interpolation and serialization behavior deliberately
ConfigParser uses BasicInterpolation by default, expanding %(name)s references from the current section or DEFAULT section. ExtendedInterpolation enables ${section:option} references, and interpolation=None preserves values literally—often the safest choice for arbitrary percent signs, templates, or opaque credentials. Interpolation happens when values are read and can raise errors then. Set optionxform = str before reading only when case-sensitive keys are a format requirement. write serializes current data but does not round-trip comments, delimiter choices, or original formatting.
from configparser import ConfigParser, ExtendedInterpolation
source = '''
[paths]
root = /srv/app
[logs]
directory = ${paths:root}/logs
'''
expanded = ConfigParser(interpolation=ExtendedInterpolation())
expanded.read_string(source)
literal = ConfigParser(interpolation=None)
literal.read_string('[message]\nprogress = 75% complete')
print(expanded['logs']['directory'])
print(literal['message']['progress'])
expanded['logs']['level'] = 'INFO'
print(expanded.get('logs', 'level')) /srv/app/logs
75% complete
INFOLocal code tester
Parse and validate application configuration
Experiment with typed TOML values and a small validation boundary using only deterministic standard-library behavior.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



