Class and Object Code

Attempted w/out Hack Helper (Doesn't work)

# Werkzeug is a collection of libraries that can be used to create a WSGI (Web Server Gateway Interface)
# A gateway in necessary as a web server cannot communicate directly with Python.
# In this case, imports are focused on generating hash code to protect passwords.
from werkzeug.security import generate_password_hash, check_password_hash
import json
from datetime import date

def calculate_age(born):
    today = date.today()
    return today.year - born.year - ((today.month, today.day) < (born.month, born.day))

dob1 = date(2010,2,10)
age1 = calculate_age(dob1)
dob2 = date(2001,5,13)
age2 = calculate_age(dob2)
dob3 = date(2012,4,3)
age3 = calculate_age(dob3)
dob4 = date(2006,7,14)
age4 = calculate_age(dob4)
dob5 = date(2009,11,22)
age5 = calculate_age(dob5)

print(age1, age2, age3, age4, age5)


# Define a User Class/Template
# -- A User represents the data we want to manage
class User:    
    # constructor of a User object, initializes the instance variables within object (self)
    def __init__(self, name, uid, password, classOf, dob, age):
        self._name = name    # variables with self prefix become part of the object, 
        self._uid = uid
        self.set_password(password)
        self.classOf = classOf
        self.dob = dob
        self.age = age


    @property
    def age(self):
        return self._age
    
    @property
    def dob(self):
        return self._dob
    
    @dob.setter
    def dob(self, dob):
        self._dob = dob
    
    @property
    def classOf(self):
        return self._classOf
    
    @classOf.setter
    def classOf(self, classOf):
        self._classOf = classOf

    def is_classOf(self, classOf):
        return self._classOf == classOf

    # a name getter method, extracts name from object
    @property
    def name(self):
        return self._name
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def name(self, name):
        self._name = name
    
    # a getter method, extracts email from object
    @property
    def uid(self):
        return self._uid
    
    # a setter function, allows name to be updated after initial object creation
    @uid.setter
    def uid(self, uid):
        self._uid = uid
        
    # check if uid parameter matches user id in object, return boolean
    def is_uid(self, uid):
        return self._uid == uid
    
    @property
    def password(self):
        return self._password[0:10] + "..." # because of security only show 1st characters


    # output content using str(object) in human readable form, uses getter
    def __str__(self):
        return f'name: "{self.name}", id: "{self.uid}", psw: "{self.password}", classOf: "{self.classOf}", dob: "{self.dob}", age: "{self.age}"'

    # output command to recreate the object, uses attribute directly
    def __repr__(self):
        return f'Person(name={self._name}, uid={self._uid}, password={self._password}, classOf={self._classOf}, dob={self._dob}, age={self._age})'


# tester method to print users
def tester(users, uid, psw):
    result = None
    for user in users:
        # test for match in database
        if user.uid == uid and user.is_password(psw):  # check for match
            print("* ", end="")
            result = user
        # print using __str__ method
        print(str(user))
    return result


        

# place tester code inside of special if!  This allows include without tester running
if __name__ == "__main__":

    u1 = User(name='Thomas Edison', uid='toby', password='123toby', classOf="2021", dob="2010-2-10", age1)
    u2 = User(name='Nicholas Tesla', uid='nick', password='123nick', classOf="2024", dob="2001-5-13", age2)
    u3 = User(name='Alexander Graham Bell', uid='lex', password='123lex', classOf="2018", dob="2012-4-3", age3)
    u4 = User(name='Eli Whitney', uid='eli', password='123eli', classOf="2015", dob="2006-7-14", age4)
    u5 = User(name='Hedy Lemarr', uid='hedy', password='123hedy', classOf="2022", dob="2009-11-22", age5)

    # put user objects in list for convenience
    users = [u1, u2, u3, u4, u5]

    # Find user
    print("Test 1, find user 3")
    u = tester(users, u3.uid, "123lex")


    # Change user
    print("Test 2, change user 3")
    u.name = "John Mortensen"
    u.uid = "jm1021"
    u.classOf = "2016"
    u.dob = "1998"
    u.set_password("123qwerty")
    u = tester(users, u.uid, "123qwerty")




    # Make dictionary
    ''' 
    The __dict__ in Python represents a dictionary or any mapping object that is used to store the attributes of the object. 
    Every object in Python has an attribute that is denoted by __dict__. 
    Use the json.dumps() method to convert the list of Users to a JSON string.
    '''
    print("Test 3, make a dictionary")
    json_string = json.dumps([user.__dict__ for user in users]) 
    print(json_string)

    print("Test 4, make a dictionary")
    json_string = json.dumps([vars(user) for user in users]) 
    print(json_string)
  Input In [27]
    u1 = User(name='Thomas Edison', uid='toby', password='123toby', classOf="2021", dob="2010-2-10", age1)
                                                                                                         ^
SyntaxError: positional argument follows keyword argument

Before the hack helper, I was able to get date of birth (dob) and classOf done but I ran into a problem with age. If you entered age as age=dob(2020-12-1) then it would show up as a error because json cannot convert that data. All in all, I came pretty close but could not do it before the hack helper

All Completed Hacks w/ Requirements

Add new attributes/variables to the Class. Make class specific to your CPT work.

  • Add classOf attribute to define year of graduation
    • Add setter and getter for classOf
  • Add dob attribute to define date of birth
    • This will require investigation into Python datetime objects as shown in example code below
    • Add setter and getter for dob
  • Add instance variable for age, make sure if dob changes age changes
    • Add getter for age, but don't add/allow setter for age
  • Update and format tester function to work with changes

Start a class design for each of your own Full Stack CPT sections of your project

  • Use new code cell in this notebook
  • Define init and self attributes
  • Define setters and getters
  • Make a tester

Start Code for Hacks + Age attempt

from datetime import date

def calculate_age(born):
    today = date.today()
    return today.year - born.year - ((today.month, today.day) < (born.month, born.day))

dob1 = date(2010,2,10)
age1 = calculate_age(dob1)
dob2 = date(2001,5,13)
age2 = calculate_age(dob2)
dob3 = date(2012,4,3)
age3 = calculate_age(dob3)
dob4 = date(2006,7,14)
age4 = calculate_age(dob4)
dob5 = date(2009,11,22)
age5 = calculate_age(dob5)

print(age1, age2, age3, age4, age5)
12 21 10 16 13

Before the hack helper, here is the starting code plus my take on how I tried to define age depending on the user

Attempted w/ Hack Helper (Works)

Includes classOf, dob, and age

from werkzeug.security import generate_password_hash, check_password_hash
from datetime import date
import json

class User:    

    def __init__(self, name, uid, password, dob, classOf):
        self._name = name    # variables with self prefix become part of the object, 
        self._uid = uid
        self.set_password(password)
        self._dob = dob
        self._classOf = classOf

   

    @property
    def classOf(self):
        return self._classOf
    
    # a setter function, allows classOf to be updated after initial object creation
    @classOf.setter
    def classOf(self, classOf):
        self._classOf = classOf
    
    @property
    def name(self):
        return self._name
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def name(self, name):
        self._name = name
    
    # a getter method, extracts email from object
    @property
    def uid(self):
        return self._uid
    
    # a setter function, allows name to be updated after initial object creation
    @uid.setter
    def uid(self, uid):
        self._uid = uid
        
    # check if uid parameter matches user id in object, return boolean
    def is_uid(self, uid):
        return self._uid == uid
    
    # dob property is returned as string, to avoid unfriendly outcomes
    @property
    def dob(self):
        dob_string = self._dob.strftime('%m-%d-%Y')
        return dob_string
    
    # dob should be have verification for type date
    @dob.setter
    def dob(self, dob):
        self._dob = dob
        
    # age is calculated and returned each time it is accessed
    @property
    def age(self):
        today = date.today()
        return today.year - self._dob.year - ((today.month, today.day) < (self._dob.month, self._dob.day))
    
    # dictionary is customized, removing password for security purposes
    @property
    def dictionary(self):
        dict = {
            "name" : self.name,
            "uid" : self.uid,
            "dob" : self.dob,
            "age" : self.age,
            "classOf" : self.classOf
        }
        return dict
    
    # update password, this is conventional setter
    def set_password(self, password):
        """Create a hashed password."""
        self._password = generate_password_hash(password, method='sha256')

    # check password parameter versus stored/encrypted password
    def is_password(self, password):
        """Check against hashed password."""
        result = check_password_hash(self._password, password)
        return result
    
    # output content using json dumps, this is ready for API response
    def __str__(self):
        return json.dumps(self.dictionary)
    
    # output command to recreate the object, uses attribute directly
    def __repr__(self):
        return f'User(name={self._name}, uid={self._uid}, password={self._password}, dob={self._dob}, classOf={self._classOf})'
    

if __name__ == "__main__":
    u1 = User(name='Theo Huntalas', uid='theoh', password='123theo', dob=date(2009, 2, 5), classOf='2024')
    u2 = User(name='Jake Weight', uid='jakew', password='123jake', dob=date(1992, 6, 19), classOf='2010')
    u3 = User(name='Justin Liporada', uid='justinl', password='123justin', dob=date(2010, 1, 12), classOf='2031')
    u4 = User(name='Jacob Fuller', uid='jacobf', password='123jacob', dob=date(1977, 9, 26), classOf='2008')
    u5 = User(name='Caleb Navarro', uid='calebn', password='123calb', dob=date(2007, 12, 28), classOf='2029')
 
    print("JSON ready string:\n", u1, u2, u3, u4, u5, "\n") 
    print("Raw Variables of object:\n", vars(u1), vars(u2), vars(u3), vars(u4), vars(u5), "\n") 
    print("Raw Attributes and Methods of object:\n", dir(u1), dir(u2), dir(u3), dir(u4), dir(u5), "\n")
    print("Representation to Re-Create the object:\n", repr(u1), repr(u2), repr(u3), repr(u4), repr(u5), "\n") 
JSON ready string:
 {"name": "Theo Huntalas", "uid": "theoh", "dob": "02-05-2009", "age": 13, "classOf": "2024"} {"name": "Jake Weight", "uid": "jakew", "dob": "06-19-1992", "age": 30, "classOf": "2010"} {"name": "Justin Liporada", "uid": "justinl", "dob": "01-12-2010", "age": 13, "classOf": "2031"} {"name": "Jacob Fuller", "uid": "jacobf", "dob": "09-26-1977", "age": 45, "classOf": "2008"} {"name": "Caleb Navarro", "uid": "calebn", "dob": "12-28-2007", "age": 15, "classOf": "2029"} 

Raw Variables of object:
 {'_name': 'Theo Huntalas', '_uid': 'theoh', '_password': 'sha256$zJrdOM7luHpn22yZ$48a59ee0e7f6138bbd7aec2451e451f0f398c4e9907d65588f7e592369cf7c05', '_dob': datetime.date(2009, 2, 5), '_classOf': '2024'} {'_name': 'Jake Weight', '_uid': 'jakew', '_password': 'sha256$yZRPwwh3CSu06FNq$3e4c6b4754a774a62705424ba1809f6412a596f9c3901342869cf4de78cd0b3b', '_dob': datetime.date(1992, 6, 19), '_classOf': '2010'} {'_name': 'Justin Liporada', '_uid': 'justinl', '_password': 'sha256$9sBZXERmaZTyXKHf$0aedce4f99edf045c041211d0cb2c9d9251e34cb85172401c777f12fc182aabf', '_dob': datetime.date(2010, 1, 12), '_classOf': '2031'} {'_name': 'Jacob Fuller', '_uid': 'jacobf', '_password': 'sha256$lBxI1i9IJ5BtBAVl$fc0067b87aff52a6ce5e42c0da9bf32f28b0aa1700031e0e113ad76f6a4787ce', '_dob': datetime.date(1977, 9, 26), '_classOf': '2008'} {'_name': 'Caleb Navarro', '_uid': 'calebn', '_password': 'sha256$duBNey2WzqX8oFVW$4c6a795ae4aec2e6761a57271f96f45d59fcb9c15ff4807be798c6ddd39d080f', '_dob': datetime.date(2007, 12, 28), '_classOf': '2029'} 

Raw Attributes and Methods of object:
 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_classOf', '_dob', '_name', '_password', '_uid', 'age', 'classOf', 'dictionary', 'dob', 'is_password', 'is_uid', 'name', 'set_password', 'uid'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_classOf', '_dob', '_name', '_password', '_uid', 'age', 'classOf', 'dictionary', 'dob', 'is_password', 'is_uid', 'name', 'set_password', 'uid'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_classOf', '_dob', '_name', '_password', '_uid', 'age', 'classOf', 'dictionary', 'dob', 'is_password', 'is_uid', 'name', 'set_password', 'uid'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_classOf', '_dob', '_name', '_password', '_uid', 'age', 'classOf', 'dictionary', 'dob', 'is_password', 'is_uid', 'name', 'set_password', 'uid'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_classOf', '_dob', '_name', '_password', '_uid', 'age', 'classOf', 'dictionary', 'dob', 'is_password', 'is_uid', 'name', 'set_password', 'uid'] 

Representation to Re-Create the object:
 User(name=Theo Huntalas, uid=theoh, password=sha256$zJrdOM7luHpn22yZ$48a59ee0e7f6138bbd7aec2451e451f0f398c4e9907d65588f7e592369cf7c05, dob=2009-02-05, classOf=2024) User(name=Jake Weight, uid=jakew, password=sha256$yZRPwwh3CSu06FNq$3e4c6b4754a774a62705424ba1809f6412a596f9c3901342869cf4de78cd0b3b, dob=1992-06-19, classOf=2010) User(name=Justin Liporada, uid=justinl, password=sha256$9sBZXERmaZTyXKHf$0aedce4f99edf045c041211d0cb2c9d9251e34cb85172401c777f12fc182aabf, dob=2010-01-12, classOf=2031) User(name=Jacob Fuller, uid=jacobf, password=sha256$lBxI1i9IJ5BtBAVl$fc0067b87aff52a6ce5e42c0da9bf32f28b0aa1700031e0e113ad76f6a4787ce, dob=1977-09-26, classOf=2008) User(name=Caleb Navarro, uid=calebn, password=sha256$duBNey2WzqX8oFVW$4c6a795ae4aec2e6761a57271f96f45d59fcb9c15ff4807be798c6ddd39d080f, dob=2007-12-28, classOf=2029) 

Here is the fully finished part of the given hacks. It has variables of name, uid, password, dob, classOf, and age that are shown in the printed json string. I added getters and setters and changed the init to make this happen

Personalized Hacks for Group Repo (Workouts)

import json
from tabulate import tabulate

class User:    

    def __init__(self, workout, sets, reps, timeToComplete):
        self._workout = workout    # variables with self prefix become part of the object, 
        self._sets = sets
        self._reps = reps
        self._timeToComplete = timeToComplete

    
    # workout GETTER
    @property
    def workout(self):
        return self._workout
    
    # workout SETTER
    @workout.setter
    def workout(self, workout):
        self._workout = workout
    
    # sets GETTER
    @property
    def sets(self):
        return self._sets
    
    # sets SETTER
    @sets.setter
    def sets(self, sets):
        self._sets = sets

    # reps GETTER
    @property
    def reps(self):
        return self._reps

    # reps GETTER
    @reps.setter
    def reps(self, reps):
        self._reps = reps

    # timeToComplete GETTER
    @property
    def timeToComplete(self):
        return self._timeToComplete
    
    # timeToComplete SETTER
    @timeToComplete.setter
    def timeToComplete(self, timeToComplete):
        self._timeToComplete = timeToComplete


    
    # dictionary is customized
    @property
    def dictionary(self):
        dict = {
            "workout" : self.workout,
            "sets" : self.sets,
            "reps" : self.reps,
            "timeToComplete" : self.timeToComplete
        }
        return dict
    
    # output content using json dumps, this is ready for API response
    def __str__(self):
        return json.dumps(self.dictionary)
    
    # output command to recreate the object, uses attribute directly
    def __repr__(self):
        return f'User(workout={self._workout}, sets={self._sets}, reps={self._reps}, timeToComplete={self._timeToComplete})'
    

if __name__ == "__main__":
    u1 = User(workout='Bench Press', sets='5', reps='12, 8, 6, 4, 3', timeToComplete='15 mins')
    u2 = User(workout='Lat Raises', sets='3', reps='9, 9, 9', timeToComplete='6 mins')
    u3 = User(workout='Seated Row', sets='4', reps='15, 12, 12, 8', timeToComplete='8 mins')
    u4 = User(workout='Leg Extensions', sets='4', reps='15, 12, 12, 12', timeToComplete='10 mins')
    u5 = User(workout='Squat', sets='5', reps='5, 5, 5, 5, 5', timeToComplete='12 mins')
 
    print("JSON ready string:\n", u1, u2, u3, u4, u5, "\n") 
    print("Raw Variables of object:\n", vars(u1), vars(u2), vars(u3), vars(u4), vars(u5), "\n") 
    print("Raw Attributes and Methods of object:\n", dir(u1), dir(u2), dir(u3), dir(u4), dir(u5), "\n")
    print("Representation to Re-Create the object:\n", repr(u1), repr(u2), repr(u3), repr(u4), repr(u5), "\n") 

    print(tabulate([[u1.workout, u1.sets, u1.reps, u1.timeToComplete], [u2.workout, u2.sets, u2.reps, u2.timeToComplete], [u3.workout, u3.sets, u3.reps, u3.timeToComplete],[u4.workout, u4.sets, u4.reps, u4.timeToComplete],[u5.workout, u5.sets, u5.reps, u5.timeToComplete]], headers=['Workout Name','Sets','Reps','Time to Complete'], tablefmt='orgtbl'))
JSON ready string:
 {"workout": "Bench Press", "sets": "5", "reps": "12, 8, 6, 4, 3", "timeToComplete": "15 mins"} {"workout": "Lat Raises", "sets": "3", "reps": "9, 9, 9", "timeToComplete": "6 mins"} {"workout": "Seated Row", "sets": "4", "reps": "15, 12, 12, 8", "timeToComplete": "8 mins"} {"workout": "Leg Extensions", "sets": "4", "reps": "15, 12, 12, 12", "timeToComplete": "10 mins"} {"workout": "Squat", "sets": "5", "reps": "5, 5, 5, 5, 5", "timeToComplete": "12 mins"} 

Raw Variables of object:
 {'_workout': 'Bench Press', '_sets': '5', '_reps': '12, 8, 6, 4, 3', '_timeToComplete': '15 mins'} {'_workout': 'Lat Raises', '_sets': '3', '_reps': '9, 9, 9', '_timeToComplete': '6 mins'} {'_workout': 'Seated Row', '_sets': '4', '_reps': '15, 12, 12, 8', '_timeToComplete': '8 mins'} {'_workout': 'Leg Extensions', '_sets': '4', '_reps': '15, 12, 12, 12', '_timeToComplete': '10 mins'} {'_workout': 'Squat', '_sets': '5', '_reps': '5, 5, 5, 5, 5', '_timeToComplete': '12 mins'} 

Raw Attributes and Methods of object:
 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_reps', '_sets', '_timeToComplete', '_workout', 'dictionary', 'reps', 'sets', 'timeToComplete', 'workout'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_reps', '_sets', '_timeToComplete', '_workout', 'dictionary', 'reps', 'sets', 'timeToComplete', 'workout'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_reps', '_sets', '_timeToComplete', '_workout', 'dictionary', 'reps', 'sets', 'timeToComplete', 'workout'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_reps', '_sets', '_timeToComplete', '_workout', 'dictionary', 'reps', 'sets', 'timeToComplete', 'workout'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_reps', '_sets', '_timeToComplete', '_workout', 'dictionary', 'reps', 'sets', 'timeToComplete', 'workout'] 

Representation to Re-Create the object:
 User(workout=Bench Press, sets=5, reps=12, 8, 6, 4, 3, timeToComplete=15 mins) User(workout=Lat Raises, sets=3, reps=9, 9, 9, timeToComplete=6 mins) User(workout=Seated Row, sets=4, reps=15, 12, 12, 8, timeToComplete=8 mins) User(workout=Leg Extensions, sets=4, reps=15, 12, 12, 12, timeToComplete=10 mins) User(workout=Squat, sets=5, reps=5, 5, 5, 5, 5, timeToComplete=12 mins) 

| Workout Name   |   Sets | Reps           | Time to Complete   |
|----------------+--------+----------------+--------------------|
| Bench Press    |      5 | 12, 8, 6, 4, 3 | 15 mins            |
| Lat Raises     |      3 | 9, 9, 9        | 6 mins             |
| Seated Row     |      4 | 15, 12, 12, 8  | 8 mins             |
| Leg Extensions |      4 | 15, 12, 12, 12 | 10 mins            |
| Squat          |      5 | 5, 5, 5, 5, 5  | 12 mins            |

For my group repo, my individual feature was based on workouts so I centered this hack around it as well. I had 4 variables which were workout, sets, reps, and timeToComplete which would help classify each workout. I simply defined setters and getters for all four variables, added them to the init, and testers. Then as extra work, I added a table that will sort the user list data nicely. To do this, I imported a python library called tabulate and used a line of code that did it all for me. All I had to do was define the headers and enter each user variable as u#.variable.