3 min read

Lesson 3: Validation & Errors — Data Safety, Type Checking

Lesson 3: Validation & Errors — Data Safety, Type Checking

📂 Series: Python CLI Mastery — Argparse Deep Dive

Goal:

Make sure your CLI tool only accepts valid, well-typed input and throws helpful errors when things go wrong.

Why Validation Matters

Your CLI tool is only as good as the inputs it accepts. If someone passes "banana" when you’re expecting a number, things break — fast.
Validation protects your logic from crashing, ensures clean output, and makes your script behave like a pro-level tool, not a fragile toy. It’s the armor between your code and the chaos.

🛠️ What You’ll Learn

  • Type enforcement (type=int, type=float, etc.)
  • Limiting input with choices=
  • Writing custom validators (like checking ranges or positive values)
  • Validating ranges and patterns
  • Defensive coding with try/except (optional but useful)
  • Using required=True to force input
  • Setting up mutually exclusive flags
  • Showing clean, clear, helpful errors — automatically!

Core Concepts

1. type= Argument
Converts the input and checks type at the same time.
parser.add_argument("--age", type=int)
If someone passes --age banana, they’ll get:
error: argument --age: invalid int value: 'banana'
Boom. Safety net.

2. Custom Validation Functions
You can write your own function to validate input.
This can check ranges, allowed choices, regexes, etc.

def positive_number(value):
    ivalue = int(value)
    if ivalue <= 0:
        raise argparse.ArgumentTypeError("Must be a positive number.")
    return ivalue

parser.add_argument("--level", type=positive_number)

Try --level -5 and watch it get smacked down. 👊

3. Choices: Limit Accepted Values
Great for enums or category selection.
parser.add_argument("--color", choices=["red", "green", "blue"])
Input like --color yellow? Nope. 🚫
You’ll get:
error: argument --color: invalid choice: 'yellow'

4. Required Arguments
Want to force the user to include a value?
parser.add_argument("--username", required=True)
No --username? The parser yells at them. With love.

5. Mutually Exclusive Inputs
User can’t pass two flags at once — only one allowed.

group = parser.add_mutually_exclusive_group()
group.add_argument("--verbose", action="store_true")
group.add_argument("--quiet", action="store_true")

Passing both = ❌ error!

Sample Code: Clean Input or No Input

import argparse

parser = argparse.ArgumentParser(description="Process numeric input safely")

# Type enforcement
parser.add_argument("--age", type=int, help="Your age in years")
parser.add_argument("--rate", type=float, help="Conversion rate")

# Limited input choices
parser.add_argument("--mode", choices=["easy", "medium", "hard"], default="easy",
                    help="Choose difficulty level (easy, medium, hard)")

args = parser.parse_args()

print(f"Age: {args.age}")
print(f"Rate: {args.rate}")
print(f"Mode: {args.mode}")

Try It Out

$ python3 validate.py --age 30 --rate 1.25 --mode medium
pyhon-Age: 30
Rate: 1.25
Mode: medium

$ python3 validate.py --age banana
# error: argument --age: invalid int value: 'banana'

$ python3 validate.py --mode nightmare
# error: argument --mode: invalid choice: 'nightmare' (choose from 'easy', 'medium', 'hard')

✔️ Beautiful, clean, and totally idiot-proof.

Pro Tips

  • Use type= for basic conversions and safety.
  • Add custom validators for logic like range checks.
  • Use choices and required when applicable.
  • Test invalid inputs! (You will thank yourself later.)
  • Combine with default= to provide safe fallbacks.
  • Don’t assume users will follow instructions — enforce rules instead.

Real-World Use Cases

  • CLI scripts with fixed modes: --env dev, --env prod
  • User age, tax rate, discount amount — all should be type-checked
  • Auto scripts with sensitive parameters like --risk or —region, —priority

Bonus Sample: Price Calculator with Validation

import argparse
def positive_float(val):
    f = float(val)
    if f <= 0:
        raise argparse.ArgumentTypeError("Value must be greater than zero.")
    return f

parser = argparse.ArgumentParser(description="Calculate price with tax")
parser.add_argument("price", type=positive_float)
parser.add_argument("--tax", type=positive_float, default=0.2)
args = parser.parse_args()

total = args.price * (1 + args.tax)
print(f"Total: ${total:.2f}")

Coming Up Next

Part 4: Grouping & Subcommands — We’ll learn to organize commands like a pro, split logic into subtools, and make your CLI feel like a real app.

🔁 New here? Catch up from Lesson 1:
📍 Lesson 1: Getting Started with argparse

💬 Got questions or want to share your CLI builds? Drop a comment or ping me on LinkedIn or Substack!

🚀 Subscribe free at novaxis.ghost.io — no ads, no spam, just powerful Python tools.