Packaging

Learn how to turn your Python code into a real, installable package that anyone can use with pip install.

Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

This lesson teaches you how to publish professional Python packages:

After this lesson, anyone can install your code with:

1. What Is a Python Package?

Think of a package like a product in a box . The box (folder) contains everything needed: the product itself (your code), instructions (README), warranty info (LICENSE), and a label with specs (pyproject.toml). Anyone can "buy" your product with pip install !

A package is just a directory with an __init__.py file that can be imported.

The src/ layout is recommended because it catches import mistakes early.

2. Basic Code Layout

3. The Modern Way: pyproject.toml

pyproject.toml is now the standard way to describe:

4. Semantic Versioning (How to Version Properly)

Think of versions like software updates on your phone . A PATCH (15.0.1 → 15.0.2) fixes bugs quietly. A MINOR update (15.1) adds features. A MAJOR update (15 → 16) might change everything and require you to relearn things — that's a breaking change.

Store the version in one place (e.g. __init__.py) and keep pyproject.toml in sync or use a tool like setuptools-scm later.

5. Writing a Good README for PyPI

Your README.md becomes the landing page on PyPI.

Make sure readme = "README.md" is set correctly in pyproject.toml.

6. Building the Distribution (Wheel + sdist)

Building a package is like baking bread. sdist is like shipping the recipe and ingredients — the customer bakes it themselves. Wheel is like shipping the finished loaf — ready to eat immediately. Most people prefer the wheel (faster to install)!

Then from your project root (same folder as pyproject.toml):

7. Uploading to TestPyPI (Safe Practice Run)

Before using the real PyPI, publish to TestPyPI.

If everything looks good, you're ready for real PyPI.

8. Publishing to the Real PyPI

9. Updating Your Package (New Versions)

PyPI will reject duplicate versions, so you must use a new version number each time.

10. Minimal Checklist Before Publishing

11. Adding Optional Features With "Extras"

Sometimes you want optional dependencies that users can install only if they need them.

Example: a core library with an optional cli or dev feature:

This keeps the base install lightweight, while still offering powerful extras for people who want them.

12. Entry Points & Console Scripts (Installing a CLI)

You can ship a command-line tool with your package so users get a global command after installing.

This is how black, pytest, pip, etc. expose commands.

13. Classifiers: Telling PyPI & Tools What Your Package Supports

14. Handling Dependencies Safely

In your own dev environment you can use a lock file from tools like pip-tools, Poetry, or uv.

15. Testing Before Publishing

Before uploading to PyPI, always run tests in a clean environment.

If tests pass in a clean venv, chances are much higher that users won't hit import errors.

16. Testing Installation Like a Real User

After building and uploading to TestPyPI, test your package the way a real user would:

If that works, your packaging, imports, and metadata are all aligned correctly.

17. Common Packaging Mistakes (and How to Avoid Them)

If __init__.py is missing, Python won't treat the directory as a package.

If you use the src/ layout, you must tell setuptools:

Otherwise your built wheel may contain no code, and imports will fail.

PyPI will reject re-uploads of a version. If you made a mistake:

18. Keeping Secrets Safe (Do Not Hardcode Keys)

Never put secrets (tokens, passwords) in your package.

Anything inside src/ will be visible to anyone on PyPI or GitHub, so treat it as public.

19. Automating Publishing With CI (Overview)

Later on, you can automate releases using CI like GitHub Actions.

Very rough example .github/workflows/release.yml structure:

After this, releasing is as simple as pushing a tag.

20. Making Your Package Friendly for Contributors

A polished package is easier for others to use and contribute to.

21. Summary of the Packaging Workflow

Use src/your_package/ layout. Add __init__.py, modules, tests

Create pyproject.toml with metadata, dependencies, optional extras, scripts

Implement core logic. Add unit tests with pytest

Upload with twine to TestPyPI. Install in a clean venv. Import and run sample code

Practice quiz

Which file is the modern standard for declaring a package's metadata and build config?

  • setup.cfg
  • requirements.txt
  • pyproject.toml
  • MANIFEST.in

Answer: pyproject.toml. pyproject.toml is the modern standard describing metadata, build backend, and dependencies.

What command builds both a wheel and a source distribution (sdist)?

  • python -m build
  • pip install .
  • twine upload dist/*
  • python setup.py register

Answer: python -m build. python -m build produces the .whl (wheel) and .tar.gz (sdist) in the dist/ folder.

What is the difference between a wheel and an sdist?

  • A wheel is source code; an sdist is pre-built
  • They are identical formats
  • A wheel can't be uploaded to PyPI
  • A wheel is a pre-built package (faster install); an sdist ships source to build from

Answer: A wheel is a pre-built package (faster install); an sdist ships source to build from. Wheels (.whl) install fast as pre-built; sdists (.tar.gz) contain source built on the user's machine.

Which tool uploads your built distributions to PyPI?

  • pip
  • twine
  • build
  • setuptools

Answer: twine. twine upload dist/* publishes your wheel and sdist to (Test)PyPI.

In MAJOR.MINOR.PATCH semantic versioning, which part bumps for a breaking change?

  • MAJOR
  • PATCH
  • MINOR
  • None of them

Answer: MAJOR. Breaking changes bump MAJOR; MINOR adds backward-compatible features; PATCH is bug fixes.

Why is publishing to TestPyPI recommended before the real PyPI?

  • It is required by law
  • TestPyPI packages auto-publish to PyPI
  • It's a safe practice run to verify upload and install without affecting the real index
  • It makes the package free

Answer: It's a safe practice run to verify upload and install without affecting the real index. TestPyPI lets you rehearse uploading and installing safely before the real release.

What happens if you try to upload a version that already exists on PyPI?

  • It silently overwrites the old one
  • PyPI rejects the duplicate; you must bump to a new version number
  • It merges the two uploads
  • It deletes the package

Answer: PyPI rejects the duplicate; you must bump to a new version number. PyPI forbids re-uploading the same version, so each release needs a new version number.

With the src/ layout, what tells setuptools where to find your package?

You must point package discovery at src via [tool.setuptools.packages.find] where = ["src"].

How do users install an optional 'extras' group, e.g. a cli extra?

  • pip install my-cool-lib --cli

Extras declared under [project.optional-dependencies] are installed with the bracket syntax pkg[extra].

Which pyproject.toml section ships a console command like 'mycool'?

[project.scripts] maps a command name to a function entry point (e.g. my_cool_lib.cli:main).