Python

TIL Python Basics Day 30 - Errors, Exceptions and JSON Data

daylee de vel 2021. 6. 17. 22:15
  • 벨로그 사이트 오류로 티스토리 블로그로 이동

Errors, Exceptions and JSON Data: Improving the Password Vault GUI app

Catch exceptions

Why?: To continue executing the whole script, even though there are errors.
When there are errors in code, it simply terminates execution at the first error, before it reaches the end of the script; however, with exception handling, we can catch errors while executing the whole program without needing to terminate it in the middle.

try: Something that might cause an exception
In most cases, it will work most of the time, but it might not work
except: Do this if there was an exception
You want the computer to execute if there was an exception, if something went wrong and if was not the way that you expected it to go. then carry out this code

else: Do this if there were no exceptions
-if 'try' had not occured any errors

finally: Do this no matter what happens
It's always going to be executed anyways to tidy things up or clean things up

Type of Errors
FileNotFoundError
TypeError
IndexError
KeyError

Exception Handling

to prevent the program from crashing.

1.try
Try this, if fails, we will do except

try:
    file = open("a_file.txt")
    a_dictionary = {"key": "value"}
    print(a_dictionary["key"])

2. except
if 'try:' didn't work, we will do this alternatively; however, if no error found at try level, nothing happens

Specifying Error:
if you give exception to catch a SPECIFIC situation, such as except FileNotFoundError, only catches an specified error (e.g.FileNotFoundError)

except FileNotFoundError:
    file = open("a_file.txt", "w")
    file.write("Something")

when catching an exception, we can hold an error message as a variable, and print out the message

except KeyError as error_message:
    print(f"The key {error_message} does not exist.")

3. else
else always has to come after except. except cannot be skipped before else.

try:
texting code
exccept:
if there is an exception(error), execute this code
else:
if there is NO excption(error), execute this code

4.finally
regardless error occurance, finally can skip 'except' and 'else'

#Exception Handling

try:
    file = open("a_file.txt")
    a_dictionary = {"key": "value"}
    print(a_dictionary["key"])
except FileNotFoundError:
    file = open("a_file.txt", "w")
    file.write("Something")
else:
    content = file.read()
    print(content)
finally:
    raise TypeError("This is an error that I made up.")

Raise your own exceptions

Even though the code is perfectly valid, in fact, it's going to generate wrong results. In the example code, human height cannot be over 3meters, so logically wrong; hence, raise an error

#BMI Example
height = float(input("Height: "))
weight = int(input("Weight: "))

if height > 3:
    raise ValueError("Human Height should not be over 3 meters.")

bmi = weight / height ** 2
print(bmi)

Task.1
Use what you've learnt about exception handling to prevent the program from crashing. If the user enters something that is out of range just print a default output of "Fruit pie". e.g.
def make_pie(index):

fruits = ["Apple", "Pear", "Orange"]

#TODO: Catch the exception and make sure the code runs without crashing.

def make_pie(index):
  try:
    fruit = fruits[index]
  except IndexError:
    print("Fruit Pie")
  else:
     print(fruit + " pie")
make_pie(4)


#printed: Fruit Pie

*Task.2 *

facebook_posts = [
    {'Likes': 21, 'Comments': 2}, 
    {'Likes': 13, 'Comments': 2, 'Shares': 1}, 
    {'Likes': 33, 'Comments': 8, 'Shares': 3}, 
    {'Comments': 4, 'Shares': 2}, 
    {'Comments': 1, 'Shares': 1}, 
    {'Likes': 19, 'Comments': 3}
]

total_likes = 0
for post in facebook_posts:
  try:
    total_likes = total_likes + post['Likes']
  except KeyError:
    total_likes += 0
    #or
    pass 
print(total_likes)
#printed: 86

Task.3 Improving NATO

phonetic_dict = {'A': 'Alfa', 'B': 'Bravo', 'C': 'Charlie', 'D': 'Delta', 'E': 'Echo', 'F': 'Foxtrot', 'G': 'Golf', 'H': 'Hotel', 'I': 'India', 'J': 'Juliet', 'K': 'Kilo', 'L': 'Lima', 'M': 'Mike', 'N': 'November', 'O': 'Oscar', 'P': 'Papa', 'Q': 'Quebec', 'R': 'Romeo', 'S': 'Sierra', 'T': 'Tango', 'U': 'Uniform', 'V': 'Victor', 'W': 'Whiskey', 'X': 'X-ray', 'Y': 'Yankee', 'Z': 'Zulu'}


def generate_phonetic():
    word = input("Enter a word: ").upper()
    try:
        output_list = [phonetic_dict[letter] for letter in word]
    except KeyError:
        print("Sorry, only letters in the alphabet please")
        generate_phonetic()
    else:
        print(output_list)

generate_phonetic()

#printed: 
Enter a word: 234
Sorry, only letters in the alphabet please
Enter a word: hi
['Hotel', 'India']

Json

Json is JavaScript Object Notation
-Dictionary format
-popular way to transfering data across the internet

Write

json.dump()

-Data format should be nested dictionary {key:{key:value}}

    new_data = {
        website: {
            "email": email,
            "password": password,
        }
    }

-Open a .json file, store dict values into data_file(==data.json), indent=4 is to create spaces on json file

with open("data.json", "w") as data_file:
    json.dump(new_data, data_file, indent=4)

#input values stored in the data.json file. Indented 4 times 
{
    "e": {
        "email": "angela@gmail.com",
        "password": "t!zYK2+zFX*6ZF"
    }
}

Read

-Take json data and convert it into python dictionary
json.load()

with open("data.json", "r") as data_file:
      data = json.load(data_file)
      print(data)

 #printed: console
 {'e': {'email': 'angela@gmail.com', 'password': 't!zYK2+zFX*6ZF'}}

Update

-Update only works when there is an existing data in the file.
if we use append as with open("data.json", "a"), it doesn't make a valid data structure in the file and cause an error.

example of invalid json data. It created two dictionaries in one file.


{

    "a": {
        "email": "angela@gmail.com",
        "password": "qjc!dU$7WTmk1(V"
    }
}
{
    "b": {
        "email": "angela@gmail.com",
        "password": "2t&+kNRlcc6Mj"
    }

}

json.update()

 with open("data.json", "r") as data_file:

        #Reading old data
        data = json.load(data_file)
        #Updating old data with new data/ variable data is json
        data.update(new_data)

 with open("data.json", "w") as data_file:
        #Saving updated data
        json.dump(data, data_file, indent=4)

- Nicely formatted at json.file


{

    "a": {
        "email": "angela@gmail.com",
        "password": "qjc!dU$7WTmk1(V"
    },
    "b": {
        "email": "angela@gmail.com",
        "password": "2t&+kNRlcc6Mj"
    },

}
  • Applied exception handling to password project
      else:
          try:
              with open("data.json", "r") as data_file:
                  # Reading old data
                  data = json.load(data_file)
    
    
    except FileNotFoundError :
        with open("data.json", "w") as data_file:
            json.dump(new_data, data_file, indent=4)

    else:
        # Updating old data with new data/ variable data is json
        data.update(new_data)

        with open("data.json", "w") as data_file:
            # Saving updated data
            json.dump(data, data_file, indent=4)

    finally:
        website_entry.delete(0, END)
        password_entry.delete(0, END)
### Final Proejct.
#### Password Manager with search function (with Json file)

![](https://images.velog.io/images/daylee/post/b1a117c6-46d5-4d2a-a9f0-dd602be67fa7/image.png) ![](https://images.velog.io/images/daylee/post/f65ab72c-f790-4a79-9a18-69e4f044b97f/image.png)

Final code 

from tkinter import *
from tkinter import messagebox
from random import choice, randint, shuffle
import pyperclip
import json

---------------------------- PASSWORD SEARCH -------------------------------

def find_password():
website = website_entry.get()
try:
with open("data.json", "r") as data_file:
# Reading old data
data = json.load(data_file) # dictionary
except FileNotFoundError:
messagebox.showwarning(title="info",
message="No Data File Found")
else:
if website in data:
password = data[website]['password']
messagebox.askokcancel(title="info",
message=f"These are the details for {website}: \nPassword: {password}\n ")
elif website not in data:
messagebox.showwarning(title="info",
message="No details for the website exists.")

---------------------------- PASSWORD GENERATOR -------------------------------

#Password Generator Project
def generate_password():
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']

password_letters = [choice(letters) for _ in range(randint(8, 10))]
password_symbols = [choice(symbols) for _ in range(randint(2, 4))]
password_numbers = [choice(numbers) for _ in range(randint(2, 4))]

password_list = password_letters + password_symbols + password_numbers
shuffle(password_list)

password = "".join(password_list)
password_entry.insert(0, password)
pyperclip.copy(password)

---------------------------- SAVE PASSWORD -------------------------------

def save():

website = website_entry.get()
email = email_entry.get()
password = password_entry.get()
new_data = {
    website: {
        "email": email,
            "password": password,
    }
}

if len(website) == 0 or len(password) == 0:
    messagebox.showinfo(title="Oops", message="Please make sure you haven't left any fields empty.")
else:
    try:
        with open("data.json", "r") as data_file:
            # Reading old data
            data = json.load(data_file)


    except FileNotFoundError :
        with open("data.json", "w") as data_file:
            json.dump(new_data, data_file, indent=4)

    else:
        # Updating old data with new data/ variable data is json
        data.update(new_data)

        with open("data.json", "w") as data_file:
            # Saving updated data
            json.dump(data, data_file, indent=4)

    finally:
        website_entry.delete(0, END)
        password_entry.delete(0, END)

---------------------------- UI SETUP -------------------------------

window = Tk()
window.title("Password Manager")
window.config(padx=50, pady=50)

canvas = Canvas(height=200, width=200)
logo_img = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=logo_img)
canvas.grid(row=0, column=1)

#Labels
website_label = Label(text="Website:")
website_label.grid(row=1, column=0)
email_label = Label(text="Email/Username:")
email_label.grid(row=2, column=0)
password_label = Label(text="Password:")
password_label.grid(row=3, column=0)

#Entries
website_entry = Entry(width=41)
website_entry.grid(row=1, column=1, columnspan=2)
website_entry.focus()
email_entry = Entry(width=41)
email_entry.grid(row=2, column=1, columnspan=2)
email_entry.insert(0, "angela@gmail.com")
password_entry = Entry(width=25)
password_entry.grid(row=3, column=1)

Buttons

search_button = Button(text="Search", width=15, command=find_password)
search_button.grid(row=1, column=2)
generate_password_button = Button(text="Generate Password", command=generate_password)
generate_password_button.grid(row=3, column=2)
add_button = Button(text="Add", width=42, command=save)
add_button.grid(row=4, column=1, columnspan=2)

window.mainloop()



```


Murphy's law is an adage or epigram that is typically stated as: "Anything that can go wrong will go wrong".

  • The Starbucks Edict - As soon as you sit down to a cup of hot coffee, your boss will ask you to do something which will last until the coffee is cold. Murphy's Law of Lockers -If there are only two people in a locker room, they will have adjacent lockers
  • Yhprum's law is the opposite of Murphy's law. The simple formula of Yhprum's law is: "Everything that can work, will work.