androidengineers.Book a session

Python 02 · Text and decisions

Input conversion and defensive validation

articleSelf-paced

Learn the concept

User input, configuration, and API payloads arrive with uncertain types and values. Validation converts that uncertainty into an explicit contract. Check shape first, then convert, then apply domain limits. A field can be syntactically numeric but still outside the allowed range.

Raise a specific exception when a caller supplies invalid input. Keep error messages actionable without echoing sensitive values. Do not catch every possible exception and return a plausible default, because that can conceal programming errors.

Python’s bool is a subclass of int. If a field must be an actual integer rather than true or false, a simple isinstance(value, int) check may be too permissive. Choose validation behavior intentionally. The boundary should reject bad inputs before expensive work begins.

Run and inspect

def read_limit(value):
    if type(value) is not int:
        raise ValueError("Limit must be an integer")
    if not 1 <= value <= 100:
        raise ValueError("Limit must be between 1 and 100")
    return value

assert read_limit(10) == 10

Your exercise

Test 1, 100, 0, 101, True, "10", and None. Decide whether your application wants to convert text or reject it, and document that choice.

Check your understanding

All invalid cases fail before downstream processing; boundary values succeed.

Guided workshop: validate a batch size

A CLI batch size starts as text. The application needs a whole number between 1 and 100. Separate three decisions: remove surrounding whitespace, parse the number, and enforce the allowed range. Reporting all failures as “the program crashed” hides useful information.

# academy-check
def batch_size(raw):
    try:
        value = int(raw.strip())
    except ValueError as error:
        raise ValueError("batch size must be an integer") from error
    if not 1 <= value <= 100:
        raise ValueError("batch size must be between 1 and 100")
    return value

assert batch_size(" 12 ") == 12
for raw in ["", "two", "1.5", "0", "101"]:
    try:
        batch_size(raw)
    except ValueError:
        pass
    else:
        raise AssertionError(raw)
print("six cases passed")

The first except handles parsing. The range check runs only after parsing succeeds. Raising from the original exception retains the cause for debugging. At the CLI boundary you would catch the final ValueError, display its message, and return a nonzero exit code. Do not catch every exception here: a misspelled variable is a programming defect, not invalid user input.

Exercise: accept a second input, a document title. Strip surrounding whitespace, reject an empty title, and reject titles longer than 80 characters. Preserve internal spaces and the original letter case. Try " Invoice A ", whitespace only, and 81 x characters.

Worked answer: assign title = raw.strip(), then reject when not title or len(title) > 80. The first case becomes Invoice A; replacing every run of spaces would make an additional content transformation that the requirement did not authorize.

Check your reasoning: would bool("false") be false? No: a nonempty string is truthy. For a configuration switch, explicitly map allowed values such as true and false. Does validation make user content trustworthy instructions? No: it establishes the properties you checked, not its meaning or authority.

YOUR LEARNING JOURNEY

0 of 42 available lessons completed

Progress saved in this browser. No account needed.
Input conversion and defensive validation | Python for AI Engineering | Android Engineers