Project Python hampir selalu dimulai dari satu file main.py. Masalah baru muncul ketika file tersebut membesar: modul helper bertambah, test tersebar, dan tidak jelas kode mana yang benar-benar dikirim ke pengguna. Struktur folder yang rapi menyelesaikan masalah ini sejak hari pertama — import menjadi jujur, test mudah ditemukan, dan langkah build maupun deployment tinggal mengikuti pola baku. Pada chapter ini kita merancang struktur project dari nol.
Flat Layout versus src Layout #
Kode package dapat ditaruh langsung di akar project (flat layout) atau di dalam folder src/ (src layout). Perbandingan keduanya:
# Flat layout
toko-api/
├── pyproject.toml
├── README.md
└── toko_api/
├── __init__.py
└── main.py# src layout
toko-api/
├── pyproject.toml
├── README.md
└── src/
└── toko_api/
├── __init__.py
└── main.pyChapter Membangun Python Package sudah memperkenalkan src layout untuk package. Untuk project utuh, keunggulan src layout terasa lebih besar. Folder kerja secara default masuk ke sys.path (perilaku yang dibahas pada Chapter Module Search Path), sehingga pada flat layout perintah import toko_api bisa lolos dari folder akar meski package belum terpasang di virtual environment. Test lalu menguji kode folder lokal, bukan kode yang benar-benar dipasang pip — celah inilah yang ditutup oleh folder src/.
Klaim tersebut mudah dibuktikan. Dari akar project src layout, sebelum package dipasang, coba import langsung:
python -c "import toko_api"Output yang Dihasilkan:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'toko_api'Interpreter Python tidak menemukan toko_api karena folder src/ tidak berada di sys.path — dan justru itulah perilaku yang kita inginkan. Setelah pip install -e ., import yang sama berhasil tanpa kita mengutak-atik path.
Di Mana Tests dan Docs Berada #
Folder tests/ ditempatkan di akar project, sejajar dengan src/, bukan di dalam package. Alasannya: test bukan bagian dari kode yang dikirim ke pengguna, jadi test tidak perlu ikut terpasang ke site-packages. Pola yang sama berlaku untuk folder lain:
| Folder | Isi | Ikut terpasang ke pengguna? |
|---|---|---|
src/toko_api/ | kode package utama | ya |
tests/ | test otomatis (pytest) | tidak |
docs/ | dokumentasi desain, arsitektur | tidak |
dist/ | hasil build (Chapter Membangun Wheel dan sdist) | tidak, artefak saja |
Berkas konfigurasi seperti pyproject.toml berada di akar project agar tool pip, build, dan ruff dapat menemukannya tanpa konfigurasi tambahan.
Satu Module atau Satu Package? #
Project kecil boleh berupa satu module .py tunggal; project yang tumbuh perlu menjadi package (folder dengan __init__.py). Panduan praktisnya:
| Kondisi | Bentuk yang cocok |
|---|---|
| Satu file cukup, tanpa sub-komponen | satu module di dalam src/ |
| Ada beberapa domain (routers, models, service) | package dengan subpackage |
| Ingin mengekspor entry point CLI | package (agar bisa memuat modul bagian dalam) |
Mengubah satu module menjadi package nanti tidak menyakitkan bila kita sudah memakai src layout — cukup pindahkan util.py menjadi src/util/__init__.py.
Konvensi Penamaan #
Dua nama berbeda hidup dalam satu project: distribution name untuk tooling (pip, PyPI) memakai kebab-case, sedangkan import name untuk folder package memakai snake_case. Tanda hubung tidak boleh ada di import name karena tidak sah sebagai identifier Python. Contoh pasangan yang benar: distribution toko-api, import toko_api; perbedaan ini dibahas lebih dalam pada Chapter Memahami Python Packages.
Contoh Struktur Utuh #
Berikut struktur lengkap sebuah project API kecil bernama toko-api:
toko-api/
├── .env.example
├── .gitignore
├── LICENSE
├── README.md
├── pyproject.toml
├── docs/
│ └── arsitektur.md
├── src/
│ └── toko_api/
│ ├── __init__.py
│ ├── main.py
│ └── routers/
│ ├── __init__.py
│ └── produk.py
└── tests/
├── __init__.py
└── test_produk.pyMari kita telaah peran setiap elemen penting:
pyproject.toml: sumber tunggal metadata dan dependencies, dibedah tuntas pada chapter berikutnya.src/toko_api/routers/: subpackage untuk memisahkan kode per-domain; pola ini lazim pada aplikasi FastAPI (Chapter Membuat API dengan FastAPI).tests/test_produk.py: penamaantest_*.pymembuat pytest menemukan test tanpa konfigurasi.docs/: catatan desain yang tidak dikirim ke pengguna, tetapi menyelamatkan tim di masa depan..env.example: daftar variabel environment tanpa nilai rahasia — konsepnya dibahas pada Chapter Environment Configuration.
README, LICENSE, dan .gitignore #
Tiga berkas kecil di akar project menentukan kesan pertama dan kebersihan repository. README.md minimal menjawab tiga pertanyaan: apa project ini, cara memasangnya, dan cara menjalankannya. LICENSE memuat teks lisensi (misalnya MIT) sesuai SPDX yang dideklarasikan di pyproject.toml. .gitignore mencegah berkas sampah masuk ke Git:
.venv/
__pycache__/
*.pyc
dist/
build/
*.egg-info/
.envEntri .env pada daftar tersebut penting: berkas .env berisi nilai konfigurasi lokal dan berpotensi memuat secret, sehingga tidak boleh ikut tercommit — hanya .env.example yang aman dibagikan.
Dengan struktur yang rapi, kita siap mengisi pyproject.toml — jantung metadata project — pada chapter berikutnya.