Detect an inexact Decimal operation with context flags
Detect an inexact Decimal operation with context flags
To detect an inexact Decimal operation, clear the active calculation context’s flags immediately before the operation, then inspect ctx.flags[Inexact]. With precision 2, Decimal('1') / Decimal('8') produces 0.12, but it cannot retain the discarded 5.
The first assignment in this example is the failure mode: code accepts the rounded value as though it were complete. The correction keeps the original in-memory record unchanged and checks the flag associated with that one calculation. Context flags are sticky, so checking without clear_flags() could report an earlier operation instead. The assertions establish the synthetic fixture’s result and that this division raised the signal; they do not establish whether rounding is acceptable for a particular business rule.
localcontext() confines the precision change to the with block, avoiding an accidental process-wide context change. Decimal context flags and Inexact are long-standing standard-library APIs; no newer Python API is required here. The decimal documentation explains that signals set flags and that flags must be reset before monitoring a calculation.
AI assistance disclosure: this article was drafted with AI assistance and uses a synthetic, locally reproducible fixture.
from decimal import Decimal, Inexact, localcontext
records = [{"ratio": (Decimal("1"), Decimal("8"))}]
with localcontext() as ctx:
ctx.prec = 2
numerator, denominator = records[0]["ratio"]
accepted_without_check = numerator / denominator
ctx.clear_flags()
corrected_result = numerator / denominator
was_inexact = ctx.flags[Inexact]
assert records == [{"ratio": (Decimal("1"), Decimal("8"))}]
assert accepted_without_check == Decimal("0.12")
assert corrected_result == Decimal("0.12")
assert was_inexact is True
print(f"input: {records}")
print(f"accepted without check: {accepted_without_check}")
print(f"corrected result: {corrected_result}")
print(f"Inexact: {was_inexact}")
input: [{'ratio': (Decimal('1'), Decimal('8'))}]
accepted without check: 0.12
corrected result: 0.12
Inexact: True