-
Notifications
You must be signed in to change notification settings - Fork 325
Currency Converter Improved #1418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
cca512c
dd4f570
b4ff9a3
f3a952a
9d81005
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,108 @@ | ||||||||||||
# 💱 Currency Converter GUI (Python + Tkinter) | ||||||||||||
|
||||||||||||
A simple, elegant desktop application that converts currencies using real-time exchange rates. Built with Python and Tkinter, and includes light/dark theme toggle support! 🌗 | ||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
## 📚 Table of Contents | ||||||||||||
|
||||||||||||
- [🚀 Features](#-features) | ||||||||||||
- [🖼️ App Preview](#️-app-preview) | ||||||||||||
- [⚙️ How to Run](#️-how-to-run) | ||||||||||||
- [🔐 API Access Notes](#-api-access-notes) | ||||||||||||
- [👤 Signature](#-project-admin) | ||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
## 🚀 Features | ||||||||||||
|
||||||||||||
- 💵 Convert any currency to another using **live exchange rates** | ||||||||||||
- 🌗 Toggle between **light and dark themes** | ||||||||||||
- ✅ Validates user input with helpful error messages | ||||||||||||
- 💡 Beginner-friendly GUI design using Tkinter | ||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
## 🖼️ App Preview | ||||||||||||
|
||||||||||||
> Example: | ||||||||||||
>  | ||||||||||||
>  | ||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
## ⚙️ How to Run | ||||||||||||
|
||||||||||||
1. **Clone this repo** | ||||||||||||
```bash | ||||||||||||
git clone https://github.com/UTSAV26/PyVerse.git | ||||||||||||
cd PyVerse/Beginner_Projects/API-key_free_Currency_Converter | ||||||||||||
``` | ||||||||||||
|
||||||||||||
2. **Create a Virtual Environment** | ||||||||||||
```bash | ||||||||||||
python -m venv venv | ||||||||||||
source venv/Scripts/activate ----> for ac use: venv/bin/activate | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix virtual environment activation command. The activation command has incorrect syntax and unclear instructions. - source venv/Scripts/activate ----> for ac use: venv/bin/activate
+ # On Windows:
+ venv\Scripts\activate
+ # On macOS/Linux:
+ source venv/bin/activate 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||
``` | ||||||||||||
3. **Install dependencies** | ||||||||||||
- Make sure Python 3.6+ is Installed | ||||||||||||
- (Only `requests` is needed) | ||||||||||||
```bash | ||||||||||||
pip install requests | ||||||||||||
``` | ||||||||||||
- Tkinter is usually pre-installed with Python. If not: | ||||||||||||
- On Windows: Install Python from the official website | ||||||||||||
- On Linux: sudo apt-get install python3-tk | ||||||||||||
- On Mac: Already included with Python | ||||||||||||
|
||||||||||||
4. **Set your API-Key** | ||||||||||||
- Create a file called `.env` in the project folder | ||||||||||||
- Add your CurrencyFreaks key: | ||||||||||||
```ini | ||||||||||||
API_KEY=your_key_here | ||||||||||||
``` | ||||||||||||
|
||||||||||||
5. **Run the application** | ||||||||||||
```bash | ||||||||||||
currency_converter.py | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix Python script execution instruction. The instruction should use - currency_converter.py
+ python currency_converter.py
+ # Alternatively, use the batch script on Windows:
+ run_converter.bat 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||
``` | ||||||||||||
Comment on lines
+66
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix Python execution command. The execution command is incomplete. - ```bash
- currency_converter.py
- ```
+ ```bash
+ python currency_converter.py
+ ```
+
+ Or use the provided batch script on Windows:
+ ```bash
+ run_converter.bat
+ ```
<details>
<summary>🤖 Prompt for AI Agents</summary>
In Beginner_Projects/Currency-Converter-with toggletheme/README.md at lines 66
|
||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
## 🔐 API Access Notes | ||||||||||||
|
||||||||||||
This app currently uses the **[CurrencyFreaks API](https://www.currencyfreaks.com/)** | ||||||||||||
Follow these steps: | ||||||||||||
|
||||||||||||
1. **Check the official docs:** | ||||||||||||
2. **API key is required**: | ||||||||||||
- Register for one on their website. Copy your API Key | ||||||||||||
- Create a file named `.env` in the project folder. (if it dooesn't alr exist) | ||||||||||||
- Add your CurrencyFreaks key: | ||||||||||||
```ini | ||||||||||||
API_KEY=your_key_here | ||||||||||||
``` | ||||||||||||
- For security: | ||||||||||||
- Never commit API keys to GitHub | ||||||||||||
|
||||||||||||
3. **Alternative APIs you can switch to**: | ||||||||||||
- [Open Exchange Rates](https://openexchangerates.org/) | ||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
### Ways to Contribute: | ||||||||||||
- 🐛 Report issues or bugs | ||||||||||||
- 🎨 Improve the UI or theme | ||||||||||||
- 🌍 Add localization/multi-language support | ||||||||||||
|
||||||||||||
Fork the repo, make your changes, and open a PR! 💖 | ||||||||||||
|
||||||||||||
--- | ||||||||||||
|
||||||||||||
## 👤 Signature: | ||||||||||||
|
||||||||||||
> **Yashasvi Jain** | ||||||||||||
> Github: https://github.com/Y4shu | ||||||||||||
> LinkedIn: https://www.linkedin.com/in/yashasvi-jain-44a553322/ | ||||||||||||
|
||||||||||||
--- |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,173 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import tkinter as tk | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import requests # type: ignore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from tkinter import messagebox | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from dotenv import load_dotenv | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
load_dotenv() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
API_KEY =os.getenv("API_KEY") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix formatting and add API key validation. Missing whitespace around the assignment operator and consider adding validation for the API key. load_dotenv()
-API_KEY =os.getenv("API_KEY")
+API_KEY = os.getenv("API_KEY")
+
+if not API_KEY:
+ import tkinter.messagebox as messagebox
+ messagebox.showerror("Configuration Error",
+ "API_KEY not found in environment variables.\n"
+ "Please create a .env file with your CurrencyFreaks API key.")
+ exit(1) 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Flake8 (7.2.0)[error] 8-8: missing whitespace around operator (E225) 🤖 Prompt for AI Agents
🛠️ Refactor suggestion Fix API key loading and add validation. The API key loading has formatting issues and lacks validation. An application should gracefully handle missing API keys. load_dotenv()
-API_KEY =os.getenv("API_KEY")
+API_KEY = os.getenv("API_KEY")
+
+if not API_KEY:
+ import tkinter.messagebox as messagebox
+ messagebox.showerror("Configuration Error",
+ "API_KEY not found in environment variables.\n"
+ "Please create a .env file with your CurrencyFreaks API key.")
+ exit(1) 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Flake8 (7.2.0)[error] 8-8: missing whitespace around operator (E225) 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#Adding placeholders to avoid hardcoding | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PLACEHOLDER_FROM = "eg: USD" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PLACEHOLDER_TO ="eg: INR" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PLACEHOLDER_AMOUNT = "eg: 250.00" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#keeping the intial theme as light | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
is_dark_mode = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#the different themes: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Themes = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"light":{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"background_color": "#E0F7FA", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"foreground_color": "#333333", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"entry_bg": "#F0F0F0", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"button_background": "#4CAF50", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"button_foreground": "#F0F0F0" #fixed typo | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"dark":{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"background_color": "#2C2C2C", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"foreground_color": "#EEEEEE", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"entry_bg": "#292929", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"button_background": "#FFB300", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"button_foreground": "#F0F7FA" #fixed typo | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#window components setting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root = tk.Tk() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root.title("Currency Converter") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root.geometry("360x380") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root.resizable(False, False) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FONT_LABEL = ("Helvetica", 10, "bold") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FONT_ENTRY = ("Helvetica", 11) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FONT_RESULT = ("Helvetica", 12, "bold") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#func to apply theme | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def apply_theme(theme_name): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
theme = Themes[theme_name] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root.configure(bg=theme["background_color"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for widget in root.winfo_children(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cls = widget.__class__.__name__ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if cls == "Entry": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
widget.configure(bg=theme["entry_bg"], fg=theme["foreground_color"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif cls == "Button": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if widget['text'] == "Toggle Theme": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
widget.configure(bg="#888", fg="#F0F0F0") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
widget.configure(bg=theme["button_background"], fg=theme["button_foreground"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif cls == "Label": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
widget.configure(bg=theme["background_color"], fg=theme["foreground_color"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#toggle func | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def toggle_theme(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
global is_dark_mode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
is_dark_mode = not is_dark_mode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
theme = "dark" if is_dark_mode else "light" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apply_theme(theme) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#conversion logic | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#modified this so that error message resets after a success and hadles the edge cases better | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def convert_currency(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#definig them | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from_curr = entry_from.get().upper().strip() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
to_curr = entry_to.get().upper().strip() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
amount = entry_amount.get().strip() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if from_curr in ["", PLACEHOLDER_FROM] or to_curr in ["", PLACEHOLDER_TO] or amount in ["", PLACEHOLDER_AMOUNT]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.config(text="Please fill all fields with valid values.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
amount = float(amount) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ValueError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.config(text="Invalid amount. Please enter a valid number.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#api url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
url = f"https://api.currencyfreaks.com/latest?apikey={API_KEY}&symbols={from_curr},{to_curr}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify API endpoint security and rate limiting. The current implementation constructs the API URL with the API key as a query parameter, which may be logged in server access logs. Consider the security implications and rate limiting. 🌐 Web query:
💡 Result: Security Best Practices for CurrencyFreaks API Key Usage
Rate Limiting Considerations
Summary Table
Following these practices will help ensure your CurrencyFreaks API usage remains secure and within quota, reducing risks of abuse, service interruption, or data loss[1][4][5][9][10]. Citations:
Ensure Secure API Key Handling & Rate Limit Resilience – Avoid embedding the API key in the URL (it can leak via logs or referrers). Instead: Locations to update:
Suggested diff: - url = f"https://api.currencyfreaks.com/latest?apikey={API_KEY}&symbols={from_curr},{to_curr}"
- response = requests.get(url)
+ url = f"https://api.currencyfreaks.com/latest?symbols={from_curr},{to_curr}"
+ headers = {"Authorization": f"Bearer {API_KEY}"}
+ response = requests.get(url, headers=headers)
+ if response.status_code == 429:
+ # TODO: back off and retry when quota resets
+ raise RuntimeError("Rate limit exceeded, retry later") 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response = requests.get(url) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.raise_for_status() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data = response.json() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
base_currency = data.get("base", "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rates = data.get("rates",{}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#taking care of base case and falling back to usd incase either from or t_curr is the base currrency. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rate_from = float(rates.get(from_curr)) if from_curr !=base_currency else 1.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rate_to = float(rates.get(to_curr)) if to_curr != base_currency else 1.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if not rate_from or not rate_to: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.config(text="Invalid currency codes or Unvailable rate. \n Please try again.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+99
to
+105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix formatting and improve logic clarity. The currency conversion logic has formatting issues and could be clearer. - #taking care of base case and falling back to usd incase either from or t_curr is the base currrency.
- rate_from = float(rates.get(from_curr)) if from_curr !=base_currency else 1.0
+ # Taking care of base case and falling back to USD in case either from or to_curr is the base currency.
+ rate_from = float(rates.get(from_curr)) if from_curr != base_currency else 1.0
rate_to = float(rates.get(to_curr)) if to_curr != base_currency else 1.0
- if not rate_from or not rate_to:
- error_label.config(text="Invalid currency codes or Unvailable rate. \n Please try again.")
+ if rate_from is None or rate_to is None:
+ error_label.config(text="Invalid currency codes or unavailable rate.\nPlease try again.")
return 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Flake8 (7.2.0)[error] 99-99: block comment should start with '# ' (E265) [error] 100-100: missing whitespace around operator (E225) 🤖 Prompt for AI Agents
Fix critical logic error in currency conversion. The current logic has a significant flaw that will cause incorrect conversions or crashes when currency codes are not found in the API response. - #taking care of base case and falling back to usd incase either from or t_curr is the base currrency.
- rate_from = float(rates.get(from_curr)) if from_curr !=base_currency else 1.0
- rate_to = float(rates.get(to_curr)) if to_curr != base_currency else 1.0
+ # taking care of base case and falling back to usd in case either from or to_curr is the base currency.
+ rate_from = float(rates.get(from_curr, 0)) if from_curr != base_currency else 1.0
+ rate_to = float(rates.get(to_curr, 0)) if to_curr != base_currency else 1.0
- if not rate_from or not rate_to:
- error_label.config(text="Invalid currency codes or Unvailable rate. \n Please try again.")
+ if rate_from == 0 or rate_to == 0:
+ error_label.config(text="Invalid currency codes or unavailable rate.\nPlease try again.")
return The original code will raise a 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Flake8 (7.2.0)[error] 99-99: block comment should start with '# ' (E265) [error] 100-100: missing whitespace around operator (E225) 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#since it used usd as base we convert using usd as base | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
usd_amount = amount/rate_from #converted to usd | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
converted = round(usd_amount * rate_to, 2) #converted to to_curr | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+99
to
+109
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical flaw in currency conversion logic. The conversion logic has a fundamental mathematical error that will produce incorrect results in most cases. The current logic assumes you can convert through USD by dividing by the source rate and multiplying by the target rate, but this is only valid when the API returns rates relative to USD as the base currency. However, the code doesn't verify this assumption. More critically, the logic on lines 100-101 uses rates directly from the API without considering what the actual base currency is. If the base currency is not USD, the conversion will be completely wrong. - #taking care of base case and falling back to usd incase either from or t_curr is the base currrency.
- rate_from = float(rates.get(from_curr)) if from_curr !=base_currency else 1.0
- rate_to = float(rates.get(to_curr)) if to_curr != base_currency else 1.0
-
- if not rate_from or not rate_to:
- error_label.config(text="Invalid currency codes or Unvailable rate. \n Please try again.")
- return
-
- #since it used usd as base we convert using usd as base
- usd_amount = amount/rate_from #converted to usd
- converted = round(usd_amount * rate_to, 2) #converted to to_curr
+ # Handle conversion properly regardless of base currency
+ if from_curr == base_currency:
+ rate_from = 1.0
+ elif from_curr in rates:
+ rate_from = float(rates[from_curr])
+ else:
+ error_label.config(text="Invalid source currency code.")
+ return
+
+ if to_curr == base_currency:
+ rate_to = 1.0
+ elif to_curr in rates:
+ rate_to = float(rates[to_curr])
+ else:
+ error_label.config(text="Invalid target currency code.")
+ return
+
+ # Convert: amount in from_curr -> base currency -> to_curr
+ base_amount = amount / rate_from
+ converted = round(base_amount * rate_to, 2) 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Flake8 (7.2.0)[error] 99-99: block comment should start with '# ' (E265) [error] 100-100: missing whitespace around operator (E225) [error] 107-107: block comment should start with '# ' (E265) [error] 108-108: at least two spaces before inline comment (E261) [error] 108-108: inline comment should start with '# ' (E262) [error] 109-109: at least two spaces before inline comment (E261) [error] 109-109: inline comment should start with '# ' (E262) 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
result_label.config(text=f"{amount} {from_curr} = {converted} {to_curr}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.config(text="")#error cleared after a success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except requests.RequestException: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.config(text="Network error. Check your internet or API key.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ValueError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.config(text="Error processing the exchange rate.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#here since the earlier one (frankfurt) changed their documents (inr isn't included anymore) i had to ended switching over currencyfreaks. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#however to access the converstion i would have to buy the starter plan so to avoid that i removed the base case. But since it's possible | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#that some currencies might be the base so to counter that i used the above logic that runs independent of what the base currency is and will work | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#even in the case of the from_curr and to_curr beign one of the base currencies. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#label+entry func | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def labeled_entry(labe_text, placeholder): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
label = tk.Label(root, text=labe_text, font=FONT_LABEL) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
label.pack(pady=(10,2)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry = tk.Entry(root, font=FONT_ENTRY, width=30, bd=2,relief="groove",fg='gray') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.insert(0, placeholder) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def on_focus_in(event): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if entry.get() == placeholder: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.delete(0, tk.END) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.config(fg='black') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def on_focus_out(event): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if not entry.get(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.insert(0, placeholder) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.config(fg='gray') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.bind("<FocusIn>", on_focus_in) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.bind("<FocusOut>", on_focus_out) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry.pack() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return entry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#Input fields: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#modified for placeholder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry_from = labeled_entry("From Currency Code (3 letters):", PLACEHOLDER_FROM) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry_to = labeled_entry("To Currency Code (3 letters):", PLACEHOLDER_TO) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
entry_amount = labeled_entry("Amount:", PLACEHOLDER_AMOUNT) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#convertion button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
convert_button = tk.Button(root, text="Convert", command=convert_currency, font=FONT_LABEL, width=15) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
convert_button.pack(pady=15) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#result label: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
result_label = tk.Label(root, text="", font=FONT_RESULT) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
result_label.pack(pady=15) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#error label: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label = tk.Label(root, text="", fg="red", font=("Helvetica", 10, "italic")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error_label.pack(pady=(5, 0)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#toggling button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
toggle_button = tk.Button(root, text="Toggle Theme", command=toggle_theme, font=("Helvetica", 9, "bold")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
toggle_button.pack(pady=5) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apply_theme("light") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#to start the conversion (instead onf clicking on convert just simply pressing enter): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root.bind("<Return>", lambda event:convert_currency()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
root.mainloop() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
@echo off | ||
start "" "%~dp0venv\Scripts\pythonw.exe" "%~dp0currency_converter.py" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect directory path in clone instructions.
The path referenced in the clone instructions doesn't match the actual project structure.
📝 Committable suggestion
🤖 Prompt for AI Agents
Fix incorrect repository path in clone instructions.
The path in the clone instructions doesn't match the actual project structure.
📝 Committable suggestion
🤖 Prompt for AI Agents
Fix incorrect repository path in clone instructions.
The clone path doesn't match the actual project structure based on the file paths provided.
📝 Committable suggestion
🤖 Prompt for AI Agents