Week 4 - Modules, Packaging, Virtual Environments, and the Import System¶
4.1 Conceptual Core¶
- A module is a
.pyfile (or.so/.pydextension) that becomes a singleton object on first import, cached insys.modules. Re-importing returns the cached object;importlib.reloadre-executes (with caveats - old references to old objects persist). - A package is a directory with an
__init__.py(or a namespace package, PEP 420, with no__init__.py). - Virtual environments are not optional. A modern Python project lives in a per-project
.venv/, managed byuv,hatch,poetry, orpip-tools. System Python is for the OS, not your code.
4.2 Mechanical Detail¶
- Import resolution order:
sys.modulescache → finders insys.meta_path→ loaders. The default finders areBuiltinImporter,FrozenImporter,PathFinder(which searchessys.path). - Absolute vs. relative imports (
from . import sibling,from ..pkg import x). Prefer absolute. __main__:python -m mypkgrunsmypkg/__main__.pyas__main__. Theif __name__ == "__main__":idiom exists because a module imported as a library has a different__name__than one run as a script.pyproject.toml(PEP 517, 518, 621, 660): the single source of truth for project metadata, build backend, dependencies, and tool configuration.setup.pyis dead for new projects.- Build backends:
hatchling,setuptools,flit-core,poetry-core,maturin(for Rust extensions),scikit-build-core(for C/C++/CMake). - Dependency resolution:
pip(legacy, slow),uv(fast, Rust, drop-inpipreplacement and resolver),poetry(lockfile-first). The curriculum standardizes onuvfor speed and ecosystem direction.
4.3 Lab - "Ship a CLI"¶
- Build a CLI tool - e.g., a Markdown table of contents generator. Project layout:
src/toctool/{__init__.py,__main__.py,cli.py,core.py},tests/,pyproject.toml. - Configure
[project.scripts] toctool = "toctool.cli:main". Verifypipx install .makestoctoolavailable system-wide. - Add a
[project.optional-dependencies] dev = [...]group.uv sync --extra devinstalls the dev tools. - Tag
v0.1.0. Build wheel + sdist withuv build. Inspect the wheel withunzip -l. Confirm no test files leaked in. - (Optional, sets up later weeks) Publish to TestPyPI.
4.4 Idiomatic & Linter Drill¶
- Enable
ruffrule setTID(banned-imports),INP(implicit namespace packages). Configure your__init__.pyto re-export a curated public API (__all__).
4.5 Production Hardening Slice¶
- Add a
pre-commitconfig runningruff check,ruff format,pyright, andpytest -x. Add a GitHub Actions (or equivalent) CI workflow that runsmake checkon push and matrix-tests over Python 3.12 and 3.13.
Month-1 Exit Criteria¶
Before starting Month 2, the reader should be able to, on a whiteboard:
- Diagram the namespace lookup order for a name in a function inside a class inside a module (LEGB, with the class scope wrinkle).
- Explain the difference between
is,==, and__eq__. - Write a generator pipeline that processes a 100GB log file in constant memory.
- Bootstrap a publishable Python package with
uv,ruff,pyright,pytest, and CI in under 30 minutes.