Welcome to Day 5! Today we shift from volatile, temporary in-memory variables to persistent storage and application durability. You will learn how to interact safely with your operating system's file system, read/write structured industry data patterns, handle real-world operational crashes gracefully, and keep execution timelines documented using professional logging architectures. 💾
1. File Handling & pathlib 📄
Python's pathlib module treats file paths as smart object structures instead of plain text strings. This avoids bugs caused by differing slash directions across operating systems (Windows uses \, while Mac/Linux use /).
-
Reading (
"r"): Loads file contents into memory. -
Writing (
"w"): Erases any existing file contents and writes a fresh payload from scratch. -
Appending (
"a"): Targets the end of a file, adding fresh text without overwriting existing contents.
🌱 Easy Starter Example
from pathlib import Path
# Create a path reference pointing to a file in the current workspace directory
file_path = Path("notes.txt")
# Write text cleanly to a file space
file_path.write_text("Hello from Day 5!")
# Read data straight back into a string variable
content = file_path.read_text()
print(content) # Output: Hello from Day 5!
🏛️ Real-World Example: Multi-Platform System Telemetry Appender
from pathlib import Path
from datetime import datetime
def log_system_status(status_message: str) -> None:
# Resolve home folder pathways seamlessly across Windows, Mac, or Linux systems
target_dir = Path.home() / "app_workspace" / "telemetry"
# Create the directory chain automatically if it doesn't exist yet
target_dir.mkdir(parents=True, exist_ok=True)
log_file = target_dir / "runtime_events.log"
timestamp = datetime.now().isoformat()
# Secure stream channel using Python's standard file-open context manager
with open(log_file, mode="a", encoding="utf-8") as file:
file.write(f"[{timestamp}] STATUS: {status_message}\n")
log_system_status("Core subsystem initialization sequence completed successfully.")
2. Structured Data Formats (JSON & CSV) 📊
A. JSON (JavaScript Object Notation)
JSON is a text format used for web data exchanges and configuration states. It mirrors Python dictionaries and lists.
🌱 Easy Starter Example
import json
user_profile = {"username": "alice", "active": True, "roles": ["admin", "dev"]}
# Convert a Python dictionary to a structured JSON data string
json_string = json.dumps(user_profile)
print(json_string) # Output: {"username": "alice", "active": true, ...}
# Parse a JSON data string straight back into a standard Python dictionary
parsed_dict = json.loads(json_string)
🏛️ Real-World Example: Storing and Modifying Local Configuration Files
import json
from pathlib import Path
config_path = Path("settings.json")
# Write configuration updates safely into a localized file storage space
default_settings = {"theme": "dark", "port": 8080, "cache_enabled": True}
with open(config_path, mode="w", encoding="utf-8") as file:
json.dump(default_settings, file, indent=4)
# Read, modify, and update configuration maps securely
if config_path.exists():
with open(config_path, mode="r", encoding="utf-8") as file:
current_config = json.load(file)
# Modify parameter configurations
current_config["theme"] = "dim-nordic-blue"
with open(config_path, mode="w", encoding="utf-8") as file:
json.dump(current_config, file, indent=4)
B. CSV (Comma-Separated Values)
CSV files store tabular spreadsheet data in plain text lines.
🌱 Easy Starter Example
import csv
# Writing records cleanly into rows
with open("basic.csv", mode="w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["Name", "Score"])
writer.writerow(["Bob", "92"])
# Reading records straight back from rows
with open("basic.csv", mode="r", encoding="utf-8") as file:
reader = csv.reader(file)
for row in reader:
print(row) # Output: ['Name', 'Score'], ['Bob', '92']
🏛️ Real-World Example: Product Inventory Report Processing Engine
import csv
from pathlib import Path
inventory_file = Path("warehouse_inventory.csv")
# Generate a cleanly tracked CSV document mapping item column cells out explicitly
products = [
{"sku": "PROD-001", "name": "Mechanical Keyboard", "quantity": "45"},
{"sku": "PROD-002", "name": "Ergonomic Mouse", "quantity": "120"}
]
with open(inventory_file, mode="w", newline="", encoding="utf-8") as file:
# Use DictWriter to map dictionaries directly to structured CSV columns
fieldnames = ["sku", "name", "quantity"]
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(products)
3. Exception Handling 🛠️
Exceptions are errors detected during application execution. Exception Handling keeps your program running smoothly when something goes wrong, instead of crashing unexpectedly.
-
try: Wraps code blocks that might trigger an unexpected error. -
except: Code block that catches and handles specific runtime errors. -
else: Runs only if the code inside thetryblock executes without any errors. -
finally: Runs always, regardless of whether an error occurred or not. Ideal for cleanup tasks like closing database connections. -
raise: Forces a specific error to occur intentionally.
🌱 Easy Starter Example
try:
number = int(input("Enter a number to divide 10 by: "))
result = 10 / number
except ZeroDivisionError:
print("Error: You cannot divide numbers by zero.")
except ValueError:
print("Error: Invalid character input. You must input digits.")
else:
print(f"Calculation success! Answer is: {result}")
finally:
print("Execution loop complete.")
🏛️ Real-World Example: Robust External API Data File Extraction Pipeline
from pathlib import Path
def fetch_transaction_payload(filename: str) -> str:
target_file = Path(filename)
try:
# Code block might trigger a FileNotFoundError if missing
with open(target_file, mode="r", encoding="utf-8") as file:
data = file.read()
if not data.strip():
# Manually raise an explicit error flag if data payload is completely blank
raise ValueError("Target file payload context space is completely empty.")
except FileNotFoundError as error:
return f"Operational Failure: Target file reference '{filename}' missing on disk. Details: {error}"
except ValueError as validation_error:
return f"Data Integrity Failure: {validation_error}"
else:
print("File parsed from local disks without encountering structural blocks.")
return data
finally:
print("System resource locks released successfully.")
print(fetch_transaction_payload("missing_ledger.dat"))
4. Custom Exceptions 🚨
Standard exceptions (like ValueError) are often too broad. Creating Custom Exceptions lets you name specific errors after real-world issues in your business logic, making bugs much easier to trace.
🌱 Easy Starter Example
# Custom exception classes inherit directly from the base Exception class
class AgeRestrictionError(Exception):
pass
def verify_voter_age(age: int):
if age < 18:
raise AgeRestrictionError("User is under the required voting age threshold.")
print("Access granted.")
try:
verify_voter_age(16)
except AgeRestrictionError as error:
print(f"Registration Denied: {error}")
🏛️ Real-World Example: Digital Wallet Transaction Guardrail
class InsufficientFundsError(Exception):
"""Raised when an account attempts to withdraw more than their active balance."""
def __init__(self, requested: float, available: float):
super().__init__(f"Attempted to withdraw ${requested}, but only ${available} is available.")
self.requested = requested
self.available = available
class BankAccount:
def __init__(self, owner: str, balance: float):
self.owner = owner
self.balance = balance
def withdraw(self, amount: float) -> float:
if amount > self.balance:
# Trigger custom exception, passing runtime values into the error context
raise InsufficientFundsError(amount, self.balance)
self.balance -= amount
return self.balance
# Execution verification handling loops
user_account = BankAccount("Sarah Jenkins", 250.00)
try:
user_account.withdraw(400.00)
except InsufficientFundsError as error:
print(f"[TRANSACTION BLOCKED] Overdraft prevention active: {error}")
5. Logging 🪵
Using print() to track errors is an anti-pattern; outputs disappear when the terminal closes. The logging module provides a permanent tracker that categorizes events by severity and writes them to disk.
Log Levels
| Level | Severity Code Value | Core Functional Destination Purpose |
|---|---|---|
DEBUG |
10 | Detailed diagnostic information for local debugging. |
INFO |
20 | Confirms the application is working as expected. |
WARNING |
30 | Indicates something unexpected happened, but the app can still run. |
ERROR |
40 | A serious issue that caused a specific operation or function to fail. |
CRITICAL |
50 | A fatal error that threatens to crash the entire application instantly. |
🌱 Easy Starter Example
import logging
# Simple logger configuration setup out of the box
logging.basicConfig(level=logging.INFO)
logging.info("System process successfully started.")
logging.warning("Disk space approaching filled capacity limits.")
logging.error("Database connection dropped.")
🏛️ Real-World Example: Enterprise Application Logging Architecture
import logging
from pathlib import Path
def initialize_production_logger():
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
# Configure production logger to write messages to a file with timestamps
logging.basicConfig(
filename=log_dir / "production_runtime.log",
filemode="a",
format="%(asctime)s - [%(levelname)s] - %(name)s - %(message)s",
level=logging.WARNING # Directs the application to log only WARNING level issues or worse
)
initialize_production_logger()
logger = logging.getLogger("PaymentGateway")
def process_credit_card():
try:
# Simulating external microservice outage breakdown error states
raise ConnectionRefusedError("Payment processor API endpoint timeout.")
except ConnectionRefusedError as error:
# Logs the detailed stack trace to your file automatically
logger.error("Failed to process transaction securely.", exc_info=True)
process_credit_card()
6. Practice Challenge: Data Processing Engine 🏋️
Let’s combine everything from today into a single, comprehensive exercise. We will write a data ingestion script that reads a user dataset from a file, validates the information using custom exceptions, and logs everything to a localized metrics file.
Step 1: Set Up Your Project Files
Using your terminal skills from Day 4, create a workspace with a fresh script file:
uv init day_5_challenge && cd day_5_challenge
touch data_processor.py
Step 2: Implement the Code Base
Open data_processor.py and implement the production data parsing pipeline:
# data_processor.py
import json
import csv
import logging
from pathlib import Path
# 1. Configure the system logging tracking layout
logging.basicConfig(
filename=Path("system_execution.log"),
filemode="w",
format="%(asctime)s - [%(levelname)s] - %(message)s",
level=logging.INFO
)
logger = logging.getLogger("DataProcessor")
# 2. Define custom domain error exception patterns
class InvalidUserDataError(Exception):
"""Raised when user data records fail business rule validation criteria."""
pass
# 3. Implement parsing pipeline logic
def validate_and_transform_records(raw_csv_path: str, output_json_path: str) -> None:
source_file = Path(raw_csv_path)
destination_file = Path(output_json_path)
processed_records = []
logger.info("Initializing raw transaction CSV import pipeline.")
try:
with open(source_file, mode="r", encoding="utf-8") as file:
reader = csv.DictReader(file)
for row_index, row in enumerate(reader, start=1):
try:
username = row.get("username", "").strip()
email = row.get("email", "").strip()
age_str = row.get("age", "").strip()
# Core Validation Rules: Check for missing data fields
if not username or not email or not age_str:
raise InvalidUserDataError(f"Row {row_index}: Missing critical data fields.")
age = int(age_str)
if age <= 0 or age > 120:
raise InvalidUserDataError(f"Row {row_index}: Age context constraint anomaly ({age}).")
# Data Transformation step
processed_records.append({
"user_id": username.lower(),
"contact": email,
"years_active": age,
"verified_status": True if age >= 18 else False
})
logger.info(f"Successfully processed user record: '{username}'.")
except InvalidUserDataError as data_error:
logger.warning(f"Skipping row registry error: {data_error}")
except ValueError:
logger.warning(f"Skipping row {row_index}: Failed parsing age string component to numerical digit.")
except FileNotFoundError:
logger.critical(f"Pipeline processing halted. Source input file missing: '{raw_csv_path}'")
print("Fatal Error: Source database file not found. Check system execution logs.")
return
# Write successfully processed data records out to JSON format storage
try:
with open(destination_file, mode="w", encoding="utf-8") as out_file:
json.dump(processed_records, out_file, indent=4)
logger.info(f"Ingestion successful! Saved {len(processed_records)} records to '{output_json_path}'.")
print(f"Success! Processed data exported cleanly to {output_json_path}")
except Exception as general_error:
logger.error(f"Failed exporting JSON package data: {general_error}")
# 4. Local Execution Test Suite Harness Setup
if __name__ == "__main__":
# Generate dummy source data for testing the validation loops
raw_data_path = "source_users.csv"
with open(raw_data_path, mode="w", newline="", encoding="utf-8") as test_csv:
writer = csv.writer(test_csv)
writer.writerow(["username", "email", "age"])
writer.writerow(["s_rogers", "cap@avengers.org", "102"]) # Valid Row
writer.writerow(["t_stark", "", "48"]) # Invalid Row: Missing Email
writer.writerow(["p_parker", "spidey@dailybugle.com", "-5"]) # Invalid Row: Bad Age
writer.writerow(["b_banner", "hulk@smash.com", "51"]) # Valid Row
# Run the data pipeline processing execution
validate_and_transform_records(raw_data_path, "cleansed_output.json")
Step 3: Run and Verify Your Outputs
Execute your processing engine script inside your terminal space:
uv run data_processor.py
Now, check the generated outputs. Your cleansed_output.json file will contain only the verified rows:
[
{
"user_id": "s_rogers",
"contact": "cap@avengers.org",
"years_active": 102,
"verified_status": true
},
{
"user_id": "b_banner",
"contact": "hulk@smash.com",
"years_active": 51,
"verified_status": true
}
]
Open system_execution.log to review how the engine tracked errors behind the scenes without crashing:
2026-07-17 23:59:00,124 - [INFO] - Initializing raw transaction CSV import pipeline.
2026-07-17 23:59:00,125 - [INFO] - Successfully processed user record: 's_rogers'.
2026-07-17 23:59:00,125 - [WARNING] - Skipping row registry error: Row 3: Missing critical data fields.
2026-07-17 23:59:00,126 - [WARNING] - Skipping row registry error: Row 4: Age context constraint anomaly (-5).
2026-07-17 23:59:00,126 - [INFO] - Successfully processed user record: 'b_banner'.
2026-07-17 23:59:00,127 - [INFO] - Ingestion successful! Saved 2 records to 'cleansed_output.json'.
Top comments (0)