1. Pengenalan Python Packaging
Python Packaging adalah proses mengemas kode Python agar bisa didistribusikan dan digunakan oleh orang lain. Ekosistem Python memiliki lebih dari 500.000 package di PyPI (Python Package Index), menjadikannya salah satu repositori package terbesar di dunia.
Memahami packaging sangat penting untuk: berbagi library yang Anda buat, mengelola dependensi proyek, deployment ke server, dan menjaga reproducibility (konsistensi) environment.
Ekosistem Packaging Python
| Tool | Fungsi | Status |
|---|---|---|
| pip | Instal dan kelola package dari PyPI | ✅ Standar |
| venv | Membuat virtual environment terisolasi | ✅ Built-in |
| setuptools | Build backend untuk packaging | ✅ Mature |
| pyproject.toml | Konfigurasi packaging modern (PEP 621) | ✅ Standar baru |
| build | Frontend untuk mem-build package | ✅ PEP 517 |
| twine | Upload package ke PyPI | ✅ Standar |
| Poetry | All-in-one: dependency + packaging | 🟢 Populer |
| uv | Package manager ultra-cepat (Rust) | 🟢 Baru |
| PDM | Modern package manager (PEP 621) | 🟢 Alternatif |
┌───────────────────────────────────────────────────────┐ │ PYTHON PACKAGING WORKFLOW │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ Tulis │ │ Build │ │ Upload ke │ │ │ │ Kode + │──►│ Package │──►│ PyPI │ │ │ │ pyproj │ │ (wheel) │ │ (twine) │ │ │ └──────────┘ └──────────┘ └────────┬─────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────┐ │ │ │ pip install │ │ │ │ oleh user │ │ │ └──────────────┘ │ │ │ │ Format Package: │ │ • .whl (wheel) — format binary, cepat diinstal │ │ • .tar.gz (sdist) — source distribution │ │ • Keduanya dibutuhkan untuk PyPI │ └───────────────────────────────────────────────────────┘
2. pip: Package Installer
pip adalah package manager standar Python untuk menginstal dan mengelola package dari PyPI. pip sudah terinstal otomatis bersama Python 3.4+.
Perintah pip Dasar
# Instal package pip install requests pip install flask==3.0.3 # Versi spesifik pip install "django>=4.2,<5.0" # Rentang versi pip install requests[security] # Dengan extras # Instal beberapa package sekaligus pip install flask sqlalchemy pytest # Instal dari file requirements pip install -r requirements.txt # Upgrade package pip install --upgrade flask pip install -U requests # Uninstall package pip uninstall requests # List semua package yang terinstal pip list # Cek info package pip show flask # Output: # Name: Flask # Version: 3.0.3 # Summary: A simple framework for building web applications. # Location: /path/to/lib/python3.12/site-packages # Freeze requirements (export dependencies) pip freeze > requirements.txt # Output format: # Flask==3.0.3 # Werkzeug==3.0.3 # Jinja2==3.1.4 # click==8.1.7 # ... # Cek package yang outdated pip list --outdated
requirements.txt
# requirements.txt — Pin versi untuk reproducibility Flask==3.0.3 Flask-SQLAlchemy==3.1.1 Flask-Migrate==4.0.7 Flask-WTF==1.2.1 gunicorn==22.0.0 psycopg2-binary==2.9.9 python-dotenv==1.0.1 # Development dependencies (pisahkan) # requirements-dev.txt pytest==8.2.2 pytest-cov==5.0.0 black==24.4.2 ruff==0.4.8 mypy==1.10.0
Jangan instal package secara global. Selalu gunakan virtual environment untuk menghindari konflik antar proyek. Tanpa venv, proyek A yang butuh Flask 2.x bisa konflik dengan proyek B yang butuh Flask 3.x.
3. Virtual Environments
Virtual environment adalah Python environment terisolasi yang memiliki package dan versi sendiri, terpisah dari environment global. Setiap proyek sebaiknya memiliki venv sendiri.
# Membuat virtual environment python -m venv venv # Aktifkan virtual environment # macOS/Linux: source venv/bin/activate # Windows (Command Prompt): venv\Scripts\activate.bat # Windows (PowerShell): venv\Scripts\Activate.ps1 # Cek bahwa venv aktif (prompt berubah) # (venv) $ which python # /path/to/proyek/venv/bin/python # Instal package di dalam venv pip install flask pip install -r requirements.txt # Deactivate venv deactivate # Menghapus venv (cukup hapus folder) rm -rf venv # macOS/Linux rmdir /s /q venv # Windows # .gitignore — JANGAN commit venv! echo "venv/" >> .gitignore echo "__pycache__/" >> .gitignore echo "*.pyc" >> .gitignore echo ".env" >> .gitignore
Alternatif: uv (Ultra Fast)
# uv — Package manager ultra-cepat ditulis dalam Rust # 10-100x lebih cepat dari pip! # Instal uv pip install uv # atau: curl -LsSf https://astral.sh/uv/install.sh | sh # Buat venv dengan uv uv venv # Instal package (sangat cepat!) uv pip install flask sqlalchemy pytest # Sync dari requirements uv pip sync requirements.txt # Compile requirements (seperti pip-compile) uv pip compile requirements.in -o requirements.txt # Jalankan script dengan uv uv run python app.py
4. pyproject.toml: Konfigurasi Modern
pyproject.toml adalah file konfigurasi standar untuk proyek Python (PEP 621 + PEP 518). File ini menggantikan setup.py, setup.cfg, requirements.txt, dan berbagai file konfigurasi lainnya dalam satu file terpadu.
# pyproject.toml — Konfigurasi proyek Python modern
[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.backends._legacy:_Backend"
[project]
name = "my-awesome-library"
version = "1.0.0"
description = "Library Python yang luar biasa untuk melakukan X"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.10"
authors = [
{name = "Budi Santoso", email = "budi@example.com"},
]
keywords = ["python", "library", "awesome"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries",
]
dependencies = [
"requests>=2.31.0",
"pydantic>=2.0",
"rich>=13.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-cov>=5.0",
"black>=24.0",
"ruff>=0.4",
"mypy>=1.10",
]
docs = [
"sphinx>=7.0",
"sphinx-rtd-theme>=2.0",
]
[project.urls]
Homepage = "https://github.com/budi/my-awesome-library"
Documentation = "https://my-awesome-library.readthedocs.io"
Repository = "https://github.com/budi/my-awesome-library"
Issues = "https://github.com/budi/my-awesome-library/issues"
[project.scripts]
# CLI entry point — bisa dijalankan dari terminal
my-cli = "my_library.cli:main"
# Konfigurasi tools
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v --tb=short"
[tool.black]
line-length = 88
target-version = ["py312"]
[tool.ruff]
line-length = 88
select = ["E", "F", "I", "N", "W", "UP"]
[tool.mypy]
python_version = "3.12"
strict = true
[tool.setuptools.packages.find]
where = ["src"]
Struktur Proyek Modern
my-awesome-library/ ├── src/ │ └── my_library/ │ ├── __init__.py ← Versi dan export utama │ ├── core.py ← Modul utama │ ├── utils.py ← Utilities │ └── cli.py ← CLI entry point ├── tests/ │ ├── __init__.py │ ├── test_core.py │ └── test_utils.py ├── docs/ │ └── index.md ├── pyproject.toml ← Konfigurasi utama ├── README.md ← Dokumentasi proyek ├── LICENSE ← Lisensi ├── .gitignore ← Git ignore rules └── CHANGELOG.md ← Riwayat perubahan
5. Building Packages
Setelah proyek siap, kita perlu mem-build package menjadi distributable artifacts (wheel dan sdist) sebelum bisa dipublish ke PyPI atau diinstal oleh orang lain.
# Instal build tool pip install build # Build package (menghasilkan wheel + sdist) python -m build # Output: # Successfully built my-awesome-library-1.0.0.tar.gz # and my_awesome_library-1.0.0-py3-none-any.whl # Struktur output: # dist/ # ├── my_awesome_library-1.0.0-py3-none-any.whl ← Wheel (binary) # └── my-awesome-library-1.0.0.tar.gz ← Sdist (source) # Instal package lokal (untuk testing) pip install dist/my_awesome_library-1.0.0-py3-none-any.whl # Instal dalam mode editable (development) pip install -e . # Editable mode: perubahan kode langsung ter-refleksi tanpa reinstall # Instal dengan dev dependencies pip install -e ".[dev]" # Build dengan hatchling (alternatif modern) pip install hatchling # Ganti build-backend di pyproject.toml: # build-backend = "hatchling.build" python -m build
Entry Points (CLI)
# src/my_library/cli.py — CLI Entry Point
import argparse
from my_library import __version__
from my_library.core import proses_data
def main():
parser = argparse.ArgumentParser(
description='My Awesome Library CLI'
)
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
parser.add_argument('input', help='Input file atau data')
parser.add_argument('-o', '--output', help='Output file')
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
args = parser.parse_args()
if args.verbose:
print(f"Memproses: {args.input}")
hasil = proses_data(args.input)
if args.output:
with open(args.output, 'w') as f:
f.write(hasil)
print(f"Output disimpan ke {args.output}")
else:
print(hasil)
if __name__ == '__main__':
main()
# Setelah install, bisa dijalankan dari terminal:
# my-cli data.txt -o output.txt -v
6. Publishing ke PyPI
PyPI (Python Package Index) adalah repositori resmi untuk package Python. Setelah di-publish, siapa saja bisa menginstal package Anda dengan pip install nama-package.
Persiapan
# 1. Buat akun di https://pypi.org/register/ # 2. Buat API token di https://pypi.org/manage/account/token/ # Instal twine pip install twine # Verifikasi package sebelum upload twine check dist/* # Output: PASSED dist/my_awesome_library-1.0.0-py3-none-any.whl # Upload ke TestPyPI dulu (testing) twine upload --repository testpypi dist/* # Upload ke PyPI (production) twine upload dist/* # Atau gunakan Trusted Publisher (tanpa API token): # 1. Setup GitHub Actions + PyPI Trusted Publisher # 2. Upload otomatis setiap push tag
Setelah Publish
# Install dari PyPI pip install my-awesome-library # Install dari TestPyPI pip install --index-url https://test.pypi.org/simple/ my-awesome-library # Install dari GitHub langsung pip install git+https://github.com/budi/my-awesome-library.git # Install dari local folder pip install /path/to/my-awesome-library/ # Install dengan extras pip install "my-awesome-library[dev]" pip install "my-awesome-library[docs]"
Best Practices Publishing
| Best Practice | Alasan |
|---|---|
| Semantic Versioning | Gunakan format MAJOR.MINOR.PATCH (contoh: 1.2.3) |
| README.md yang bagus | Dokumentasi, instalasi, contoh penggunaan |
| LICENSE | Jelaskan lisensi (MIT, Apache 2.0, GPL, dll) |
| CHANGELOG.md | Catat perubahan di setiap versi |
| CI/CD | Otomatisasi test dan publish dengan GitHub Actions |
| py.typed marker | Untuk library yang mendukung type hints |
7. Docker untuk Python
Docker mengemas aplikasi Python beserta semua dependensinya ke dalam container yang bisa dijalankan di mana saja. Docker memastikan aplikasi berjalan konsisten di development, testing, dan production.
Dockerfile Multi-Stage (Best Practice)
# Dockerfile — Multi-stage build untuk Python
# Stage 1: Build
FROM python:3.12-slim as builder
WORKDIR /app
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# Stage 2: Production
FROM python:3.12-slim
WORKDIR /app
# Copy installed packages from builder
COPY --from=builder /install /usr/local
# Copy application code
COPY . .
# Create non-root user (security best practice)
RUN adduser --disabled-password --gecos '' appuser
USER appuser
# Environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
FLASK_ENV=production
EXPOSE 5000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
# Run with gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "--timeout", "120", "app:create_app()"]
docker-compose.yml
# docker-compose.yml — Full stack Python app
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "5000:5000"
environment:
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
- SECRET_KEY=my-secret-key-change-this
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
worker:
build: .
command: celery -A app.celery worker --loglevel=info
environment:
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
volumes:
pgdata:
Best Practices Docker Python
# .dockerignore — Jangan masukkan ini ke Docker image __pycache__ *.pyc *.pyo .git .gitignore .venv venv .env *.md tests/ docs/ dist/ build/ .pytest_cache .mypy_cache .coverage htmlcov/
# Build image docker build -t my-python-app:latest . # Jalankan container docker run -p 5000:5000 my-python-app:latest # Jalankan dengan docker-compose docker-compose up -d # Background docker-compose up --build # Rebuild and start docker-compose down # Stop and remove docker-compose logs -f web # Lihat logs # Masuk ke container (debugging) docker exec -it container_id /bin/bash # Cek ukuran image docker images my-python-app docker system df # Cek disk usage Docker # Cleanup docker system prune -a # Hapus semua yang tidak terpakai
Gunakan python:3.12-slim sebagai base image (bukan python:3.12 yang full) untuk mengurangi ukuran image. Selalu gunakan --no-cache-dir saat pip install di Docker. Gunakan multi-stage build untuk production image yang lebih kecil.
8. Dependency Managers
Selain pip + venv, ada beberapa dependency manager modern yang menyediakan fitur lebih lengkap seperti lock files, dependency resolution, dan build system terintegrasi.
Poetry
# Instal Poetry curl -sSL https://install.python-poetry.org | python3 - # Buat proyek baru poetry new my-project cd my-project # Tambah dependency poetry add requests flask sqlalchemy poetry add --group dev pytest black ruff # Instal semua dependencies poetry install # Jalankan perintah dalam environment poetry run python app.py poetry run pytest # Update dependencies poetry update # Export ke requirements.txt poetry export -f requirements.txt -o requirements.txt # Build dan publish poetry build poetry publish # Lock file (poetry.lock) — commit ke Git! # Memastikan semua developer menggunakan versi yang sama
Perbandingan Tools
| Tool | Lock File | Kecepatan | Built-in Build | Learning Curve |
|---|---|---|---|---|
| pip | ❌ (pip freeze manual) | 🟡 Sedang | ❌ | 🟢 Mudah |
| Poetry | ✅ poetry.lock | 🟡 Sedang | ✅ | 🟡 Sedang |
| PDM | ✅ pdm.lock | 🟡 Sedang | ✅ | 🟡 Sedang |
| uv | ✅ uv.lock | 🟢 Sangat Cepat | ✅ | 🟢 Mudah |
Pemula: Gunakan pip + venv — sederhana dan banyak tutorial. Proyek menengah: Gunakan Poetry atau PDM — lock file dan dependency resolution lebih baik. Performa tinggi: Gunakan uv — sangat cepat karena ditulis dalam Rust. Tim besar: Poetry atau PDM dengan CI/CD yang terkonfigurasi.
9. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Python packaging: