tomllib parse_float: Precise TOML Decimals

Published on: October 18, 2026
Reading time: 4 minutes
Python code for precise TOML configuration parsing

The parse_float parameter in Python’s tomllib module lets you control how TOML floating-point literals are converted. By default, values such as 0.1, 3.14, and 1e-6 become Python float objects. That behavior is convenient, but it may be unsuitable for financial settings, exact decimal thresholds, audit-sensitive systems, or applications that need custom numeric types.

This guide explains how to use parse_float with tomllib.load and tomllib.loads, why Decimal is often the best choice, which restrictions apply, and how to test the result. For a broader introduction, see our Python tomllib guide.

What parse_float does

parse_float receives a callable. Every time the TOML parser finds a floating-point literal, it passes the original text to that callable. The callable returns the object stored in the final dictionary.

import tomllib
from decimal import Decimal

config = tomllib.loads('rate = 0.1', parse_float=Decimal)
print(config['rate'])
print(type(config['rate']))

The result is Decimal('0.1'), preserving the digits exactly as written.

Why float may be insufficient

Python float uses binary IEEE 754 representation. Many simple decimal fractions do not have an exact binary representation. Therefore, calculations may produce values such as 0.30000000000000004. This is expected behavior, not a parser bug.

For graphics, approximate measurements, and many scientific workloads, binary floating point is perfectly appropriate. For prices, tax rates, accounting rules, contractual limits, or exact comparisons, decimal arithmetic is often a better fit. Read our Python Decimal guide for more context.

Using tomllib.load

When reading a file, open it in binary mode and pass the converter:

from decimal import Decimal
import tomllib

with open('config.toml', 'rb') as file:
    data = tomllib.load(file, parse_float=Decimal)

Only TOML floating-point literals use this callback. Integers remain int, booleans remain bool, strings remain strings, and date or time values use the appropriate datetime types.

Custom converters

The callable can perform validation or return a custom type:

from decimal import Decimal

def parse_nonnegative(text: str) -> Decimal:
    value = Decimal(text)
    if value < 0:
        raise ValueError('negative values are not allowed')
    return value

This approach can reject bad configuration values early. However, parsing should not replace full schema validation. You should still validate required keys, nested structures, ranges, and relationships after loading. A typed configuration layer using classes or dataclasses can help; see our Python dataclasses guide.

Important restrictions

The callback must not return a list or dictionary. Returning container types would interfere with TOML’s own structural mapping. Use scalar-like values or custom objects instead.

If the callback raises an exception, parsing stops. Catch both TOML syntax errors and converter errors at the application boundary:

try:
    data = tomllib.loads(text, parse_float=parse_nonnegative)
except (tomllib.TOMLDecodeError, ValueError) as exc:
    print(f'Invalid configuration: {exc}')

Decimal context and precision

Constructing Decimal from the original string preserves the literal exactly. Later arithmetic follows the active decimal context, including precision and rounding. Configure the context only where necessary, preferably with localcontext for isolated calculations.

Do not convert the TOML literal to float first and then to Decimal. That would preserve the binary approximation rather than the original decimal value. The key advantage of parse_float=Decimal is direct string-to-decimal conversion.

Price configuration example

# config.toml
[product]
price = 19.90
discount = 0.15
from decimal import Decimal
import tomllib

with open('config.toml', 'rb') as file:
    config = tomllib.load(file, parse_float=Decimal)

price = config['product']['price']
discount = config['product']['discount']
final_price = price * (Decimal('1') - discount)
print(final_price.quantize(Decimal('0.01')))

The application stays in decimal arithmetic from input to final rounding.

Scientific notation

TOML supports exponent notation. The converter receives the original text, so 1e-6 becomes Decimal('1e-6'). This makes the technique useful for tolerances, probabilities, and engineering constants that require controlled precision.

Custom numeric wrappers

A project can return a custom wrapper that stores the original literal, unit metadata, source location, or audit information. This may be useful in specialized systems, but it increases complexity. Most applications should prefer Decimal because it is standard, well documented, and compatible with established arithmetic patterns.

Validation after parsing

TOML parsing confirms syntax, not business correctness. After loading, verify that all required sections exist, types match expectations, and values stay within acceptable ranges. Type hints can make that contract clearer; see our Python type hints guide.

Testing strategy

Test exact decimals, negative values, zero, exponent notation, large magnitudes, and malformed TOML. Check both the value and the resulting type.

def test_exact_decimal():
    data = tomllib.loads('value = 0.1', parse_float=Decimal)
    assert data['value'] == Decimal('0.1')
    assert isinstance(data['value'], Decimal)

Also verify that integer literals do not use the callback. The TOML literal 1 remains an integer, while 1.0 uses parse_float.

Performance considerations

Decimal arithmetic is slower than binary floating point. Configuration files are usually small and loaded infrequently, so the overhead is normally negligible. If a system parses very large TOML documents repeatedly, benchmark the actual workload before optimizing.

TOML is primarily a configuration format. It should not be used as a high-volume analytics transport when throughput is the main requirement.

Security and maintainability

Keep the callback deterministic, small, and free from network access or hidden global mutations. Parsing configuration should not execute arbitrary code. Document the resulting numeric type so downstream code does not assume float.

The official Python tomllib documentation describes the API, while the TOML specification defines valid floating-point syntax.

When to use parse_float

Use it when exact decimal representation is required, when configuration values need early validation, or when a custom numeric type provides clear benefits. Keep the default float behavior for approximate UI settings, noncritical measurements, coordinates, or parameters where binary floating point is expected.

Conclusion

tomllib.parse_float is a small but powerful extension point. It lets you preserve decimal literals, apply controlled validation, and align configuration parsing with your application’s numeric requirements. Combined with post-parse validation, clear error handling, tests, and documentation, it produces a reliable configuration pipeline without requiring a third-party TOML parser.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Email address validation with Python getaddresses strict
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    getaddresses strict: Validate Email Address Lists

    Learn Python getaddresses strict for safer email address-list parsing, validation, security, compatibility, and testing.

    Ler mais

    Tempo de leitura: 4 minutos
    17/10/2026
    Python code representing functools.Placeholder and positional arguments
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    functools.Placeholder: Flexible Arguments in partial

    Learn functools.Placeholder in Python 3.14 to build flexible partial and partialmethod calls with open positional arguments.

    Ler mais

    Tempo de leitura: 5 minutos
    17/10/2026
    Code on a screen representing Python t-strings
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python 3.14 T-strings: Structured Templates

    Learn Python t-strings in Python 3.14, inspect Template and Interpolation objects, and build structured, extensible renderers.

    Ler mais

    Tempo de leitura: 5 minutos
    16/10/2026
    CPU and memory modules representing Python shared_memory track
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    shared_memory track: Control the Resource Tracker

    Learn Python shared_memory track for safe resource tracking, ownership, cleanup, and independent process coordination.

    Ler mais

    Tempo de leitura: 5 minutos
    16/10/2026
    Data storage unit representing compression with Python compression.zstd
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Streaming and Safe Compression

    Learn Python compression.zstd for fast file and data compression with streaming, dictionaries, testing, and safe limits.

    Ler mais

    Tempo de leitura: 6 minutos
    15/10/2026
    Code on screen for diagnosing processes with Python sys.remote_exec
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    sys.remote_exec: Diagnose Running Python Processes

    Learn Python sys.remote_exec for diagnosing running processes with controlled scripts, strong permissions, and safe operational practices.

    Ler mais

    Tempo de leitura: 6 minutos
    15/10/2026