Unable to call a method within a schedule job - python

I have a class that looks like this:
class Account(object):
"""A simple bank account"""
def __init__(self, balance=0.0):
"""
Return an account object with a starting balance of *balance*.
"""
self.balance = balance
def withdraw(self, amount):
"""
Return the balance remaining after withdrawing *amount* dollars.
"""
self.balance -= amount
return self.balance
def deposit(self, amount):
"""
Return the amount remaining after depositing *amount* dollars.
"""
self.balance += amount
return self.balance
I'll initialize it in xyz:
xyz = Account(balance=6000)
xyz.balance
> 6000
I also have a dumb printing function:
def thing():
print("I am doing a thing...")
When I try to call the deposit method in my schedule flow:
import schedule
# this works
# schedule.every(5).seconds.do(thing)
# this doesn't work
schedule.every(5).seconds.do(xyz.deposit(2300))
while True:
schedule.run_pending()
I get the following error:
TypeError: the first argument must be callable
Any ideas? Is it even possible to call methods within a schedule flow?

Not familiar with schedule, but it seems like do() wants a callable, i.e. a method. You're giving it the return value of xyz.deposit(2300), rather than the method xyz.deposit and the argument 2300. Try this:
schedule.every(5).seconds.do(xyz.deposit, 2300)

Related

why does object turn to int after one use

I am learning python and while going through this OOP'S exercise:
For this challenge, create a bank account class that has two attributes:
owner
balance
and two methods:
deposit
withdraw
As an added requirement, withdrawals may not exceed the available balance.
Now the problem that I am facing is when I run the withdrawal once it works fine, but when I work it the second time it shows the error
" TypeError Traceback (most recent call last)
/var/folders/15/yqw5v0lx20q5lrbvg8bb69jr0000gn/T/ipykernel_79159/1232198771.py in
----> 1 acct1.withdraw(200)
TypeError: 'int' object is not callable"
here is my code
class Account:
def __init__(self, owner, balance = 0):
self.owner = owner
self.balance = balance
def __str__(self):
return f"the account holder is {self.owner} \nand the balance is {self.balance}"
def deposit(self,deposit):
self.deposit = deposit
self.balance += deposit
print("deposit accepted")
def withdraw(self, withdraw):
self.withdraw = withdraw
if self.balance >= withdraw:
self.balance -= withdraw
print("money withdrawn")
else:
print("Funds Unavailable!")
Kindly let me know where am I going wrong.
Do not name a method the same as a class attribute:
def withdraw(self, withdraw):
self.withdraw = withdraw
Possible solution:
def perform_withdraw(self, withdraw):
self.withdraw = withdraw
Before the first call to withdraw, the attribute withdraw of an instance of Account is the method that does your calculation.
After the first call to withdraw, the attribute is whatever argument you called withdraw with, because you issue self.withdraw = withdraw. Use another name or remove the line altogether if it is not needed.

Python TDD assert statements not working like i thought

I am just confused about why this is happening. When I run my assert it seems that each test is not creating its own object. so when i get to the last assert statement the test fails because the other assert are still in the list. Any help would be great thank you
My Class code:
from datetime import date
class Transaction():
"""
Transaction
"""
balance = 0.0
timestamp = date.today()
def __init__(self, amount, dt=None):
self.balance = amount
self.transactions = []
if dt is None:
self.timestamp = date.today()
else:
self.timestamp = dt
def __repr__(self):
return '{self.__class__.__name__}({self.balance:,.2f}, {self.timestamp})'.format(self=self)
def __str__(self):
return f'{self.timestamp}: ${self.balance:,.2f}'
class Account():
"""
Account Class
"""
balance = 0.0
transaction = Transaction(balance)
def __init__(self):
self.balance = 0.0
def deposit(self, amount):
self.balance += +amount
self.transaction.transactions.append(+amount)
def withdraw(self, amount):
self.balance -= amount
self.transaction.transactions.append(-amount)
def get_balance(self):
if len(self.transaction.transactions) < 1:
return 0
return sum(self.transaction.transactions)
My Code for pytest:
def test_append_transaction():
account = Account()
account.deposit(200)
assert account.transaction.transactions == [200]
def test_deposit():
user = Account()
user.deposit(300)
assert user.balance == +300.00
def test_append_withdraw():
account = Account()
account.withdraw(50)
assert account.transaction.transactions == [-50]
def test_withdraw():
account = Account()
account.withdraw(50)
assert account.balance == -50.0
Your tests are failing because your code is wrong - i.e. they are failing because you've written your tests correctly, in a way which is able to detect bugs, and they detected a bug in your code.
Yes, each test function does create a new Account instance, as you can clearly see in the test functions themselves. However, each Account instance does not have its own distinct Transaction instance, because you made this a class attribute instead of an instance attribute.
To fix the bug in your Account class, you should initialise
self.transaction = Transaction(self.balance)
in the __init__ method, so that each Account instance has a reference to a distinct Transaction instance.

How to implement transfer method for a account class in python

So, I'm making a Account class in python. It has the basic functions of deposit, withdrawing, and checking your balance. I'm having trouble with a transfer method though.
This is my code(sorry for the code dump):
class Account:
"""simple account balance of bank"""
def __init__ (self, name, balance):
self.name = name
self.balance = balance
print('Account of ' + self.name)
def deposit(self, amount):
if amount > 0:
self.balance += amount
self.statement()
def withdrawal(self, amount):
if amount > 0 and self.balance > amount:
self.balance -= amount
self.statement()
else:
print("the ammount in your is not sufficent")
self.statement()
def statement(self):
print("Hi {} your current balance is {}".format(self.name,self.balance))
def transfer(self, amount, name):
self.balance = self.balance - amount
name.balance = name.balance + amount
return name.balance()
Now, it works for
abc = Account("abc", 0)
abc.deposit(1000)
siddharth = Account("siddharth", 159)
So how do I run following code:
siddharth.transfer(11, "abc")
siddharth.transfer(11, Account.abc)
also, how do I create account "abc" if account "abc" doesn't exist
Your code will be your best lesson about taking care of variables/parameters naming. Your method transfer(self, amount, name) should be transfer(self, amount, account). I think that now, it will be obvious that the correct code is
abc = Account("abc", 0)
abc.deposit(1000)
siddharth = Account("siddharth", 159)
siddharth.transfer(11, abc)
Be really careful on misleading names.
Aside of your question, I don't think that an Account should have a transfer method. An Account only cares about deposits and withdraws, not about what is done with them. IMO Transfer should be a function with 2 Account parameters, withdrawing from the first, making a deposit on the second. This is just to follow the Single Responsibility principle.
Following the same principle, don't put print functions in an Account. Consider that you don't know the context in which your class will be used. If it is in a web app, prints are redirected to /dev/null…
Finally, always do what you said you'll do. If I have an account with a balance b, I expect that after the call to deposit with a value v, my account balance will be b + v. No matter the value of v. You are right to check the value and not adding a negative value (that is a withdraw) so you have to warn the caller that you'll not add the value, so rise an exception. Same for withdraw.
You can first have an array of all accounts somewhere declared. Then, you can first try to find if an account exists. If not, create an account and pass them.
allAccounts = []
#create bunch of accounts including 'abc'
siddharth = Account("siddharth", 159)
searchResult = [x for x in allAccounts if x.name == 'abc']
#assuming that account names are unique
if len(searchResult) == 0:
acc = Account("abc", 11)
else:
acc = searchResult[0]
siddarth.transfer(11, acc)

Unitest in python to deposit amount

I am new to unittesting in python and this is my first unit test. I don't know whether I am doing right or wrong unit test , need some help. I have to test function, in first function i want to test legal deposit and in second function I want to test illegal deposit, like depositing "apple" or "lizard" instead of amount . Since I am new to unit test, I have lot of confusion about it. I read different post,but in my case I am still felling difficult to write unit test for this two functions.
bankaccount.py
class BankAccount():
def __init__(self):
self.account_number=0
self.pin_number=""
self.balance=0.0
self.interest=0.0
self.transaction_list=[]
def deposit_funds(self, amount):
self.balance+=amount
def withdraw_funds(self, amount):
if amount<=balance:
self.balance-=amount
import unittest
from bankaccount import BankAccount
class TestBankAcount(unittest.TestCase):
def setUp(self):
# Create a test BankAccount object
self.account = BankAccount()
# Provide it with some property values
self.account.balance = 1000.0
def test_legal_deposit_works(self):
# code here to test that depsositing money using the account's
# 'deposit_funds' function adds the amount to the balance.
self.assertTrue(100,self.account.deposit_funds(100))
def test_illegal_deposit_raises_exception(self):
# code here to test that depositing an illegal value (like 'bananas'
# or such - something which is NOT a float) results in an exception being
# raised.
unittest.main()
You could do something like this:
Have your class raise an error when the type of values provided to deposit_funds does not match the use case.
class BankAccount:
def __init__(self):
self.account_number = 0
self.pin_number = ""
self.balance = 0.0
self.interest = 0.0
self.transaction_list = []
def deposit_funds(self, amount):
try:
self.balance += amount
except TypeError:
raise TypeError
def withdraw_funds(self, amount):
if amount <= balance:
self.balance -= amount
Have your tests detect that a TypeError is thrown when that happens.
class TestBankAcount(unittest.TestCase):
def setUp(self):
self.test_account = BankAccount()
self.test_account.balance = 1000.0
def test_legal_deposit(self):
expected_balance = 1100.0
self.test_account.deposit_funds(100.0)
self.assertEqual(expected_balance, self.test_account.balance)
def test_illegal_deposit_raises_exception(self):
# code here to test that depositing an illegal value (like 'bananas'
# or such - something which is NOT a float) results in an exception being
# raised.
with self.assertRaises(TypeError):
self.test_account.deposit_funds('dummy value')
if __name__ == '__main__':
unittest.main()

Confused about why I'm getting a TypeError: 'int' object is not callable

I've looked at similar questions and still have not been able to figure this out. I'm absolutely sure i'm making a very stupid mistake somewhere but I just can't seem to find it.
For this code.
class BankAccount:
def __init__(self, initial_balance):
self.balance = initial_balance
def deposit(self, amount):
self.deposit = amount
self.balance = self.balance + self.deposit
def withdraw(self, amount):
self.withdraw = amount
self.balance = self.balance - self.withdraw
self.fee = 5
self.total_fees = 0
if self.balance < 0:
self.balance = self.balance - self.fee
self.total_fees += self.fee
def get_balance(self):
current_balance = self.balance
return current_balance
def get_fees(self):
return self.total_fees
When I run the code everything works fine when I run this
my_account = BankAccount(10)
my_account.withdraw(15)
my_account.deposit(20)
print my_account.get_balance(), my_account.get_fees()
However, if I make an additional call to withdraw
my_account = BankAccount(10)
my_account.withdraw(15)
my_account.withdraw(15)
my_account.deposit(20)
print my_account.get_balance(), my_account.get_fees()
It throws this error.
TypeError: 'int' object is not callable
I don't understand why it works fine until I make an additional call to withdraw. Please help.
When you do self.deposit = amount, you overwrite your deposit method with the amount. You do the same in withdraw with self.withdraw = amount. You need to give the data attributes a different name from the methods (like call the method withdraw but the attribute withdrawalAmount or something like that).
When you do this inside the withdraw method
self.withdraw = amount
you replace the it with whatever amount is. Next time you call withdraw, you get the amount object. Which in your case is an int.
The same applies to deposit:
self.deposit = amount
Give your data members names that are different to your methods.

Categories

Resources