Semua chapter sebelumnya berbicara tentang mengemas library — kode yang diserahkan ke pengguna lewat pip dan PyPI. Aplikasi berbeda: kita yang menjalankannya, di server milik kita. Perbedaan ini mengubah keputusan packaging secara fundamental, mulai dari cara memasang dependencies sampai bagaimana kemasan akhir dibagikan. Pada chapter ini kita menegaskan perbedaannya, lalu mempraktikkan satu teknik kemasan aplikasi yang bisa dijalankan tanpa instalasi: zipapp.

Aplikasi versus Library #

AspekLibrary (dipasang pengguna)Aplikasi (dijalankan kita)
Cara berpindahdiunggah ke PyPI, dipasang dengan pipdideploy sebagai image atau berkas
Batasan dependenciesrentang semantis (>=, ~=) agar kompatibel dengan project penggunaversi terpasak persis lewat lockfile
Konfigurasiditerima sebagai parameter dari kode pemanggildibaca dari environment server
Konsumenratusan project tak dikenalsatu tim dengan satu kebutuhan
Kegagalan versipecah pengguna di luar sanapecah deployment kita sendiri

Rentang dependencies pada library memberi ruang bagi pengguna; versi terpasak pada aplikasi menjamin environment staging dan produksi identik — alasan di balik Chapter Dependency Pinning. Konfigurasi lewat environment untuk aplikasi dibahas tuntas pada Chapter Environment Variables.

zipapp: Aplikasi dalam Satu Berkas #

Module standar zipapp mengemas folder berisi kode Python menjadi satu berkas .pyz yang bisa langsung dijalankan. Mari kita siapkan struktur berikut:

text
zipapp-demo/
├── src_app/
│   ├── __main__.py
│   └── layanan/
│       ├── __init__.py
│       └── sapa.py

Kunci utamanya adalah nama berkas __main__.py — Python menjalankan berkas ini ketika arsip dieksekusi. Isinya:

python
# src_app/__main__.py
import sys

from layanan.sapa import sapa


def main() -> None:
    nama = sys.argv[1] if len(sys.argv) > 1 else "dunia"
    print(sapa(nama))


if __name__ == "__main__":
    main()

Sedangkan layanan/sapa.py berisi satu fungsi sapa() penghasil sapaan. Dari folder zipapp-demo, kemas src_app menjadi satu berkas:

bash
python -m zipapp src_app -o aplikasi.pyz

Perintah tersebut tidak mencetak apa pun — tanda proses berhasil. Sekarang aplikasi berjalan dari berkas tunggal itu:

bash
python aplikasi.pyz
python aplikasi.pyz Budi

Output yang Dihasilkan:

text
Halo, dunia! Ini berasal dari dalam .pyz.
Halo, Budi! Ini berasal dari dalam .pyz.

Interpreter Python membuka arsip .pyz itu sendiri — menambahkan path virtual aplikasi.pyz ke sys.path lalu menjalankan __main__.py di dalamnya. Isi arsip bisa diperiksa seperti berkas ZIP biasa:

bash
unzip -l aplikasi.pyz

Output yang Dihasilkan:

text
Archive:  aplikasi.pyz
  Length      Date    Time    Name
---------  ---------- -----   ----
      183  2026-10-12 23:03   __main__.py
        0  2026-10-12 23:03   layanan/
        0  2026-10-12 23:03   layanan/__init__.py
       85  2026-10-12 23:03   layanan/sapa.py
---------                     -------
      268                     4 files

Batasan .pyz perlu jujur diakui: aplikasi hanya boleh bergantung pada standard library, dan mesin target tetap butuh interpreter Python dengan versi yang cocok. Untuk kebutuhan yang lebih besar, tool shiv dan pex memakai teknik serupa namun menyertakan dependencies pihak ketiga di dalam arsip dan membuat launcher yang lebih cerdas.

Berkas Data di Dalam Package #

Aplikasi kerap membawa berkas pendamping: data referensi, template, aset. Kode bisa menempel pada berkas tersebut lewat module importlib.resources, tetapi berkas harus ikut masuk ke wheel dulu. Deklarasinya di pyproject.toml:

toml
[tool.setuptools.package-data]
demo_pkg = ["data/*.txt"]

Setelah menambahkan berkas src/demo_pkg/data/kota.txt dan membangun ulang, isi wheel-nya berubah:

Output yang Dihasilkan (cuplikan unzip -l, diringkas):

text
      138  2026-10-12 23:01   demo_pkg/__init__.py
      139  2026-10-12 23:01   demo_pkg/cli.py
       25  2026-10-12 23:04   demo_pkg/data/kota.txt
      ...

Baris demo_pkg/data/kota.txt terbukti masuk — folder data ikut terbawa, dan isinya terverifikasi utuh di dalam arsip. Tanpa deklarasi ini, wheel tetap berhasil dibangun tetapi berkas data diam-diam absen, lalu aplikasi error saat dijalankan di server.

Konfigurasi dan Secret Tetap di Luar Kemasan #

Apa pun bentuk kemasan — wheel, .pyz, atau image Docker pada chapter berikutnya — satu kelompok data tidak boleh ikut terbungkus: kredensial. Password database dan API key tidak ditulis di kode maupun berkas data; keduanya diinjeksikan lewat environment saat aplikasi berjalan, dengan pengelolaannya dibahas pada Chapter Mengelola Secrets. Kemasan hanya berisi kode; server yang memegang kuncinya.