Session 3: Standard library modules
Phase 4 — Intermediate Python · Session 3 of 9
What we’re learning today
Python comes with a huge collection of pre-written code called
the standard library — modules for working with dates,
files, paths, web pages, and dozens of other things. You’ve
already met two (random and turtle). Today we tour several
more useful ones and use them to build a real CLI tool: a
daily journal you run from the terminal.
You’ll need to remember from last time
import yourfile— same syntax for stdlib modules.- The terminal — running scripts with
python script.py. - File I/O from Phase 3 —
open(...), append mode"a". - f-strings for formatting output.
Part A: A tour of useful modules
Open Thonny and start a new file. Save it as tour.py.
datetime — dates and times
The datetime module handles dates, times, and date math.
from datetime import datetime
now = datetime.now()
print(now)
today = now.strftime("%Y-%m-%d")
print(today)
time = now.strftime("%H:%M")
print(time)
Run.
2026-04-25 14:32:18.123456
2026-04-25
14:32
datetime.now() returns the current date and time. .strftime(...)
formats it as a string. The %Y-%m-%d and %H:%M are
format codes — %Y means 4-digit year, %m is 2-digit
month, etc. There are dozens of format codes; look them up
when you need them.
You can also do date math:
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
last_week = now - timedelta(days=7)
print(f"Now: {now.strftime('%Y-%m-%d')}")
print(f"Tomorrow: {tomorrow.strftime('%Y-%m-%d')}")
print(f"Last week: {last_week.strftime('%Y-%m-%d')}")
timedelta(days=1) represents a day. Add or subtract from a
datetime to get a different date. Useful for “calculate the
date 30 days from now” type problems.
pathlib — modern file paths
pathlib is the modern way to handle file paths in Python.
Cleaner than the older os.path style.
from pathlib import Path
home = Path.home()
print(f"Home: {home}")
current = Path.cwd()
print(f"Current: {current}")
# build a path
notes_file = home / "notes.txt"
print(f"Path: {notes_file}")
# check if it exists
print(f"Exists? {notes_file.exists()}")
Walk through:
Path.home()— your home directory.Path.cwd()— the current working directory (where you’re running from).home / "notes.txt"— uses/to combine paths. Way cleaner than string concatenation..exists()— does this file or folder actually exist?
Path also has methods like .is_file(), .is_dir(),
.mkdir(), and many others.
sys — command-line arguments
Remember how the terminal lets you pass extra arguments to
commands? Like cp source destination or mkdir new_folder?
Your Python scripts can take arguments too.
import sys
print(f"Number of arguments: {len(sys.argv)}")
print(f"All arguments: {sys.argv}")
if len(sys.argv) > 1:
print(f"First argument: {sys.argv[1]}")
sys.argv is a list. The first item (sys.argv[0]) is
always the script name. The rest are whatever the user
typed after.
Run from the terminal:
$ python tour.py hello world
Number of arguments: 3
All arguments: ['tour.py', 'hello', 'world']
First argument: hello
This is how real CLI tools work — git commit "message",
python script.py argument, etc. Each space-separated word
becomes an item in argv.
About different machines: the class machines run Linux, where
python tour.py hello worldworks exactly as shown. If you try this from a Windows home laptop andpythonisn’t found, trypy tour.py hello worldinstead. Same behavior —sys.argvworks on every operating system once you can launch the script.
os — operating system stuff
os has lots of functions for interacting with the operating
system:
import os
# environment variables
home = os.environ.get("HOME", "unknown")
print(f"Home from env: {home}")
# list files in a directory
files = os.listdir(".")
print(f"Files here: {files}")
We mostly use pathlib instead of os.path these days, but
os still has useful environment-variable and process stuff.
Checkpoint: You’ve used datetime, pathlib, and sys
in at least one program each. This is the natural stop
point if class is cut short.
Part B: A daily journal CLI
Time to build something real that uses these modules.
What you’re building
A command-line journal. Each day gets its own file. You add entries by running:
$ python journal.py "Today I learned about modules"
Saved to /home/sam/journals/2026-04-25.txt
The script:
- Takes the entry text from
sys.argv. - Uses
datetimeto figure out today’s date. - Uses
pathlibto build the filename. - Appends the entry (with a timestamp) to today’s file.
Real CLI tool — runs from the terminal, takes an argument, does its job, exits.
Build it
# journal.py
import sys
from datetime import datetime
from pathlib import Path
JOURNAL_DIR = Path.home() / "journals"
JOURNAL_DIR.mkdir(exist_ok=True)
if len(sys.argv) < 2:
print("Usage: python journal.py <entry text>")
sys.exit(1)
# get the entry text (everything after the script name)
entry_text = " ".join(sys.argv[1:])
# build today's filename
today = datetime.now().strftime("%Y-%m-%d")
filename = JOURNAL_DIR / f"{today}.txt"
# append the entry with a timestamp
timestamp = datetime.now().strftime("%H:%M")
with open(filename, "a") as f:
f.write(f"[{timestamp}] {entry_text}\n")
print(f"Saved to {filename}")
Save. Then in the terminal:
$ cd Desktop/today
$ python journal.py "First entry of the day"
Saved to /home/sam/journals/2026-04-25.txt
Walk through what’s happening:
JOURNAL_DIR = Path.home() / "journals"— build a path to ajournalsfolder in the home directory..mkdir(exist_ok=True)— make the folder if it doesn’t exist. Theexist_ok=Truemeans “no error if it already exists.”len(sys.argv) < 2— check that the user provided at least one argument. If not, print usage and exit.sys.exit(1)— exit the program with status code 1 (meaning “error”). Any non-zero status code is conventional for “something went wrong.”" ".join(sys.argv[1:])— slice off the script name (the[1:]), then join the rest with spaces. So if the user typedpython journal.py hello world, you get"hello world"as a single string.- The rest is familiar — file path with
pathlib, append with"a"mode.
Try it a few times. Each entry gets appended to today’s file. Tomorrow’s entries will go to a different file automatically.
That’s the base goal.
Stretch — a “view” subcommand
Allow the user to view today’s entries. Detect the special
case of view as the argument:
# journal.py
import sys
from datetime import datetime
from pathlib import Path
JOURNAL_DIR = Path.home() / "journals"
JOURNAL_DIR.mkdir(exist_ok=True)
today = datetime.now().strftime("%Y-%m-%d")
today_file = JOURNAL_DIR / f"{today}.txt"
if len(sys.argv) < 2:
print("Usage: python journal.py <entry text>")
print(" python journal.py view")
sys.exit(1)
if sys.argv[1] == "view":
if today_file.exists():
print(f"\n=== {today} ===")
with open(today_file, "r") as f:
print(f.read())
else:
print(f"No entries yet for {today}.")
else:
# add a new entry
entry_text = " ".join(sys.argv[1:])
timestamp = datetime.now().strftime("%H:%M")
with open(today_file, "a") as f:
f.write(f"[{timestamp}] {entry_text}\n")
print(f"Saved to {today_file}")
Now:
$ python journal.py view
=== 2026-04-25 ===
[14:32] First entry of the day
[14:45] Made the journal a real CLI tool
$ python journal.py "Adding a third entry"
Saved to /home/sam/journals/2026-04-25.txt
Two ways to use the same script — subcommands. Real CLI
tools (Git, Docker, etc.) work this way: git commit, git push, git status — different verbs, same git command.
Extension — view a specific day
if sys.argv[1] == "view":
if len(sys.argv) >= 3:
# view a specific date
date_arg = sys.argv[2]
target_file = JOURNAL_DIR / f"{date_arg}.txt"
else:
# view today
target_file = today_file
if target_file.exists():
with open(target_file, "r") as f:
print(f.read())
else:
print(f"No entries for that date.")
Now python journal.py view 2026-04-20 shows entries from
that date.
Extension — list all journals
if sys.argv[1] == "list":
files = sorted(JOURNAL_DIR.glob("*.txt"))
for f in files:
print(f.stem) # filename without extension
.glob("*.txt") returns all .txt files in the directory.
.stem is the filename without the extension (so
2026-04-25.txt → 2026-04-25).
Add this to your subcommand check. Now you have three commands: add (default), view, list. Real CLI app.
Wrap-up
Before we leave, share with the room:
- For the kids who built the base journal — does it feel weird to run it from the terminal with arguments?
- For the stretch — was the subcommand pattern clean?
- For the extension — anyone build a
deletecommand or acountcommand?
You learned today how to use Python’s standard library to
build real, useful CLI tools. The patterns you saw — sys.argv
for arguments, datetime for now-aware programs, pathlib
for file paths — are exactly how professional Python
scripts are built.
You also learned subcommands — the way real CLI tools
expose multiple actions through one entry point. git, npm,
docker, kubectl — they all work this way. Today’s journal
is a tiny version of the same shape.
If you missed this session
Open Thonny. Then:
- Try the
datetimeexamples from Part A — print today’s date and the time. - Try the
pathlibexamples — print your home directory. - Try
sys.argv— pass a few arguments when you run the script and print them. - Build the journal CLI from Part B base.
Run from the terminal each time. About 30-40 minutes.
If you get stuck, ask your buddy at the start of next class.
Stretch and extension ideas
json— read and write JSON files. Useful for saving structured data.json.dump(data, f)to save;json.load(f)to load.csv— read and write CSV files (spreadsheet format).import csv.shutil— file operations like copy, move, delete whole directories.subprocess— run other programs from your Python script.subprocess.run(["ls", "-la"]).urllib.request— fetch content from URLs (basic web requests).
Browse the standard library docs when you’re curious — there’s a whole world to explore.
What’s next
Next week we add classes to your toolkit — a way to bundle
data and the functions that work on that data into a single
unit. Classes are how Path and datetime are built — and
how almost all “object-oriented” Python is structured.