Unit testing method that raises and exception - python

I try to unit-test if method responsible for returning price of given product raises an exception if we pass bad item_id - find_price_of_given_id.
Test:
import unittest
from Automat import Automat
from Bank import Bank
from Item import Item
from exceptions.NoItemException import NoItemException
class AutomatTest(unittest.TestCase):
def test_checkPriceOfGivenID(self):
bank = Bank()
automat = Automat(bank)
Cola = Item(2)
automat.add_object(Cola)
self.assertEqual(automat.find_price_of_given_id(30), 2)
def test_checkPriceOfGivenIDWithInvalidID(self):
bank = Bank()
automat = Automat(bank)
Cola = Item(2)
automat.add_object(Cola)
self.assertRaises(NoItemException, automat.find_price_of_given_id(31))
Automat class:
if __name__ == '__main__':
unittest.main()
from Item import Item
from exceptions.NoItemException import NoItemException
from exceptions.NoProperAmountException import NoProperAmountException
from Coin import Coin
from decimal import *
class Automat:
def __init__(self, _bank, objects=None):
self.item_id = 30
self.bank = _bank
if objects is None:
objects = {}
self.objects = objects
self.purchaseItemBank = []
def add_object(self, obj: Item):
id_to_assign = self.item_id
self.objects.update({id_to_assign: obj})
self.item_id += 1
return id_to_assign
def find_price_of_given_id(self, item_id):
if self.objects.get(item_id) is not None:
return self.objects.get(item_id).get_price()
else:
raise NoItemException
def find_amount_of_given_id(self, item_id):
if self.objects.get(item_id) is not None:
return self.objects.get(item_id).get_amount()
else:
raise NoItemException
def checkIfAmountIsPositive(self, item_id):
if self.objects.get(item_id) is not None:
var = True if self.objects.get(item_id).get_amount() > 0 else False
return var
else:
raise NoItemException
def withdrawItem(self, item_id):
self.objects.get(item_id).decrease()
def getAmountOfGivenNominal(self, coinValue):
counter = 0
for iterator in self.bank.bank:
if iterator.getCoinValue() == coinValue:
counter += 1
return counter
Unfortunately I got
Error
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\unittest\case.py", line 59, in testPartExecutor
yield
File "C:\ProgramData\Anaconda3\lib\unittest\case.py", line 615, in run
testMethod()
File "C:\Users\Admin\PycharmProjects\vending-machine\AutomatTest.py", line 22, in test_checkPriceOfGivenIDWithInvalidID
self.assertRaises(NoItemException, automat.find_price_of_given_id(31))
File "C:\Users\Admin\PycharmProjects\vending-machine\Automat.py", line 28, in find_price_of_given_id
raise NoItemException
exceptions.NoItemException.NoItemException
Ran 1 test in 0.003s
FAILED (errors=1)
Process finished with exit code 1
Item class:
class Item:
def __init__(self, price, amount=5):
self.amount = amount
self.price = price
def get_price(self):
return self.price
def get_amount(self):
return self.amount
def decrease(self):
self.amount -= 1
def __str__(self):
return f"{self.amount} # {self.price}"

self.assertRaises(NoItemException, automat.find_price_of_given_id(31))
You're calling the method, and then pass its return value into assertRaises; but before that can happen, the exception is already raised. This is not how you use assertRaises. You can use it in two ways:
Pass the method you want to call and its arguments to assertRaises:
self.assertRaises(NoItemException, automat.find_price_of_given_id, 31)
Note: no (), you're not calling it yourself!
Use it as context manager:
with self.assertRaises(NoItemException):
automat.find_price_of_given_id(31)

Related

Python - error message when not using private member [duplicate]

This question already has an answer here:
Setting property causes maximum recursion depth exceeded
(1 answer)
Closed 5 months ago.
I get an error when i run the following:
class Product:
def __init__(self, price):
self.setprice(price)
def getprice(self):
return self.price
def setprice(self, value):
if value < 0:
raise ValueError("Price cannot be negative")
self.price = value
price = property(getprice, setprice)
x = Product(23)
print(x.price)
The error is below:
File "c:\Users\Sonam\OneDrive\Desktop\PYTHON\tempCodeRunnerFile.py", line 9, in setprice self.price = value [Previous line repeated 993 more times] File "c:\Users\Sonam\OneDrive\Desktop\PYTHON\tempCodeRunnerFile.py", line 7, in setprice if value < 0: RecursionError: maximum recursion depth exceeded in comparison
However when i make the price a private member, it runs ok :
class Product:
def __init__(self, price):
self.setprice(price)
def getprice(self):
return self.__price
def setprice(self, value):
if value < 0:
raise ValueError("Price cannot be negative")
self.__price = value
price = property(getprice, setprice)
x = Product(23)
print(x.price)
Can anyone tell me why we get this error???? Why do we need to make price private in the setprice method?
The appropriate way to define properties with property is:
class Product
def __init__(self, price):
self.price = price
#property
def price(self):
return self._price
#price.setter
def price(self, value):
if value < 0:
raise ValueError("Price can't be negative.")
self._price = value
Then you can use it as you would expect:
>>> p = Product(3)
>>> p.price
3
>>> p.price = -1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in price
ValueError: Price can't be negative.
>>> p.price
3
>>> p.price = 4
>>> p.price
4
>>>
Your error stems from the fact that when you define self.price = ..., you actually call the setter once again, thus recurring over and over again, until the max depth recursion limit is reached. When you set self._price instead, you are not using the setter, but doing a regular assignment instead.

numpy.ndarray' object has no attribute 'append' - error comes up when creating stack using numpy

I want to create a stack using numpy
I tried following code but "numpy.ndarray' object has no attribute 'append' " this error comes
I tried replace the append with other attributes , but any of those methods didnt work for me .
can someone run the codes in your pc and suggest me a way to fix this.
Traceback (most recent call last):
File "C:\Users\Banchi\Desktop\numpy\main.py", line 3, in <module>
myStack.push(11)
File "C:\Users\Banchi\Desktop\numpy\stackf.py", line 8, in push
return self.Stack.append(data)
AttributeError: 'numpy.ndarray' object has no attribute 'append'
stackf.py
import numpy as np
class Stack:
def __init__(self):
self.Stack =np.array([])
def push(self,data):
return self.Stack.append(data)
print("stack overfolow")
def pop(self):
if len(self.Stack)==0:
print("stack underflow")
else:
return self.Stack.pop()
def __len(self):
return len(self.Stack)
def top(self):
if len(self.Stack)==0:
print("stack under flow")
else:
return self.Stack[len(self.Stack)-1]
def is_empty(self):
return len(self.Stack) == 0
def is_full(self):
return len(self.Stack) == self.limit
def size(self):
return len(self.Stack)
main.py
from stackf import Stack
myStack = Stack()
myStack.push(11)
myStack.push(11)
myStack.push(11)
myStack.push(11)
print(myStack.size())
myStack.push(10)
myStack.push(20)
myStack.push(30)
print(myStack)
You can define your class e.g. as:
class Stack:
def __init__(self, limit : int = 0):
self.arr = np.array([])
self.limit = limit
def is_empty(self) -> bool:
return self.size() == 0
def pop(self):
n = self.size() - 1
if n < 0:
raise Exception('pop - Stack is empty')
rv = self.arr[n]
self.arr = np.delete(self.arr, n)
return rv
def push(self, data):
if self.limit > 0 and self.limit == self.size():
raise Exception('push - Limit exceeded')
self.arr = np.append(self.arr, data)
def size(self) -> int:
return self.arr.size
def top(self):
if self.size() == 0:
raise Exception('top - stack underflow')
return self.arr[-1]
def __str__(self):
return np.array_str(self.arr)
Note that I added some functionality concerning the limit, but the
default value of limit is 0, meaning "no limit".
Since the class contains size() method, there is no need to repeat
just the same code in __len() method.
I added also some exceptions instead of printing an error message.
__str__ method is added to get any meaningful result when you print
a Stack instance.
Then, if you run your main code, the result is:
4
[11. 11. 11. 11. 10. 20. 30.]
But if you create your Stack instance e.g. as myStack = Stack(3)
(with the limit set to a non-zero value), then at some point you
will get Exception: push - Limit exceeded.

What is error all about? and why?

class account(object):
__duser_id = ''
__duser_name =''
__duser_no = ''
def __init__(self, default, entry_name, password, user_id='', user_name='', user_no=''):
if type(default) != bool:
raise Exception("Error 0x1: type(default) is boolean ")
if default == False:
self.__user_id = user_id
self.__user_name = user_name
self.__user_no = user_no
else:
self.__user_id = __duser_id
self.__user_name = __duser_name
self.__user_no = __duser_no
self.__entry_name = entry_name
self.__password = password
def dset(self, duser_id=__duser_id, duser_name=__duser_name, duser_no=__duser_no):
__duser_id = duser_id
__duser_name = duser_name
__duser_no = duser_no
return (__duser_id, __duser_name, __duser_no)
def dget(self):
return (__duser_id, __duser_name, __duser_no)
def set(self, user_name=self.__user_name, user_id=self.__user_id, user_no=self.__user_no, password=self.__password):
self.__user_id = user_id
self.__user_name = user_name
self.__user_no = user_no
self.__password = password
return (self.__user_id, self.__user_name, self.__user_no, self.password)
def get(self):
return (self.__user_id, self.__user_name, self.__user_no, self.password)
if __name__ == '__main__':
gmail = account(default=True, entry_name='gmail', password='pass***')
print(gmail.dget())
print(gmail.get())
out put is:
Traceback (most recent call last):
File "interface.py", line 1, in
class account(object):
File "interface.py", line 30, in account
def set(self, user_name=self.__user_name, user_id=self.__user_id, user_no=self.__user_no, password=self.__password):
NameError: name 'self' is not defined
Ok o got it.
but there is another one i just changed code.
This is a decorator with arbitrary number of arguments and keyword
arguments
def user_no_is_number(func):
def wrapper(*args, **kargs):
if 'user_no' in kargs:
if type(kargs['user_no']) != int:
raise Exception('Error 1x0: user_no must contains only numbers.')
else:
return func(*args, **kargs)
return wrapper
#staticmethod
#user_no_is_number
def dset(user_id=None, user_name=None, user_no=None):
if user_id:
account.__duser_id = user_id
if user_name:
account.__duser_name = user_name
if user_no:
account.__duser_no = user_no
return (account.__duser_id, account.__duser_name, account.__duser_no)
but the dset() function return always None
*I think there is problem with arbitrary keywords parameters. by using **kargs in decorator parameter it becomes dictionary and by again passing **kargs it just return values of that dictionary.*

Converting from SimPy2 to SimPy3

I am trying to simulate customers going to a bank. And I want to print the average length of the queue, and each value pair of time a request begins and the pairs [time of request or release, length of queue]
I am aware that there is no monitor class in simpy3, so I tried using the example here Below I have left the relevant code from the file I'm converting from and my attempt to convert it.
simpy2 and python2
from SimPy.Simulation import *
import random as rnd
interarrival_time = 10.0
service_time = 8.0
class CustomerGenerator( Process ):
def produce( self, b ):
while True:
c = Customer( b )
c.start( c.doit() )
yield hold, self, rnd.expovariate(1.0/interarrival_time)
class Customer( Process ):
def __init__( self, resource ):
Process.__init__( self )
self.bank = resource
def doit( self ):
yield request, self, self.bank
yield hold, self, self.bank.servicetime()
yield release, self, self.bank
class Bank( Resource ):
def servicetime( self ):
return rnd.expovariate(1.0/service_time)
initialize()
bank = Bank( capacity=1, monitored=True, monitorType=Monitor )
src = CustomerGenerator()
activate( src, src.produce( bank ) )
simulate( until=100)
print bank.waitMon.mean()
print
for evt in bank.waitMon:
print evt[0], evt[1]
simpy3 and python3
from simpy import *
import random as rnd
interarrival_time = 10.0
service_time = 8.0
def produce( env, b ):
while True:
customer(env,b)
yield env.timeout(rnd.expovariate(1.0/interarrival_time))
def customer(env,bank):
yield bank.request()
yield env.timeout(bank.servicetime())
bank.release()
class MonitoredResource(Resource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.data = []
self.num_requests = 0
def mean(self):
try:
mean = 0
for el in self.data:
mean += el[1]
mean /= self.num_requests
return mean
except ZeroDivisionError:
pass
def request(self, *args, **kwargs):
self.data.append((self._env.now, len(self.queue)))
self.num_requests += 1
return super().request(*args, **kwargs)
def release(self, *args, **kwargs):
self.data.append((self._env.now, len(self.queue)))
return super().release(*args, **kwargs)
class Bank(MonitoredResource):
def servicetime( self ):
return rnd.expovariate(1.0/service_time)
env = Environment()
bank = Bank(env,capacity=1)
src = env.process(produce(env,bank))
env.run( until=100)
print(bank.mean())
print()
for evt in bank.data:
print(evt[0], evt[1])
How can I get the output of my SimPy3 simulator to resemble the SimPy2 simulator instead of just printing None?
It seems I just needed to tell release() which request() was being released to get the desired output. And to run Customer as a process.
from simpy import *
import random as rnd
interarrival_time = 10.0
service_time = 8.0
def produce( env, bank ):
print("generating")
while True:
env.process(customer(env,bank))
t = rnd.expovariate(1.0/interarrival_time)
yield env.timeout(t)
def customer(env,bank):
req = bank.request()
yield req
yield env.timeout(bank.servicetime())
bank.release(req)
class MonitoredResource(Resource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.data = []
self.num_requests = 0
def mean(self):
if(self.num_requests > 0):
mean = 0
for el in self.data:
mean += el[1]
mean /= self.num_requests
return mean
def request(self, *args, **kwargs):
self.data.append((self._env.now, len(self.queue)))
self.num_requests += 1
return super().request(*args, **kwargs)
def release(self, *args, **kwargs):
self.data.append((self._env.now, len(self.queue)))
return super().release(*args, **kwargs)
class Bank(MonitoredResource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def servicetime( self ):
return rnd.expovariate(1.0/service_time)
env = Environment()
bank = Bank(env,capacity=1)
#bank = Bank( capacity=1, monitored=True, monitorType=Monitor )
src = env.process(produce(env,bank))
env.run(until=100)
print(bank.mean())
print()
for evt in bank.data:
print(evt[0], evt[1])

NameError: name '_length' is not defined

I'm using python3 and when trying to run the following code, I'm facing the error:
NameError: name '_length' is not defined
The code itself:
class OFPHELLO(GenericStruct):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._length = self.get_size()
_msg_type = OFPType.OFPT_HELLO
_build_order = ('header', 'x')
header = OFPHeader(type = _msg_type, length = _length)
x = UBInt8()
The problem is the _length variable that I'm passing in OFPHeader, the value of which is computed in GenericStruct. How can I compute the _length variable inside the OFPHELLO class and use it as parameter in the OFPHeader class?
Following the GenericStruct code:
class GenericStruct(object):
def __init__(self, **kwargs):
for a in kwargs:
try:
field = getattr(self, a)
field.value = kwargs[a]
except AttributeError:
raise OFPException("Attribute error: %s" % a)
def build(self):
hexa = ""
for field in self._build_order:
hexa += getattr(self, field).build()
return hexa
def parse(self, buff):
begin = 0
for field in self._build_order:
size = getattr(self, field).get_size()
getattr(self,field).parse(buff, offset=begin)
begin += size
def get_size(self):
tot = 0
for field in self._build_order:
tot += getattr(self, field).get_size()
return tot
- how have you defined (GenericStruct)
- header = OFPHeader(type = _msg_type, length = _lenght)
- correct the spelling to _length
-- and please post the entire code next time

Categories