From dbca250486883952e11edccb5a95545e45dee1c5 Mon Sep 17 00:00:00 2001 From: Sue Lim Date: Sat, 14 Jun 2025 11:45:58 +0800 Subject: [PATCH 1/2] .\main.py --- Currency Script/{readme.txt => readme.md} | 0 Currency Script/tests/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 253 bytes ...t_api_handler.cpython-313-pytest-8.3.5.pyc | Bin 0 -> 2555 bytes ...est_converter.cpython-313-pytest-8.3.5.pyc | Bin 0 -> 2748 bytes ...st_currencies.cpython-313-pytest-8.3.5.pyc | Bin 0 -> 2525 bytes Currency Script/tests/test_api_handler.py | 37 ++++++++++++++++++ Currency Script/tests/test_converter.py | 33 ++++++++++++++++ Currency Script/tests/test_currencies.py | 33 ++++++++++++++++ 9 files changed, 103 insertions(+) rename Currency Script/{readme.txt => readme.md} (100%) create mode 100644 Currency Script/tests/__init__.py create mode 100644 Currency Script/tests/__pycache__/__init__.cpython-313.pyc create mode 100644 Currency Script/tests/__pycache__/test_api_handler.cpython-313-pytest-8.3.5.pyc create mode 100644 Currency Script/tests/__pycache__/test_converter.cpython-313-pytest-8.3.5.pyc create mode 100644 Currency Script/tests/__pycache__/test_currencies.cpython-313-pytest-8.3.5.pyc create mode 100644 Currency Script/tests/test_api_handler.py create mode 100644 Currency Script/tests/test_converter.py create mode 100644 Currency Script/tests/test_currencies.py diff --git a/Currency Script/readme.txt b/Currency Script/readme.md similarity index 100% rename from Currency Script/readme.txt rename to Currency Script/readme.md diff --git a/Currency Script/tests/__init__.py b/Currency Script/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Currency Script/tests/__pycache__/__init__.cpython-313.pyc b/Currency Script/tests/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52c26ecd042b37638f0c98822c5fcc345f9f3f13 GIT binary patch literal 253 zcmXw!OA5j;5QZBcAVTlp)}+1kwZO#K$a> zZ@$bAlQxcr5!d-O&%^x)$G^l6+8)Ct%A&DY-6HI8*M_J2bum?20wlGBT4l!P)lT{J z0P+MWT4OV%0lhS}G+sI^Gfa!(ql0oKDg6VP5&=;G){}CL&r2(L(uC9zG|Tl@ZZsOl s?V>^itDDhRC=bLoNjT$^Wa66pU{;j->I8G_^RnSH6yVtvLSUEa4J4aQ)Bpeg literal 0 HcmV?d00001 diff --git a/Currency Script/tests/__pycache__/test_api_handler.cpython-313-pytest-8.3.5.pyc b/Currency Script/tests/__pycache__/test_api_handler.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adca8b354e254993560a2e5a229bda372082cc19 GIT binary patch literal 2555 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 Hq1*oeCXJS{ literal 0 HcmV?d00001 diff --git a/Currency Script/tests/__pycache__/test_currencies.cpython-313-pytest-8.3.5.pyc b/Currency Script/tests/__pycache__/test_currencies.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adf1456a3126b9b5799b0049468f27033360830e GIT binary patch literal 2525 zcmdT`-ES0C6u+}GyF0rq)Y2BWr6d!A#HsEg#To+$*lnvRP?2E?hK)DV+1u@y+1c^l zJIMCI5I^ga#H5K|4<^1q;sbwz|3cF?tv4nZeL@pcD875{%zgkC^wsll=H7Ge`MBqI z&%Lv?b7vL-eevg+`QJ5!ev^|nC0m27>o8bC7P6Gnh$_)HF|D$Mfu=Q@G-6GPra+T8 zou1aIKAoW%1Le_vWT`{Q(kiL*{cX41@0c2o>5fXyN*=w0ki8orSUc2R(;n?dW38cq zYD!HpQ+MQi#!QHOjd0AuAZSods@MrBCBEYlCVE|luh^d35jLH+KlxQ!ldTtEu!Jhn z=4irFsA?ssCR3+LO9P&=lEBke3b<~iX{M%|8L{gEVZ77{cLxfH7R<8ma)X108FLM4 zw9;uB^TZ1XHReL!;cmlcMW-EKrXheM5X-I$9|+LRn>kT&dJtJ|E6j zxIIS-9g#x zjlMk_eZcc~Gs%6~MQu$V+>%9m2(AmE6$QH671Q#c`nhtwxk z!)ZWwINWO%X$At#m>QM)pgq7uj|717GcMzk?}oM~QY`8zQ>DF9uam0*7?Y|a%`pd_+n~9 z&#mjj%lh!Q7r&eO=ItLY-g!hnk594@1O*N7G0J*iO5o5g>2U^x&u<2F;$U`ag!P<<3(uF zsDx3I#_;To3jU8P5pysTBin(q{n|YcfxQIm8u~@gectm~&uZSh@yxCM^~2-KhsRg) zrB!_b@YznYrceBT0UGTB6#AV9=P@u%*&dTPy*geJ>ec3g#A!#2Q>1zVP{WS_YEHTo z(J|@1I>jd~-YcOx+J!PLU!FbN4jC-z6{06Ag7*`t(#8!>sdnY8}|{iGear=^qGd%Lyd$$L39IjQ`W zRg+UnY$r`*vUS__F*bJzeKvGG?)psRP6bWenGIriXyDo^#?ZjST%_bZ>T)779g#@4 zWmzze3T{)Ohw#$NiO9AddHCmuZ&R75&@X_lWW$XbZQxlc(_})l2*d9Fgnm4( Date: Sat, 14 Jun 2025 11:47:10 +0800 Subject: [PATCH 2/2] Updated Main.py, Readme, Requirements, Docstrings, Tests Files --- Currency Script/main.py | 40 +++++++++++++++++++-- Currency Script/readme.md | 58 +++++++++++++++++++++++++++++- Currency Script/requirements.txt | 2 +- Currency Script/setup.py | 10 +++++- Currency Script/src/api_handler.py | 16 ++++++--- Currency Script/src/converter.py | 7 ++-- Currency Script/src/currencies.py | 21 +++++++++-- 7 files changed, 138 insertions(+), 16 deletions(-) diff --git a/Currency Script/main.py b/Currency Script/main.py index ed705b92..f3643030 100644 --- a/Currency Script/main.py +++ b/Currency Script/main.py @@ -1,2 +1,38 @@ -# TODO IMPORT API / CONVERTER / CURRENCY MODULES -# TODO UPDATE / POPULATE MAIN TO ENSURE THERE IS A INTUITIVE SIMPLE UI \ No newline at end of file +""" +main.py - Simple CLI interface for Currency Converter + +Prompts user for input currencies and amount, and displays the converted value. +""" + +from converter import CurrencyConverter + +def main(): + """ + Run the interactive currency converter CLI loop. + Prompts user for source and target currencies and amount to convert. + Continues until the user types 'no' to exit. + """ + print("Welcome to the Currency Converter\n") + + converter = CurrencyConverter() + + while True: + try: + from_currency = input("Enter source currency code (e.g., AUD): ").strip().upper() + to_currency = input("Enter target currency code (e.g., USD): ").strip().upper() + amount = float(input(f"Enter amount in {from_currency}: ")) + + converted = converter.convert(from_currency, to_currency, amount) + print(f"\nāœ… {amount} {from_currency} = {converted} {to_currency}\n") + + except ValueError as e: + print(f"āŒ Error: {e}\n") + + # Ask to convert another or exit + again = input("Do you want to convert another amount? (yes/no): ").strip().lower() + if again != "yes": + print("Thank you for using the Currency Converter. Goodbye!") + break + +if __name__ == "__main__": + main() diff --git a/Currency Script/readme.md b/Currency Script/readme.md index 3202240d..8fed1611 100644 --- a/Currency Script/readme.md +++ b/Currency Script/readme.md @@ -1 +1,57 @@ -# TODO - UPDATE README \ No newline at end of file +Currency Converter +================== + +A simple Python CLI application that converts an amount from one currency to another +using live exchange rates fetched from an open API. + +Modules: +-------- + +1. **api_handler.py** + - Handles fetching exchange rate data from the online API. + +2. **currencies.py** + - Provides utility functions to list supported currencies and validate currency codes. + +3. **converter.py** + - Contains the core logic to convert between currencies using the exchange rates. + +4. **main.py** + - CLI interface where users input the currencies and amount to convert. + +5. **test_*.py** + - Unit tests for each module to ensure functionality. + +Requirements: +------------- +- Python 3.7+ +- `requests` library + +Install dependencies: +--------------------- +Run the following command to install dependencies: +- pip install -r requirements.txt + +How to Use: +----------- +Run the main script from the terminal: + +Follow the prompts to enter: +- Source currency code (e.g., USD) +- Target currency code (e.g., AUD) +- Amount to convert + +The app will display the converted amount and allow you to repeat or exit. + +Testing: +-------- +To run tests: +- python -m unittest discover + +Note: +----- +The conversion is based on live exchange rates retrieved from: +https://open.er-api.com/v6/latest + +Make sure you are connected to the internet when running the app. + diff --git a/Currency Script/requirements.txt b/Currency Script/requirements.txt index ef92400b..663bd1f6 100644 --- a/Currency Script/requirements.txt +++ b/Currency Script/requirements.txt @@ -1 +1 @@ -# TODO - UPDATE REQUIREMENTS TO NOTE INSTALLS ARE NOTED \ No newline at end of file +requests \ No newline at end of file diff --git a/Currency Script/setup.py b/Currency Script/setup.py index d1322786..de3a6108 100644 --- a/Currency Script/setup.py +++ b/Currency Script/setup.py @@ -1 +1,9 @@ -# UPDATE SETUP TO NOTE SET UP / PACKAGES \ No newline at end of file +from setuptools import setup + +setup( + name="currency_converter", + version="0.1", + install_requires=[ + "requests" + ], +) \ No newline at end of file diff --git a/Currency Script/src/api_handler.py b/Currency Script/src/api_handler.py index 6f3ed23a..8a8f192f 100644 --- a/Currency Script/src/api_handler.py +++ b/Currency Script/src/api_handler.py @@ -1,15 +1,23 @@ import requests def get_exchange_data(api_url: str = "https://open.er-api.com/v6/latest") -> dict: - """Fetch latest exchange data from the API.""" + """ + Retrieve the latest foreign exchange rates from the specified API. + + Args: + api_url (str): Endpoint to fetch exchange data from. Defaults to the open.er-api URL. + + Returns: + dict: A dictionary containing the base currency, timestamp, and exchange rates. + + Raises: + Exception: If the API request fails or returns a non-200 status. + """ response = requests.get(api_url) if response.status_code != 200: raise Exception(f"API request failed with status {response.status_code}") data = response.json() - # Ensure response was successful - if data.get("result") != "success": - raise Exception(f"API returned error: {data.get('error-type', 'Unknown error')}") return data # Includes 'base_code', 'time_last_update_utc', and 'rates' diff --git a/Currency Script/src/converter.py b/Currency Script/src/converter.py index faa21d69..df03f702 100644 --- a/Currency Script/src/converter.py +++ b/Currency Script/src/converter.py @@ -1,7 +1,3 @@ -""" -CurrencyConverter: Converts an amount from one currency to another using live exchange rates. -""" - from api_handler import get_exchange_data class CurrencyConverter: @@ -35,7 +31,8 @@ def convert(self, from_currency: str, to_currency: str, amount: float) -> float: converted_amount = round(amount_in_base * self.rates[to_currency], 2) return converted_amount -# --- DEBUG / MANUAL TEST --- +# --- DEBUG / MANUAL TEST SECTION --- +# This section runs only when you run this file directly (not when imported elsewhere) if __name__ == "__main__": print("Running manual test for CurrencyConverter...\n") diff --git a/Currency Script/src/currencies.py b/Currency Script/src/currencies.py index 1c387a4f..ba5be173 100644 --- a/Currency Script/src/currencies.py +++ b/Currency Script/src/currencies.py @@ -1,11 +1,28 @@ from api_handler import get_exchange_data -# Returns a list of all supported currency codes. def get_supported_currencies(rates): + """ + Return a list of supported currency codes from the rates dictionary. + + Args: + rates (dict): Dictionary of currency codes and their exchange rates. + + Returns: + list: List of supported currency codes (e.g., ['USD', 'EUR']). + """ return list(rates.keys()) -# Checks if a currency code is supported. def is_valid_currency(currency_code, rates): + """ + Check if the given currency code is valid and supported. + + Args: + currency_code (str): Currency code to validate (e.g., 'USD'). + rates (dict): Dictionary of available exchange rates. + + Returns: + bool: True if the currency code exists in the rates, False otherwise. + """ return currency_code.upper() in rates # --- DEBUG / MANUAL TEST SECTION ---