From a08490cfdc53e863465d01940ad7edde48d978e9 Mon Sep 17 00:00:00 2001 From: maulana saputra Date: Wed, 8 Apr 2020 10:52:10 +0700 Subject: [PATCH] Tambahkan fitur saran entri lain yang mirip --- .pre-commit-config.yaml | 1 + README.md | 9 + src/kbbi/kbbi.py | 34 +- tests/_mock.py | 23 +- tests/buat_kasus.py | 11 +- tests/conftest.py | 6 +- tests/html/auth/entri/huk.html | 299 ++++++++++++++++++ tests/html/auth/entri/idn45.html | 180 +++++++++++ tests/html/nonauth/entri/huk.html | 167 ++++++++++ tests/html/nonauth/entri/idn45.html | 167 ++++++++++ tests/kasus/auth/serialisasi/huk.json | 35 ++ tests/kasus/auth/serialisasi/idn45.json | 4 + tests/kasus/auth/str/huk.txt | 2 + tests/kasus/auth/str/idn45.txt | 1 + tests/kasus/auth/str_tanpa_contoh/huk.txt | 2 + tests/kasus/auth/str_tanpa_contoh/idn45.txt | 1 + tests/kasus/nonauth/serialisasi/huk.json | 4 + tests/kasus/nonauth/serialisasi/idn45.json | 4 + tests/kasus/nonauth/str/huk.txt | 1 + tests/kasus/nonauth/str/idn45.txt | 1 + tests/kasus/nonauth/str_tanpa_contoh/huk.txt | 1 + .../kasus/nonauth/str_tanpa_contoh/idn45.txt | 1 + tests/test_cli.py | 48 +++ 23 files changed, 986 insertions(+), 16 deletions(-) create mode 100644 tests/html/auth/entri/huk.html create mode 100644 tests/html/auth/entri/idn45.html create mode 100644 tests/html/nonauth/entri/huk.html create mode 100644 tests/html/nonauth/entri/idn45.html create mode 100644 tests/kasus/auth/serialisasi/huk.json create mode 100644 tests/kasus/auth/serialisasi/idn45.json create mode 100644 tests/kasus/auth/str/huk.txt create mode 100644 tests/kasus/auth/str/idn45.txt create mode 100644 tests/kasus/auth/str_tanpa_contoh/huk.txt create mode 100644 tests/kasus/auth/str_tanpa_contoh/idn45.txt create mode 100644 tests/kasus/nonauth/serialisasi/huk.json create mode 100644 tests/kasus/nonauth/serialisasi/idn45.json create mode 100644 tests/kasus/nonauth/str/huk.txt create mode 100644 tests/kasus/nonauth/str/idn45.txt create mode 100644 tests/kasus/nonauth/str_tanpa_contoh/huk.txt create mode 100644 tests/kasus/nonauth/str_tanpa_contoh/idn45.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91ea425..334c690 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,4 @@ repos: rev: "4.3.21-2" hooks: - id: isort + args: [-sg **/*.txt] diff --git a/README.md b/README.md index e651f29..605f286 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,15 @@ Etimologi: [Arab] (n) (sg) (f/m) رُوْحٌ rūh: tiupan; sesuatu yang membua Gabungan Kata roh Kudus; roh suci ``` +Fitur khusus pengguna untuk memanfaatkan fitur saran entri yang mirip apabila entri tidak dapat ditemukan. + +```python +>>> auth = AutentikasiKBBI("posel@saya.tld", "password_saya") +>>> huk = KBBI("huk", auth) +>>> print(roh) +Berikut beberapa saran entri lain yang mirip. +auk; buk (1); buk (2); cuk; duk; hak (1); hak (2); hak (3); hak (4); huh; hun; hus; Hut; kuk (1); kuk (2); luk; muk; suk; tuk (1); yuk (1); yuk (2); DUK; HUT; KUK; UK; hub (2); Hud; tuk (2); guk +``` Fitur khusus pengguna yang didukung saat ini adalah etimologi, entri terkait (kata turunan, gabungan kata, peribahasa, dan idiom), dan batas pencarian yang diff --git a/src/kbbi/kbbi.py b/src/kbbi/kbbi.py index 09c92a1..533d941 100644 --- a/src/kbbi/kbbi.py +++ b/src/kbbi/kbbi.py @@ -38,6 +38,8 @@ def __init__(self, kueri, auth=None): :type auth: AutentikasiKBBI """ self.nama = kueri + self.entri = [] + self.saran_entri = None self._init_lokasi() self._init_sesi(auth) laman = self.sesi.get(f"{self.host}/{self.lokasi}") @@ -74,12 +76,20 @@ def _cek_galat(self, laman): if "Beranda/BatasSehari" in laman.url: raise BatasSehari() if "Entri tidak ditemukan." in laman.text: - raise TidakDitemukan(self.nama) + self._init_saran(laman) + raise TidakDitemukan(self.nama, objek=self) + + def _init_saran(self, laman): + if "Berikut beberapa saran entri lain yang mirip." not in laman.text: + return + sup = BeautifulSoup(laman.text, "html.parser") + self.saran_entri = [ + saran.text.strip() for saran in sup.find_all(class_="col-md-3") + ] def _init_entri(self, laman): sup = BeautifulSoup(laman.text, "html.parser") estr = "" - self.entri = [] label = sup.find("hr").next_sibling while not (label.name == "hr" and label.get("style") is None): if label.name == "h2": @@ -99,14 +109,22 @@ def serialisasi(self, fitur_pengguna=True): :returns: Dictionary hasil serialisasi :rtype: dict """ - return { + kbbi = { "pranala": f"{self.host}/{self.lokasi}", "entri": [ entri.serialisasi(fitur_pengguna) for entri in self.entri ], } + if self.saran_entri and fitur_pengguna: + kbbi["saran_entri"] = self.saran_entri + return kbbi def __str__(self, contoh=True, terkait=True, fitur_pengguna=True): + if self.saran_entri and fitur_pengguna: + return ( + "Berikut beberapa saran entri lain yang mirip.\n" + f"{', '.join(self.saran_entri)}" + ) return "\n\n".join( entri.__str__(contoh, terkait, fitur_pengguna) for entri in self.entri @@ -558,8 +576,9 @@ class Galat(Exception): class TidakDitemukan(Galat): """Galat ketika laman tidak ditemukan dalam KBBI.""" - def __init__(self, kueri): + def __init__(self, kueri, objek=None): super().__init__(f"{kueri} tidak ditemukan dalam KBBI.") + self.objek = objek class TerjadiKesalahan(Galat): @@ -787,6 +806,13 @@ def main(argv=None): return 1 try: laman = KBBI(args.laman, auth) + except TidakDitemukan as e: + laman = e.objek + if not args.json: + print(e) + if laman.saran_entri or args.json: + print(_keluaran(laman, args)) + return 1 except Galat as e: print(e) return 1 diff --git a/tests/_mock.py b/tests/_mock.py index e812854..55642cb 100644 --- a/tests/_mock.py +++ b/tests/_mock.py @@ -1,18 +1,31 @@ -from kbbi import KBBI, AutentikasiKBBI, GagalAutentikasi +from kbbi import KBBI, AutentikasiKBBI, GagalAutentikasi, TidakDitemukan class MockKBBI(KBBI): host = "http://localhost:8000" _host = KBBI.host - lokasi = None def __init__(self, kueri, auth=None, lokasi=None): self._auth = auth - self.lokasi = self.lokasi or lokasi + self._lokasi = lokasi + self.lokasi = lokasi super().__init__(kueri, auth) + + def _cek_autentikasi(self, laman): + super()._cek_autentikasi(laman) + self._kembalikan_host_lokasi() + + def _kembalikan_host_lokasi(self): self.host = self._host - if lokasi is None: - self.lokasi = self._lokasi + self.lokasi = self._lokasi + + @classmethod + def _init_aman(cls, kueri, auth=None, lokasi=None): + try: + return cls(kueri, auth, lokasi) + except TidakDitemukan as e: + e.objek._kembalikan_host_lokasi() + return e.objek def _init_lokasi(self): if self.lokasi is not None: diff --git a/tests/buat_kasus.py b/tests/buat_kasus.py index 99a70e6..6042f11 100755 --- a/tests/buat_kasus.py +++ b/tests/buat_kasus.py @@ -35,6 +35,8 @@ "sage", # terdapat info (bahasa latin) "semakin", # terdapat entri tanpa makna dan entri lain berupa rujukan "tampak", # terdapat rujukan dengan nomor + "huk", # saran entri lain yang mirip apabila entri tidak dapat ditemukan + "idn45", # tidak ditemukan dan tidak ada saran entri lain yang mirip ] @@ -124,15 +126,14 @@ def buat_semua_objek(daftar): auth = MockAutentikasiKBBI("foo", "bar") semua = {"auth": [], "nonauth": []} for laman in daftar: - semua["auth"].append(MockKBBI(laman, auth)) - semua["nonauth"].append(MockKBBI(laman)) + semua["auth"].append(MockKBBI._init_aman(laman, auth)) + semua["nonauth"].append(MockKBBI._init_aman(laman)) return semua def buat_semua_kasus(semua, jenis): - for laman, objek in semua.items(): - for buat in jenis: - buat(semua) + for buat in jenis: + buat(semua) def main(daftar=None): diff --git a/tests/conftest.py b/tests/conftest.py index 134e4e8..920cfeb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,14 +47,16 @@ def ambil_atau_simpan(dct, key, func): @pytest.fixture def aktual_objek(request, laman): kueri = request.param - return ambil_atau_simpan(laman, kueri, lambda a: MockKBBI(a)) + return ambil_atau_simpan(laman, kueri, lambda a: MockKBBI._init_aman(a)) @pytest.fixture def aktual_objek_terautentikasi(request, autentikasi, laman_terautentikasi): kueri = request.param return ambil_atau_simpan( - laman_terautentikasi, kueri, lambda a: MockKBBI(a, autentikasi) + laman_terautentikasi, + kueri, + lambda a: MockKBBI._init_aman(a, autentikasi), ) diff --git a/tests/html/auth/entri/huk.html b/tests/html/auth/entri/huk.html new file mode 100644 index 0000000..5d684a2 --- /dev/null +++ b/tests/html/auth/entri/huk.html @@ -0,0 +1,299 @@ + + + + + + + + Hasil Pencarian - KBBI Daring + + + + + + + +
+ + + + + + + +
+ +
+

+ + Halo sage! + Sudahkah Anda mengecek halaman manajemen akun Anda? + Anda dapat melihat cara membukanya di sini. + Jika Anda pernah mengajukan usulan-usulan, + mungkin usulan-usulan tersebut telah diproses oleh redaksi kami. +

+
+
+ +
+
+
+
+ + + + +
+
+
+

+ +
+ +
+

huk

+

Entri tidak ditemukan.

+

+ Jika Anda mengetahui makna entri [huk], silakan memberikan usulan kepada redaksi melalui tautan di bawah (bertuliskan Usulkan Entri Baru). + Usulan Anda akan langsung masuk ke meja redaksi. Jika usulan Anda telah diluluskan, usulan tersebut akan ditemukan di dalam KBBI Daring. +

+
+

Berikut beberapa saran entri lain yang mirip.

+
+ auk + +
+
+ buk (1) + +
+
+ buk (2) + +
+
+ cuk + +
+
+ duk + +
+
+ hak (1) + +
+
+ hak (2) + +
+
+ hak (3) + +
+
+ hak (4) + +
+
+ huh + +
+
+ hun + +
+
+ hus + +
+
+ Hut + +
+
+ kuk (1) + +
+
+ kuk (2) + +
+
+ luk + +
+
+ muk + +
+
+ suk + +
+
+ tuk (1) + +
+
+ yuk (1) + +
+
+ yuk (2) + +
+
+ DUK + +
+
+ HUT + +
+
+ KUK + +
+
+ UK + +
+
+ hub (2) + +
+
+ Hud + +
+
+ tuk (2) + +
+
+ guk + +
+

+

+ + + + Usulkan entri baru + +

+ +
+ + +
+ + + + + + + + + + + + + diff --git a/tests/html/auth/entri/idn45.html b/tests/html/auth/entri/idn45.html new file mode 100644 index 0000000..c72b1d7 --- /dev/null +++ b/tests/html/auth/entri/idn45.html @@ -0,0 +1,180 @@ + + + + + + + + Hasil Pencarian - KBBI Daring + + + + + + + +
+ + + + + + + +
+ +
+

+ + Halo sage! + Sudahkah Anda mengecek halaman manajemen akun Anda? + Anda dapat melihat cara membukanya di sini. + Jika Anda pernah mengajukan usulan-usulan, + mungkin usulan-usulan tersebut telah diproses oleh redaksi kami. +

+
+
+ +
+
+
+
+ + + + +
+
+
+

+ +
+ +
+

idn45

+

Entri tidak ditemukan.

+

+ Jika Anda mengetahui makna entri [idn45], silakan memberikan usulan kepada redaksi melalui tautan di bawah (bertuliskan Usulkan Entri Baru). + Usulan Anda akan langsung masuk ke meja redaksi. Jika usulan Anda telah diluluskan, usulan tersebut akan ditemukan di dalam KBBI Daring. +

+

+ + + + Usulkan entri baru + +

+ +
+ + +
+ + + + + + + + + + + + + diff --git a/tests/html/nonauth/entri/huk.html b/tests/html/nonauth/entri/huk.html new file mode 100644 index 0000000..cb10f5c --- /dev/null +++ b/tests/html/nonauth/entri/huk.html @@ -0,0 +1,167 @@ + + + + + + + + Hasil Pencarian - KBBI Daring + + + + + + + +
+ + + + + +
+ +
+

+ + Informasi: Temukan bantuan menggunakan KBBI Daring di sini. +

+
+
+ +
+
+
+
+ + + + +
+
+
+

+ +
+ +
+

huk

+

Entri tidak ditemukan.

+

+ Jika Anda mengetahui makna entri [huk], silakan memberikan usulan kepada redaksi melalui tautan di bawah (bertuliskan Usulkan Entri Baru). + Usulan Anda akan langsung masuk ke meja redaksi. Jika usulan Anda telah diluluskan, usulan tersebut akan ditemukan di dalam KBBI Daring. +

+
+

Pesan Redaksi

+

Untuk memberikan masukan/usulan pada KBBI Daring, Anda perlu masuk menggunakan akun yang terdaftar dalam laman KBBI Daring.

+

Jika Anda belum memiliki akun yang terdaftar, silakan mendaftar melalui tautan ini.

+

Mendaftar dalam laman KBBI Daring akan

+ + +
+ + +
+ + + + + + + + + + + + + diff --git a/tests/html/nonauth/entri/idn45.html b/tests/html/nonauth/entri/idn45.html new file mode 100644 index 0000000..2483be1 --- /dev/null +++ b/tests/html/nonauth/entri/idn45.html @@ -0,0 +1,167 @@ + + + + + + + + Hasil Pencarian - KBBI Daring + + + + + + + +
+ + + + + +
+ +
+

+ + Informasi: Temukan bantuan menggunakan KBBI Daring di sini. +

+
+
+ +
+
+
+
+ + + + +
+
+
+

+ +
+ +
+

idn45

+

Entri tidak ditemukan.

+

+ Jika Anda mengetahui makna entri [idn45], silakan memberikan usulan kepada redaksi melalui tautan di bawah (bertuliskan Usulkan Entri Baru). + Usulan Anda akan langsung masuk ke meja redaksi. Jika usulan Anda telah diluluskan, usulan tersebut akan ditemukan di dalam KBBI Daring. +

+
+

Pesan Redaksi

+

Untuk memberikan masukan/usulan pada KBBI Daring, Anda perlu masuk menggunakan akun yang terdaftar dalam laman KBBI Daring.

+

Jika Anda belum memiliki akun yang terdaftar, silakan mendaftar melalui tautan ini.

+

Mendaftar dalam laman KBBI Daring akan

+ + +
+ + +
+ + + + + + + + + + + + + diff --git a/tests/kasus/auth/serialisasi/huk.json b/tests/kasus/auth/serialisasi/huk.json new file mode 100644 index 0000000..bdbf7f3 --- /dev/null +++ b/tests/kasus/auth/serialisasi/huk.json @@ -0,0 +1,35 @@ +{ + "pranala": "https://kbbi.kemdikbud.go.id/entri/huk", + "entri": [], + "saran_entri": [ + "auk", + "buk (1)", + "buk (2)", + "cuk", + "duk", + "hak (1)", + "hak (2)", + "hak (3)", + "hak (4)", + "huh", + "hun", + "hus", + "Hut", + "kuk (1)", + "kuk (2)", + "luk", + "muk", + "suk", + "tuk (1)", + "yuk (1)", + "yuk (2)", + "DUK", + "HUT", + "KUK", + "UK", + "hub (2)", + "Hud", + "tuk (2)", + "guk" + ] +} diff --git a/tests/kasus/auth/serialisasi/idn45.json b/tests/kasus/auth/serialisasi/idn45.json new file mode 100644 index 0000000..6601eeb --- /dev/null +++ b/tests/kasus/auth/serialisasi/idn45.json @@ -0,0 +1,4 @@ +{ + "pranala": "https://kbbi.kemdikbud.go.id/entri/idn45", + "entri": [] +} diff --git a/tests/kasus/auth/str/huk.txt b/tests/kasus/auth/str/huk.txt new file mode 100644 index 0000000..d906981 --- /dev/null +++ b/tests/kasus/auth/str/huk.txt @@ -0,0 +1,2 @@ +Berikut beberapa saran entri lain yang mirip. +auk, buk (1), buk (2), cuk, duk, hak (1), hak (2), hak (3), hak (4), huh, hun, hus, Hut, kuk (1), kuk (2), luk, muk, suk, tuk (1), yuk (1), yuk (2), DUK, HUT, KUK, UK, hub (2), Hud, tuk (2), guk diff --git a/tests/kasus/auth/str/idn45.txt b/tests/kasus/auth/str/idn45.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/kasus/auth/str/idn45.txt @@ -0,0 +1 @@ + diff --git a/tests/kasus/auth/str_tanpa_contoh/huk.txt b/tests/kasus/auth/str_tanpa_contoh/huk.txt new file mode 100644 index 0000000..d906981 --- /dev/null +++ b/tests/kasus/auth/str_tanpa_contoh/huk.txt @@ -0,0 +1,2 @@ +Berikut beberapa saran entri lain yang mirip. +auk, buk (1), buk (2), cuk, duk, hak (1), hak (2), hak (3), hak (4), huh, hun, hus, Hut, kuk (1), kuk (2), luk, muk, suk, tuk (1), yuk (1), yuk (2), DUK, HUT, KUK, UK, hub (2), Hud, tuk (2), guk diff --git a/tests/kasus/auth/str_tanpa_contoh/idn45.txt b/tests/kasus/auth/str_tanpa_contoh/idn45.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/kasus/auth/str_tanpa_contoh/idn45.txt @@ -0,0 +1 @@ + diff --git a/tests/kasus/nonauth/serialisasi/huk.json b/tests/kasus/nonauth/serialisasi/huk.json new file mode 100644 index 0000000..e1d8877 --- /dev/null +++ b/tests/kasus/nonauth/serialisasi/huk.json @@ -0,0 +1,4 @@ +{ + "pranala": "https://kbbi.kemdikbud.go.id/entri/huk", + "entri": [] +} diff --git a/tests/kasus/nonauth/serialisasi/idn45.json b/tests/kasus/nonauth/serialisasi/idn45.json new file mode 100644 index 0000000..6601eeb --- /dev/null +++ b/tests/kasus/nonauth/serialisasi/idn45.json @@ -0,0 +1,4 @@ +{ + "pranala": "https://kbbi.kemdikbud.go.id/entri/idn45", + "entri": [] +} diff --git a/tests/kasus/nonauth/str/huk.txt b/tests/kasus/nonauth/str/huk.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/kasus/nonauth/str/huk.txt @@ -0,0 +1 @@ + diff --git a/tests/kasus/nonauth/str/idn45.txt b/tests/kasus/nonauth/str/idn45.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/kasus/nonauth/str/idn45.txt @@ -0,0 +1 @@ + diff --git a/tests/kasus/nonauth/str_tanpa_contoh/huk.txt b/tests/kasus/nonauth/str_tanpa_contoh/huk.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/kasus/nonauth/str_tanpa_contoh/huk.txt @@ -0,0 +1 @@ + diff --git a/tests/kasus/nonauth/str_tanpa_contoh/idn45.txt b/tests/kasus/nonauth/str_tanpa_contoh/idn45.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/kasus/nonauth/str_tanpa_contoh/idn45.txt @@ -0,0 +1 @@ + diff --git a/tests/test_cli.py b/tests/test_cli.py index 95df5ba..79e6c16 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -199,3 +199,51 @@ def test_program_utama_lokasi_kuki_tidak_ada(capsys, kbbi_mock, tanpa_kuki): tangkap = capsys.readouterr() assert tangkap.out == "Kuki tidak ditemukan pada kukiku.json!\n" assert hasil == 1 + + +@pytest.mark.parametrize( + "kbbi_mock,lokasi", [("auth", "kasus/auth/str/huk.txt")], indirect=True +) +def test_tidak_ditemukan_ada_saran(capsys, kbbi_mock, lokasi): + hasil = kbbi.main(["huk"]) + tangkap = capsys.readouterr() + assert tangkap.out == ( + f"huk tidak ditemukan dalam KBBI.\n{lokasi.read_text()}" + ) + assert hasil == 1 + + +@pytest.mark.parametrize( + "kbbi_mock,lokasi", [("auth", "kasus/auth/str/idn45.txt")], indirect=True +) +def test_tidak_ditemukan_tidak_ada_saran(capsys, kbbi_mock, lokasi): + hasil = kbbi.main(["idn45"]) + tangkap = capsys.readouterr() + assert tangkap.out == ( + f"idn45 tidak ditemukan dalam KBBI.\n{lokasi.read_text()[:-1]}" + ) + assert hasil == 1 + + +@pytest.mark.parametrize( + "kbbi_mock,lokasi", + [("auth", "kasus/auth/serialisasi/huk.json")], + indirect=True, +) +def test_tidak_ditemukan_ada_saran_json(capsys, kbbi_mock, lokasi): + hasil = kbbi.main(["huk", "--json", "--indentasi", "2"]) + tangkap = capsys.readouterr() + assert tangkap.out == lokasi.read_text() + assert hasil == 1 + + +@pytest.mark.parametrize( + "kbbi_mock,lokasi", + [("auth", "kasus/auth/serialisasi/idn45.json")], + indirect=True, +) +def test_tidak_ditemukan_tidak_ada_saran_json(capsys, kbbi_mock, lokasi): + hasil = kbbi.main(["idn45", "--json", "--indentasi", "2"]) + tangkap = capsys.readouterr() + assert tangkap.out == lokasi.read_text() + assert hasil == 1