""" atm.py Write a program to simulate an ATM machine. Store balances and account info in a file. Use objects. --- initial thinking --- started in class May 3 put information in a file named '_atm_data_.csv' name, username, password, checking_balance, savings_balance name2, username2, pass2, check2, save2 ... initial screen *************** * IntroCS ATM * *************** Type your name to start your login : What do you want to do? 1. Withdraw cash 2. Transfer money 3. See accounts ----------------------------------- Sun May 9 refinements to show working code : - completed the user interaction logic : login_screen user_interaction screen account actions : balances, deposit, withdraw, transfer - dropped Account class for simplicity - added DataFile class to put the file input/output in one place - moved account_name & amount into a dictionary - changed datafilename to have .csv (more appropriate) extension - moved prompt strings to global variables, in an attempt to make the left margins more consistent and keep the code cleaner - bunch of debugging Jim Mahoney | cs.bennington.college | May 2021 | MIT License """ # input from terminal without echoing what is typed; # see https://docs.python.org/3/library/getpass.html from getpass import getpass debug = False # turn extra debug printing on or off datafilename = '_atm_data_.csv' atm_prompt = """ *************** * IntroCS ATM * *************** """ username_prompt = """ What is your username? """ password_prompt = """ What is your password? """ invalid_user_message = """ That username or password is invalid. Please try again. """ session_prompt = """ Hello {}! What would you like to do? 1 balances 2 deposit 3 withdraw 4 transfer 5 exit """ choice_prompt = """ Your choice (1 to 5) is : """ amount_prompt = """ Amount is ? """ which_account_prompt = """ {} which account, checking (1) or savings (2) ? """ def choose_account(prompt): """ Ask user for account, starting question with given prompt. Return 'checking' or 'savings' """ while True: choice = input(which_account_prompt.format(prompt)) if int(choice) == 1: return 'checking' if int(choice) == 2: return 'savings' print(" Invalid response; please try again. ") def choose_amount(): """ Return an amount of money entered by user """ while True: try: amount = float(input(amount_prompt)) return amount except ValueError: print(" You entered an invalid amount. Please try again.") class User: """ A person with atm account balances """ def __init__(self, fullname, username, password): self.fullname = fullname self.username = username self.password = password self.accounts = {} # dictionary {'checking': amount} ; will set later. def set_account(self, account_name, amount): """ setup a named (checking or savings) account """ self.accounts[account_name] = amount def is_valid(self, username, password): """ Return True if this user has this name and password """ if debug: print("# is_valid debug ") print(f"# testing username='{username}' password='{password}'") print(f"# actual username='{self.username}' " + f"password='{self.password}'") return self.username == username and self.password == password def __str__(self): return f"" class DataFile: """ read and write users to a file """ # file format is lines 'name,password,checking_amount,savings_amount' # for example 'John Smith,jsmith,fakepassword,100.00,500.00' def __init__(self, filename): self.filename = filename def read_users(self): """ Read and return list of Users defined by contents of data file """ datafile = open(self.filename) users = [] for line in datafile: (fullname, username, password, checking, savings) = line.split(',') user = User(fullname, username, password) user.set_account('checking', float(checking)) user.set_account('savings', float(savings)) users.append(user) datafile.close() return users def write_users(self, users): """ Write each User to the data file """ datafile = open(self.filename, 'w') for user in users: datafile.write(f"{user.fullname},{user.username},{user.password},") # google "python format 2 decimal digits" to find formatting # of a float 2.34 to a string "2.34", namely ':.24' checking = user.accounts['checking'] savings = user.accounts['savings'] datafile.write(f"{checking:.2f},{savings:.2f}") datafile.write("\n") # newline character at end of line datafile.close() class ATM: """ An ATM machine """ def __init__(self): self.datafile = DataFile(datafilename) self.users = self.datafile.read_users() def __str__(self): # For debugging result = "--- ATM " + '-'*56 for user in self.users: result = result + '\n ' + str(user) return result + '\n' + '-'*64 def run(self): """ main interactive loop """ while True: user = self.login() self.user_session(user) def login(self): """ Display ATM information and prompt for user info. Return User if valid information is input. If not valid info, loop and try again. """ while True: print(atm_prompt) username = input(username_prompt) password = getpass(password_prompt) if debug: print(f"# login debug:") print(f"# username='{username}'") print(f"# password='{password}'") for user in self.users: if user.is_valid(username, password): return user print(invalid_user_message) def user_session(self, user): """ Let this user make changes to their accounts; save changes """ # give choices for what that user can do # 1 show balances # 2 withdraw # 3 deposit # 4 transfer # 5 finished while True: print(session_prompt.format(user.fullname)) try: choice = int(input(choice_prompt)) # PUT ERROR HERE assert 1 <= choice <= 5 except (ValueError, AssertionError): print (" That is not a valid choice. Please try again. ") continue if choice == 1: print() for which in ('checking', 'savings'): balance = user.accounts[which] acct_name = which.title() print(f" {acct_name} balance is {balance:.2f}.") elif choice == 2: which = atm.choose_account('Deposit to') amount = choose_amount() user.accounts[which] = user.accounts[which] + amount elif choice == 3: which = choose_account('Withdraw from') amount = choose_amount() user.accounts[which] = user.accounts[which] - amount elif choice == 4: from_account = choose_account('Transfer from') to_account = choose_account('Transfer to') amount = choose_amount() elif choice == 5: print("\n Saving account changes.") self.datafile.write_users(self.users) return def main(): atm = ATM() if debug: print(atm) atm.run() if __name__ == '__main__': main()