Menulis library berbeda dari menulis skrip sekali jalan. Skrip hidup untuk dirinya sendiri, sedangkan library hidup untuk dipakai orang lain: dipasang dengan pip, diimpor dari kode yang tidak kita kendalikan, dan diuji secara terpisah dari kode pemakainya. Perbedaan itu harus tercermin sejak struktur folder pertama, sebelum satu baris function pun ditulis. Pada bagian ini kita menyiapkan kerangka package example-package tersebut.
Rancangan Package #
Kita membangun satu package dengan satu module yang memuat tiga function utilitas teks:
| Function | Tugas | Contoh hasil |
|---|---|---|
slugify() | Mengubah teks menjadi slug URL | "Belajar Python Dasar!" → "belajar-python-dasar" |
hitung_kata() | Menghitung jumlah kata | "Belajar Python setiap hari" → 4 |
ringkas() | Memotong teks panjang | teks 42 karakter dipotong jadi 20 karakter |
Package ini tidak membutuhkan dependency eksternal — seluruh logikanya cukup memakai standard library re dan unicodedata. Desain tanpa dependency membuat siklus build dan testing nanti berjalan cepat dan bersih.
src Layout versus Layout Datar #
Chapter Membangun Python Package memperkenalkan dua gaya penempatan kode. Pada layout datar, folder package langsung berada di akar proyek; pada src layout, kode berada di dalam folder src. Kita memakai src layout dengan alasan yang berkaitan langsung dengan sys.path.
Saat kita menjalankan Python dari dalam folder proyek, interpreter Python memasukkan folder kerja ke sys.path — mekanisme yang dibahas tuntas pada Chapter Module Search Path. Akibatnya, pada layout datar perintah import example_package bisa lolos secara tidak sengaja meskipun package belum pernah dipasang. Bug yang hanya muncul di komputer pembuat library seperti itu paling sulit dilacak. Dengan src layout, import hanya berhasil jika package benar-benar dipasang atau folder src sengaja dimasukkan ke sys.path — sama seperti pengalaman pengguna package kita.
Membuat Struktur Folder #
Buat folder proyek beserta kerangkanya dari terminal:
mkdir -p paket-python-sederhana/src/example_package paket-python-sederhana/tests
cd paket-python-sederhanaHasil akhir proyek — termasuk tiga berkas yang baru dibuat pada bagian-bagian berikutnya — berbentuk seperti ini:
paket-python-sederhana/
├── pyproject.toml
├── README.md
├── src/
│ └── example_package/
│ └── __init__.py
└── tests/
└── test_package.pyBerkas __init__.py baru diisi pada Bagian 2 dan test_package.py pada Bagian 3; README.md baru dibutuhkan ketika melengkapi metadata pada Bagian 4.
pyproject.toml Awal #
Tabel [project] dan [build-system] sudah dibahas pada Chapter *pyproject.toml; berikut versi awal untuk proyek kita — simpan sebagai pyproject.toml` di akar proyek:
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
[project]
name = "example-package"
version = "0.1.0"
description = "Utilitas teks sederhana: slug URL, penghitung kata, dan peringkas teks"
requires-python = ">=3.10"
dependencies = []
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]Mari kita bedah baris-baris kuncinya:
- Baris 1-3 (
[build-system]…build-backend): menunjuk setuptools sebagai backend build — alat yang kelak mengubah foldersrc/menjadi wheel dan sdist pada Bagian 4. Syaratsetuptools>=61dipilih karena versi 61 adalah versi pertama yang membaca tabel[project]PEP 621. - Baris 6 (
name = "example-package"): distribution name — nama yang dipakai pengguna padapip install. Nama ini yang harus unik di PyPI kelak. - Baris 7 (
version = "0.1.0"): versi rilis pertama, mengikuti semantic versioning:MAJOR.MINOR.PATCH. - Baris 9 (
requires-python = ">=3.10"): pip menolak instalasi bila interpreter pengguna lebih tua dari Python 3.10. - Baris 10 (
dependencies = []): array kosong yang sah — package ini memang tidak butuh dependency, sehingga pengguna tidak men-download apa pun selain package kita. - Baris 12-14 (
[tool.pytest.ini_options]): konfigurasi pytest —testpathsmembatasi pencarian test ke foldertests, danpythonpathmemasukkan foldersrckesys.pathsaat test berjalan. Mekanisme lengkapnya dibahas pada Bagian 3.
Normalisasi Nama Package #
Perhatikan dua ejaan yang hidup berdampingan pada proyek ini:
| Jenis nama | Nilai | Di mana dipakai |
|---|---|---|
| Distribution name | example-package | pip install example-package, URL halaman PyPI |
| Import name | example_package | import example_package di kode Python |
Chapter Memahami Python Packages menjelaskan aturannya: distribution name bebas memakai tanda hubung, sedangkan import name harus merupakan identifier Python yang sah — dan tanda hubung bukan identifier sah. setuptools menjembatani keduanya secara otomatis: folder src/example_package/ dipetakan ke distribution name example-package, dan sebaliknya setiap tanda hubung pada distribution name dinormalisasi menjadi garis bawah pada nama berkas artefak — wheel hasil build nanti bernama example_package-0.1.0-py3-none-any.whl, bukan example-package-.... Aturan normalisasi ini akan terus muncul pada Bagian 4.
Kerangka proyek kini berdiri: folder siap, metadata tertulis, dan konvensi penamaan jelas. Berkas pyproject.toml lengkapnya dapat dilihat pada bagian Berkas Sumber di bawah halaman ini. Pada bagian berikutnya kita mengisi __init__.py dengan tiga function utilitas yang sesungguhnya.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
pyproject.toml
Unduh berkas[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
[project]
name = "example-package"
version = "0.1.0"
description = "Utilitas teks sederhana: slug URL, penghitung kata, dan peringkas teks"
requires-python = ">=3.10"
dependencies = []
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]