- Mahasiswa mampu mengimplementasikan alur tidak normal menggunakan mekanisme exception throwing (raise).
- Mahasiswa mampu mengimplementasikan penanganan error menggunakan konstruksi try–except(sertaelsedanfinallybila diperlukan).
- Mahasiswa mampu mengimplementasikan custom exception yang bermakna bagi domain masalah.
- Mahasiswa mampu melakukan exception chaining untuk memperkaya konteks error (opsional namun direkomendasikan).
- 
Platform: Python 3.10+ 
- 
Bahasa: Python 
- 
Editor/IDE: - VS Code + Python Extension
- Terminal
 
- 
Clone repositori project oop-exception-handling-pythonke direktori lokal Anda:git clone https://github.com/USERNAME/oop-exception-handling-python.git cd oop-exception-handling-python
- 
Buat & aktifkan virtual environment: python -m venv .venv source .venv/bin/activate # Linux/macOS .venv\Scripts\activate # Windows 
- 
Install dependensi: pip install -r requirements.txt 
- 
Jalankan unit test: pytest 
PERINGATAN: Push ke remote hanya jika seluruh unit test lulus (semua hijau).
Lokasi: src/bank_account/
Namespace (modul): bank_account
Buat exception yang mewarisi Exception:
- SaldoTidakCukupError→ pesan default:- "Saldo tidak mencukupi!"
- RekeningTidakDitemukanError→ pesan default:- "Rekening tidak ditemukan!"
- BatasPenarikanError→ pesan default:- "Melebihi batas penarikan harian."
Catatan: Sediakan opsi untuk mengisi pesan kustom pada
__init__, namun memiliki default message di atas.
- 
Atribut privat: - _nomor: str
- _saldo: float
 
- 
Konstanta kelas: BATAS_PENARIKAN_HARIAN = 100_000(dalam satuan yang konsisten, mis. rupiah).
- 
Metode: - 
penarikan(self, jumlah: float) -> None- Validasi jumlah > 0(jika tidak, raiseValueError("Jumlah penarikan harus > 0")).
- Jika jumlah > BATAS_PENARIKAN_HARIAN→ raiseBatasPenarikanError.
- Jika jumlah > _saldo→ raiseSaldoTidakCukupError.
- Jika valid → kurangi _saldo.
 
- Validasi 
- 
get_saldo(self) -> float
- 
get_nomor(self) -> str
 
- 
- 
Atribut: - _daftar: dict[str, Rekening](key = nomor rekening)
 
- 
Metode: - 
tambah_rekening(self, rek: Rekening) -> None- Tolak duplikasi nomor (jika duplikat, raise ValueError("Nomor rekening sudah ada")).
 
- Tolak duplikasi nomor (jika duplikat, raise 
- 
cari_rekening(self, nomor: str) -> Rekening- Jika tidak ada, raise RekeningTidakDitemukanError.
 
- Jika tidak ada, raise 
 
- 
- 
Tambah beberapa rekening. 
- 
Lakukan beberapa penarikan dalam blok try–exceptyang spesifik:- SaldoTidakCukupError
- BatasPenarikanError
- RekeningTidakDitemukanError
- Exception as e(fallback) → hanya untuk logging.
 
- 
Cetak saldo akhir tiap rekening di blok finally.
Kriteria Lulus (unit test inti):
- Menarik di atas saldo → SaldoTidakCukupError.
- Menarik di atas batas harian → BatasPenarikanError.
- Mencari rekening tak ada → RekeningTidakDitemukanError.
- Penarikan valid mengubah saldo dengan benar.
Lokasi: src/online_course/
Namespace (modul): online_course
- UsiaTidakMemenuhiSyaratError→- "Maaf, usia Anda tidak memenuhi syarat untuk mengikuti kursus ini."
- PendidikanTidakMemenuhiSyaratError→- "Maaf, tingkat pendidikan Anda tidak memenuhi syarat untuk mengikuti kursus ini."
- 
Atribut privat: - _nama: str
- _usia: int
- _tingkat_pendidikan: str
 
- 
Metode: - 
cek_kelayakan(self) -> None- Jika usia < 18→ raiseUsiaTidakMemenuhiSyaratError
- Jika tingkat_pendidikanbukan salah satu dari{"Sarjana", "Magister"}→ raisePendidikanTidakMemenuhiSyaratError
 
- Jika 
 
- 
- 
Atribut: - _peserta: list[Peserta]
 
- 
Metode: - 
daftar_peserta(self, peserta: Peserta) -> None- Panggil peserta.cek_kelayakan()
- Jika lolos → tambahkan ke daftar
 
- Panggil 
- 
get_daftar_peserta(self) -> list[Peserta]
 
- 
- 
Coba daftarkan beberapa peserta dalam loop: - Tangani exception menggunakan try–exceptsesuai tipe.
- Selalu cetak "Proses pendaftaran selesai."pada blokfinally(menandakan pendaftaran berhasil/gagal tetap menutup proses).
 
- Tangani exception menggunakan 
- 
Tampilkan nama peserta yang berhasil mendaftar di akhir. 
Kriteria Lulus (unit test inti):
- Usia < 18 → UsiaTidakMemenuhiSyaratError.
- Pendidikan tidak termasuk ketentuan → PendidikanTidakMemenuhiSyaratError.
- Peserta valid masuk ke daftar.
- finallydieksekusi (bisa dites via spy pada- stdoutatau flag internal).
Lokasi: src/medical_record/
Namespace (modul): medical_record
- DataTidakLengkapError→- "Data pasien tidak lengkap."
- DataTidakValidError→- "Data yang dimasukkan tidak valid."
- 
Atribut: - _nama: str
- _umur: int
- _alamat: str
 
- 
Metode: - 
validasi_data(self) -> None- Jika nama.strip() == ""ataualamat.strip() == ""→ raiseDataTidakLengkapError
- Jika umur < 0atauumur > 120→ raiseDataTidakValidError
 
- Jika 
 
- 
- 
Metode: - 
periksa_data(self, pasien: Pasien) -> str- 
Gunakan trymemanggilpasien.validasi_data()
- 
Jika terjadi exception: - 
Tangkap DataTidakLengkapErroratauDataTidakValidError
- 
Rethrow (melempar ulang) dengan pesan yang lebih spesifik, gunakan chaining: - 
Contoh: except DataTidakLengkapError as e: raise DataTidakLengkapError("Validasi gagal: nama/alamat kosong.") from e 
 
- 
 
- 
- 
Jika lolos, kembalikan string ringkas status, mis. "Data pasien valid"
 
- 
 
- 
- 
Buat beberapa instans Pasien(valid & tidak valid).
- 
Panggil Pemeriksaan.periksa_data()dalamtry–except:- Cetak pesan error spesifik dari hasil rethrow.
- Tunjukkan perbedaan pesan asli vs pesan baru (bisa log __cause__).
 
Kriteria Lulus (unit test inti):
- Nama/alamat kosong → DataTidakLengkapErrordengan pesan diperbarui (cekstr(e)).
- Umur di luar rentang → DataTidakValidErrordengan pesan diperbarui.
- Chaining menautkan penyebab (e.__cause__bukanNone).
- Pasien valid → mengembalikan "Data pasien valid".
Lokasi: src/ticket_booking/
Namespace (modul): ticket_booking
- KapasitasPenuhError→- "Kursi sudah penuh, tidak dapat memproses pemesanan."
- TiketSudahDipesanError→- "Tiket untuk penumpang ini sudah dipesan."
- NomorTiketTidakDitemukanError→- "Nomor tiket tidak ditemukan dalam sistem."
Semua turunan dari Exception.
- 
Atribut privat: - _nama: str
- _nomor_identitas: str
 
- 
Metode: - get_identitas(self) -> str
- get_nama(self) -> str
 
- 
Atribut: - _kapasitas: int
- _data_tiket: dict[str, Penumpang](key =- nomor_tiket)
 
- 
Metode: - 
__init__(self, kapasitas: int)→ inisialisasi dictionary kosong.
- 
pesan_tiket(self, nomor_tiket: str, penumpang: Penumpang) -> None- Jika jumlah tiket sudah mencapai kapasitas → raise KapasitasPenuhError.
- Jika nomor_tiketsudah ada → raiseTiketSudahDipesanError.
- Jika valid → tambahkan ke _data_tiket.
 
- Jika jumlah tiket sudah mencapai kapasitas → raise 
- 
batalkan_tiket(self, nomor_tiket: str) -> None- Jika nomor tidak ditemukan → raise NomorTiketTidakDitemukanError.
- Jika ditemukan → hapus tiket dari dictionary.
 
- Jika nomor tidak ditemukan → raise 
- 
get_jumlah_terpesan(self) -> int
- 
get_kapasitas(self) -> int
 
- 
- 
Buat instance PemesananTiket(kapasitas=3).
- 
Coba lakukan beberapa pemesanan: - Berhasil menambah 3 penumpang.
- Pesanan ke-4 → KapasitasPenuhError.
- Ulangi pemesanan dengan nomor tiket sama → TiketSudahDipesanError.
 
- 
Tangani semua exception spesifik dengan try–except.
- 
Gunakan finallyuntuk mencetak ringkasan:Jumlah tiket terpesan: X dari Y Proses pemesanan selesai.
Fokus: kombinasi validasi, exception spesifik, cleanup/reporting dengan finally.
Kriteria Lulus (unit test inti):
- Kapasitas melebihi → KapasitasPenuhError.
- Tiket duplikat → TiketSudahDipesanError.
- Pembatalan tiket salah → NomorTiketTidakDitemukanError.
- Pemesanan valid menambah entri.
Lokasi: src/extra/extra.py
Mahasiswa diminta membuat studi kasus sendiri menggunakan prinsip exception handling Python yang telah dipelajari.
- 
Minimal 2 custom exception. 
- 
Harus menggunakan try–except dan raise. 
- 
Salah satu fungsi harus menggunakan raise ... from e (chaining). 
- 
Harus ada demo dengan output error yang jelas & blok finallyyang menunjukkan bahwa program tetap berakhir normal.
- 
Buat file extra.pyberisi seluruh implementasi dan contoh demo:if __name__ == "__main__": # buat beberapa skenario error dan tangani 
=== Selesai ===