π Quick Recap (Day 24)
You wrote tests with
unittest/pytestand learned how to debug with breakpoints and tracebacks.
π― What Youβll Learn Today
A simple project structure for a Python package.
How to configure
pyproject.tomlwith setuptools.How to build sdist (source) and wheel (binary) files.
How to install your package locally and add a CLI command.
How to (optionally) publish to TestPyPI with twine.
Friendly versioning and metadata tips.
π Why Package Your Code?
Packaging lets anyone (including you on another computer) install your project with one command: pip install yourpackage. Itβs useful for:
Reusing utilities across projects.
Sharing tools with classmates or teammates.
Creating small commandβline apps you can run from any folder.
Two build types:
β’ sdist = a source archive of your code.
β’ wheel = a readyβtoβinstall build (faster to install).
π Project Layout
Create a new folder, e.g. dmagogreet/, with this structure:
dmagogreet/
ββ dmagogreet/
β ββ __init__.py
β ββ cli.py
ββ pyproject.toml
ββ README.md
ββ LICENSE (optional)What each file does:
dmagogreet/: your actual Python package (same name as the project).__init__.py: makes it a package; good place for__version__.cli.py: code for a tiny commandβline tool.pyproject.toml: build configuration (who you are, version, entry points).README.md: a short βwhat it does / how to use it.β
dmagogreet/__init__.py
__version__ = "0.1.0"
def greet(name: str) -> str:
return f"Hello from Digital Mago, {name}!"dmagogreet/cli.py
from . import greet, __version__
def main() -> None:
import argparse
p = argparse.ArgumentParser(description="Digital Mago greeter")
p.add_argument("name", help="Your name")
p.add_argument("--shout", action="store_true", help="Uppercase greeting")
args = p.parse_args()
msg = greet(args.name)
if args.shout:
msg = msg.upper()
print(f"{msg} (v{__version__})")README.md
Explain in 4β6 lines what the tool does and show one example command.
π pyproject.toml with setuptools
This file tells build tools how to package your project.
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "dmagogreet"
version = "0.1.0"
description = "A tiny Digital Mago greeting CLI"
readme = "README.md"
requires-python = ">=3.8"
authors = [{ name = "Your Name", email = "[email protected]" }]
license = { text = "MIT" }
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
# No runtime dependencies for this tiny tool
dependencies = []
[project.scripts]
# Creates a console command named `dmagogreet`
dmagogreet = "dmagogreet.cli:main"
[tool.setuptools.packages.find]
include = ["dmagogreet*"]Why this matters: project.scripts wires your main() to a real terminal command, so you can type dmagogreet anywhere after install.
π Build Your Package
Do these in your virtual environment from Day 16.
Install build tools:
pip install build twineBuild:
python -m buildThis creates a dist/ folder with:
dmagogreet-0.1.0.tar.gz(sdist)dmagogreet-0.1.0-py3-none-any.whl(wheel)
Try a Local Install
pip install dist/dmagogreet-0.1.0-py3-none-any.whlRun your CLI:
dmagogreet YourNameExpected output:
Hello from Digital Mago, YourName! (v0.1.0)Try the shout option:
dmagogreet YourName --shoutExpected output:
HELLO FROM DIGITAL MAGO, YOURNAME! (V0.1.0)Uninstall during testing:
pip uninstall dmagogreet -yπ (Optional) Publish to TestPyPI
Create an account/token on the TestPyPI index.
Upload your files:
twine upload --repository testpypi dist/*Test install from there (keeping the main PyPI for dependency fallback):
python -m pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple dmagogreet==0.1.0Ready for the real thing later? Replace testpypi with the default repository:
twine upload dist/*π Versioning & Metadata Tips
Use Semantic Versioning:
MAJOR.MINOR.PATCH(e.g., 0.1.1 for small fixes).Update both
__version__andproject.versiontogether.Keep a friendly CHANGELOG.md.
Write a clear README with a quick start.
Include a LICENSE file (MIT is beginnerβfriendly).
π§° Troubleshooting
Command not found after install
Close and reopen your terminal, or ensure your virtual environment is active. On Windows, the script lives inenv\Scripts; on macOS/Linux inenv/bin.Build fails
Check thatpyproject.tomlis valid TOML (matching quotes/brackets) and your package folder name matchesinclude.Upload denied
Make sure the version number is new (PyPI/TestPyPI doesnβt allow replacing the same version).
π§ββοΈ Take the Wand and Try Yourself
Goal: Ship a tiny package with a CLI and install it locally.
Create the project layout shown above.
Fill in
__init__.py,cli.py,pyproject.toml, andREADME.md.Build with
python -m build.Install the wheel and run
dmagogreetwith and without--shout.Bump the version to
0.1.1, rebuild, reinstall, and confirm the new version prints in the CLI output.(Optional) Upload to TestPyPI and test remote installation.
Expected terminal output (abridged):
$ python -m build
... Successfully built dmagogreet-0.1.0 ...
$ pip install dist/dmagogreet-0.1.0-py3-none-any.whl
Successfully installed dmagogreet-0.1.0
$ dmagogreet YourName
Hello from Digital Mago, YourName! (v0.1.0)
$ dmagogreet YourName --shout
HELLO FROM DIGITAL MAGO, YOURNAME! (V0.1.0)Up next: Day 26: Introduction to Frameworks β a tour of popular web and data frameworks and when to use each.