mypy
mypy memeriksa kecocokan tipe tanpa menjalankan kode. Ini pemasangan dan konfigurasi awal yang perlu kamu siapkan.
Intisari
- mypy membaca type hint dan menemukan bug sebelum kode dijalankan โ tidak ada dampak ke runtime.
- Type hint di Python bersifat opsional dan tidak dicek saat program jalan. mypy-lah yang mengeceknya.
- Jalankan dengan
uvx mypy .โ tidak perlu ditambahkan sebagai dependency proyek. - Mulai dari mode longgar, naikkan ketat secara bertahap. Jangan langsung
--strictdi hari pertama. - Yang paling sering ditangkap:
Noneyang tidak diperiksa, salah tipe argumen, dan atribut yang tidak ada.
Apa yang sebenarnya dilakukan mypy
Python tidak memeriksa type hint saat program berjalan. Kode ini jalan mulus sampai meledak di baris ketiga:
def sapa(nama: str) -> str:
return "Halo " + nama
sapa(42) # Python: diam saja sampai runtime โ TypeError
mypy membaca file yang sama tanpa menjalankannya, dan langsung melapor:
error: Argument 1 to "sapa" has incompatible type "int"; expected "str" [arg-type]
Jadi type hint punya dua konsumen berbeda:
- Manusia & editor โ autocomplete, dokumentasi hidup, refactor yang aman
- mypy โ pengecekan otomatis yang menangkap bug sebelum ada yang menjalankan kodenya
Pemakaian
uvx mypy . # cek seluruh proyek
uvx mypy src/ # satu folder
uvx mypy src/llm.py # satu file
Pakai uvx, bukan uv add --dev mypy. mypy adalah tool, bukan sesuatu yang
kodemu impor. Kecuali kamu butuh versinya terkunci untuk CI โ baru masukkan ke grup dev.
Konfigurasi bertahap
Taruh di pyproject.toml. Mulai dari sini:
Tahap 1 โ sekarang (Fase 0โ1)
[tool.mypy]
python_version = "3.13"
warn_unused_ignores = true
warn_redundant_casts = true
Ringan. Hanya mengecek kode yang sudah punya type hint, tidak memaksa apa-apa.
Tahap 2 โ mulai Fase 2
[tool.mypy]
python_version = "3.13"
strict = true
[[tool.mypy.overrides]]
module = ["chromadb.*", "beberapa_lib_tanpa_stub.*"]
ignore_missing_imports = true
strict = true menyalakan sekitar sepuluh flag sekaligus โ yang terpenting:
fungsi tanpa anotasi jadi error, dan Any implisit tidak diizinkan.
Blok overrides diperlukan karena beberapa library pihak ketiga belum menyertakan
informasi tipe; tanpa itu mypy akan mengeluh soal import.
Tiga error yang paling sering muncul
1. Nilai bisa None tapi tidak diperiksa
def cari(id: str) -> Dokumen | None: ...
d = cari("abc")
print(d.judul) # error: Item "None" of "Dokumen | None" has no attribute "judul"
Perbaikannya adalah memeriksanya โ dan itu memang bug nyata yang baru saja dicegah:
d = cari("abc")
if d is None:
raise DokumenTidakDitemukan("abc")
print(d.judul) # aman: mypy tahu d pasti Dokumen di sini
2. Fungsi tanpa anotasi (mode strict)
error: Function is missing a type annotation [no-untyped-def]
Tambahkan anotasi. Untuk fungsi yang tidak mengembalikan apa-apa, tulis -> None secara eksplisit.
3. Library tanpa informasi tipe
error: Skipping analyzing "chromadb": module is installed, but missing library stubs
Dua kemungkinan solusi:
uv add --dev types-requests # kalau ada paket stub resminya
# kalau tidak ada โ daftarkan di overrides seperti contoh Tahap 2 di atas
Kabur dari mypy (seperlunya)
hasil = fungsi_aneh() # type: ignore[no-any-return]
from typing import cast
x = cast(Dokumen, data_mentah) # "percaya saja, ini Dokumen"
Selalu sertakan kode errornya di dalam kurung siku. # type: ignore polos
mematikan semua pengecekan di baris itu โ termasuk error baru yang muncul nanti karena
perubahan yang tidak kamu sadari. Flag warn_unused_ignores akan memberi tahu kalau
ada ignore yang sudah tidak diperlukan.
Di CI
uvx mypy . --no-error-summary # exit code non-nol kalau ada error
Yang perlu diingat
Di Fase 0 kamu cukup memasang mypy dan tahu cara menjalankannya. Type hint yang sebenarnya โ
sintaks modern, generic, Protocol, Literal โ dibahas tuntas di
Fase 2. Checkpoint fase itu adalah uvx mypy . lolos tanpa error.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.