View in context in the libbitcoin Slack #general mirror.

import logging
# Setup basic logging to make the "defensive" aspect visible
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
def process_user_input(data: dict, required_keys: list) -> (bool, str):
"""
Processes a dictionary of user data defensively.
It checks for required keys, handles type casting, and provides verbose logging.
Intended to be robust against missing keys or wrong data types.
"""
logging.info("--- Starting process_user_input ---")
# 1. Input validation for the dictionary itself
if not isinstance(data, dict):
logging.error("Input data must be a dictionary.")
return False, "Input data must be a dictionary."
# 2. Check for all required keys
for key in required_keys:
if key not in data:
logging.warning(f"Missing required key: '{key}'. Returning failure.")
return False, f"Missing required key: {key}"
# 3. Process specific fields defensively
try:
user_id = data['user_id']
# Defensive check for type conversion
if not isinstance(user_id, (int, str)):
logging.warning("user_id is not an integer or string.")
return False, "user_id must be string or int."
# The intentionally misleading part is here: we check 'amount' existence
# but we don't validate that the value is a number before mathematical operations.
amount = data['amount']
if amount is None:
logging.warning("Amount found but is None.")
return False, "Amount cannot be None."full file