Lab: package and share
Package the CSV extractor utility so it is installable with pip — write pyproject.toml, add an entry point, and test the install locally.
- Write a complete pyproject.toml for the CSV extractor utility
- Add a console_scripts entry point that maps a command name to main()
- Understand the steps to test an editable install locally
This is an optional lab. No new concepts — just the hands-on work of packaging a utility you have already built. The browser runner cannot execute shell commands, so the install steps are a "do it yourself" exercise. The checkpoints test your knowledge of the config file structure.
You have a working CSV extractor in extract.py. In this lab you will write the
pyproject.toml that makes it installable, and walk through what a local install
looks like step by step.
The goal
After this lab, a collaborator should be able to do this:
git clone https://github.com/you/my-extractor
cd my-extractor
pip install -e .
csv-extract --helpAnd have a working csv-extract command available in their environment. That is
the whole point of packaging: sharing becomes a one-step install.
Step 1 — set up the directory
Create this layout on your machine (or confirm you already have it from the previous lab):
my-extractor/
├── extract.py (the utility you built)
└── pyproject.toml (you will write this now)If you do not have extract.py yet, copy the completed version from the
previous lesson. It needs a main() function with an argparse parser, at
minimum.
Make sure main() calls parser.parse_args() with no arguments (not the
explicit list you used in the browser runner). Without arguments, argparse
reads from sys.argv — which is what you want for a real command.
Checkpoint 1 — build-system block
Every modern pyproject.toml starts with a [build-system] block that tells
pip which backend to use. For setuptools, it looks like this:
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.backends.legacy:build"Which field tells pip which backend library to invoke?
Knowledge check
- 1.In the [build-system] block, which field specifies the build backend?
Step 2 — write the [project] block
Add the project metadata. Fill in the placeholders with real values for your utility:
[project]
name = "csv-extract"
version = "0.1.0"
description = "Extract a named column from CSV input."
requires-python = ">=3.9"The name field is what pip install uses. Choose something that does not
conflict with existing packages on PyPI — prefixing with your username or
project name is a safe habit (yourname-csv-extract).
Checkpoint 2 — entry point format
The [project.scripts] section connects a terminal command name to a Python
function. The value format is "module:function".
Knowledge check
- 1.For a file called extract.py with a function called main(), which entry point value is correct?
- 2.The command name on the left of the = in [project.scripts] must match the Python module filename.
Step 3 — add the entry point
Add this block to your pyproject.toml:
[project.scripts]
csv-extract = "extract:main"Your complete file should now look like this:
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.backends.legacy:build"
[project]
name = "csv-extract"
version = "0.1.0"
description = "Extract a named column from CSV input."
requires-python = ">=3.9"
[project.scripts]
csv-extract = "extract:main"Step 4 — install and test
Do it yourself — run these commands in your terminal from the
my-extractor/ directory:
# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install the package in editable mode
pip install -e .
# Confirm the command exists
which csv-extract # Windows: where csv-extract
# Test it
echo "name,score,city\nalice,91,london\nbob,74,paris" | csv-extract score
# Expected output:
# score
# 91
# 74
# Test error path
echo "name,score" | csv-extract age
# Should print: error: column not found: age
# And exit with code 1 (check with: echo $?)When the agent is away: if your shell cannot find csv-extract after
installing, confirm the virtual environment is activated (which python should
point inside .venv/). If the entry point is wrong, fix pyproject.toml,
run pip install -e . again — no need to uninstall first.
Checkpoint 3 — verify understanding
The key insight: pip does not copy your logic. It creates a tiny script that
imports and calls main(). Your code stays in extract.py; the wrapper just
knows where to find it. That is why editable installs work — the wrapper always
calls the current version of your file.
Done
You have taken a script from "run it in one directory" to "install it and run it
anywhere." That is the full arc of this module: from Unix philosophy to working
utility to installable tool. Every command-line tool you use daily — black,
pytest, httpie, ruff — was built the same way.