Joshua Blewitt

Josh Bank in Python! 🐍

I've recently been learning Python and it is growing on me as one of my favourite languages to work in. So in this week's blog post - I'll be talking about the new and improved, world famous, Josh Bank in Python! 🐍

If you want to take a look at the code, it can be found on my GitLab here.

For those who are unfamiliar with Josh Bank, it uses this api to get the recent exchange rates from the European Central Bank. I find that writing Josh Bank is a good project to get to grips with learning the syntax and the behaviours of a language.

First things first, we need to make a GET request! But to do that, we need to install an additional package called requests. In addition, we need to use the JSON and datetime packages as well.

import requests
import json
import datetime

With appropriate packages imported, lets get some user input for which currency they want to compare with!

# boolean for ensuring that a valid currency choice has been entered
check = False

while check == False:
    # take user selection and convert the string to upper
    selection = input(
        "Welcome to Josh Bank! Please enter the three character code for a currency (GBP, USD, JPY).\n> ").upper()
    #selection = selection.upper
    print(f"You have selected {selection}")
    address = "https://api.exchangeratesapi.io/latest?base=" + selection
    print(address)
    rates = requests.get(address)
    # printing the status code returned
    print(f"Status code from request is", rates.status_code)
    # print the content type of the response
    print(f"Content type is", rates.headers['content-type'])
    if rates.status_code == 400:
        print(f"Error! Please try again!")
        print(rates.content)
    if rates.status_code == 200:
        # break while loop
        check = True

So first, the program asks the user for a three character currency code and performs a GET request. Then, it will print some information about the request performed such as the status code and the content type of the response (which is an application/json). Then we move onto some error handling, an if statement which looks at the status code.

If the response returns 400 then the program will print an error message and the content from the response. The user will be asked to enter a three character code again (as this is in a while loop).

If the response returns 200 then the peogram will set the boolean variable check to true, which will end the loop.

Once we have content from the GET request - we need to get the content into something that can be read by Python.

# check the type of the rates variable
print(f"The type of variable rates is", type(rates))
# assign the response into a dictionary variable
rawData = rates.json()
print(f"The type of variable rawData is", type(rawData))
# since the data has nested objectes, a new dictionary is created consisting of just the currency rates
# a dictionary in Python is a collection which is unordered, changeable and indexed. No duplicate members are allowed.
currencyRates = rawData['rates']
print(f"The type of variable currencyRates is", type(currencyRates))

By using the 'type' function, I was able to determine the type of each variable. So...

  • The rates variable is a 'requests.models.Response' type
  • The rawData variable is a 'dict' type
  • The currencyRates variable is 'dict' type

A dictionary type will be useful! So the currencyRates dictionary holds the nested object of 'rates' from the rawData dictionary (which is from the rates variable).

Now we have our currencies loaded, let's create a switch statement for the menu!

....except Python doesn't have a switch statement.

To get around this, I wrote the menu in a while loop with a if/elif statement.

# boolean for menu loop
menuLoop = True
while menuLoop == True:
    print("""
Main menu
Enter a character for a menu choice!
(V)iew rates
(P)rint to file
(S)wap currency
(Q)uit application""")
    # since switch statement don't exist in Python, a nested if statement is used
    menuChoice = input(">").upper()
    if menuChoice == 'V':
        # print(currencyRates)
        viewRates(currencyRates)
    elif menuChoice == 'P':
        # print currency rates to an external file
        printToFile(currencyRates)
    if menuChoice == 'S':
        # swap selected currency to another currency
        swapCurrency(currencyRates, selection)
    if menuChoice == 'Q':
        # exist the program
        menuLoop = False
    else:
        # error handling
        print("")

Let's take a look at the viewRates function (which takes the currencyRates dictionary as an argument):

# function for viewing the rates
def viewRates(currencyRates):
    print(f"Now viewing rates as of", datetime.datetime.now())
    for key in currencyRates:
        print(key, currencyRates[key])
    enter = input("Press enter to return to the main menu.")

This function is straight forward - for every element in the dictionary, print them! (The key/value pair that is)

Next, we have the function for printing to an external file.

# function for printing currency rates to a file
def printToFile(currencyRates):
    time = datetime.datetime.now()
    # formatting datetime to string format (so that it can be written to a file)
    time.strftime("%d,%m,%Y,%H,%M")
    time = str(time)
    location = input(
        "Please state where you want the currency rates to be written to. \n>")
    print(f"You have specified", location)
    print(f"Now writing CurrencyRates.txt to - {location}")
    # creating a new file, using parameter w - will create a file if the specified file doesn't exist
    # you could use x but the program will fail if the file exists in specified location
    file = open("CurrencyRates.txt", "w")
    # writing to a file only allows text format, so json.dumps takes the dictionary and serialises it to a formatted string
    # write function only allows 1 argument
    file.write(time)
    file.write("\n")
    file.write(json.dumps(currencyRates))
    file.close()
    print("Complete!")
    enter = input("Press enter to return to the main menu.")

This was actually a little bit more challenging than I previously thought, one of which is that the write function only accepts the text format. So I couldn't use the dictionary in it's current state. I'd need to convert the contents to a string - but how? Well, by using json.dumps takes the dictionary and serialises it to a formatted string. That solves that!

I also wanted to print the current date as well - but again, write will only allow the text format. To get around that I used time.strftime to format the current time to a string. I added the directives to print; the day, the month, the year, the hour and the minute.

Before we start writing to a file, we need to open one or create one if it doesn't exist. That's why I use the parameter 'w' under opening a file. If the file doesn't exist, then Python will create it.

When it comes to writing content to the file, the write function only allows 1 argument, so I have to type out the write function multiple times. 🤦‍♂️

When all is said and done, we close it. Great! Now what does the file look like?

2019-12-16 18:26:32.823558
{"CAD": 1.7528022538, "HKD": 10.4125157346, "ISK": 163.9992807049, "PHP": 67.6389138644, "DKK": 8.9589402386, "HUF": 394.4254630462, "CZK": 30.5496613319, "GBP": 1.0, "RON": 5.7293052808, "SEK": 12.4933165498, "IDR": 18713.6246478451, "INR": 94.8346220704, "BRL": 5.453575496, "RUB": 83.7159983216, "HRK": 8.9193790086, "JPY": 146.2207037104, "THB": 40.3872205239, "CHF": 1.3130731883, "EUR": 1.1988251514, "MYR": 5.5346160762, "BGN": 2.344662231, "TRY": 7.8151411617, "CNY": 9.3538332434, "NOK": 12.0218186178, "NZD": 2.0210993227, "ZAR": 19.3376491039, "USD": 1.3362105137, "MXN": 25.417730624, "SGD": 1.8097464485, "AUD": 1.9393394473, "ILS": 4.6660672541, "KRW": 1564.071210214, "PLN": 5.1138284481}

Looks good! 👏

Our final function, is for swapping currency:

# function for swapping currency
def swapCurrency(currencyRates, selection):
    choice = input(f"Please enter the three character code of the currency you want to swap to.\nYou are currently looking at exchange rates for {selection}\n>").upper()
    print(f"You have selected {choice}")
    # try/except block to catch errors
    try:
        # accessing specific element in dictionary
        print(f"{choice} -", currencyRates[choice])
        print(f"The type of the currencyRates[choice] variable is", type(currencyRates[choice]))
        value = input(f"Please enter how much {selection} you would like to convert to {choice}\n>")
        value = float(value)
        print(f"The type of the value variable is,", type(value))
        calculation = value * currencyRates[choice]
        print(f"For {value} {selection} - you will receieve {calculation} {choice}")
        enter = input("Press enter to return to the main menu.")
    except:
        retry = input("An error occurred! Press enter to return to the main menu!")

One of the first things that you might notice here is the use of try and except. This is very similar to a try/catch statement in C#. It's designed to catch errors in case anything goes wrong.

The user's choice is then searched in the dictionary, when the value for said choice would be located.

Since the values in the dictionary are floats, the value the user enters for how much they want to convert is converted into a float from an int, so the calculation can take place.

This program is still very much in development, I need to add a try and except statement to printing a file for example.

I've enjoyed writing JoshBank in Python, the language itself is growing on me as one of my favourites.

Be sure to check back here next week for another post! 👏

Thanks for reading!

Tags:


A photo of me!

I'm Joshua Blewitt, I'm passionate about product, a technology advocate, customer champion, curious mind and writer. I've worked for companies such as Rightmove, Domino's Pizza and IQVIA.

Let me know your thoughts!
More about me