Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Python  Module 6 – Modules, packages and the standard library

A tour of the Python standard library

Find the standard module for everyday jobs, read the library reference with its availability and version notes, and spot the modules Python removed.

  • Beginner
  • 20 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free: 20 minutes

What you will learn

  • Find the standard module for an everyday job, such as matching a typo or checking an address
  • Read a module's page for its version, availability and security notes
  • Check whether a standard module works on the platform where your code runs
  • Replace an import of a module that Python 3.12 or 3.13 removed
  • Run standard modules as commands with python -m, keeping http.server on your own computer

Before you start

What you’ll learn · Before you start

What you will learn

  • Find the standard module for an everyday job, such as matching a typo or checking an address
  • Read a module's page for its version, availability and security notes
  • Check whether a standard module works on the platform where your code runs
  • Replace an import of a module that Python 3.12 or 3.13 removed
  • Run standard modules as commands with python -m, keeping http.server on your own computer

Before you start

On this page

Python 3.14.8 lists 297 module names in sys.stdlib_module_names, 194 of them without a leading underscore, and every one of them comes with Python itself. That set is the standard library: The modules that come with Python itself, such as json, pathlib and sqlite3, documented in the library reference. sys.stdlib_module_names lists their names for the Python that runs, whether or not each one works there.: install Python 3.14 and import json, import pathlib or import sqlite3 work straight away, with nothing to download.

Nobody learns all of it, and nobody needs to. What pays off is a rough map of what is there, so that you look for a module before you write the code yourself or install a package, and the habit of reading two kinds of note on a module’s page: in which version something appeared or changed, and on which platforms it works. This lesson gives you the map, runs ten modules in ten lines, shows which modules recent versions removed, and ends with modules that also work as commands.

The library has a module for many everyday jobs

The library reference sorts its modules into about thirty chapters by topic, from Text Processing Services to Unix-specific services, and some of its modules are packages with modules of their own, such as email, xml and concurrent. This table follows the jobs you meet first instead, with the modules to try for each:

Job Start with One thing it does
Work with text string, re, textwrap, difflib, unicodedata re.findall(r"\d+", text) lists every number in a text
Organise data collections, heapq, bisect, enum, dataclasses, itertools collections.Counter(words) counts each word
Calculate math, decimal, fractions, statistics, random statistics.median(marks) finds the middle value
Handle dates and times datetime, zoneinfo, time zoneinfo.ZoneInfo("Asia/Kolkata") is a time zone with its rules
Use files and folders pathlib, shutil, tempfile, glob pathlib.Path("data").glob("*.csv") finds the CSV files of a folder
Read and write formats csv, json, tomllib, sqlite3, zipfile tomllib.load() reads a pyproject.toml
Compress zlib, gzip, bz2, lzma, compression.zstd gzip.open() reads a .gz file as if it were a plain one
Protect secrets and data hashlib, hmac, secrets secrets.token_urlsafe() makes an unguessable token
Talk to the system os, sys, subprocess, logging, argparse subprocess.run() starts another program and waits for it
Use the network urllib.parse, urllib.request, http, email, ipaddress urllib.parse.urlencode() builds a query string
Do several things at once threading, multiprocessing, concurrent.futures, asyncio concurrent.futures runs a function over many inputs in a pool
Test and measure unittest, doctest, pdb, timeit timeit measures how long a small piece of code takes

Here are ten small jobs in ten lines, each done by a different module, and every one of those modules is already on your computer if Python is:

Ten jobs, ten modules Python · tour/one_liners.py
"""Ten everyday jobs, each done by a different module of the standard library."""
import collections
import difflib
import hashlib
import ipaddress
import json
import pathlib
import statistics
import textwrap
import unicodedata
import urllib.parse

sentence = "The standard library ships with every copy of Python."
jobs = [
    ("textwrap", textwrap.shorten(sentence, width=36, placeholder=" ...")),
    ("difflib", difflib.get_close_matches("pirnt", ["print", "input", "point", "sprint"])),
    ("collections", collections.Counter("mississippi").most_common(2)),
    ("statistics", statistics.median([72, 85, 64, 91])),
    ("json", json.dumps({"name": "Asha", "marks": [92, 88]}, sort_keys=True)),
    ("pathlib", pathlib.PurePosixPath("reports/marks.csv").with_suffix(".json").as_posix()),
    ("urllib.parse", urllib.parse.urlencode({"q": "python modules", "page": 2})),
    ("hashlib", hashlib.sha256(b"hello").hexdigest()[:16]),
    ("ipaddress", ipaddress.ip_address("192.168.1.20").is_private),
    ("unicodedata", unicodedata.name("₹")),
]
for module, result in jobs:
    print(f"{module:<13}{result!r}")

Output

textwrap     'The standard library ships with ...'
difflib      ['print', 'point', 'sprint']
collections  [('i', 4), ('s', 4)]
statistics   78.5
json         '{"marks": [92, 88], "name": "Asha"}'
pathlib      'reports/marks.json'
urllib.parse 'q=python+modules&page=2'
hashlib      '2cf24dba5fb0a30e'
ipaddress    True
unicodedata  'INDIAN RUPEE SIGN'

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 one_liners.py

  • textwrap.shorten() collapsed the spaces, cut the sentence at a word boundary and added the marker, so the result fits in 36 characters, a job people often write by hand with slicing that cuts words in half.
  • difflib.get_close_matches() ranked the candidates by their similarity to the typo pirnt, best first, keeping those above its default cutoff of 0.6. It is the “Did you mean…?” of many command-line tools. Press Edit, change "pirnt" to "imput" and run it again: the only suggestion left is input.
  • Counter.most_common(2) found the two most frequent letters. i and s both occur four times, and equal counts keep the order in which the letters first appeared.
  • ipaddress knows the address blocks that are set aside for private networks, so 192.168.1.20 is private. A text test such as address.startswith("192.168.") would get 10.0.0.5 and 172.16.0.1 wrong, and both are private too.
  • hashlib.sha256() gives the same 64 hexadecimal digits for the same bytes on every computer; the example prints the first 16. unicodedata.name() gives the official Unicode name of a character, here the rupee sign.

Checkpoint

Check: A standard module for each everyday job

  1. Question 1 of 2 A program must tell whether 10.0.0.5 belongs to a private network. What should it use?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: ipaddress.ip_address("10.0.0.5").is_private

    The ipaddress module knows the blocks reserved for private networks, so ip_address("192.168.1.20").is_private and ip_address("10.0.0.5").is_private are both True. A test on the text of the address gets 10.0.0.5 and 172.16.0.1 wrong.

  2. Question 2 of 2 Which module shortens a sentence to a width, cutting at a word boundary and adding a marker?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: textwrap, with shorten()

    textwrap.shorten(sentence, width=36, placeholder=" ...") gave 'The standard library ships with ...': spaces collapsed, the cut between two words, and the marker added, all inside 36 characters.

Every module page has the same five parts

Every module has a page in the library reference, and the pages share one layout. Knowing it makes the library quicker to use than any list of modules:

  1. The heading and summary, such as “csv — CSV File Reading and Writing”, and for modules written in Python a Source code link (Lib/csv.py). The source is ordinary Python, and reading it is a good way to settle what a function really does.
  2. The functions and classes, each with its parameters, what it returns and what it raises, and on most pages examples at the end.
  3. Version notes under an entry: “Added in version 3.11”, “Changed in version 3.14”, “Deprecated since version 3.13”. Compare them with the version you run (python --version): code written for 3.14 may use something that a 3.10 installation does not have.
  4. availability note: A line on a page of the library reference, such as Availability: POSIX, not WASI, not Android, not iOS, that says on which platforms a function or a module exists., such as “Availability: POSIX, not WASI, not Android, not iOS.” under os.fork(). They say where a function or a module exists at all.
  5. Warnings and “See also” boxes. Security warnings matter most: the pickle page warns that the module is not secure and that you should only unpickle data you trust, and the http.server page says it is not recommended for production.

The flowchart turns the two kinds of note into two questions to answer before you rely on a module, here for the job of reading a CSV file:

Flowchart: from a job to the library reference and a module page, then two checks, availability and version, before using it.A job to do:read a CSV fileLibrary reference:the chapter for the topic(File Formats: csv),the module indexor the search boxThe module's page:summary, Source code link,functions and examplesAvailability note:does it work wherethe code will run?Added in, Changed in,Deprecated since:does my Pythonhave it?Use itAnother standard module,or a package from PyPIyesnoyesno

Finding a standard module and checking it before you use it

Text description of the diagram

The flowchart reads from top to bottom.

  • It starts with a job to do, for example reading a CSV file.
  • Next, the library reference: the chapter for the topic (here File Formats, which holds csv), the module index or the search box.
  • That leads to the module's page, with its summary, a link to its source code, and its functions and examples.
  • First check, the availability note: does the module work where the code will run? If not, use another standard module or a package from PyPI.
  • Second check, the version notes (Added in, Changed in, Deprecated since): does the Python you run have what the page describes? If not, again choose another module or a package from PyPI.
  • When both answers are yes, use the module.

To reach a page, open the chapter for the topic, the alphabetical module index (the “modules” link at the top of every page of the documentation) or the search box. Without a network, help("csv") at the interactive prompt shows the module’s own documentation strings.

Checkpoint

Check: Reading a module's page

  1. Question 1 of 2 A function's entry says "Added in version 3.11", and your server runs Python 3.10. What happens when your code uses it there?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It fails, because Python 3.10 does not have the function yet

    Version notes ("Added in", "Changed in", "Deprecated since") tie each entry to a version. Compare them with the Python that will run the code, here 3.10, before relying on anything a page describes.

  2. Question 2 of 2 What does the page of the pickle module warn about?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: That the module is not secure, so only unpickle data you trust

    Warnings and "See also" boxes are the fifth part of a module page, and security warnings matter most. The pickle page warns that the module is not secure: only unpickle data you trust.

A listed module may still be missing where your code runs

The library’s introduction explains the availability notes. “Availability: Unix” marks a function that Unix systems usually have, and unless the note says otherwise it covers macOS, iOS and Android as well, which are all Unix-like underneath. Each “not” takes a platform away again. Two groups of platforms lose the most:

  • A portable format for compiled programs that runs inside a browser or a runtime such as wasmtime. CPython can be compiled to it, with only part of the operating system's interface., where Python runs inside a browser or a runtime such as wasmtime. The Emscripten and WASI builds have only a subset of the operating system’s interface, so modules that start processes, use threads, open network connections or send signals are missing or behave differently, and subprocess can be imported but does not work.
  • Android and iOS apps, which embed Python. They have no terminal, so curses and readline are not available, and an iOS app cannot start a subprocess at all.

The runner on these pages belongs to the first group. It uses Pyodide, which is CPython compiled for Emscripten, and Pyodide also leaves out modules that could not work there or would only make its download bigger, such as tkinter, curses and venv. This program asks the Python that runs it what works:

What works where? Python · available/available.py
"""Which standard modules can this Python import?
And do the ones that need the operating system work?"""
import importlib
import subprocess
import sys
import threading

MODULES = [
    "sqlite3", "zoneinfo", "compression.zstd", "tkinter", "curses", "venv",
    "concurrent.interpreters",
]

names = sys.stdlib_module_names
public = [name for name in names if not name.startswith("_")]
print(len(names), "names in sys.stdlib_module_names,", len(public), "without a leading underscore")
for name in MODULES:
    try:
        importlib.import_module(name)
        print(f"import {name}: works")
    except ImportError as error:
        print(f"import {name}: {type(error).__name__}")


def attempt(action):
    """'works', or the kind of error the action raised."""
    try:
        action()
        return "works"
    except (OSError, RuntimeError) as error:
        return f"fails with {type(error).__name__}"


def run_program():
    subprocess.run([sys.executable, "-c", "pass"], check=True)


def start_thread():
    worker = threading.Thread(target=lambda: None)
    worker.start()
    worker.join()


print("subprocess.run():", attempt(run_program))
print("Thread.start():", attempt(start_thread))

Output

297 names in sys.stdlib_module_names, 194 without a leading underscore
import sqlite3: works
import zoneinfo: works
import compression.zstd: works
import tkinter: works
import curses: works
import venv: works
import concurrent.interpreters: works
subprocess.run(): works
Thread.start(): works

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 available.py

Version note

The recorded output comes from CPython 3.14.8 on macOS, where every import and both calls work. Press Run in the browser and four imports fail with ModuleNotFoundError, subprocess.run() fails with OSError because a browser cannot start programs, and Thread.start() fails with RuntimeError because the runner has no threads. The first line stays the same.

In your browser, Pyodide 314.0.7 (CPython 3.14.2) prints:

297 names in sys.stdlib_module_names, 194 without a leading underscore
import sqlite3: works
import zoneinfo: works
import compression.zstd: works
import tkinter: ModuleNotFoundError
import curses: ModuleNotFoundError
import venv: ModuleNotFoundError
import concurrent.interpreters: ModuleNotFoundError
subprocess.run(): fails with OSError
Thread.start(): fails with RuntimeError

The same program, run in two places, gives two answers. Side by side:

What the program tried CPython 3.14.8 on macOS The browser runner (Pyodide)
Count sys.stdlib_module_names 297, 194 without a leading underscore the same
import sqlite3, zoneinfo, compression.zstd works works
import tkinter, curses, venv works ModuleNotFoundError
import concurrent.interpreters works ModuleNotFoundError
subprocess.run() works fails with OSError
Thread.start() works fails with RuntimeError

Two details of that output are worth keeping. sys.stdlib_module_names names every standard module of that version of Python, whether or not it can be imported where you are, so 297 is printed in the browser too; the only test of whether a module works is to import it. And the standard library you have is not always complete even on a laptop: on Unix-like systems Python often comes as a set of packages of the operating system, and an optional part such as tkinter may need one more package from the system’s package manager before import tkinter works.

Key idea

A name in sys.stdlib_module_names belongs to that version of Python; whether the module works is settled only by importing and using it where the code runs.

Checkpoint

Check: Where a module works

  1. Question 1 of 2 In the browser runner, import subprocess works but subprocess.run() fails with OSError. Why?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The runner is WebAssembly in a browser, which can import the module but cannot start other programs

    The runner on these pages is Pyodide, CPython compiled for Emscripten, and WebAssembly builds have only part of the operating system's interface. subprocess can be imported there, but starting a program fails with OSError, and starting a thread fails with RuntimeError.

  2. Question 2 of 2 "tkinter" in sys.stdlib_module_names is True on a Linux server, yet import tkinter fails there. What is the likely reason?

    Choose one answer.

    A hint

    Where did that server's Python come from?

    Show the answer: Question 2 of 2

    Answer: Python came as packages of the operating system, and the part with tkinter is not installed

    sys.stdlib_module_names says what belongs to that version of Python, not what is installed. When Python comes as several packages of the operating system, an optional part such as tkinter may be missing until its package is installed. The only test is to import the module where the code runs.

Python removes old modules after warning for two releases

Python also takes modules away. Its compatibility policy, PEP 387, asks for a deprecation: Notice that a feature will be removed in a later version, given in the documentation and usually by a DeprecationWarning. Python's compatibility policy, PEP 387, asks for such a warning in at least two releases before a removal. warning in at least two feature releases, such as 3.11 and 3.12, before something is removed. Walk through the releases that changed the list of modules this lesson uses:

Timeline · 4 events in order How the list of standard modules changed Walk through four releases in order. Each one either added modules or removed some, and code written for an older version meets the removals first.
  1. 3.11

    tomllib joins the library added

    tomllib reads TOML files such as pyproject.toml. It cannot write them, and code that must also run on older versions installs the tomli package from PyPI instead.

  2. 3.12

    distutils and four other modules are removed removed

    distutils, the old packaging library, goes (PEP 632), and with it imp, asynchat, asyncore and smtpd. Code that imports them stops with ModuleNotFoundError; importlib replaces imp, and asyncio replaces asyncore.

  3. 3.13

    19 old modules are removed at once removed

    PEP 594 takes out the "dead batteries", among them cgi, cgitb, crypt, pipes, telnetlib, nntplib, imghdr and audioop. lib2to3, the 2to3 tool and tkinter.tix go in the same release.

  4. 3.14

    Four new modules added

    annotationlib, compression with its compression.zstd, concurrent.interpreters and string.templatelib arrive. The next section runs three of them.

The timeline has 4 events, from 3.11 to 3.14.

Python 3.12 removed distutils, the old packaging library (PEP 632), together with imp, asynchat, asyncore and smtpd. Python 3.13 removed 19 modules at once, the “dead batteries” of PEP 594, among them cgi, cgitb, crypt, pipes, telnetlib, nntplib, imghdr and audioop, and also lib2to3, the 2to3 tool and tkinter.tix. Code from an old tutorial that imports one of them now stops at once with ModuleNotFoundError. This program tries eight of those imports and prints what to use instead:

Imports that old tutorials still use Python · removed/removed.py
"""Modules that older tutorials import, and what to use instead on Python 3.14."""
import importlib

INSTEAD = {
    "distutils": ("3.12", "setuptools, or sysconfig, shutil.which() and subprocess.run()"),
    "imp": ("3.12", "importlib"),
    "asyncore": ("3.12", "asyncio"),
    "cgi": ("3.13", "urllib.parse for query strings, email.message for headers"),
    "crypt": ("3.13", "hashlib, or a password-hashing package such as argon2-cffi"),
    "pipes": ("3.13", "subprocess, and shlex.quote()"),
    "mailcap": ("3.13", "mimetypes"),
    "telnetlib": ("3.13", "telnetlib3 or Exscript from PyPI"),
}

for name, (version, advice) in INSTEAD.items():
    try:
        importlib.import_module(name)
        print(f"{name}: still in the standard library")
    except ModuleNotFoundError:
        print(f"{name}: removed in {version}; use {advice}")

Output

distutils: removed in 3.12; use setuptools, or sysconfig, shutil.which() and subprocess.run()
imp: removed in 3.12; use importlib
asyncore: removed in 3.12; use asyncio
cgi: removed in 3.13; use urllib.parse for query strings, email.message for headers
crypt: removed in 3.13; use hashlib, or a password-hashing package such as argon2-cffi
pipes: removed in 3.13; use subprocess, and shlex.quote()
mailcap: removed in 3.13; use mimetypes
telnetlib: removed in 3.13; use telnetlib3 or Exscript from PyPI

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 removed.py

The library reference keeps a chapter called Removed Modules, with a page for each module and its replacement. For most of the modules removed in 3.13 the release notes also name a copy published on PyPI, such as standard-telnetlib. Such a copy keeps old code running, but new code should use the replacement.

Checkpoint

Check: Modules that were removed

  1. Question 1 of 2 Old code starts with import telnetlib. On which versions of Python does that line still work?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Python 3.12 and older

    Python 3.13 removed telnetlib with the other "dead batteries" of PEP 594, so the import works on 3.12 and older and fails with ModuleNotFoundError from 3.13 on.

  2. Question 2 of 2 What does Python's compatibility policy, PEP 387, ask for before something is removed?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: A deprecation warning in at least two releases

    PEP 387 asks for a deprecation warning in at least two releases before a removal. Running code with deprecation warnings shown on a version before the removal is how you find what a later upgrade will break.

Python 3.14 added four modules

Version 3.14 adds four modules:

  • annotationlib reads annotations (PEP 749). Since 3.14, Python evaluates annotations only when something asks for them, so a type hint may name a class that is defined further down the file.
  • compression is a package that gathers the compression modules, and its new compression.zstd handles the Zstandard format (PEP 784).
  • concurrent.interpreters runs Python code in several interpreters inside one process (PEP 734). The browser runner does not have it, as the program above showed.
  • string.templatelib holds the types behind template strings, the new A string literal with t before its opening quote, new in Python 3.14. It makes a Template that keeps the fixed text and the values apart, instead of a str. literals (PEP 750).
Three new modules at work Python · new/new_in_314.py
"""Three of the modules that are new in Python 3.14, at work."""
import annotationlib
import bz2
import lzma
import zlib
from compression import zstd
from string.templatelib import Template

# compression.zstd: Zstandard, next to the older zlib, bz2 and lzma.
# The data: 500 copies of one line of a CSV file.
data = b"92,Asha\n" * 500
for module in (zstd, zlib, bz2, lzma):
    packed = module.compress(data)
    assert module.decompress(packed) == data
    print(f"{module.__name__:<17}{len(data)} bytes -> {len(packed)} bytes")

# string.templatelib: a t-string keeps its fixed text and its values apart.
name = "Asha"
greeting = t"Hello, {name}!"
print("t-string:", type(greeting) is Template, greeting.strings, greeting.values)


# annotationlib: annotations are evaluated only when something asks for them,
# so a class that is defined further down is no error.
def best_mark(student: Student) -> int:
    return max(student.marks)


hints = annotationlib.get_annotations(best_mark, format=annotationlib.Format.STRING)
print("annotations:", hints)


class Student:
    marks = [92, 88, 95]


print("now evaluated:", annotationlib.get_annotations(best_mark)["student"] is Student)
print("best mark:", best_mark(Student()))

Output

compression.zstd 4000 bytes -> 25 bytes
zlib             4000 bytes -> 43 bytes
bz2              4000 bytes -> 66 bytes
lzma             4000 bytes -> 100 bytes
t-string: True ('Hello, ', '!') ('Asha',)
annotations: {'student': 'Student', 'return': 'int'}
now evaluated: True
best mark: 95

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 new_in_314.py

  • On 4,000 bytes of very repetitive text, Zstandard produced 25 bytes, against 43 for zlib, 66 for bz2 and 100 for lzma. Real files compress far less. PEP 784 argues for Zstandard on balance: its output is clearly smaller than that of zlib or bzip2, and it unpacks much faster than LZMA.
  • The t-string did not become a str. A Template keeps its fixed text (strings) apart from its values (values), so that a library can escape the values for HTML or SQL before it joins them, which an f-string never allows.
  • get_annotations() read the hint Student as text while no class of that name existed, and as the class itself once it did.

Checkpoint

Check: The new modules of Python 3.14

  1. One question Why can a library escape the values of a t-string for HTML, which it cannot do with an f-string?

    Choose one answer.

    Show the answer: One question

    Answer: A t-string keeps its fixed text and its values apart, while an f-string joins them into one str at once

    t"Hello, {name}!" gives a string.templatelib.Template with strings ('Hello, ', '!') and values ('Asha',). An f-string would already be the finished text, Hello, Asha!, so no library could tell which part was a value.

Many standard modules also run as commands

python -m module runs a module as a program, and the library reference lists 50 modules that have a command-line interface. This program runs three of them, json on two small files, and shows what each command printed:

Standard modules as commands

Python · cli/cli.py

"""Standard modules as command-line tools: each command, then what it printed."""
import subprocess
import sys


def run(*args):
    print("$ python", *args)
    result = subprocess.run([sys.executable, *args], capture_output=True, text=True)
    print(result.stdout, end="")
    if result.returncode:
        print(result.stderr.strip().splitlines()[-1], f"(exit status {result.returncode})")


run("-m", "json", "student.json")
run("-m", "json", "--sort-keys", "--compact", "student.json")
run("-m", "json", "broken.json")
run("-m", "uuid", "-u", "uuid5", "-n", "@url", "-N", "https://example.com/")
run("-m", "mimetypes", "marks.csv", "report.pdf")

Output

$ python -m json student.json
{
    "name": "Asha",
    "marks": [
        92,
        88,
        95
    ],
    "city": "Pune"
}
$ python -m json --sort-keys --compact student.json
{"city":"Pune","marks":[92,88,95],"name":"Asha"}
$ python -m json broken.json
Expecting ',' delimiter: line 1 column 17 (char 16) (exit status 1)
$ python -m uuid -u uuid5 -n @url -N https://example.com/
dd2c1780-811a-5296-81c5-178a0ef488bc
$ python -m mimetypes marks.csv report.pdf
type: text/csv encoding: None
type: application/pdf encoding: None

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 cli.py

cli/student.json

{"name": "Asha", "marks": [92, 88, 95], "city": "Pune"}

cli/broken.json

{"name": "Ravi" "marks": [71, 64, 80]}
  • python -m json checks a JSON file and prints it indented. The short name is new in 3.14; older versions spell it python -m json.tool, which still works. --sort-keys sorts the keys and --compact drops the spaces.
  • On broken.json it named the line and column where a comma is missing and ended with exit status 1, so a shell script or a CI step can use it as a check.
  • python -m uuid, a command since 3.12, makes a UUID. Version 5 is computed from a namespace and a name, so it prints the same value on every computer, while the default, version 4, is random. Python 3.14 added versions 6, 7 and 8, and -C to make several at once.
  • python -m mimetypes, a public command since 3.14, guesses a file’s type from its name.

Others worth knowing are python -m venv .venv for a virtual environment, python -m zipfile -l archive.zip to list an archive, python -m timeit to time a snippet, python -m sqlite3 marks.db for an SQLite shell, and python -m unittest and python -m pdb for tests and the debugger.

Keep python -m http.server on your own computer

python -m http.server serves the files of the current folder on port 8000, which is handy for looking at a page you are building. By default it listens on every network interface, so anyone who can reach your computer, on the same Wi-Fi for example, can read every file in that folder. Add --bind 127.0.0.1 to keep it to your own computer, and never use it for a real site: its documentation says that it only implements basic security checks.

Checkpoint

Check: Standard modules as commands

  1. Question 1 of 2 python -m json broken.json named the line and column of the error and ended with exit status 1. Why does the status matter?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: A shell script or a CI step can use the command as a check, because a status other than 0 means it failed

    A command that ends with a non-zero exit status has failed, and shells and CI systems act on that. So python -m json file.json works both as a pretty-printer and as a check that stops a script when the JSON is broken.

  2. Question 2 of 2 Which command serves the current folder to your own computer only?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: python -m http.server --bind 127.0.0.1

    python -m http.server listens on every network interface by default, so anyone who can reach your computer can read the files of the folder. --bind 127.0.0.1 keeps it to your own computer, and it is never a server for a real site.

JSON Formatter Paste JSON to check and indent it in the browser, as python -m json does in a terminal.

Practise: a scavenger hunt

Each function of the exercise names the module that does its job. The work is finding the right function on that module’s page, and the sample tests also read your file to check that every function really uses its module.

Exercise · Easy · Python

A scavenger hunt through the standard library

hunt.py has ten small functions, and each docstring names the standard module that does the job. Write each body with that module: find the function you need on the module's page of the library reference, then call it. Every module is already imported at the top of the file.

  • shorten_title(title, width): the title cut at a word boundary to at most width characters, ending in ... when something was cut, with runs of spaces collapsed (textwrap).
  • median_mark(marks): the middle mark, or the mean of the two middle marks for an even count (statistics).
  • new_ticket_id(): a new random identifier as a string of 36 characters, such as "3f1c9a2e-8d4b-4e6f-9a0b-1c2d3e4f5a6b" (uuid, version 4).
  • did_you_mean(word, commands): the one command closest to a mistyped word, or None when none is close (difflib).
  • top_words(text, n): the n most common words of the text, ignoring case, as (word, count) pairs, most common first (collections).
  • extension(path): the file extension of a path in lower case, with its dot, such as ".pdf", or "" when there is none (pathlib).
  • query_value(url, key): the first value of a query parameter of a URL, decoded, or None when the URL does not have that parameter (urllib.parse).
  • fingerprint(text): the SHA-256 hash of the text's UTF-8 bytes as 64 hexadecimal digits (hashlib).
  • is_private(address): True for an address of a private network, such as 192.168.1.20 (ipaddress).
  • pretty(data): the data as JSON text, indented by 2 spaces, with the keys sorted (json).

The sample tests import your file as hunt and also read it, to check that each function really uses its module.

Starter code · hunt.py

"""Ten small jobs, each done with one module of the standard library."""
import collections
import difflib
import hashlib
import ipaddress
import json
import pathlib
import statistics
import textwrap
import urllib.parse
import uuid


def shorten_title(title, width):
    """The title cut to at most `width` characters at a word boundary, ending in "..." when cut (textwrap)."""
    return title


def median_mark(marks):
    """The middle mark, or the mean of the two middle marks (statistics)."""
    return marks[0]


def new_ticket_id():
    """A new random identifier, as a string of 36 characters (uuid, version 4)."""
    return ""


def did_you_mean(word, commands):
    """The command closest to a mistyped word, or None when nothing is close (difflib)."""
    return None


def top_words(text, n):
    """The n most common words, ignoring case, as (word, count) pairs, most common first (collections)."""
    return []


def extension(path):
    """The extension of a path in lower case, with its dot (".pdf"), or "" when there is none (pathlib)."""
    return ""


def query_value(url, key):
    """The first value of a query parameter of a URL, decoded, or None when it is missing (urllib.parse)."""
    return None


def fingerprint(text):
    """The SHA-256 hash of the text's UTF-8 bytes, as 64 hexadecimal digits (hashlib)."""
    return ""


def is_private(address):
    """True for an address of a private network, such as 192.168.1.20 (ipaddress)."""
    return False


def pretty(data):
    """The data as JSON text, indented by 2 spaces, keys sorted (json)."""
    return str(data)
The sample tests · test_hunt.py
import ast
import pathlib
import uuid

import hunt

# Each function of hunt.py and the module it must use.
MODULES = {
    "shorten_title": "textwrap",
    "median_mark": "statistics",
    "new_ticket_id": "uuid",
    "did_you_mean": "difflib",
    "top_words": "collections",
    "extension": "pathlib",
    "query_value": "urllib.parse",
    "fingerprint": "hashlib",
    "is_private": "ipaddress",
    "pretty": "json",
}


def imported_names(tree):
    """Each name that an import in the file binds, and the dotted name it stands for."""
    names = {}
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                if alias.asname:
                    names[alias.asname] = alias.name
                else:
                    top = alias.name.split(".")[0]
                    names[top] = top
        elif isinstance(node, ast.ImportFrom) and node.module and not node.level:
            for alias in node.names:
                names[alias.asname or alias.name] = node.module + "." + alias.name
    return names


def dotted(node):
    """"urllib.parse.urlsplit" for the expression urllib.parse.urlsplit; None for anything else."""
    parts = []
    while isinstance(node, ast.Attribute):
        parts.append(node.attr)
        node = node.value
    if not isinstance(node, ast.Name):
        return None
    parts.append(node.id)
    return ".".join(reversed(parts))


def uses_module(function, module):
    """Whether the function's body refers to the module, or to a name imported from it."""
    tree = ast.parse(pathlib.Path("hunt.py").read_text(encoding="utf-8"))
    names = imported_names(tree)
    for node in tree.body:
        if isinstance(node, ast.FunctionDef) and node.name == function:
            for inner in ast.walk(node):
                text = dotted(inner) if isinstance(inner, (ast.Name, ast.Attribute)) else None
                if not text:
                    continue
                first, _, rest = text.partition(".")
                if first in names:
                    full = names[first] + ("." + rest if rest else "")
                    if full == module or full.startswith(module + "."):
                        return True
    return False


def test_shorten_title():
    """shorten_title cuts at a word boundary and ends in ..."""
    assert hunt.shorten_title("A tour of the Python standard library", 20) == "A tour of the..."
    assert hunt.shorten_title("  Python   modules  ", 20) == "Python modules"


def test_median_mark():
    """median_mark gives the middle value"""
    assert hunt.median_mark([72, 85, 64, 91]) == 78.5
    assert hunt.median_mark([3, 1, 2]) == 2


def test_new_ticket_id():
    """new_ticket_id gives a different version 4 UUID each time"""
    first, second = hunt.new_ticket_id(), hunt.new_ticket_id()
    assert isinstance(first, str) and len(first) == 36
    assert uuid.UUID(first).version == 4
    assert first != second


def test_did_you_mean():
    """did_you_mean finds the closest command, or None"""
    assert hunt.did_you_mean("pirnt", ["print", "input", "exit"]) == "print"
    assert hunt.did_you_mean("xyz", ["print", "input"]) is None


def test_top_words():
    """top_words counts words without regard to case"""
    assert hunt.top_words("the cat and the hat and THE bat", 2) == [("the", 3), ("and", 2)]


def test_extension():
    """extension gives the last suffix in lower case"""
    assert hunt.extension("reports/Term-2/Marks.CSV") == ".csv"
    assert hunt.extension("archive.tar.gz") == ".gz"
    assert hunt.extension("README") == ""


def test_query_value():
    """query_value decodes a parameter, or gives None"""
    url = "https://example.com/search?q=python+modules&page=2"
    assert hunt.query_value(url, "q") == "python modules"
    assert hunt.query_value(url, "page") == "2"
    assert hunt.query_value(url, "lang") is None


def test_fingerprint():
    """fingerprint is the SHA-256 of the UTF-8 bytes"""
    assert hunt.fingerprint("hello") == "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
    assert hunt.fingerprint("₹") == "d8c3e87cd7f5b7d388f9dc1e35ccee09640ef3dca63d449d9ef59fc323a87a20"


def test_is_private():
    """is_private knows private networks from public ones"""
    assert hunt.is_private("192.168.1.20") is True
    assert hunt.is_private("10.0.0.5") is True
    assert hunt.is_private("8.8.8.8") is False


def test_pretty():
    """pretty indents by 2 spaces and sorts the keys"""
    assert hunt.pretty({"name": "Asha", "marks": [92, 88]}) == '{\n  "marks": [\n    92,\n    88\n  ],\n  "name": "Asha"\n}'


def test_each_function_uses_its_module():
    """every function uses the module its docstring names"""
    missing = [f"{function} ({module})" for function, module in MODULES.items() if not uses_module(function, module)]
    assert missing == []
A hint

Open the library reference page of each module and read its list of functions before you write any code: every job here is one call, sometimes followed by picking an item from the result. For example, difflib.get_close_matches() returns a list, which is empty when nothing is close, and urllib.parse.parse_qs() needs only the query part of the URL, which urllib.parse.urlsplit() gives you.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Sixteen short questions on the six parts of the tour come next, one at a time. The session leads with the part you have answered least well so far, and the reason behind each choice appears once you check it:

Practice that adapts to you

Practise this lesson

16 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 16 A command-line tool should answer a typo such as pirnt with "Did you mean print?". Which standard module finds the closest entry of a list of commands?

    Choose one answer.

    Show the answer: Question 1 of 16

    Answer: difflib, with get_close_matches()

    difflib compares sequences, and get_close_matches(word, candidates) returns the candidates that are similar enough, best first, or an empty list when nothing is close. The lesson's example picked print, then point and sprint, for the typo pirnt.

  2. Question 2 of 16 Which standard module reads a pyproject.toml file?

    Choose one answer.

    Show the answer: Question 2 of 16

    Answer: tomllib

    The table of jobs lists tomllib under reading and writing formats: tomllib.load() reads a pyproject.toml into dictionaries. It joined the library in Python 3.11.

  3. Question 3 of 16 A password-reset link needs a token that nobody can guess. Which module makes one?

    Choose one answer.

    Show the answer: Question 3 of 16

    Answer: secrets, with token_urlsafe()

    secrets is the module of the table for protecting secrets and data: secrets.token_urlsafe() returns a random token in URL-safe characters, made to be unguessable.

  4. Question 4 of 16 The page of os.fork() says "Availability: POSIX, not WASI, not Android, not iOS." What does that tell you?

    Choose one answer.

    Show the answer: Question 4 of 16

    Answer: It exists on POSIX systems such as Linux and macOS, but not on Windows, under WASI, or in Android and iOS apps

    An availability note says where a function or module exists. POSIX covers Unix-like systems, so Windows is not included, and each "not" removes a platform that would otherwise count: WASI, Android and iOS cannot start new processes this way.

  5. Question 5 of 16 The page of a module written in Python has a link next to its summary. Where does it lead?
    Show the answer: Question 5 of 16

    Answer: To the module's source code, such as Lib/csv.py, which is ordinary Python you can read

    Each module page starts with its heading and summary, and for modules written in Python a Source code link to the file, such as Lib/csv.py. Reading it settles what a function really does.

  6. Question 6 of 16 Unless the note says otherwise, which systems does "Availability: Unix" include?

    Choose one answer.

    Show the answer: Question 6 of 16

    Answer: Unix systems such as Linux, and also macOS, iOS and Android, which are all Unix-like underneath

    The library's introduction explains the notes: "Availability: Unix" marks a function that Unix systems usually have, and unless the note says otherwise it covers macOS, iOS and Android as well. A "not" removes a platform.

  7. Question 7 of 16 How can you be sure that a standard module works where your code will run?

    Choose one answer.

    Show the answer: Question 7 of 16

    Answer: Import it, and use what it must do, on that platform

    sys.stdlib_module_names printed 297 names both on macOS and in the browser, yet four imports failed in the browser. Availability notes tell you what to expect, and importing the module where the code runs settles it.

  8. Question 8 of 16 An old tutorial imports these modules. Which imports fail with ModuleNotFoundError on Python 3.14?

    Choose every answer that is right.

    Show the answer: Question 8 of 16

    Answer:

    • cgi
    • distutils
    • telnetlib

    distutils was removed in Python 3.12 (PEP 632), and telnetlib and cgi in 3.13 with the other old modules of PEP 594. tomllib (added in 3.11) and zoneinfo (added in 3.9) are recent additions and are still there. The library reference's Removed Modules chapter lists every removed module with its replacement.

  9. Question 9 of 16 What replaces the removed imp module?

    Choose one answer.

    Show the answer: Question 9 of 16

    Answer: importlib

    Python 3.12 removed imp together with distutils, asynchat, asyncore and smtpd. The replacement for imp is importlib, as the program of the removed modules printed.

  10. Question 10 of 16 Legacy code that imports telnetlib has to run on Python 3.14 this week. Which change keeps it running with the least rewriting?

    Choose one answer.

    Show the answer: Question 10 of 16

    Answer: Install the copy published on PyPI, standard-telnetlib, and plan the move to a maintained replacement

    For most of the modules removed in 3.13 the release notes name a copy on PyPI, such as standard-telnetlib. Installing it keeps old code running now; new code should use the replacement the Removed Modules chapter names.

  11. Question 11 of 16 What does this print on Python 3.14?

    Read the code, then choose one answer.

    name = "Asha"
    greeting = t"Hello, {name}!"
    print(greeting.strings, greeting.values)
    Show the answer: Question 11 of 16

    Answer: ('Hello, ', '!') ('Asha',)

    A t-string is new in Python 3.14 and makes a string.templatelib.Template instead of a str. The template keeps the fixed pieces of text in strings and the values in values, so code such as an HTML or SQL library can treat the values before it joins them. An f-string would have printed Hello, Asha!.

  12. Question 12 of 16 Which of these modules is new in Python 3.14?

    Choose one answer.

    Show the answer: Question 12 of 16

    Answer: annotationlib

    Python 3.14 added annotationlib, compression with compression.zstd, concurrent.interpreters and string.templatelib. tomllib (3.11) and zoneinfo (3.9) came earlier.

  13. Question 13 of 16 In the example, Zstandard turned 4,000 bytes into 25 and zlib into 43. What should you expect on your own files?

    Choose one answer.

    Show the answer: Question 13 of 16

    Answer: Far less compression, because the 4,000 bytes were 500 copies of one short line

    The program compressed 500 copies of "92,Asha" plus a line break, which is as repetitive as data gets. Real files compress far less. PEP 784 argues for Zstandard on balance: clearly smaller output than zlib or bzip2, and much faster unpacking than LZMA.

  14. Question 14 of 16 You run python -m http.server in a folder to look at a page you built. Which computers can fetch your files?

    Choose one answer.

    Show the answer: Question 14 of 16

    Answer: Any computer that can reach yours on port 8000, because it listens on every network interface unless you add --bind 127.0.0.1

    By default the server binds to all interfaces, so on a shared network others can read every file in the folder. Add --bind 127.0.0.1 when only you need it, and never use http.server for a real website: its documentation says it only implements basic security checks.

  15. Question 15 of 16 What does python -m json student.json do with a valid JSON file?

    Choose one answer.

    Show the answer: Question 15 of 16

    Answer: It checks the file and prints its contents indented

    python -m json, the short name new in Python 3.14 for python -m json.tool, checks a JSON file and prints it indented. --sort-keys sorts the keys and --compact drops the spaces.

  16. Question 16 of 16 python -m uuid -u uuid5 -n @url -N https://example.com/ printed dd2c1780-811a-5296-81c5-178a0ef488bc. What will it print on another computer?

    Choose one answer.

    Show the answer: Question 16 of 16

    Answer: The same value, because a version 5 UUID is computed from the namespace and the name

    A version 5 UUID is a hash of a namespace and a name, so it is the same on every computer, which makes it useful for stable identifiers. The default, version 4, is random every time.

Interview questions

Fresher · What is the standard library, and how do you tell whether a module belongs to it?

The standard library is the set of modules that is distributed with Python itself and documented in the library reference, such as json, pathlib, sqlite3 and asyncio, so it is there wherever that Python is installed, with nothing to install from PyPI. To check a name, look it up in the library reference’s module index, or ask the interpreter: "tomllib" in sys.stdlib_module_names is True on Python 3.11 and newer. A good answer adds two cautions. Being listed does not mean that a module works everywhere: availability notes, WebAssembly builds and mobile apps leave parts out, and some Linux systems package parts such as tkinter separately. And the list changes between versions: 3.12 and 3.13 removed old modules such as distutils and telnetlib, while 3.14 added compression.zstd.

Key takeaways

  • The standard library ships with Python: 297 top-level module names in Python 3.14.8, sorted by topic in the library reference, and worth searching before you write code or install a package.
  • Modules such as difflib, ipaddress, textwrap and unicodedata do jobs that people often write by hand.
  • On a module’s page, read the version notes, the availability notes and the warnings before you rely on it.
  • Being listed in sys.stdlib_module_names does not mean a module works where you run it: WebAssembly, Android and iOS lack parts of the library, and the browser runner here has no working subprocess and no threads.
  • Python 3.12 removed distutils, imp and asyncore, 3.13 removed 19 old modules such as cgi, crypt and telnetlib, and 3.14 added annotationlib, compression.zstd, concurrent.interpreters and string.templatelib.
  • Many modules are also commands, such as python -m json, python -m uuid and python -m venv, and python -m http.server belongs on your own computer, with --bind 127.0.0.1.

Terms in this lesson

availability note
A line on a page of the library reference, such as Availability: POSIX, not WASI, not Android, not iOS, that says on which platforms a function or a module exists.
deprecation
Notice that a feature will be removed in a later version, given in the documentation and usually by a DeprecationWarning. Python's compatibility policy, PEP 387, asks for such a warning in at least two releases before a removal.
standard library
The modules that come with Python itself, such as json, pathlib and sqlite3, documented in the library reference. sys.stdlib_module_names lists their names for the Python that runs, whether or not each one works there.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.