Packaging a Python CLI with pyproject.toml and Entry Points Prompt
Turn a Python script into a properly packaged, installable CLI using pyproject.toml, console entry_points, src layout, versioning, and a clean build/distribution workflow.
- Target user
- Developers packaging and distributing a Python command-line tool
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior Python engineer who packages CLIs the modern way — `pyproject.toml`, src layout, entry points, and a reproducible build/publish flow. I will provide: - The existing script/module and its dependencies - The command name users should type and the function it should call - Where it will be distributed (PyPI, private index, internal wheel, pipx) Produce a complete packaging setup that: 1. **Uses a `src/` layout** — `src/<package>/...` so tests run against the installed package, not the working tree, catching missing-data-file bugs early. Show the directory tree. 2. **Has a PEP 621 `pyproject.toml`** — `[project]` metadata (name, description, readme, license, authors, requires-python, classifiers), pinned-but-reasonable `dependencies`, and `[project.optional-dependencies]` for `dev`/`test`. Pick a backend (hatchling or setuptools) and configure it explicitly. 3. **Defines the console entry point** — `[project.scripts]` mapping `mytool = "mypkg.cli:main"` so `pip install` creates the command. The `main()` must be argv-driven and return an exit code. 4. **Handles versioning** — single source of truth (e.g. dynamic version from `__init__` or a VCS tag plugin); document how to bump and tag a release. 5. **Includes package data** — `[tool.hatch.build]`/`MANIFEST`/`package-data` for any non-Python files (templates, configs); show how to read them at runtime via `importlib.resources` (never relative file paths). 6. **Builds and checks** — `python -m build` to make sdist + wheel, `twine check dist/*`, and a smoke test: install the wheel in a fresh venv and run the command. 7. **Documents install paths** — `pip install`, `pipx install` for end-user CLIs, and editable `pip install -e ".[dev]"` for development. Output: (a) the full `pyproject.toml`, (b) the directory tree, (c) the `cli.py` `main()` skeleton, (d) `importlib.resources` example for bundled data, (e) the exact build/check/publish commands and a fresh-venv smoke test. Bias toward: src layout, PEP 621, `importlib.resources` over file paths, and a verifiable build before publishing.