Technical
Simple Python Scripting for Daily Automation
Most Python tutorials build toy apps. Real daily scripting is different. You need something that runs in ten seconds, reads a file, does one thing, and exits. Here are the patterns I use for the little scripts that save me an hour a day.
The Single-File Script
My automation scripts live in ~/scripts/. Each one is a single .py file. No packages, no setup.py, no virtual environments. Just a shebang line and a function.
#!/usr/bin/env python3
"""Rename all downloads to include their date."""
import os
import sys
from datetime import datetime
def main():
downloads = os.path.expanduser('~/Downloads')
for name in os.listdir(downloads):
full = os.path.join(downloads, name)
if os.path.isfile(full):
date = datetime.fromtimestamp(os.path.getctime(full))
prefix = date.strftime('%Y-%m-%d')
if not name.startswith(prefix):
os.rename(full, os.path.join(downloads, f'{prefix}_{name}'))
if __name__ == '__main__':
main()Save, chmod +x, run. Done.
Use the Standard Library
For scripts, I prefer stdlib over third-party packages. Not because pip is bad, but because scripts that use only stdlib work on any Python install without setup.
jsonfor parsing JSON filesurllib.requestfor simple HTTPcsvfor spreadsheetspathlibfor path manipulationsubprocessfor shelling out
These five modules cover 80% of what I automate.
Keep Arguments Simple
Two options for a single-purpose script:
- Use
sys.argvdirectly for one or two args - Use
argparseif there are more than two
I skip fancy frameworks like Click for throwaway scripts. They add a dependency for features I do not need.
Fail Loudly
Scripts should crash when things go wrong, not silently skip. I do not wrap my scripts in try: except:. If a file is missing, let Python raise. If the API is down, let urllib raise. I read the traceback and fix the issue. Silent failures are how automation lies to you.
Scheduling
macOS: launchd. Linux: cron. Both handle the 'run this every hour' use case without any Python-specific tooling. I write the script to run once and let the OS schedule it.
The Compounding Payoff
Each script saves a few minutes. But I have 30 of them now. That is an hour a day freed up for actual work. The investment was maybe an hour per script, so the break-even was fast.
A Script Index
With 30 scripts, I forget what each one does. I maintain a README.md in ~/scripts/ that lists every script, its purpose, and an example invocation. When I want to clean up my downloads folder, I open the README and find the right script name. Two seconds of lookup beats remembering filenames.
Naming for Discoverability
I use verb-noun names: rename-downloads.py, archive-screenshots.py, sync-notes.py. The verb tells me what it does, the noun tells me what it acts on. Tab completion finds the right script in two keystrokes.
Upgrading Old Scripts
Occasionally a script breaks because an API changed or a file format changed. I fix it when it breaks, not before. Pre-emptively 'modernizing' scripts that still work is a distraction. The goal is never elegant code; it is time saved.
See the Python standard library documentation for the full set of modules available without installing anything.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read