Faragiri

Learn The standard library Python

A command line parser, a timezone that knows about half hours, grouping without a loop, and the module that stops you writing your own random token.

4Sections
3Min read
4Depth

Six imports, no dependencies

What each module is for, grouped by the job you had

Every branch here is a thing people install a package for, and every leaf on it is already on the machine.

  • Taking argumentsA script that other people run
    • argparse: flags, types and a usage line for free
  • Loops you were about to writeGrouping, pairing, chunking
    • itertools.groupby: sort by the key first, or it groups twice
    • itertools.pairwise: consecutive pairs, since Python 3.10
    • itertools.batched: chunks, and the short last one is handled
  • Getting it on screenWidths, and space on disk
    • textwrap: cuts on a word boundary
    • shutil: free bytes, before writing rather than after failing
already installed
  • Time that is not arithmeticOffsets, and half hour ones
    • zoneinfo: Asia/Tehran, not a number of hours
  • Anything a stranger seesTokens, links, reset URLs
    • secrets: not random, which is predictable from its output

The branches are jobs rather than categories, because the module index is organised the other way and that is exactly why nobody finds these. A branch missing from this figure is anything needing a network, which is where a dependency genuinely starts.

Most small dependencies in a Python project are replacing something already
installed. Six modules cover the majority of it, and each of them is one import
with no version to pin and nothing to break on the day it is unmaintained.

argparse turns a script into a command.
ap.add_argument("--limit", type=int, default=50) and a bad value
exits with invalid int value: 'many' after printing the usage line,
before your code runs at all. action="store_true" gives a
--dry-run flag, and parsing
["shelves", "--dry-run"] answers
Namespace(folder='shelves', dry_run=True, limit=50). Note the
underscore: a dash in the flag becomes an underscore on the attribute.

zoneinfo handles the part of time that is not arithmetic.
ZoneInfo("Asia/Tehran") on a September morning gives
2026-09-02T09:30:00+03:30, and converting to UTC gives
2026-09-02T06:00:00+00:00. The half hour offset is the reason to
use a real timezone database and never an integer of hours, and it has been in
the standard library since Python 3.9.

Three that replace a loop you were about to write

itertools.groupby collapses a grouping loop, with one
condition attached that catches everybody: it groups only runs that are
already adjacent, so the rows must be sorted by the same key first. On sorted
choir rows it yields alto with ['Ladan', 'Simin'] and then bass.
Unsorted input silently produces the same key twice.

itertools.pairwise gives consecutive pairs:
[(1, 4), (4, 9), (9, 16)] from four readings, which is every
difference-between-consecutive-values loop ever written, in one call, since
Python 3.10. itertools.batched chunks a sequence:
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)], and the short last
batch is the case a hand written chunker gets wrong.

One that is a security decision rather than a convenience

secrets is the one to know by name.
secrets.token_urlsafe(16) returns a 22 character string safe to put
in a URL, drawn from the operating system's cryptographic source. The
random module is not that: it is fast, reproducible and predictable
from its output, which is exactly right for shuffling a deck and exactly wrong
for a password reset link. Using random where secrets
belongs is a real vulnerability that no test fails on, and it is the reason the
two modules exist separately.

textwrap and shutil fill the gaps around
those. textwrap.shorten(text, width=24, placeholder=" ...") gives
a very long shelf ..., cutting on a word boundary rather than
mid-word, and shutil.disk_usage("/").free answers in bytes, which
is the check a script that writes files should do before it starts rather than
after it fails.

What to run in 2026

The standard library documentation's module index is the tool, free, and the
habit worth building is to open it before adding a dependency rather than after.
It replaced searching for a package first, which reliably finds one, because
somebody has published a package for everything in this list.

Python 3.14 is what these versions assume, free and open source. Three of the
six modules above gained the specific function named here after 2020, so a
codebase pinned to an old interpreter has fewer of these than this page
suggests, and checking the version note in the docs is a ten second habit that
prevents a confusing import error.

Where this stalls people

The stall is not knowing what to look for, which no amount of reading fixes
directly. Nobody searches for pairwise without knowing the word,
and the loop that computes differences between consecutive readings gets written
by hand a hundred times because it is easy enough to write.

What does work is reading one module's index page whenever you write a loop
that feels generic. A loop that groups, chunks, pairs, counts or flattens is one
of eight functions in itertools and collections, and
fifteen minutes with those two indexes is the highest return reading in this
language. The idioms those functions replace are
syntax, types and the
standard idioms
, and what to do when the answer genuinely is a dependency is
pip, venv, and
keeping projects apart
. Both sit under
readable, everywhere, and the usual
first language
.

Alongside this

Above this