diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..47e91cb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.gitignore +.mergify.yml +.pre-commit-config.yaml +CONTRIBUTING.md +LICENSE +README.md +.github/* +.github \ No newline at end of file diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 4a00bdb..acecead 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -1,8 +1,11 @@ -name: Upload Python Package +# git action yang digunakan untuk mengupload project dari github +# kemudian di upload ke pypi + +name: upload OpenSeries ke pypi on: push: - branches: [release] + branches: [main] jobs: deploy: @@ -20,6 +23,6 @@ jobs: - name: Build package run: python -m build - name: Publish package - uses: pypa/gh-action-pypi-publish@v1 + uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/pythontesting.yml b/.github/workflows/pythontesting.yml index 687ef11..8629663 100644 --- a/.github/workflows/pythontesting.yml +++ b/.github/workflows/pythontesting.yml @@ -1,10 +1,12 @@ name: openseries testing on: + # membuat unittesting untuk mengecek dari pull request dan push + # branch dari yang akan di cek adalah main dan develop-library pull_request: - branches: [main] + branches: [main, develop-library] push: - branches: [main] + branches: [main, develop-library] jobs: build: @@ -12,21 +14,27 @@ jobs: strategy: matrix: + # operasi sistem yang dijadikan sebagai environment dari testnya os: [macos-latest, windows-latest, ubuntu-latest] steps: + # check out kode dimana adalah git action + # mengecek kode daripada project - name: checkout kode uses: actions/checkout@v4 + # memanggil environment dari python - name: setting python uses: actions/setup-python@v4 + # install requirement yang sudah disedikan dari project - name: install requirement run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt python -m pip install -r dev-requirements.txt + # testing kode dengan pytest - name: testing kode dengan pytest run: | pytest testing/main_test.py --verbose diff --git a/.mergify.yml b/.mergify.yml index ae398e0..96066ad 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -5,7 +5,6 @@ pull_request_rules: # ketika dikasih label 'ready-to-merge' akan dicentang - name: testing dengan label ready-to-merge conditions: - - base=main - label=ready-to-merge actions: comment: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f308e26..1246c29 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,6 +35,7 @@ repos: - --ignore-missing-imports - --non-interactive - --install-types + exclude: example additional_dependencies: [types-requests] - repo: https://github.com/pre-commit/mirrors-prettier diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afbfd03..fa5b9fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,6 +129,12 @@ kendala atau masalah ketika melakukan pull request. Kamu juga bisa bertanya pada ``` - Lakukan _push_ ke _branch_ kamu dan kemudian _open pull request_. +> [!IMPORTANT] +> Lakukan pull request ke branch ``develop-library`` jika ingin pull request library dan ``develop`` untuk pull request ke web dari OpenSeries. + +> [!CAUTION] +> Pull request akan di close jika mengarah ke branch ``main`` atau ``web``. + **Saran pesan commit** - `feat:` untuk menambah algoritma atau tambahan lainnya; diff --git a/Dockerfile.openseries_test b/Dockerfile.openseries_test new file mode 100644 index 0000000..a0ed139 --- /dev/null +++ b/Dockerfile.openseries_test @@ -0,0 +1,17 @@ +# Import image with tag version 3.12 +FROM python:3.12.1-alpine + +# Custom workdir to save all project +WORKDIR /openseries + +# Copy all local project to inside image +COPY . . + +# Install requirement +RUN pip install -r requirements.txt + +# Install dev-requirements +RUN pip install -r dev-requirements.txt + +# Running pytest +CMD ["pytest"] diff --git a/OpenSeries/fisika.py b/OpenSeries/fisika.py index c3f3cc1..ae4c02f 100644 --- a/OpenSeries/fisika.py +++ b/OpenSeries/fisika.py @@ -2,120 +2,135 @@ from typing import Union -def kecepatan(jarak: Union[float, int], waktu: Union[float, int]) -> Union[float, str]: +def kecepatan( + jarak: Union[float, int], waktu: Union[float, int] +) -> Union[float, error.ErrorDibagiNol, error.ErrorTipeData]: """ fungsi untuk menghitung kecepatan Parameter: - jarak (float atau int): jarak tempuh - waktu (float atau int): waktu tempuh (sekon) + jarak (float atau int): jarak tempuh + waktu (float atau int): waktu tempuh (sekon) Return: - float: hasil dari jarak / waktu + float: hasil dari jarak / waktu + error.ErrorTipeData: error jika tipe data data salah + error.ErrorDibagiNol: error jika angka dibagikan dengan 0 """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if isinstance(jarak, (float, int)) and isinstance(waktu, (float, int)): + if all(isinstance(data, (float, int)) for data in [jarak, waktu]): try: return jarak / waktu except ZeroDivisionError: # error jika hasil pembagian dibagikan dengan 0 - return error.error_dibagi_nol() + return error.ErrorDibagiNol() else: - return error.error_tipe_data(["int", "float"]) + return error.ErrorTipeData(["int", "float"]) def percepatan( kecepatan: Union[float, int], waktu: Union[float, int] -) -> Union[float, str]: +) -> Union[float, error.ErrorDibagiNol, error.ErrorTipeData]: """ fungsi untuk menghitung percepatan parameter: - kecepatan (float atau int): kecepatan (m/s) - waktu (float atau int): waktu tempuh (sekon) + kecepatan (float atau int): kecepatan (m/s) + waktu (float atau int): waktu tempuh (sekon) Return: - float: hasil dari kecepatan / waktu + float: hasil dari kecepatan / waktu + error.ErrorTipeData: error jika tipe data data salah + error.ErrorDibagiNol: jika angka dibagikan dengan 0 """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if isinstance(kecepatan, (float, int)) and isinstance(waktu, (float, int)): + if all(isinstance(data, (float, int)) for data in [kecepatan, waktu]): try: return kecepatan / waktu except ZeroDivisionError: # error jika hasil pembagian dibagikan dengan 0 - return error.error_dibagi_nol() + return error.ErrorDibagiNol() else: - return error.error_tipe_data(["int", "float"]) + return error.ErrorTipeData(["int", "float"]) def gerak_lurus_beraturan( kecepatan_awal: float, a: float, t: float -) -> Union[float, str]: +) -> Union[float, error.ErrorTipeData]: """ fungsi untuk menghitung jarak yang ditempuh oleh benda yang bergerak lurus beraturan - parameter: + Parameter: kecepatan_awal (float): kecepatan awal (m/s) a (float): percepatan (m/s**2) t (float): waktu (s) + + Return: + float: jarak yang ditempuh oleh benda + error.ErrorTipeData: error jika tipe data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if ( - isinstance(kecepatan_awal, float) - and isinstance(a, float) - and isinstance(t, float) - ): + if all(isinstance(data, (float)) for data in [kecepatan_awal, a, t]): return kecepatan_awal * t + 0.5 * a * t**2 else: - return error.error_tipe_data(["float"]) + return error.ErrorTipeData(["float"]) def energi_kinetik( massa: Union[float, int], kecepatan: Union[int, float] -) -> Union[int, float, str]: +) -> Union[int, float, error.ErrorTipeData]: """ menghitung energi kinetik - parameter: + Parameter: massa (float): massa benda kecepatan (float atau int): kecepatan benda + + Return: + (int, float): hasil dari perhitungan energi kinetik + error.ErrorTipeData: error jika tipe data data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if isinstance(massa, (int, float)) and isinstance(kecepatan, (int, float)): + if all(isinstance(data, (float, int)) for data in [massa, kecepatan]): return 0.5 * massa * kecepatan**2 else: - return error.error_tipe_data(["int", "float"]) + return error.ErrorTipeData(["int", "float"]) def masa_jenis( massa: Union[int, float], volume: Union[int, float] -) -> Union[int, float, str]: +) -> Union[int, float, error.ErrorDibagiNol, error.ErrorTipeData]: """ menghitung masa jenis suatu benda - parameter: + Parameter: massa (float atau int): massa benda volume (float atau int): volume benda + + Return: + (int, flloat): hasil dari kalkulasi fungsi dari masa jenis + error.ErrorTipeData: error jika tipe data data salah + error.ErrorDibagiNol: error jika angka dibagikan dengan 0 """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if isinstance(massa, (int, float)) and isinstance(volume, (int, float)): + if all(isinstance(data, (float, int)) for data in [massa, volume]): try: return massa / volume except ZeroDivisionError: # error jika hasil pembagian dibagikan dengan 0 - return error.error_dibagi_nol() + return error.ErrorDibagiNol() else: - return error.error_tipe_data(["int", "float"]) + return error.ErrorTipeData(["int", "float"]) def energi_potensial( m: Union[int, float], g: Union[int, float], h: Union[int, float] -) -> Union[float, int, str]: +) -> Union[float, int, error.ErrorTipeData]: """ menghitung energi potensial dengan rumus Ep = m * g * h @@ -123,18 +138,21 @@ def energi_potensial( m (float atau int): masa benda g (float atau int): gravitasi bumi h (float atau int): ketinggian suatu benda + + Return: + (float, int): hasil dari kalkulasi energei potensial + error.ErrorTipeData: error jika tipe data data salah """ - if ( - not isinstance(m, (float, int)) - and not isinstance(g, (float, int)) - and not isinstance(h, (float, int)) - ): - return error.error_tipe_data(["float", "int"]) + # melakukan pengecekan apakah semua parameter memiliki tipe data dari float atau int + if not all(isinstance(data, (float, int)) for data in [m, g, h]): + return error.ErrorTipeData(["float", "int"]) else: return m * g * h -def hukum_ohm(i: Union[float, int], r: Union[float, int]) -> Union[float, int, str]: +def hukum_ohm( + i: Union[float, int], r: Union[float, int] +) -> Union[float, int, error.ErrorTipeData]: """ menghitung hukum ohm dengan besar arus listrik yang mengalir melalui sebuah hantaran akan berbanding lurus dengan tengangan potensial @@ -143,10 +161,110 @@ def hukum_ohm(i: Union[float, int], r: Union[float, int]) -> Union[float, int, s Parameter: i (float atau int): kuat arus r (float atau int): hambatan (ditulis omega) + + Return: + (float, int): hasil dari kalkulasi dari hukum ohm + error.ErrorTipeData: error jika tipe data data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if not isinstance(i, (float, int)) and not isinstance(r, (float, int)): - return error.error_tipe_data(["float", "int"]) + if not all(isinstance(data, (float, int)) for data in [i, r]): + return error.ErrorTipeData(["float", "int"]) else: return i * r + + +def ketinggian_barometrik( + tekanan: float, +) -> Union[float, error.ErrorTipeData, error.Error]: + """ + fungsi untuk menghitung perkiraan ketinggian berdasarkan dari + tekanan udara yang menggunakan rumus barometrik + + Parameter: + tekanan (float): tekanan udara + + Return: + (float): hasil dari kalkulasi ketinggian barometrik + error.ErrorTipeData: error jika tipe data data salah + error.Error: jika nilai lebih tinggi dari tekanan di permukaan laut + error.Error: jika tekanan atmosfir tidak bisa negatif + """ + # mengecek apakah variable tersebut bertipe data float + # jika tidak maka error + if not isinstance(tekanan, float): + return error.ErrorTipeData(["float"]) + else: + if tekanan > 101325: + return error.Error("nilai lebih tinggi dari tekanan di permukaan laut") + if tekanan < 0: + return error.Error("tekanan atmosfir tidak bisa negatif") + else: + hasil = 44_330 * (1 - (tekanan / 101_325) ** (1 / 5.5255)) + return hasil + + +def gaya_sentripental( + massa: Union[float, int], velocity: Union[float, int], radius: Union[float, int] +) -> Union[float, int, error.Error, error.ErrorTipeData]: + """ + fungsi untuk menghitung gaya sentripental. gaya sentripental adalah gaya yang bekerja + pada benda dalam gerak lengkung arahnya menuju ke sumbu rotasi atau pusat kelengkungan + + Parameter: + massa (float): masa benda + v (float): kecepatan dari benda + radius (float): jari-jari lintasan melingkar + + Return: + (float, int): hasil dari kalkulasi nilai sentripental + error.ErrorTipeData: error jika tipe data data salah + error.Error: jika massa negatif + error.Error: jika radius negatif + """ + # mengecek apakah variable tersebut bertipe data int atau float + # jika tidak maka error + if not all(isinstance(data, (float, int)) for data in [massa, velocity, radius]): + return error.ErrorTipeData(["float", "int"]) + if massa < 0: + return error.Error("Massa tidak boleh negatif") + if radius <= 0: + return error.Error("Radius selalu angka positif") + return (massa * (velocity) ** 2) / radius + + +def efek_doppler( + org_frek: Union[float, int], + gelombang_vel: Union[float, int], + obs_vel: Union[float, int], + src_vel: Union[float, int], +) -> Union[float, error.ErrorDibagiNol, error.ErrorTipeData, error.Error]: + """ + fungsi untuk menghitung efek doppler + + Parameter: + org_frek (int atau float): frekuensi gelombang sumber diam + gelombang_vel_vel (int atau float): kecepatan gelombang dalam medium + obs_vel (int atau float): kecepatan pengamatan + src_vel (int atau float): kecepatan sumber + + Return: + (float): hasil dari kalkulasi efek doppler + error.ErrorTipeData: error jika tipe data data salah + error.Error: jika nilai doppler negatif + """ + # mengecek apakah variable tersebut bertipe data int atau float + # jika tidak maka error + if not all( + isinstance(data, (float, int)) + for data in [org_frek, gelombang_vel, obs_vel, src_vel] + ): + return error.ErrorTipeData(["int", "float"]) + if gelombang_vel == src_vel: + return error.ErrorDibagiNol() + doppler = (org_frek * (gelombang_vel + obs_vel)) / (gelombang_vel - src_vel) + if doppler <= 0: + return error.Error( + "frekuensi tidak positif, kecepatan sumber relatif lebih besar dari kecepatan gelombang dalam medium" + ) + return doppler diff --git a/OpenSeries/matematika.py b/OpenSeries/matematika.py index 2672dc3..aedec54 100644 --- a/OpenSeries/matematika.py +++ b/OpenSeries/matematika.py @@ -1,169 +1,215 @@ from OpenSeries.util import constant as constant -from OpenSeries.util import error as pesan_error +from OpenSeries.util import error as error from typing import Union, Sequence +import numpy as np import math -def radian_ke_derajat(radian: Union[float, int]) -> Union[float, str]: +def radian_ke_derajat(radian: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ mengubah nilai radian ke derajat - parameter: + Parameter: radian (float atau integer): nilai radian + + Return: + (float): hasil dari kalkulasi radian ke derajat + error.ErrorTipeData: error jika tipe data salah """ + # mengecek apakah variable tersebut bertipe data int atau float + # jika tidak maka error if not isinstance(radian, (float, int)): - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) else: return radian * (180 / constant.pi) -def derajat_ke_radian(derajat: Union[float, int]) -> Union[float, str]: +def derajat_ke_radian(derajat: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ mengubah nilai derajat ke nilai radian - parameter: + Parameter: derajat (float atau int): nilai derajat + + Return: + (float): hasil dari kalkulasi derajat ke radian + error.ErrorTipeData: error jika tipe data salah """ + # mengecek apakah variable tersebut bertipe data int atau float + # jika tidak maka error if not isinstance(derajat, (float, int)): - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) else: return derajat * (constant.pi / 180) -def radian_ke_gradian(radian: Union[float, int]) -> Union[float, str]: +def radian_ke_gradian(radian: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ mengubah nilai radian ke gradian Parameter: radian (float atau int): nilai radian + + Return: + (float): hasil dari kalkulasi radian ke gradian + error.ErrorTipeData: error jika tipe data salah """ + # mengecek apakah variable tersebut bertipe data int atau float + # jika tidak maka error if not isinstance(radian, (float, int)): - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) else: return radian * (200 / constant.pi) -def gradian_ke_radian(gradian: Union[float, int]) -> Union[float, str]: +def gradian_ke_radian(gradian: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ mengubah nilai gradian ke radian - parameter: + Parameter: gradian (float atau int): nilai gradian + + Return: + (float): hasil dari kalkulasi gradian ke radian + error.ErrorTipeData: error jika tipe data salah """ + # mengecek apakah variable tersebut bertipe data int atau float + # jika tidak maka error if not isinstance(gradian, (float, int)): - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) else: return gradian * (constant.pi / 200) -def luas_lingkaran(jari: Union[float, int]) -> Union[float, str]: +def luas_lingkaran(jari: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ menghitung luas lingkaran Parameter: - jari-jari (float atau integer): jari jari yang akan dihitung + jari-jari (float atau integer): jari jari yang akan dihitung + + Return: + (float): hasil dari kalkulasi luas lingkaran + error.ErrorTipeData: error jika tipe data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error if isinstance(jari, (float, int)): return constant.pi * jari**2 else: - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) -def keliling_lingkaran(jari: Union[float, int]) -> Union[float, str]: +def keliling_lingkaran(jari: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ menghitung keliling lingkaran - parameter: + Parameter: jari (float atau integer): jari-jari lingkaran + + Return: + (float): hasil dari kalkulasi keliling lingkaran """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error if isinstance(jari, (float, int)): return 2 * constant.pi * jari else: - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) -def diameter_lingkaran(jari: Union[float, int]) -> Union[float, str]: +def diameter_lingkaran(jari: Union[float, int]) -> Union[float, error.ErrorTipeData]: """ menghitung diameter lingkaran - parameter: + Parameter: jari (float atau integer): jari-jari lingkaran + + Return: + (float): hasil dari kalkulasi diameter lingkaran + error.ErrorTipeData: error jika tipe data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error if isinstance(jari, (float, int)): return 2 * jari else: - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) def persamaan_kuadrat( a: Union[int, float], b: Union[int, float], c: Union[int, float] -) -> Union[float, int, str]: +) -> Union[float, int, error.Error, error.ErrorTipeData]: """ menghitung persamaan linear - parameter: + Parameter: a (float atau integer): nilai a b (float atau integer): nilai b c (float atau integer): nilai c - return: + Return: (float atau integer): hasil persamaan linear dari 3 bilangan a, b, dan c + error.ErrorTipeData: error jika tipe data salah + error.Error: jika memiliki nilai complex """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error - if ( - isinstance(a, (int, float)) - and isinstance(b, (int, float)) - and isinstance(c, (int, float)) - ): + if all(isinstance(data, (int, float)) for data in [a, b, c]): diskriminan = b**2 - 4 * a * c if diskriminan >= 0: akar1 = (-b + math.sqrt(diskriminan)) / (2 * a) return akar1 else: - return pesan_error.error_format("Persamaan memiliki solusi complex") + return error.Error("Persamaan memiliki solusi complex") else: - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) -def rata_rata(nilai: Sequence[Union[int, float]]) -> Union[int, float, str]: +def rata_rata( + nilai: Sequence[Union[int, float]], +) -> Union[int, float, error.Error, error.ErrorTipeData]: """ menghitung nilai rata-rata - parameter: + Parameter: nilai (list(float atau integer)): nilai yang dihitung + + Return: + (int, float): hasil dari kalkulasi nilai rata-rata + error.ErrorTipeData: error jika tipe data error + error.Error: jika di dalam list nilai kosong """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error if isinstance(nilai, list): # mengecek apakah nilai dalam list kodong if not nilai: - return pesan_error.error_format("List tidak boleh kosong") + return error.Error("List tidak boleh kosong") # membuat looping untuk memecah nilai yang terdapat pada list for cek_nilai in nilai: # mengecek nilai dalam list apakah semua tipe data berbentuk int # atau float, jika tidak error if not isinstance(cek_nilai, (int, float)): - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) # menghitung nilai rata-rata return sum(nilai) / len(nilai) else: - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) -def faktorial(nilai: int) -> Union[int, float, str]: +def faktorial(nilai: int) -> Union[int, float, error.Error, error.ErrorTipeData]: """ menghitung produk dari semua bilangan bulat positif contoh `4! = 24 = 4 x 3 x 2 x 1` - parameter: + Parameter: nilai (int): nilai yang akan di faktorial + + Return: + (int, float): hasil dari kalkulasi faktorial + error.ErrorTipeData: error jika tipe data salah + error.Error: jika nilai dimasukkan negatif """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error @@ -171,42 +217,54 @@ def faktorial(nilai: int) -> Union[int, float, str]: if nilai == 0 or nilai == 1: return 1 elif nilai < 0: - return pesan_error.error_format("Tidak bisa menggunakan angka negatif") + return error.Error("Tidak bisa menggunakan angka negatif") else: - return int(nilai * faktorial(nilai - 1)) + hasil_rekursif = faktorial(nilai - 1) + if isinstance(hasil_rekursif, int): + return nilai * hasil_rekursif + else: + return hasil_rekursif else: - return pesan_error.error_tipe_data(["int"]) + return error.ErrorTipeData(["int"]) -def permutasi(nilai: int, r: int) -> Union[int, float, str]: +def permutasi(nilai: int, r: int) -> Union[int, float, error.ErrorTipeData]: """ menghitung nilai permutasi dari n objek yang diambil dari r - parameter: + Parameter: nilai (int): nilai objek r (int): jumlah objek yang diambil + + Return: + (int, float): hasil dari kalkulasi permutasi + error.ErrorTipeData: error jika tipe data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error if not isinstance(nilai, int) or not isinstance(r, int): - return pesan_error.error_tipe_data(["int"]) + return error.ErrorTipeData(["int"]) else: faktorial_nilai = faktorial(nilai) faktorial_nilai_r = faktorial(nilai - r) - if isinstance(faktorial_nilai, str) or isinstance(faktorial_nilai_r, str): - return pesan_error.error_tipe_data(["int"]) - else: + if isinstance(faktorial_nilai, int) and isinstance(faktorial_nilai_r, int): return faktorial_nilai / faktorial_nilai_r + else: + return error.ErrorTipeData(["int"]) -def kombinasi(nilai: int, r: int) -> Union[int, float, str]: +def kombinasi(nilai: int, r: int) -> Union[int, float, error.ErrorTipeData]: """ - menghitung nilai kombasi dari n objek yang diambil dari r + menghitung nilai kombinasi dari n objek yang diambil dari r - parameter: + Parameter: nilai (int): nilai objek r (int): jumlah objek yang diambil + + Return: + (int, float): hasil dari kalkulasi kombinasi + error.ErrorTipeData: error jika tipe data salah """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error @@ -216,26 +274,31 @@ def kombinasi(nilai: int, r: int) -> Union[int, float, str]: faktorial_nilai_r = faktorial(nilai - r) if ( - isinstance(faktorial_nilai, str) - or isinstance(faktorial_r, str) - or isinstance(faktorial_nilai_r, str) + isinstance(faktorial_nilai, int) + and isinstance(faktorial_r, int) + and isinstance(faktorial_nilai_r, int) ): - return pesan_error.error_tipe_data(["int"]) - else: return faktorial_nilai / (faktorial_r * faktorial_nilai_r) + else: + return error.ErrorTipeData(["int"]) else: - return pesan_error.error_tipe_data(["int"]) + return error.ErrorTipeData(["int"]) def fpb( bilangan_pertama: Union[int, float], bilangan_kedua: Union[int, float] -) -> Union[int, float, str]: +) -> Union[int, float, error.Error, error.ErrorTipeData]: """ menghitung faktor persekutuan terbesar dari dua buah bilangan - parameter: + Parameter: bilangan_pertama (float atau integer): bilagan pertama bilangan_kedua (float atau integer): bilangan kedua + + Return: + (int, float): hasil dari kalkulasi fpb + error.ErrorTipeData: error jika tipe data salah + error.Error: jika nilai yang diberikan negatif """ # mengecek apakah variable tersebut bertipe data int atau float # jika tidak maka error @@ -243,7 +306,7 @@ def fpb( bilangan_kedua, (int, float) ): if bilangan_pertama < 0 and bilangan_kedua < 0: - return pesan_error.error_format("Angka tidak boleh negatif") + return error.Error("Angka tidak boleh negatif") else: while bilangan_kedua: bilangan_pertama, bilangan_kedua = ( @@ -252,23 +315,28 @@ def fpb( ) return abs(bilangan_pertama) else: - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) -def faktor_prima(n: int) -> Union[list[int], str]: +def faktor_prima(n: int) -> Union[list[int], error.Error, error.ErrorTipeData]: """ membuat fungsi untuk mengurutkan nilai faktor prima - parameter: + Parameter: n (int): rentang angka yang mau di tampilkan bilangan faktor prima + + Return: + (list[int]): hasil dari kalkulasi dari faktor prima + error.ErrorTipeData: jika tipe data yang dimasukkan salah + error.Error: jika angka diberikan nilai negatif """ # mengecek apakah variable n bertipe data integer atau float - if not isinstance(n, (int)) and not isinstance(n, (float)): + if not isinstance(n, (int)): # menampilkan pesan error jika tipe data salah - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["int"]) else: if n < 0: - return pesan_error.error_format("Angka tidak boleh negatif") + return error.Error("Angka tidak boleh negatif") else: # jika desimal mengubah bilangan ke integer n = int(n) @@ -288,61 +356,117 @@ def faktor_prima(n: int) -> Union[list[int], str]: def peluang_kejadian( kejadian: Union[int, float], ukuran_sampel: Union[int, float] -) -> Union[int, float, str]: +) -> Union[int, float, error.ErrorTipeData, error.ErrorDibagiNol]: """ menghitung probabilitas dari suatu kejadian - parameter: + Parameter: kejadian (float atau integer): jumlah hasil yang menguntungkan (n(A)) ukuran sampel (float atau integer): ukurang ruang sampel (n(S)) + + Return: + (int, float): hasil dari kalkulasi peluang kejadian + error.ErrorTipeData: error jika tipe data salah + error.ErrorDibagiNol: error jika nilai dibagi dengan 0 """ # mengecek apakah variable kejadian, ukuran sampel bertipe data integer atau float if not isinstance(kejadian, (float, int)) and not isinstance( ukuran_sampel, (float, int) ): - return pesan_error.error_tipe_data(["float", "int"]) + return error.ErrorTipeData(["float", "int"]) else: try: return kejadian / ukuran_sampel except ZeroDivisionError: # menampilkan pesan error jika dibagi dengan 0 - return pesan_error.error_dibagi_nol() + return error.ErrorDibagiNol() def hitung_jumlah_deret( n: Union[float, int], a: Union[float, int], b: Union[float, int] -) -> Union[float, int, str]: +) -> Union[float, int, error.ErrorTipeData]: """ menghitung jumlah deret aritmatika - parameter: + Parameter: n (float atau integer): jumlah suku dalam deret a (float atau integer): suku pertama dalam deret b (float atau integer): selisih antara dua suku berturut-turut + + Return: + (float, int): hasil dari kalkulasi jumlah deret + error.ErrorTipeData: error jika tipe data salah """ # mengecek apakah variable n, a dan b bertipe data integer atau float - if ( - not isinstance(n, (float, int)) - and not isinstance(a, (float, int)) - and not isinstance(b, (float, int)) - ): - return pesan_error.error_tipe_data(["float", "int"]) + if all(isinstance(data, (float, int)) for data in [n, a, b]): + return error.ErrorTipeData(["float", "int"]) else: return 0.5 * n * (2 * a + (n - 1) * b) def transpose_matriks( matriks: list[list[Union[float, int]]], -) -> Union[list[list[Union[float, int]]], str]: +) -> Union[list[list[Union[float, int]]], error.ErrorTipeData]: """ fungsi untuk transpose matrix - parameter: + Parameter: matriks: list[float, int]: matriks yang akan di transpose + + Return: + (list[float atau int]): hasil dari kalkulasi transpose matriks + error.ErrorTipeData: jika error tipe data yang diberikan salah """ if not isinstance(matriks, list): - return pesan_error.error_tipe_data(["list"]) + return error.ErrorTipeData(["list"]) else: return [ [matriks[j][i] for j in range(len(matriks))] for i in range(len(matriks[0])) ] + + +def euler_pi( + n: int, +) -> Union[int, float, error.ErrorTipeData, error.Error]: + """ + menghitung fungsi dari euler pi + + Parameter: + n (int): bilangan untuk menghitung fungsi dari euler phi + + Return: + (int, float): hasil dari kalkulasi fungsi euler pi + error.ErrorTipeData: error jika tipe data salah + error.Error: jika nilai yang diberikan negatif + """ + if not isinstance(n, int): + return error.ErrorTipeData(["int"]) + elif n <= 0: + return error.Error("nilai dari bilangan tidak boleh negatif atau 0") + else: + s = float(n) + faktor_prima_n = faktor_prima(n) + if isinstance(faktor_prima_n, list): + for x in set(faktor_prima_n): + s *= (x - 1) / x + return s + else: + return faktor_prima_n + + +def sigmoid(vektor: np.ndarray) -> Union[error.ErrorTipeData, np.ndarray]: + """ + fungsi sigmoid adalah fungsi yang berbentuk huruf S. fungsi ini biasanya + digunakan untuk mengubah nilai input dari neuron menjadi nilai output yang + lebih mudah diproses oleh neuron lain + + Parameter: + vektor (np.ndarray): rentang nilai array yang ingin dimasukkan + + Return: + (np.ndarray): hasil dari kalkulasi sigmoid + error.ErrorTipeData: error jika tipe data salah + """ + if not isinstance(vektor, np.ndarray): + return error.ErrorTipeData(["numpy.narray"]) + return 1 / (1 + np.exp(-vektor)) diff --git a/OpenSeries/statistika.py b/OpenSeries/statistika.py index 38af6f7..c48fa6d 100644 --- a/OpenSeries/statistika.py +++ b/OpenSeries/statistika.py @@ -1,21 +1,29 @@ import numpy as np from typing import Union -from OpenSeries.util import error as pesan_error +from OpenSeries.util import error as error -def entropy(label: list[int], base: int) -> Union[float, int, str]: +def entropy( + label: list[int], base: int +) -> Union[float, int, error.Error, error.ErrorTipeData]: """ fungsi menghitung entropy dari suatu fitur pada suatu dataset - parameter: + Parameter: label (list (int)): label fitur yang akan di hitung entropynya + base (int): label dari entropy + + Return: + (float, int): hasil dari kalkulasi dari entropy + error.ErrorTipeData: error jika tipe data salah + error.Error: jika nilai label yang diberikan kosong """ if not isinstance(label, (list)): - return pesan_error.error_tipe_data(["list"]) + return error.ErrorTipeData(["list"]) if not label: - return pesan_error.error_format("label tidak boleh kosong") + return error.Error("label tidak boleh kosong") if not all(isinstance(cek_nilai, int) for cek_nilai in label): - return pesan_error.error_tipe_data(["int"]) + return error.ErrorTipeData(["int"]) _, count = np.unique(label, return_counts=True) probabilitas = count / len(label) probabilitas[probabilitas == 0] = 1 @@ -24,17 +32,24 @@ def entropy(label: list[int], base: int) -> Union[float, int, str]: return np.sum(abs(probabilitas * log)) -def standar_deviasi(vektor: np.ndarray) -> Union[float, str]: +def standar_deviasi( + vektor: np.ndarray, +) -> Union[float, error.Error, error.ErrorTipeData]: """ fungsi untuk mengukur penyebaran data terhadap nilai rata-ratanya - parameter: + Parameter: vektor (np.array) + + Return: + (float): hasil dari kalkulasi standar deviasi + error.ErrorTipeData: error jika tipe data salah + error.Error: jika vektor yang diberikan kosong """ if not isinstance(vektor, np.ndarray): - return pesan_error.error_tipe_data(["numpy array"]) + return error.ErrorTipeData(["numpy array"]) if len(vektor) == 0: - return pesan_error.error_format("vektor tidak boleh kosong") + return error.Error("vektor tidak boleh kosong") mean_value = np.mean(vektor) squared_diff = np.square(vektor - mean_value) diff --git a/OpenSeries/util/constant.py b/OpenSeries/util/constant.py index 6bd0760..f3e3b70 100644 --- a/OpenSeries/util/constant.py +++ b/OpenSeries/util/constant.py @@ -5,3 +5,9 @@ # bilangan euler adalah nilai konstant yang dimana nilai kira-kiranya sama dengan 2.71828 # dan dikarakterisasi dalam berbagai cara bilangan_euler: float = 2.718281828459045235360 + +# default error dari warna menggunakan kode ANSI escape +# merah +red: str = "\033[91m" +# reset kembali warna ke default +reset_warna: str = "\033[0m" diff --git a/OpenSeries/util/error.py b/OpenSeries/util/error.py index b7a6260..bb1106b 100644 --- a/OpenSeries/util/error.py +++ b/OpenSeries/util/error.py @@ -1,27 +1,61 @@ -def error_tipe_data(error_data: list[str]) -> str: +from OpenSeries.util import constant as warna + + +class ErrorTipeData(TypeError): """ - fungsi panggilan untuk menampilkan pesan error + kelas untuk mendeteksi error dari tipe data - Parameter: - error_data (list(str)): tipe data yang ingin diisi + parameter: + expected_types (list[str]): tipe data yang dimasukkan + + return: + (str): pesan error tipe data sesuai dari inputan """ - return f"Kamu memasukkan tipe data yang salah, harus {','.join(error_data)}" + + def __init__(self, expected_types: list[str]): + message = f"{warna.red}Error Tipe:{warna.reset_warna} tipe data Harus {' atau '.join(expected_types)}" + super().__init__(message) -def error_format(format_string: str) -> str: +class Error(Exception): """ - fungsi untuk menampilkan format error - sesuai keinginan dari pesan error + kelas untuk membuat kostumisasi error parameter: - format_string (str): pesan yang akan diisi + pesan (str): pesan kostum yang ingin dimasukkan """ - return "Error: " + format_string + def __init__(self, pesan: str): + message = f"{warna.red}Error:{warna.reset_warna} {pesan}" + super().__init__(message) -def error_dibagi_nol(): + +class IndeksError(IndexError): """ - fungsi panggilan untuk menampilkan pesan error - pesan error berupa `tidak bisa dibagikan dengan 0 + kelas untuk membuat error dari index jika tidak selaras dengan dimensi atau lain """ - return "Tidak bisa dibagikan dengan 0" + + def __init__(self, pesan: str): + message = f"{warna.red}Indeks Error:{warna.reset_warna} {pesan}" + super().__init__(message) + + +class ErrorValue(ValueError): + """ + kelas untuk membuat error dari index dengan throw dari ValueError + """ + + def __init__(self, pesan: str): + message = f"{warna.red}Error Value:{warna.reset_warna} {pesan}" + super().__init__(message) + + +class ErrorDibagiNol(ZeroDivisionError): + """ + kelas untuk menampilkan error yang tidak bisa dibagi dengan nol + """ + + def __init__(self): + super().__init__( + f"{warna.red}Error Dibagi Nol:{warna.reset_warna} Tidak bisa dibagi dengan nol" + ) diff --git a/README.md b/README.md index e1bf4e8..02354f7 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ ![codequality](https://img.shields.io/codacy/grade/06ba6d6d345f4c15bf8e5cc3eac19d4d?style=flat-square&logo=codacy) ![build badge](https://img.shields.io/github/actions/workflow/status/bellshade/OpenSeries/pythontesting.yml?style=flat-square&logo=github&label=Build%20(%20Linux%2C%20Windows%2C%20MacOS)) -Project Untuk Menghitung Segala Jenis Persamaan atau Rumus-Rumus yang terdapat pada bangku sekolah (SMA/SMK/Sederajat). -Project ini bertujuan untuk memudahkan siswa dalam menghitung persamaan atau problem-problem yang terdapat pada pelajaran sekolah (cheat egine untuk Sekolah). +Project Untuk Menghitung Segala Jenis Persamaan atau Rumus-Rumus yang terdapat pada bangku sekolah (SMA/SMK/Sederajat) dan jenjang yang lebih lanjut. +Project ini bertujuan untuk memudahkan siswa dalam menghitung persamaan atau problem-problem yang terdapat pada pelajaran sekolah (cheat egine untuk hitung-menghitung). **Menghitung nilai probabilitas dari suatu kejadian** @@ -33,9 +33,17 @@ Untuk Menjalankan Library ini, kamu harus Memiliki Python dengan versi: 3.11.6 h kamu bisa menginstall package `OpenSeries` via pip dengan cara ```bash -pip install git+https://github.com/bellshade/OpenSeries +pip install OpenSeriesBellshade ``` +## Docker +kamu juga bisa testing package via `docker`` dengan cara + +```bash +bash docker.sh +``` +> Note: untuk windows kalian bisa install dulu dockernya dengan panduan yang ada di [`Docker Docs`](https://docs.docker.com/desktop/install/windows-install/) + Informasi: kamu bisa melihat pada [wiki](https://github.com/bellshade/OpenSeries/wiki) atau ke [website](openseries.pages.dev/), untuk dokumentasi installasi dan pengunaan dari `OpenSeries` diff --git a/docker.sh b/docker.sh new file mode 100644 index 0000000..119e5cc --- /dev/null +++ b/docker.sh @@ -0,0 +1,24 @@ +#!/bin/bash +os_checking(){ + . /etc/os-release + case $ID in + ubuntu) sudo apt install docker docker.io + ;; + arch) sudo pacman -S docker + ;; + darwin) brew install docker + ;; + debian) sudo apt install docker docker.io + ;; + *) echo "If windows you can see the documentation" + ;; + esac +} + +running_docker() { + docker build -t openseries:1.0 -f Dockerfile.openseries_test . + docker run openseries:1.0 +} + +os_checking +running_docker \ No newline at end of file diff --git a/example/fisika/efek_doppler.py b/example/fisika/efek_doppler.py new file mode 100644 index 0000000..ebad7c3 --- /dev/null +++ b/example/fisika/efek_doppler.py @@ -0,0 +1,5 @@ +import OpenSeries.fisika as fisika + +# menghitung fungsi dari efek doppler +doppler_efek = fisika.efek_doppler(100, 330, 10) +print(doppler_efek) diff --git a/example/fisika/gaya_sentripental.py b/example/fisika/gaya_sentripental.py new file mode 100644 index 0000000..df365fa --- /dev/null +++ b/example/fisika/gaya_sentripental.py @@ -0,0 +1,5 @@ +import OpenSeries.fisika as fisika + +# menghitung gaya sentripental +hasil = round(fisika.gaya_sentripental(10, 15, 5)) +print(hasil) diff --git a/example/fisika/tekanan_barometrik.py b/example/fisika/tekanan_barometrik.py new file mode 100644 index 0000000..0d90bb2 --- /dev/null +++ b/example/fisika/tekanan_barometrik.py @@ -0,0 +1,7 @@ +import OpenSeries.fisika as fisika + +# tekanan udara +tekanan = 100_000.0 +# memanggil fungsi dari ketinggian barometrik +hasil = fisika.ketinggian_barometrik(tekanan) +print(f"tekanan: {tekanan} Pa, Ketinggian adalah: {hasil} meter") diff --git a/example/matematika/radian_ke_derajat.py b/example/matematika/radian_ke_derajat.py new file mode 100644 index 0000000..9bde155 --- /dev/null +++ b/example/matematika/radian_ke_derajat.py @@ -0,0 +1,3 @@ +import OpenSeries.matematika as matematika + +print(matematika.radian_ke_derajat(3)) diff --git a/example/matematika/sigmoid.py b/example/matematika/sigmoid.py new file mode 100644 index 0000000..1bb0592 --- /dev/null +++ b/example/matematika/sigmoid.py @@ -0,0 +1,6 @@ +import OpenSeries.matematika as matematika +import numpy as np + +# membuat fungsi sigmoid +array = np.array([-1.0, 1.0, 2.0]) +print(matematika.sigmoid(array)) diff --git a/pyproject.toml b/pyproject.toml index 2b99a7a..0e893c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "OpenSeriesBellshade" -version = "1.1.2" +version = "1.6.6" dynamic = [ "dependencies" ] @@ -8,8 +8,9 @@ description = "library untuk membantu temen-temen dalam perhitungan matematika" readme = "README.md" requires-python = ">=3.11.6" keywords = [ - "OpenSeries", - "openseries" + "OpenSeriesBellshade", + "openseries", + "bellshade", ] license = {text = "MIT"} authors = [ @@ -19,6 +20,7 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", + "Natural Language :: Indonesian", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", diff --git a/setup.py b/setup.py index 381f3fd..23d76fc 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ # nama dari project name="OpenSeries", # versi dari project - version="1.0.0", + version="1.6.6", # deskripsi singkat dari project description="library untuk membantu temen-temen SMA/SMK/Sederajat", # deskripsi detail tentang project diff --git a/testing/fisika_test.py b/testing/fisika_test.py index 7c7a11e..5609a6a 100644 --- a/testing/fisika_test.py +++ b/testing/fisika_test.py @@ -10,17 +10,17 @@ def test_angka_valid(self): def test_dibagi_nol(self): hasil = fisika.kecepatan(150.0, 0) - self.assertEqual(hasil, error.error_dibagi_nol()) + with self.assertRaises(error.ErrorDibagiNol): + raise hasil def test_invalid_input(self): - hasil = fisika.kecepatan("12", 5.0) - self.assertIsInstance(hasil, str) - self.assertIn(error.error_tipe_data(["int", "float"]), hasil) + with self.assertRaises(error.ErrorTipeData): + raise fisika.kecepatan("12", 30) def test_kecepatan_invalid_input2(self): hasil = fisika.kecepatan("12", "50") - self.assertIsInstance(hasil, str) - self.assertIn(error.error_tipe_data(["int", "float"]), hasil) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestPercepatan(unittest.TestCase): @@ -30,12 +30,13 @@ def test_percepatan_valid(self): def test_percepatan_dibagi_nol(self): hasil = fisika.percepatan(30.0, 0) - self.assertEqual(error.error_dibagi_nol(), hasil) + with self.assertRaises(error.ErrorDibagiNol): + raise hasil def test_percepatan_nilai_tidak_valid(self): hasil = fisika.percepatan("20", 30) - self.assertIsInstance(hasil, str) - self.assertIn(error.error_tipe_data(["int", "float"]), hasil) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestGerakLurusBeraturan(unittest.TestCase): @@ -45,7 +46,8 @@ def test_valid(self): def test_invalid_int(self): hasil = fisika.gerak_lurus_beraturan(8, 1.5, 2) - self.assertEqual(hasil, error.error_tipe_data(["float"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestEnergiKinetik(unittest.TestCase): @@ -55,4 +57,75 @@ def test_valid_input(self): def test_invalid_input_mix_tipe_data(self): hasil = fisika.energi_kinetik("3", 4.5) - self.assertEqual(hasil, error.error_tipe_data(["int", "float"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil + + +class TestKetinggianBarometrik(unittest.TestCase): + def test_valid_input_tekanan(self): + hasil = fisika.ketinggian_barometrik(101325.0) + self.assertIsInstance(hasil, float) + + def test_tekanan_lebih_besar_daripada_air(self): + hasil = fisika.ketinggian_barometrik(110000.0) + with self.assertRaises(error.Error): + raise hasil + + def test_tekanan_angka_negatif(self): + hasil = fisika.ketinggian_barometrik(-820.3) + with self.assertRaises(error.Error): + raise hasil + + def test_tekanan_tipe_data_salah(self): + hasil = fisika.ketinggian_barometrik("12") + with self.assertRaises(error.ErrorTipeData): + raise hasil + + +class TestGayaSentripental(unittest.TestCase): + def test_gaya_sentripental(self): + hasil = fisika.gaya_sentripental(10, 5, 2) + self.assertEqual(hasil, 125.0) + + def test_gaya_sentripental_error_tipe_data(self): + hasil = fisika.gaya_sentripental("12", 5, 2) + self.assertIsInstance(hasil, error.ErrorTipeData) + with self.assertRaises(error.ErrorTipeData): + raise hasil + + def test_gaya_sentripental_minus(self): + hasil = fisika.gaya_sentripental(-10, 5, 2) + self.assertIsInstance(hasil, error.Error) + with self.assertRaises(error.Error): + raise hasil + + def test_gaya_sentripental_nol(self): + hasil = fisika.gaya_sentripental(10, 5, 0) + self.assertIsInstance(hasil, error.Error) + with self.assertRaises(error.Error): + raise hasil + + +class TestEfekDoppler(unittest.TestCase): + def test_efek_doppler(self): + hasil = fisika.efek_doppler(100, 340, 20, 10) + rounding_hasil = round(hasil) + self.assertEqual(rounding_hasil, 109) + + def test_efek_doppler_invalid_tipe_data(self): + hasil = fisika.efek_doppler("12", "340", "20", 10) + self.assertIsInstance(hasil, error.ErrorTipeData) + with self.assertRaises(error.ErrorTipeData): + raise hasil + + def test_efek_doppler_dibagi_nol(self): + hasil = fisika.efek_doppler(0, 0, 0, 0) + self.assertIsInstance(hasil, error.ErrorDibagiNol) + with self.assertRaises(error.ErrorDibagiNol): + raise hasil + + def test_efek_doppler_nilai_negatif(self): + hasil = fisika.efek_doppler(-100, -340, 20, 10) + self.assertIsInstance(hasil, error.Error) + with self.assertRaises(error.Error): + raise hasil diff --git a/testing/main_test.py b/testing/main_test.py index b7fec00..8e0a59e 100644 --- a/testing/main_test.py +++ b/testing/main_test.py @@ -11,6 +11,8 @@ TestFPB, TestFaktorPrima, TestMatriksTranspose, + TestFungsiEuler, + TestSigmoid, ) from testing.fisika_test import ( @@ -18,6 +20,9 @@ TestPercepatan, TestGerakLurusBeraturan, TestEnergiKinetik, + TestKetinggianBarometrik, + TestGayaSentripental, + TestEfekDoppler, ) from testing.statistika_test import TestFungsiEntropy, TestFungiStandardDeviasi @@ -35,6 +40,8 @@ TestFPB, TestFaktorPrima, TestMatriksTranspose, + TestFungsiEuler, + TestSigmoid, ] testing_fisika: list = [ @@ -42,6 +49,9 @@ TestPercepatan, TestGerakLurusBeraturan, TestEnergiKinetik, + TestKetinggianBarometrik, + TestGayaSentripental, + TestEfekDoppler, ] testing_statistika: list = [ diff --git a/testing/matematika_test.py b/testing/matematika_test.py index faeea10..718a374 100644 --- a/testing/matematika_test.py +++ b/testing/matematika_test.py @@ -1,34 +1,31 @@ import unittest from OpenSeries import matematika as matematika from OpenSeries.util import error as error +import numpy as np class TestKonversi(unittest.TestCase): def test_radian_ke_derajat(self): self.assertAlmostEqual(matematika.radian_ke_derajat(1), 57.2957795131) self.assertAlmostEqual(matematika.radian_ke_derajat(0), 0) - self.assertEqual( - matematika.radian_ke_derajat("12"), error.error_tipe_data(["float", "int"]) - ) + with self.assertRaises(error.ErrorTipeData): + raise matematika.radian_ke_derajat("12") def test_derajat_ke_radian(self): self.assertAlmostEqual(matematika.derajat_ke_radian(180), 3.1415926535) self.assertAlmostEqual(matematika.derajat_ke_radian(0), 0) - self.assertEqual( - matematika.derajat_ke_radian("15"), error.error_tipe_data(["float", "int"]) - ) + with self.assertRaises(error.ErrorTipeData): + raise matematika.derajat_ke_radian("12") def test_radian_ke_gradian(self): self.assertAlmostEqual(matematika.radian_ke_gradian(180), 11459.1559026) - self.assertEqual( - matematika.radian_ke_gradian("128"), error.error_tipe_data(["float", "int"]) - ) + with self.assertRaises(error.ErrorTipeData): + raise matematika.radian_ke_gradian("128") def test_gradian_ke_radian(self): self.assertAlmostEqual(matematika.gradian_ke_radian(52), 0.8168140899) - self.assertEqual( - matematika.gradian_ke_radian("200"), error.error_tipe_data(["float", "int"]) - ) + with self.assertRaises(error.ErrorTipeData): + raise matematika.gradian_ke_radian("200") class TestKelilingLingkaran(unittest.TestCase): @@ -42,7 +39,8 @@ def test_tipe_data_int(self): def test_nilai_input_tidak_valid(self): hasil = matematika.keliling_lingkaran("45") - self.assertEqual(hasil, error.error_tipe_data(["float", "int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestDiameterLingkaran(unittest.TestCase): @@ -56,7 +54,8 @@ def test_tipe_data_int(self): def test_nilai_input_tidak_valid(self): hasil = matematika.diameter_lingkaran("800") - self.assertEqual(hasil, error.error_tipe_data(["float", "int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestPersamaanKuadrat(unittest.TestCase): @@ -70,11 +69,13 @@ def test_nilai_valid_float(self): def test_nilai_input_tidak_valid(self): hasil = matematika.persamaan_kuadrat("12", 2, 3) - self.assertEqual(hasil, error.error_tipe_data(["float", "int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil def test_nilai_complex(self): hasil = matematika.persamaan_kuadrat(1, 2, 5) - self.assertEqual(hasil, error.error_format("Persamaan memiliki solusi complex")) + with self.assertRaises(error.Error): + raise hasil class TestRataRata(unittest.TestCase): @@ -88,7 +89,8 @@ def test_nilai_valid_float(self): def test_list_kosong(self): hasil = matematika.rata_rata([]) - self.assertEqual(hasil, error.error_format("List tidak boleh kosong")) + with self.assertRaises(error.Error): + raise hasil class TestFaktorial(unittest.TestCase): @@ -102,13 +104,13 @@ def test_faktorial_nilai_int(self): def test_faktorial_nilai_float(self): hasil = matematika.faktorial(2.5) - self.assertEqual(hasil, error.error_tipe_data(["int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil def test_faktorial_nilai_negatif(self): hasil = matematika.faktorial(-20) - self.assertEqual( - hasil, error.error_format("Tidak bisa menggunakan angka negatif") - ) + with self.assertRaises(error.Error): + raise hasil class TestPermutasi(unittest.TestCase): @@ -118,11 +120,13 @@ def test_input_valid(self): def test_input_invalid_float(self): hasil = matematika.permutasi(5.2, 2.0) - self.assertEqual(hasil, error.error_tipe_data(["int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil def test_nilai_input_tidak_valid(self): hasil = matematika.permutasi("12", "14") - self.assertEqual(hasil, error.error_tipe_data(["int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestKombinasi(unittest.TestCase): @@ -132,11 +136,13 @@ def test_input_valid(self): def test_input_invalid_float(self): hasil = matematika.kombinasi(5.2, 2.0) - self.assertEqual(hasil, error.error_tipe_data(["int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil def test_nilai_input_tidak_valid(self): hasil = matematika.kombinasi("12", "14") - self.assertEqual(hasil, error.error_tipe_data(["int"])) + with self.assertRaises(error.ErrorTipeData): + raise hasil class TestFPB(unittest.TestCase): @@ -150,7 +156,8 @@ def test_invalid_input(self): def test_angka_invalid(self): hasil = matematika.fpb(-36, -40) - self.assertEqual(hasil, error.error_format("Angka tidak boleh negatif")) + with self.assertRaises(error.Error): + raise hasil def test_angka_nol(self): hasil = matematika.fpb(0, 48) @@ -164,7 +171,8 @@ def test_input_valid(self): def test_input_float(self): hasil = matematika.faktor_prima(25.0) - self.assertEqual(hasil, [5, 5]) + with self.assertRaises(error.ErrorTipeData): + raise hasil def test_faktor_prima_kosong(self): hasil = matematika.faktor_prima(1) @@ -172,7 +180,8 @@ def test_faktor_prima_kosong(self): def test_input_negatif(self): hasil = matematika.faktor_prima(-30) - self.assertEqual(hasil, error.error_format("Angka tidak boleh negatif")) + with self.assertRaises(error.Error): + raise hasil class TestMatriksTranspose(unittest.TestCase): @@ -181,3 +190,38 @@ def test_valid_input(self): ekspetasi = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] hasil = matematika.transpose_matriks(matriks_a) self.assertEqual(hasil, ekspetasi) + + +class TestFungsiEuler(unittest.TestCase): + def test_nilai_positif(self): + hasil = matematika.euler_pi(100) + self.assertEqual(hasil, 40.0) + + def test_nilai_tidak_integer(self): + hasil = matematika.euler_pi(3.14) + with self.assertRaises(error.ErrorTipeData): + raise hasil + + def test_nilai_negatif(self): + hasil = matematika.euler_pi(-20) + with self.assertRaises(error.Error): + raise hasil + + def test_nilai_nol(self): + hasil = matematika.euler_pi(0) + with self.assertRaises(error.Error): + raise hasil + + +class TestSigmoid(unittest.TestCase): + def test_sigmoid(self): + input_nilai_array = np.array([1, 2, 3]) + hasil = matematika.sigmoid(input_nilai_array) + nilai_ekspetasi = np.array([0.73105858, 0.88079708, 0.95257413]) + np.testing.assert_allclose(hasil, nilai_ekspetasi, rtol=1e-7) + + def test_invalid_input(self): + hasil = matematika.sigmoid(5) + self.assertIsInstance(hasil, error.ErrorTipeData) + with self.assertRaises(error.ErrorTipeData): + raise hasil diff --git a/testing/statistika_test.py b/testing/statistika_test.py index 9fba2b9..243e803 100644 --- a/testing/statistika_test.py +++ b/testing/statistika_test.py @@ -13,17 +13,20 @@ def test_entropy_dengan_none(self): def test_nilai_kosong(self): label = [] hasil = statistika.entropy(label, base=2) - self.assertEqual(hasil, pesan_error.error_format("label tidak boleh kosong")) + with self.assertRaises(pesan_error.Error): + raise hasil def test_nilai_element_dalam_label(self): label = [1, 2, "3", 4] hasil = statistika.entropy(label, base=2) - self.assertEqual(hasil, pesan_error.error_tipe_data(["int"])) + with self.assertRaises(pesan_error.ErrorTipeData): + raise hasil def test_tipe_data_tuple(self): label = (1, 2, 3) hasil = statistika.entropy(label, base=2) - self.assertEqual(hasil, pesan_error.error_tipe_data(["list"])) + with self.assertRaises(pesan_error.ErrorTipeData): + raise hasil class TestFungiStandardDeviasi(unittest.TestCase): @@ -35,9 +38,11 @@ def test_standard_deviasi_dengan_numpy_array(self): def test_standard_deviasi_dengan_list(self): vektor = [1, 2, 3, 4, 5] hasil = statistika.standar_deviasi(vektor) - self.assertEqual(hasil, pesan_error.error_tipe_data(["numpy array"])) + with self.assertRaises(pesan_error.ErrorTipeData): + raise hasil def test_standard_deviasi_dengan_numpy_kosong(self): vektor = np.array([]) hasil = statistika.standar_deviasi(vektor) - self.assertEqual(hasil, pesan_error.error_format("vektor tidak boleh kosong")) + with self.assertRaises(pesan_error.Error): + raise hasil