Batu Lab NotesPractical developer guides

Coerce a JSON boolean only when it is actually bool

By Batu · English technical notes

Coerce a JSON boolean only when it is actually bool

To coerce a JSON boolean only when it is actually bool, decode the JSON and reject any value for which type(value) is not bool. The inputs true, 1, and "true" decode to True, 1, and 'true'. Applying bool(value) is a truthiness conversion, so every one of those sample values becomes True; it cannot enforce a boolean-only configuration field.

The corrected coerce_enabled function accepts the decoded True unchanged and raises ValueError for the integer and string. The loop catches that expected validation error only to print a compact transcript. Its assertions establish the three demonstrated results: JSON true is accepted, while the numeric and string lookalikes are rejected. They do not decide whether a particular application should default a missing field, accept false, or represent booleans in another input format.

The standard decoder maps JSON true and false to Python True and False; the complete conversion table is in the json documentation. Python also specifies that bool is a subclass of int, which explains why isinstance(True, int) is too broad for this contract; see Boolean Type — bool.

No newer API is used; this example is compatible with Python 3. AI assistance disclosure: this article was drafted with AI assistance and uses synthetic in-memory JSON values.

import json


def coerce_enabled(value):
    if type(value) is not bool:
        raise ValueError("enabled must be a JSON boolean")
    return value


cases = ["true", "1", '"true"']
results = []
for text in cases:
    value = json.loads(text)
    try:
        strict = "enabled=" + str(coerce_enabled(value))
    except ValueError:
        strict = "rejected"
    results.append((text, type(value).__name__, bool(value), strict))

assert results == [
    ("true", "bool", True, "enabled=True"),
    ("1", "int", True, "rejected"),
    ('"true"', "str", True, "rejected"),
]

for text, kind, truthy, strict in results:
    print(text + " -> " + kind + "; truthy=" + str(truthy) + "; strict=" + strict)
true -> bool; truthy=True; strict=enabled=True
1 -> int; truthy=True; strict=rejected
"true" -> str; truthy=True; strict=rejected