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 #
| Aspek | Library (dipasang pengguna) | Aplikasi (dijalankan kita) |
|---|---|---|
| Cara berpindah | diunggah ke PyPI, dipasang dengan pip | dideploy sebagai image atau berkas |
| Batasan dependencies | rentang semantis (>=, ~=) agar kompatibel dengan project pengguna | versi terpasak persis lewat lockfile |
| Konfigurasi | diterima sebagai parameter dari kode pemanggil | dibaca dari environment server |
| Konsumen | ratusan project tak dikenal | satu tim dengan satu kebutuhan |
| Kegagalan versi | pecah pengguna di luar sana | pecah 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:
zipapp-demo/
├── src_app/
│ ├── __main__.py
│ └── layanan/
│ ├── __init__.py
│ └── sapa.pyKunci utamanya adalah nama berkas __main__.py — Python menjalankan berkas ini ketika arsip dieksekusi. Isinya:
# 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:
python -m zipapp src_app -o aplikasi.pyzPerintah tersebut tidak mencetak apa pun — tanda proses berhasil. Sekarang aplikasi berjalan dari berkas tunggal itu:
python aplikasi.pyz
python aplikasi.pyz BudiOutput yang Dihasilkan:
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:
unzip -l aplikasi.pyzOutput yang Dihasilkan:
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 filesBatasan .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:
[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):
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.