python adding a negative sign to calculation result - python

First, I will warn you, I am new at this so please bear with me. I created the following program (for a class, of course) and everything works except that the withdrawal calculation spits out a negative number when the value shouldn't be negative. Can you guys see what I'm doing wrong?
Thanks in advance
#define the main
def main():
name=input('Enter the customer\'s name: ')
account_id=input('Enter the account ID: ')
code=input('Enter the transaction code:')
previous_balance=float(input('Enter the previous balance: '))
transaction_amount=float(input('Enter the transaction amount: '))
if code == "w" or code == "W":
process_withdrawal (transaction_amount, previous_balance)
else:
if code == "d" or code == "D":
process_deposit (transaction_amount, previous_balance)
else:
process_invalid_transaction_code (previous_balance)
#define process withdrawal
def process_withdrawal (previous_balance, transaction_amount):
if previous_balance >= transaction_amount:
print('You have entered an invalid transaction amount')
balance=previous_balance
print_balance (balance)
else:
balance=previous_balance-transaction_amount
print_balance (balance)
#define process deposit
def process_deposit (previous_balance, transaction_amount):
balance=previous_balance+transaction_amount
print_balance (balance)
#define invalid transaction code
def process_invalid_transaction_code (previous_balance):
print('You have entered an invalid transaction code.')
balance=previous_balance
print_balance (balance)
#define print balance
def print_balance(balance):
print('Your current balance is :', format(balance, '.2f'))
main()

Your call to process_withdrawal has the first argument as transaction_amount and the second as previous_balance, but the function declaration has previous_balance as the first argument and transaction_amount as the second.
Try this:
if code == "w" or code == "W":
process_withdrawal(previous_balance, transaction_amount)

You are passing the arguments backwards.
process_withdrawal (transaction_amount, previous_balance)
and
def process_withdrawal (previous_balance, transaction_amount):

I think your if statement within process withdrawl should be
if previous_balance < transaction_amount:

Related

How can I unit test a function that is called by another function

I am trying to unit test my program and have decided to unit test the withdraw_cash function. However, it is called by the bank_atm function. I have never called a function that is dependent on another function and am confused about how to do this. Would i use mock and patch to do this?
The tests would be:
check whether entering valid amount
check whether amount is less than balance
user = {
'pin': 1234,
'balance': 100
}
def withdraw_cash():
while True:
try:
amount = int(input("Enter the amount of money you want to withdraw: "))
except ValueError as v:
print(f"Enter correct amount: ")
else:
if amount > user['balance']:
raise ValueError("You don't have sufficient balance to make this withdrawal")
else:
user['balance'] = user['balance'] - amount
print(f"£{user['balance']}")
return
finally:
print("Program executed")
def bank_atm():
count = 0
to_exit = False
while (count < 3) and (not to_exit):
try:
pin = int(input('Please enter your four digit pin: '))
except ValueError:
print("Please enter correct pin")
count += 1
if pin != user['pin']:
print("Pin does not match.. Try Again")
count += 1
else:
withdraw_cash()
to_exit = True
if count == 3:
print('3 UNSUCCESFUL PIN ATTEMPTS, EXITING')
print('!!!!!YOUR CARD HAS BEEN LOCKED!!!!!')
try:
bank_atm()
except ValueError as v:
print(f"ERROR: {v}")
To expand on the comments. Put UI interactions in separate functions, such as getpin and getpounds. They can then be tested separately from the business functions. One can either mix manual input with the unittests or automate them by patching sys.stdin/out. My proof-of-concept experiment, which passes on 3.11.0b3 run from IDLE editor.
import sys
import unittest
from unittest.mock import patch
def getpin(realpin):
return input('Your pin? ') == realpin
class ManualTest(unittest.TestCase):
def test_pin(self):
print('\n(Enter 1234)')
self.assertEqual(getpin('1234'), True)
print('\n(Enter 1)')
self.assertEqual(getpin('1234'), False)
class MockOut:
def write(self, string): pass
# Or 'write = Mock()' to save and check prompts, using mockout.
class MockIn:
def readline(self): # input() uses readline, not read.
return self.line
#patch('sys.stdin', new_callable=MockIn)
#patch('sys.stdout', new_callable=MockOut)
class AutoTest(unittest.TestCase):
def test_pin(self, mockout, mockin):
mockin.line='1234\n' # input removes '\n' if present.
self.assertEqual(getpin('1234'), True)
mockin.line='1233'
self.assertEqual(getpin('1234'), False)
if __name__ == '__main__':
unittest.main(verbosity=2)
I have now refactored my program, by breaking it down into separate functions as you said but when I try and run a test specifically for one function, it runs the whole thing and asks for input from each function. I feel like testing each function individually will have to require specific parameters not dependent on the other function.
user = {
'pin': 1234
}
def withdraw_cash(amount):
balance_account = 100
if amount > balance_account:
raise ValueError("You don't have sufficient balance to make this withdrawal")
else:
new_balance = balance_account - amount
return new_balance
def get_pin():
count = 0
to_exit = False
while (count < 3) and (not to_exit):
try:
pin = int(input('Please enter your four digit pin: '))
except ValueError:
print("Please enter correct pin")
count += 1
if pin != user['pin']:
print("Pin does not match.. Try Again")
count += 1
else:
return get_amount(pin)
#return pin
if count == 3:
a = '3 UNSUCCESFUL PIN ATTEMPTS, EXITING \n !!!!!YOUR CARD HAS BEEN LOCKED!!!!!'
return a
def get_amount(pin):
while True:
try:
amount = int(input("Enter the amount of money you want to withdraw: "))
except ValueError as v:
print(f"Enter correct amount: ")
else:
#print(amount)
return withdraw_cash(amount)
#return amount
try:
get_pin()
except ValueError as v:
print(f"ERROR: {v}")

Python saying 'int' object isn't callable

I got a small project for my course, I am to write a program that simulates a person's bank account.
I'll spare the talk, the code is down below, along with the commenting....
# -*- coding: utf-8 -*-
#This program starts by taking in a user input as shown in the While loop..
#the 2 Methods in the class, 1 is for depositing money and the second is for a withdrawal..
class Account:
newBal = 0
post_bal=0
def __init__(self, balance):
self.balance = balance
def deposit(self, deposit):
self.deposit = int(deposit)
#newBal is the variable that takes the new Balance
Account.newBal = self.balance + self.deposit
print("Your Balance is now {}".format(Account.newBal))
return Account.newBal
def withdraw(self, withdraw):
self.withdraw = int(withdraw)
if self.withdraw > Account.newBal:
return "Error, we have a hard time finding that kind of money..."
else:
print("Withdrawal Accepted, have fun with that dough!")
#post_bal is the variable that stores the balance with the withdrawal taken from it
Account.post_bal = Account.newBal - self.withdraw
return("Your Balance is now {}".format(Account.post_bal))
a = Account(balance=0)
while True:
input_1 = input("What would you like to do today? [1] Deposit, [2] Withdraw ")
if int(input_1) == 1:
print(a.deposit(input("How much would you like to deposit? ")))
elif int(input_1) == 2:
print(a.withdraw(input("How much would you like to withdraw? ")))
else:
print(" I'm not too sure I understand what you're saying...")
With this I've been able to run a full loop successfully, depositing and amount and then withdrawing another, with all the outputs being returned. However, once I get either action for the second time in the loop, I get the error call...
TypeError
Traceback (most recent call last)
<ipython-input-4-6a19e620e3d6> in <module>
33 print(a.deposit(input("How much would you like to deposit? ")))
34 elif int(input_1) == 2:
---> 35 print(a.withdraw(input("How much would you like to withdraw? ")))
36 else:
37 print(" I'm not too sure I understand what you're saying...")
TypeError: 'int' object is not callable
I'm not sure what I did wrong here...
You are changing the withdraw to an int here.
def withdraw(self, withdraw):
self.withdraw = int(withdraw)
Use a different name like
def withdraw(self, withdraw):
self.withdraw_value = int(withdraw)

why does this python while loop not work in the program?

I'm trying to run the program in the following article:
https://blockgeeks.com/guides/python-blockchain-2/
I've copied all of the code into my Spyder IDE. When i run it there's a while loop which starts up asking the user to choose a number from the list of options it prints.
After selecting a number the program should perform the requested action. When i select it though it just loops back to the start of the while loop.
It appears to be ignoring the rest of the code in the while loop (the if statement part).
Confusingly if i take the parts of the code from the program which are used in the while loop and run them separately they work i.e if i run the below code and select the number 1 for my choice it will run the code in the if statement.
Why would the if statement run here but not in the main program?
#function 1:
def get_user_choice():
user_input = input("enter a number: ")
return user_input
#function 2:
def get_transaction_value():
tx_recipient = input('Enter the recipient of the transaction: ')
tx_amount = float(input('Enter your transaction amount '))
return tx_recipient, tx_amount
while True:
print("Choose an option")
print('Choose 1 for adding a new transaction')
print('Choose 2 for mining a new block')
print('Choose 3 for printing the blockchain')
print('Choose anything else if you want to quit')
user_choice = get_user_choice()
if user_choice == '1':
tx_data = get_transaction_value()
print(tx_data)
Update:
Sorry i realise i may not have been very clear what the problem is.
The above code is part of the code from the entire program and runs as expected in isolation from the main program.
The below code is the entire program from the article in the link. It includes all of the code in the program. If i run this main program the while loop doesn't use the if statement. It appears to just be breaking straight out of the loop after i select 1, 2 or 3 (any other number should break out of the loop anyway).
Here's a link for a screen shot showing what the console looks like after i have selected the number 1 for the option.
https://ibb.co/RNy2r0m
# Section 1
import hashlib
import json
reward = 10.0
genesis_block = {
'previous_hash': '',
'index': 0,
'transaction': [],
'nonce': 23
}
blockchain = [genesis_block]
open_transactions = []
owner = 'Blockgeeks'
def hash_block(block):
return hashlib.sha256(json.dumps(block).encode()).hexdigest()
# Section 2
def valid_proof(transactions, last_hash, nonce):
guess = (str(transactions) + str(last_hash) + str(nonce)).encode()
guess_hash = hashlib.sha256(guess).hexdigest()
print(guess_hash)
return guess_hash[0:2] == '00'
def pow():
last_block = blockchain[-1]
last_hash = hash_block(last_block)
nonce = 0
while not valid_proof(open_transactions, last_hash, nonce):
nonce += 1
return nonce
# Section 3
def get_last_value():
""" extracting the last element of the blockchain list """
return(blockchain[-1])
def add_value(recipient, sender=owner, amount=1.0):
transaction = {'sender': sender,
'recipient': recipient,
'amount': amount}
open_transactions.append(transaction)
# Section 4
def mine_block():
last_block = blockchain[-1]
hashed_block = hash_block(last_block)
nonce = pow()
reward_transaction = {
'sender': 'MINING',
'recipient': owner,
'amount': reward
}
open_transactions.append(reward_transaction)
block = {
'previous_hash': hashed_block,
'index': len(blockchain),
'transaction': open_transactions,
'nonce': nonce
}
blockchain.append(block)
# Section 5
def get_transaction_value():
tx_recipient = input('Enter the recipient of the transaction: ')
tx_amount = float(input('Enter your transaction amount '))
return tx_recipient, tx_amount
def get_user_choice():
user_input = input("Please give your choice here: ")
return user_input
# Section 6
def print_block():
for block in blockchain:
print("Here is your block")
print(block)
# Section 7
while True:
print("Choose an option")
print('Choose 1 for adding a new transaction')
print('Choose 2 for mining a new block')
print('Choose 3 for printing the blockchain')
print('Choose anything else if you want to quit')
user_choice = get_user_choice()
if user_choice == 1:
tx_data = get_transaction_value()
recipient, amount = tx_data
add_value(recipient, amount=amount)
print(open_transactions)
elif user_choice == 2:
mine_block()
elif user_choice == 3:
print_block()
else:
break
[1]: https://i.stack.imgur.com/FIrn7.png
When comparing values, Python takes a stronger route regarding data types than some other languages. That means no string in Python will equal a number.
Or in other terms "1" == 1 will be False.
That means you have to consider that in Python 3 you will receive a string from input() (not necessarily so in Python 2).
You can either compare this directly to another string:
user_choice = input()
if user_choice == "1":
print("You chose item 1")
Or you can convert it into a number first and compare it to a number:
user_choice = int(input())
if user_choice == 1:
print("You chose item 1")
Note that in the former case it might not be robust if the user enters extra spaces and in the latter case it will fail very loudly with an exception if the user doesn't enter an integer (or even nothing at all).
Both ways can be handled with extra code if necessary. In the former case, you can strip whitespace with user_input = input().strip() and in the latter case you can catch the exception with a try ... except ... block.
You have only handled the case for user_choice == '1'. If you enter anything other than 1, the program will return control to the beginning of the while loop.
I'll suggest you use a debugger to see what user_choice is before the if condition. If not, just use prints.
print("user_choice: {}, type: {}".format(user_choice, type(user_choice))

Python: setting max for bank withdraw

I'm new to python and I am still trying to get the hang of it. I'm attempting to change the processing function in the following code so that the user can not withdraw more money then what the "bank" has on record, which is 500. I was hoping that someone could help. Would I enter an if statement for >500?
#Simple Bank Atm
def main():
PIN=7777;balance=500;pin=0;success=False
Pin=getInput(pin)
Pin,PIN,balance,success=processing(pin,PIN,balance,success)
Display(success,balance)
#Input Function
def getInput(pin):
pin=int(input(“Please enter your PIN:”))
return pin
#Processing Function
def processing(pin,PIN,balance,success):
if pin==PIN:
success=True
amt=float(input(“How much would you like to withdraw?”))
balance=balance-amt
return pin,PIN,balance,success
else:
success=false
return pin,PIN,balance,success
You can use an if condition to do this.
if amt <= balance: #Can't withdraw over your current balance
balance -= amt
else:
print("Error. Amount exceeds funds on record.")
Also, other things aside you're returning the same thing inside your if and else condition and if this is what you really want to return it's redundant to have it in both. You can just have it after your else statement at the same indentation level
def main():
PIN=7777;balance=500;pin=0;success=False
Pin=getInput(pin)
Pin,PIN,balance,success=processing(pin,PIN,balance,success)
Display(success,balance)
#Input Function
def getInput(pin):
pin=int(input("Please enter your PIN:"))
return pin
#Processing Function
def processing(pin,PIN,balance,success):
if pin==PIN:
success=True
amt=float(input("How much would you like to withdraw?"))
if balance<amt:
print("Amount to draw is greater than balance.")
return pin,PIN,balance,false
balance=balance-amt
return pin,PIN,balance,success
else:
success=false
return pin,PIN,balance,success
Yes. You should use an if statement - this should happen before they can withdrawal the amount (balance = balance - amt).
So you could do something like this:
if amt <= balance:
balance -= amt
return True
else:
# do not change balance and stop withdrawal
return False

While Loop in function ( Python )

So I basically created my functions ( def main(), load(), calc(), and print().
But I do not know how I can allow the user to input the information as many times as he/she wants until they want to stop. Like I they input 5 times, it would also output 5 times. I have tried putting the while loop in the def main() function and the load function but it won't stop when I want it to. Can someone help? Thanks!
def load():
stock_name=input("Enter Stock Name:")
num_share=int(input("Enter Number of shares:"))
purchase=float(input("Enter Purchase Price:"))
selling_price=float(input("Enter selling price:"))
commission=float(input("Enter Commission:"))
return stock_name,num_share,purchase,selling_price,commission
def calc(num_share, purchase, selling_price, commission):
paid_stock = num_share * purchase
commission_purchase = paid_stock * commission
stock_sold = num_share * selling_price
commission_sale = stock_sold * commission
profit = (stock_sold - commission_sale) - ( paid_stock + commission_purchase)
return paid_stock, commission_purchase, stock_sold, commission_sale, profit
def Print(stock_name,paid_stock, commission_purchase, stock_sold, commission_sale, profit):
print("Stock Name:",stock_name)
print("Amount paid for the stock:\t$",format(paid_stock,'10,.2f'))
print("Commission paid on the purchase:$", format(commission_purchase,'10,.2f'))
print("Amount the stock sold for:\t$", format(stock_sold,'10,.2f'))
print("Commission paid on the sale:\t$", format(commission_sale,'10,.2f'))
print("Profit(or loss if negative):\t$", format(profit,'10,.2f'))
def main():
stock_name,num_share,purchase,selling_price,commission = load()
paid_stock,commission_purchase,stock_sold,commission_sale,profit = calc(num_share, purchase, selling_price, commission)
Print(stock_name, paid_stock,commission_purchase, stock_sold, commission_sale, profit)
main()
You have to give the user some kind of way to declare their wish to stop the input. A very simple way for your code would be to include the whole body of the main() function in a while loop:
response = "y"
while response == "y":
stock_name,num_share,purchase,selling_price,commission = load()
paid_stock,commission_purchase,stock_sold,commission_sale,profit = calc(num_share, purchase, selling_price, commission)
Print(stock_name, paid_stock,commission_purchase, stock_sold, commission_sale, profit)
response = input("Continue input? (y/n):")
an even simpler way would be two do the following....
while True:
<do body>
answer = input("press enter to quit ")
if not answer: break
alternatively
initialize a variable and avoid the inner if statement
sentinel = True
while sentinel:
<do body>
sentinel = input("Press enter to quit")
if enter is pressed sentinel is set to the empty str, which will evaluate to False ending the while loop.

Categories