Learning Python - Packaging, Distribution & PyPI
Series/Learn Python/Episode 19
Episode 19 of 23

Learning Python - Packaging, Distribution & PyPI

This episode takes your package to the world: the pyproject.toml standard, build backends like setuptools, Poetry, and Flit, building wheels, publishing to PyPI with twine, plus versioning strategies and managing releases.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Building a library that others can use is a major achievement. Episode 19 teaches packaging and distribution: how to declare a package with pyproject.toml, choose a build backend, build a wheel, and publish it to PyPI.

We'll also cover versioning and release strategies so your library is managed professionally. By the end of the episode, your package can be installed with pip install nama-package by anyone in the world.

The pyproject.toml Standard

Declaring a Complete Package

pyproject.toml per PEP 621 is the source of truth for metadata:

pyproject.toml lengkap
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
 
[project]
name = "belajar-utils"
version = "0.1.0"
description = "Library util untuk belajar packaging Python"
readme = "README.md"
requires-python = ">=3.12"
license = {text = "MIT"}
dependencies = ["requests>=2.31"]
 
[project.optional-dependencies]
dev = ["pytest>=8.0", "twine"]

[project] declares the name, version, description, and license. readme = "README.md" points to the documentation. The [project.optional-dependencies] section separates dev dependencies. This structure is read by all modern build backends.

Build Backends

setuptools is the most widely used build backend:

Install build
pip install build
Membangun dengan build
python3 -m build

python3 -m build builds the package using the backend declared in pyproject.toml. The output is a dist/ directory containing a source distribution and a wheel. setuptools is flexible for almost any package structure.

Poetry and Flit as Alternatives

Poetry and Flit provide alternative backends:

Backend Poetry
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Backend Flit
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

Poetry uses poetry.core.masonry.api and Flit uses flit_core.buildapi. All three produce the same artifacts — wheel and sdist. Choose the backend that's most comfortable for your team's workflow.

Building Wheels

Understanding Wheel and sdist

Builds produce two artifacts:

  • wheel (.whl): a binary format ready to install.
  • sdist (.tar.gz): a source distribution for rebuilding.

Wheel is the faster-to-install format. Look at the contents of dist after building:

Melihat hasil build
ls dist/

ls dist/ shows files like belajar_utils-0.1.0-py3-none-any.whl and belajar-utils-0.1.0.tar.gz. The wheel name encodes the version, Python tag, and platform. py3-none-any means universal for Python 3 on all platforms.

Testing the Package Locally

Before publishing, test the package from the built wheel:

Menginstall package dari wheel
python3 -m venv .venv-test
source .venv-test/bin/activate
pip install dist/belajar_utils-0.1.0-py3-none-any.whl

pip install dist/belajar_utils-0.1.0-py3-none-any.whl installs the package from the wheel into a clean venv. Test the import and functions in this venv. This guarantees the package doesn't depend on your development environment.

Publishing with twine

Preparing a PyPI Account

To publish, register at PyPI and create an API token. Store the token as an environment variable:

Menetapkan token PyPI
export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="pypi-TokenRahasiaAnda"

export TWINE_USERNAME="__token__" sets twine's credentials. Modern PyPI uses API tokens, not account passwords. Never write the token in code or committed files — follow the secret best practices from episode 11.

Uploading to PyPI

Upload the artifacts with twine:

Install dan jalankan twine
pip install twine
twine check dist/*
twine upload dist/*

twine check dist/* verifies the metadata before uploading. twine upload dist/* uploads the wheel and sdist to PyPI. After success, the package can be installed anywhere with pip install belajar-utils.

TestPyPI for Trials

Test the upload on TestPyPI first to avoid mistakes:

Upload ke TestPyPI
twine upload --repository testpypi dist/*

twine upload --repository testpypi dist/* uploads to the test server. After testing on TestPyPI, publish to the official PyPI. This habit prevents broken versions or wrong metadata from landing on the main index.

Versioning and Releases

Semantic Versioning

Use semantic versioning with the MAJOR.MINOR.PATCH format:

Format semantic versioning
MAJOR.MINOR.PATCH
1.4.2
  • MAJOR: breaking, backwards-incompatible changes.
  • MINOR: feature additions that remain compatible.
  • PATCH: compatible bug fixes.

These rules help users know how much risk an upgrade carries.

Tagging Releases in Git

Every release is marked with a Git tag:

Menandai release
git tag -a v0.1.0 -m "Rilis pertama belajar-utils"
git push origin v0.1.0

git tag -a v0.1.0 -m "Rilis pertama belajar-utils" marks a specific version in history. This tag serves as a reference for release notes and can trigger an automated publishing pipeline in episode 20. Managed releases make your library easy to maintain.

Closing

Key takeaways:

  • pyproject.toml per PEP 621 declares all package metadata.
  • Build backends: setuptools, Poetry, and Flit produce the same artifacts.
  • Wheel is a binary format; sdist is for the source distribution.
  • Test the package from the wheel in a clean venv before publishing.
  • Twine uploads artifacts to PyPI and TestPyPI.
  • Semantic versioning and Git tags mark releases clearly.

In the next episode, episode 20, we'll cover CI/CD, containerization, and deployment — CI pipelines with GitHub Actions, caching and matrix builds for multiple Python versions, multi-stage Docker, running Gunicorn and Uvicorn, and deployment targets like Cloud Run, AWS Lambda, and Kubernetes. Your application is ready to launch to production!

Learning Python - Packaging, Distribution & PyPI | Learn Python