🔄 Quick Recap (Day 26)
You met three popular frameworks (Flask, Django, FastAPI) and built tiny apps in each.
🎯 What You’ll Learn Today
Why automation matters and common use cases.
How to run external commands with
subprocess.run(capture output, timeouts, exit codes).How to schedule scripts on macOS/Linux with cron.
How to schedule scripts on Windows with Task Scheduler (via
schtasks).Practical tips: absolute paths, logs, virtual environments.
📖 Why Automate?
Automation saves time and prevents mistakes. Typical tasks:
Nightly reports or cleanup jobs.
Periodic backups or data pulls.
Checking service health and logging results.
📖 Running Commands with subprocess
subprocess.run lets your Python script call other programs and capture results.
import subprocess
# Basic call (raises no error on non‑zero exit)
res = subprocess.run(["python", "-V"], capture_output=True, text=True)
print(res.returncode) # 0 on success
print(res.stdout.strip())
# Safer: fail fast and set timeout
try:
res = subprocess.run(["python", "-V"], capture_output=True, text=True,
check=True, timeout=10)
print("OK:", res.stdout.strip())
except subprocess.CalledProcessError as e:
print("Command failed:", e)
except subprocess.TimeoutExpired:
print("Command timed out")Tips
Prefer explicit lists (no shell) for portability and safety.
Use
sys.executableto call the exact Python of your virtualenv.Log
returncode,stdout, andstderrto diagnose failures.
📖 Scheduling on macOS/Linux with cron
cron runs commands on a schedule.
Open your crontab:
crontab -eAdd a line in the format
min hour day month weekday command.
Examples
Every day at 09:00:
0 9 * * * /full/path/to/venv/bin/python /full/path/to/daily_report.pyEvery 5 minutes:
*/5 * * * * /full/path/to/venv/bin/python /full/path/to/daily_report.py
Notes
Always use absolute paths to Python and your script.
Environments are minimal in cron; rely on full paths rather than
PATH.Redirect output if needed:
... >> /full/path/logs/cron.log 2>&1.
📖 Scheduling on Windows with Task Scheduler
Use the GUI Task Scheduler or the schtasks command.
Command‑line example (run daily at 09:00):
schtasks /Create /SC DAILY /ST 09:00 /TN "DailyReport" ^
/TR "\"C:\\Path\\to\\python.exe\" \"C:\\Path\\to\\daily_report.py\"" /FTips
Use the full path to your virtualenv Python (e.g.,
C:\path\env\Scripts\python.exe).If you don’t want a console window, you can use
pythonw.exefor GUI‑less scripts.In Task properties, set Start in to your project folder if your script uses relative paths.
🧩 Example Script: daily_report.py
A simple job that logs timestamp + your Python and pip versions. Cross‑platform and virtualenv‑friendly.
# daily_report.py
from __future__ import annotations
import sys, subprocess
from datetime import datetime
from pathlib import Path
LOG_DIR = Path(__file__).with_suffix("").parent / "logs"
LOG_DIR.mkdir(parents=True, exist_ok=True)
LOG_FILE = LOG_DIR / "daily_report.log"
def run_cmd(args: list[str], timeout: int = 10) -> tuple[int, str, str]:
"""Run a command, capture output, return (code, stdout, stderr)."""
try:
r = subprocess.run(args, capture_output=True, text=True, timeout=timeout)
return r.returncode, r.stdout.strip(), r.stderr.strip()
except subprocess.TimeoutExpired:
return 124, "", "timeout"
def main() -> None:
py = sys.executable # current interpreter (works in venvs)
code_v, py_v, py_err = run_cmd([py, "-V"]) # e.g., "Python 3.11.x"
code_p, pip_v, pip_err = run_cmd([py, "-m", "pip", "--version"]) # e.g., "pip 24.x ..."
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
status = "OK" if code_v == 0 and code_p == 0 else "ERROR"
line = f"{ts} | {status} | {py_v or py_err} | {pip_v or pip_err}"
LOG_FILE.write_text((LOG_FILE.read_text() if LOG_FILE.exists() else "") + line + "\n")
print(f"Wrote: {LOG_FILE}")
if __name__ == "__main__":
main()Run once to test:
python daily_report.pySample output (terminal):
Wrote: /full/path/logs/daily_report.logSample log lines (logs/daily_report.log):
2025-08-12 09:00:00 | OK | Python 3.11.9 | pip 24.0 from ...
2025-08-13 09:00:00 | OK | Python 3.11.9 | pip 24.0 from ...🧙♂️ Take the Wand and Try Yourself
Goal: Schedule daily_report.py to run automatically and verify the logs.
Save
daily_report.pyin your project folder and run it once manually.macOS/Linux: add a cron entry to run at 09:00 daily (use your absolute paths).
Windows: create a Task Scheduler job at 09:00 daily using your virtualenv
python.exe.Wait for the next run (or change the schedule to every 5 minutes for testing).
Open
logs/daily_report.logand check a new line was appended.
Expected results:
Terminal shows
Wrote: /.../logs/daily_report.logwhen run manually.The log file contains a fresh timestamped line after the scheduled time.
If a command fails or times out, the line shows
ERRORand the captured stderr.
Up next: Day 28: Mini Project Kickoff — define requirements, architecture, and set up your repo.