Skip to content

Commit

Permalink
Refactor and add tests (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
affonsobrian authored Dec 5, 2021
1 parent 604c11d commit b7da103
Show file tree
Hide file tree
Showing 22 changed files with 448 additions and 42 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
pytest tests
3 changes: 1 addition & 2 deletions geld/asyncio/base.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from geld.common.base_client import BaseClient
from datetime import date
from decimal import Decimal

from geld.common.helpers import AsynClientHelper


class AsyncClientBase(BaseClient):
class AsyncClientBase:
helper = AsynClientHelper

async def convert_currency(
Expand Down
21 changes: 1 addition & 20 deletions geld/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,7 @@
from decimal import Decimal


class ClientHelper:
@staticmethod
def get_url(base_url, date: str):
return f"{base_url}/{date}/"

@staticmethod
def get_params(from_currency: str, to_currency: str):
return {
"base": from_currency,
"symbols": to_currency,
}

@staticmethod
def get_rate_from_response(response: dict, to_currency: str):
data = json.loads(response.text)
rate = Decimal(data["rates"][to_currency])
return rate


class AsynClientHelper(ClientHelper):
class AsynClientHelper:
@staticmethod
async def get_rate_from_response(response: dict, to_currency: str):
text = await response.text()
Expand Down
2 changes: 2 additions & 0 deletions geld/common/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ def amount_validator(amount):
amount = Decimal(amount)
except Exception:
raise InvalidAmount
if amount < 0:
raise InvalidAmount
return amount
51 changes: 45 additions & 6 deletions geld/sync/base.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,55 @@
from geld.common.base_client import BaseClient
import json
import requests
from datetime import date
from decimal import Decimal
from geld.common.helpers import ClientHelper
from geld.common.exceptions import APICallError, BaseUrlNotDefined

class SyncClientBase:
_base_url = None

class SyncClientBase(BaseClient):
helper = ClientHelper
def __init__(self):
if not self._base_url:
raise BaseUrlNotDefined

def convert_currency(
self,
from_currency: str,
to_currency: str,
amount: Decimal,
date: date = None,
date: str = None,
):
raise NotImplementedError
if from_currency == to_currency:
return amount

url = self._get_url(date)
params = self._get_params(from_currency, to_currency)
response = self._execute_request(url, params)

if not response.status_code == 200:
raise APICallError

rate = self._get_rate_from_response(response, to_currency)
converted_amount = self._convert_amount(amount, rate)

return converted_amount

def _get_url(self, date: str):
return f"{self._base_url}/{date}/"

def _get_params(self, from_currency: str, to_currency: str):
return {
"base": from_currency,
"symbols": to_currency,
}

def _execute_request(self, url: str, params: dict):
requests.get(url, params=params)

def _get_rate_from_response(self, response, to_currency: str):
data = json.loads(response.text)
rate = Decimal(data["rates"][to_currency])
return rate

def _convert_amount(self, amount: Decimal, rate: Decimal):
return amount*rate

17 changes: 4 additions & 13 deletions geld/sync/client.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
from geld.common.constants import BASE_URL
from geld.common.decorators import validate_currency_conversion_data
from geld.common.exceptions import APICallError
from geld.sync.base import SyncClientBase

from decimal import Decimal

import requests

class SyncClient(SyncClientBase):
_base_url = BASE_URL

@validate_currency_conversion_data
def convert_currency(self, from_currency: str, to_currency: str, amount: Decimal = 1, date: str = "latest"):
url = self.helper.get_url(self.base_url, date)
params = self.helper.get_params(from_currency, to_currency)
response = requests.get(url, params=params)

if not response.status_code == 200:
raise APICallError

rate = self.helper.get_rate_from_response(response, to_currency)
converted_amount = amount * rate
return converted_amount
return super(SyncClient, self).convert_currency(from_currency, to_currency, amount, date)
Empty file added tests/asyncio/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions tests/asyncio/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from geld.common.base_client import BaseClient
from datetime import date
from decimal import Decimal

from geld.common.helpers import AsynClientHelper


class AsyncClientBase(BaseClient):
helper = AsynClientHelper

async def convert_currency(
from_currency: str,
to_currency: str,
amount: Decimal,
date: date = None,
):
raise NotImplementedError
27 changes: 27 additions & 0 deletions tests/asyncio/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from geld.common.decorators import validate_currency_conversion_data
from geld.common.exceptions import APICallError
from geld.asyncio.base import AsyncClientBase

from decimal import Decimal

import aiohttp


class AsyncClient(AsyncClientBase):
@validate_currency_conversion_data
async def convert_currency(
self,
from_currency: str,
to_currency: str,
amount: Decimal = 1,
date: str = "latest",
):
url = self.helper.get_url(self.base_url, date)
params = self.helper.get_params(from_currency, to_currency)
async with aiohttp.ClientSession() as session:
response = await session.get(url, params=params)
if not response.status == 200:
raise APICallError
rate = await self.helper.get_rate_from_response(response, to_currency)
converted_amount = amount * rate
return converted_amount
Empty file added tests/common/__init__.py
Empty file.
File renamed without changes.
164 changes: 164 additions & 0 deletions tests/common/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
BASE_URL = "https://theforexapi.com/api"

CURRENCY_DATA = {
"AED": {"symbol": "د.إ;", "name": "UAE dirham"},
"AFN": {"symbol": "Afs", "name": "Afghan afghani"},
"ALL": {"symbol": "L", "name": "Albanian lek"},
"AMD": {"symbol": "AMD", "name": "Armenian dram"},
"ANG": {"symbol": "NAƒ", "name": "Netherlands Antillean gulden"},
"AOA": {"symbol": "Kz", "name": "Angolan kwanza"},
"ARS": {"symbol": "$", "name": "Argentine peso"},
"AUD": {"symbol": "$", "name": "Australian dollar"},
"AWG": {"symbol": "ƒ", "name": "Aruban florin"},
"AZN": {"symbol": "AZN", "name": "Azerbaijani manat"},
"BAM": {
"symbol": "KM",
"name": "Bosnia and Herzegovina konvertibilna marka",
},
"BBD": {"symbol": "Bds$", "name": "Barbadian dollar"},
"BDT": {"symbol": "৳", "name": "Bangladeshi taka"},
"BGN": {"symbol": "лв", "name": "Bulgarian lev"},
"BHD": {"symbol": ".د.ب", "name": "Bahraini dinar"},
"BIF": {"symbol": "FBu", "name": "Burundi franc"},
"BMD": {"symbol": "BD$", "name": "Bermudian dollar"},
"BND": {"symbol": "B$", "name": "Brunei dollar"},
"BOB": {"symbol": "Bs.", "name": "Bolivian boliviano"},
"BRL": {"symbol": "R$", "name": "Brazilian real"},
"BSD": {"symbol": "B$", "name": "Bahamian dollar"},
"BTC": {"symbol": "₿", "name": "Bitcoin"},
"BTN": {"symbol": "Nu.", "name": "Bhutanese ngultrum"},
"BWP": {"symbol": "P", "name": "Botswana pula"},
"BYR": {"symbol": "Br", "name": "Belarusian ruble"},
"BZD": {"symbol": "BZ$", "name": "Belize dollar"},
"CAD": {"symbol": "$", "name": "Canadian dollar"},
"CDF": {"symbol": "F", "name": "Congolese franc"},
"CHF": {"symbol": "Fr.", "name": "Swiss franc"},
"CLP": {"symbol": "$", "name": "Chilean peso"},
"CNY": {"symbol": "¥", "name": "Chinese/Yuan renminbi"},
"COP": {"symbol": "Col$", "name": "Colombian peso"},
"CRC": {"symbol": "₡", "name": "Costa Rican colon"},
"CUC": {"symbol": "$", "name": "Cuban peso"},
"CVE": {"symbol": "Esc", "name": "Cape Verdean escudo"},
"CZK": {"symbol": "Kč", "name": "Czech koruna"},
"DJF": {"symbol": "Fdj", "name": "Djiboutian franc"},
"DKK": {"symbol": "Kr", "name": "Danish krone"},
"DOP": {"symbol": "RD$", "name": "Dominican peso"},
"DZD": {"symbol": "د.ج", "name": "Algerian dinar"},
"EEK": {"symbol": "KR", "name": "Estonian kroon"},
"EGP": {"symbol": "£", "name": "Egyptian pound"},
"ERN": {"symbol": "Nfa", "name": "Eritrean nakfa"},
"ETB": {"symbol": "Br", "name": "Ethiopian birr"},
"EUR": {"symbol": "€", "name": "European Euro"},
"FJD": {"symbol": "FJ$", "name": "Fijian dollar"},
"FKP": {"symbol": "£", "name": "Falkland Islands pound"},
"GBP": {"symbol": "£", "name": "British pound"},
"GEL": {"symbol": "GEL", "name": "Georgian lari"},
"GHS": {"symbol": "GH₵", "name": "Ghanaian cedi"},
"GIP": {"symbol": "£", "name": "Gibraltar pound"},
"GMD": {"symbol": "D", "name": "Gambian dalasi"},
"GNF": {"symbol": "FG", "name": "Guinean franc"},
"GQE": {"symbol": "CFA", "name": "Central African CFA franc"},
"GTQ": {"symbol": "Q", "name": "Guatemalan quetzal"},
"GYD": {"symbol": "GY$", "name": "Guyanese dollar"},
"HKD": {"symbol": "HK$", "name": "Hong Kong dollar"},
"HNL": {"symbol": "L", "name": "Honduran lempira"},
"HRK": {"symbol": "kn", "name": "Croatian kuna"},
"HTG": {"symbol": "G", "name": "Haitian gourde"},
"HUF": {"symbol": "Ft", "name": "Hungarian forint"},
"IDR": {"symbol": "Rp", "name": "Indonesian rupiah"},
"ILS": {"symbol": "₪", "name": "Israeli new sheqel"},
"INR": {"symbol": "₹", "name": "Indian rupee"},
"IQD": {"symbol": "د.ع", "name": "Iraqi dinar"},
"IRR": {"symbol": "IRR", "name": "Iranian rial"},
"ISK": {"symbol": "kr", "name": "Icelandic króna"},
"JMD": {"symbol": "J$", "name": "Jamaican dollar"},
"JOD": {"symbol": "JOD", "name": "Jordanian dinar"},
"JPY": {"symbol": "¥", "name": "Japanese yen"},
"KES": {"symbol": "KSh", "name": "Kenyan shilling"},
"KGS": {"symbol": "сом", "name": "Kyrgyzstani som"},
"KHR": {"symbol": "៛", "name": "Cambodian riel"},
"KMF": {"symbol": "KMF", "name": "Comorian franc"},
"KPW": {"symbol": "W", "name": "North Korean won"},
"KRW": {"symbol": "W", "name": "South Korean won"},
"KWD": {"symbol": "KWD", "name": "Kuwaiti dinar"},
"KYD": {"symbol": "KY$", "name": "Cayman Islands dollar"},
"KZT": {"symbol": "T", "name": "Kazakhstani tenge"},
"LAK": {"symbol": "KN", "name": "Lao kip"},
"LBP": {"symbol": "£", "name": "Lebanese lira"},
"LKR": {"symbol": "Rs", "name": "Sri Lankan rupee"},
"LRD": {"symbol": "L$", "name": "Liberian dollar"},
"LSL": {"symbol": "M", "name": "Lesotho loti"},
"LTL": {"symbol": "Lt", "name": "Lithuanian litas"},
"LVL": {"symbol": "Ls", "name": "Latvian lats"},
"LYD": {"symbol": "LD", "name": "Libyan dinar"},
"MAD": {"symbol": "MAD", "name": "Moroccan dirham"},
"MDL": {"symbol": "MDL", "name": "Moldovan leu"},
"MGA": {"symbol": "FMG", "name": "Malagasy ariary"},
"MKD": {"symbol": "MKD", "name": "Macedonian denar"},
"MMK": {"symbol": "K", "name": "Myanma kyat"},
"MNT": {"symbol": "₮", "name": "Mongolian tugrik"},
"MOP": {"symbol": "P", "name": "Macanese pataca"},
"MRO": {"symbol": "UM", "name": "Mauritanian ouguiya"},
"MUR": {"symbol": "Rs", "name": "Mauritian rupee"},
"MVR": {"symbol": "Rf", "name": "Maldivian rufiyaa"},
"MWK": {"symbol": "MK", "name": "Malawian kwacha"},
"MXN": {"symbol": "$", "name": "Mexican peso"},
"MYR": {"symbol": "RM", "name": "Malaysian ringgit"},
"MZM": {"symbol": "MTn", "name": "Mozambican metical"},
"NAD": {"symbol": "N$", "name": "Namibian dollar"},
"NGN": {"symbol": "₦", "name": "Nigerian naira"},
"NIO": {"symbol": "C$", "name": "Nicaraguan córdoba"},
"NOK": {"symbol": "kr", "name": "Norwegian krone"},
"NPR": {"symbol": "NRs", "name": "Nepalese rupee"},
"NZD": {"symbol": "NZ$", "name": "New Zealand dollar"},
"OMR": {"symbol": "OMR", "name": "Omani rial"},
"PAB": {"symbol": "B./", "name": "Panamanian balboa"},
"PEN": {"symbol": "S/.", "name": "Peruvian nuevo sol"},
"PGK": {"symbol": "K", "name": "Papua New Guinean kina"},
"PHP": {"symbol": "₱", "name": "Philippine peso"},
"PKR": {"symbol": "Rs.", "name": "Pakistani rupee"},
"PLN": {"symbol": "zł", "name": "Polish zloty"},
"PYG": {"symbol": "₲", "name": "Paraguayan guarani"},
"QAR": {"symbol": "QR", "name": "Qatari riyal"},
"RON": {"symbol": "L", "name": "Romanian leu"},
"RSD": {"symbol": "din.", "name": "Serbian dinar"},
"RUB": {"symbol": "₽", "name": "Russian ruble"},
"SAR": {"symbol": "SR", "name": "Saudi riyal"},
"SBD": {"symbol": "SI$", "name": "Solomon Islands dollar"},
"SCR": {"symbol": "SR", "name": "Seychellois rupee"},
"SDG": {"symbol": "SDG", "name": "Sudanese pound"},
"SEK": {"symbol": "kr", "name": "Swedish krona"},
"SGD": {"symbol": "S$", "name": "Singapore dollar"},
"SHP": {"symbol": "£", "name": "Saint Helena pound"},
"SLL": {"symbol": "Le", "name": "Sierra Leonean leone"},
"SOS": {"symbol": "Sh.", "name": "Somali shilling"},
"SRD": {"symbol": "$", "name": "Surinamese dollar"},
"SYP": {"symbol": "LS", "name": "Syrian pound"},
"SZL": {"symbol": "E", "name": "Swazi lilangeni"},
"THB": {"symbol": "฿", "name": "Thai baht"},
"TJS": {"symbol": "TJS", "name": "Tajikistani somoni"},
"TMT": {"symbol": "m", "name": "Turkmen manat"},
"TND": {"symbol": "DT", "name": "Tunisian dinar"},
"TRY": {"symbol": "TRY", "name": "Turkish new lira"},
"TTD": {"symbol": "TT$", "name": "Trinidad and Tobago dollar"},
"TWD": {"symbol": "NT$", "name": "New Taiwan dollar"},
"TZS": {"symbol": "TZS", "name": "Tanzanian shilling"},
"UAH": {"symbol": "UAH", "name": "Ukrainian hryvnia"},
"UGX": {"symbol": "USh", "name": "Ugandan shilling"},
"USD": {"symbol": "US$", "name": "United States dollar"},
"UYU": {"symbol": "$U", "name": "Uruguayan peso"},
"UZS": {"symbol": "UZS", "name": "Uzbekistani som"},
"VEB": {"symbol": "Bs", "name": "Venezuelan bolivar"},
"VND": {"symbol": "₫", "name": "Vietnamese dong"},
"VUV": {"symbol": "VT", "name": "Vanuatu vatu"},
"WST": {"symbol": "WS$", "name": "Samoan tala"},
"XAF": {"symbol": "CFA", "name": "Central African CFA franc"},
"XCD": {"symbol": "EC$", "name": "East Caribbean dollar"},
"XDR": {"symbol": "SDR", "name": "Special Drawing Rights"},
"XOF": {"symbol": "CFA", "name": "West African CFA franc"},
"XPF": {"symbol": "F", "name": "CFP franc"},
"YER": {"symbol": "YER", "name": "Yemeni rial"},
"ZAR": {"symbol": "R", "name": "South African rand"},
"ZMK": {"symbol": "ZK", "name": "Zambian kwacha"},
"ZWR": {"symbol": "Z$", "name": "Zimbabwean dollar"},
}
18 changes: 18 additions & 0 deletions tests/common/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from geld.common.validators import (
amount_validator,
currency_code_validator,
date_validator,
)


def validate_currency_conversion_data(func):
def _validate_entry_values(
self, from_currency, to_currency, amount=1, date="latest"
):
from_currency = currency_code_validator(from_currency)
to_currency = currency_code_validator(to_currency)
amount = amount_validator(amount)
date = date_validator(date)
return func(self, from_currency, to_currency, amount, date)

return _validate_entry_values
22 changes: 22 additions & 0 deletions tests/common/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class BaseUrlNotDefined(Exception):
pass


class InvalidCurrencyCode(Exception):
pass


class InvalidDate(Exception):
pass


class InvalidAmount(Exception):
pass


class APICallError(Exception):
pass


class HelperNotDefined(Exception):
pass
Loading

0 comments on commit b7da103

Please sign in to comment.