I want to design an error in python.
Here is my code
class TwitchException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return "The input ", self.value ," is not a valid reaction."
valid_reactions = ["Poggers", "4Head","SMOrc", "TheIlluminati"]
def react(reaction):
"""
>>> react("Poggers")
Poggers
>>> react("Hello")
Traceback (most recent call last):
...
TwitchException: The input Hello is not a valid reaction.
>>> react("SMOrc")
SMOrc
"""
try:
if reaction in valid_reactions:
print(reaction)
except TwitchException:
raise TwitchException(reaction)
Help!!! I am not sure how to fulfill the second doctest.
You want to raise the exception in the else clause of the if statement; there is no need for a try statement here.
def react(reaction):
if reaction in valid_reactions:
print(reaction)
else:
raise TwitchException(reaction)
This is, however, typically written as
def react(reaction):
if reaction not in valid_reactions:
raise TwitchException(reaction)
print(reaction)
Method __str__ must return a string. Yours returns a tuple:
def __str__(self):
return "The input ", self.value ," is not a valid reaction."
It should be:
def __str__(self):
return "The input {} is not a valid reaction.".format(self.value)
Related
I'm porting some code from IronPython to CPython (3.8) + Python.NET and I have a custom class that's broken in an odd way: it gives me an AttributeError even though the member is present in __dict__. This class derives from uuid.UUID to add support to BLE short UUIDs:
import uuid
class UUID(uuid.UUID):
"""Represents a more general version of the uuid.UUID, so we can have both
regular and short UUIDs.
"""
def __init__(self, hex=None, bytes=None, is_short=False, **kwargs):
try:
super(UUID, self).__init__(hex=hex, bytes=bytes, **kwargs)
self.__dict__['is_short'] = False
except ValueError as val_ex:
if hex is None or len(hex) != 4:
raise val_ex
# Remove braces GUIDs
hex_digits = hex.strip('{}').replace('-', '')
# remove RFC 4122 URN's 'urn:uuid:deadbeef-1234-fedc-5678-deadbeefaaaa'
hex_digits = hex_digits.replace('uuid:', '').replace('urn:', '')
if len(hex_digits) != 4:
raise ValueError('badly formed hexadecimal UUID string')
self.__dict__['int'] = int(hex, 16)
self.__dict__['is_short'] = True
if is_short is True:
self.__dict__['is_short'] = True
def __str__(self):
if self.is_short:
hex = '%04x' % self.int
return '%s' % (hex[:4])
else:
return super(UUID, self).__str__()
And I'm using it like so:
class Test_UUID(unittest.TestCase):
def test_create(self):
x = pybletestlibrary.UUID("1800")
pprint(x.__dict__)
print(x)
The above code yields:
{'int': 6144, 'is_short': True}
E
======================================================================
ERROR: test_create (__main__.Test_UUID)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test\test_pybletestlibrary.py", line 27, in test_create
print(x)
File "my_uuid.py", line 66, in __str__
hex = '%04x' % self.int
AttributeError: int
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (errors=1)
I can't use setattr() because uuid.UUID is immutable. I don't understand why the AttributeError as int is present in __dict__. Any suggestions?
Thanks!!
Here's what I mean:
import uuid
class UUID(uuid.UUID):
"""Represents a more general version of the uuid.UUID, so we can have both
regular and short UUIDs.
"""
def __init__(self, hex=None, bytes=None, is_short=False, **kwargs):
self.is_short = False
if len(hex) == 4:
self.is_short = True
hex = "0000"+hex+"-0000-1000-8000-00805f9b34fb"
super(UUID, self).__init__(hex=hex, bytes=bytes, **kwargs)
def __str__(self):
val = super(UUID, self).__str__()
if self.is_short:
return val[4:8]
else:
return val
You might have to override some of the other attributes, too.
For understanding decorators in Python, i created in a class an example. But when i run it i receive an error.
class Operation:
def __init__(self, groupe):
self.__groupe = groupe
#property
def groupe(self):
return self.__groupe
#groupe.setter
def groupe(self, value):
self.__groupe = value
def addition(self, func_goodbye):
ln_house = len('house')
ln_school = len('school')
add = ln_house + ln_school
print('The result is :' + str(add))
return func_goodbye
#addition
def goodbye(self):
print('Goodbye people !!')
if __name__ == '__main__':
p1 = Operation('Student')
p1.goodbye()
I receive this error :
Traceback (most recent call last):
File "Operation.py", line 1, in
class Operation:
File "Operation.py", line 21, in Operation
#addition
TypeError: addition() missing 1 required positional argument: 'func_goodbye'
You can have a class scoped decorator, however there won't be a self when the decorator is called
a decorator:
#foo
def bar(): ...
is roughly equivalent to
def bar(): ...
bar = foo(bar)
in your particular example, if you remove the self parameter, it should function as you expect:
def addition(func_goodbye):
ln_house = len('house')
ln_school = len('school')
add = ln_house + ln_school
print('The result is :' + str(add))
return func_goodbye
#addition
def goodbye(self):
print('Goodbye people !!')
for good measure, I might del addition after that just to ensure it isn't accidentally called later
(an aside: one unfortunate side-effect of this is many linters and type checkers will consider this "odd" so I've yet to find a way to appease them (for example mypy))
I wrote a code to catch my error message using try and except (I want to write it without using isinstance) and I am getting the error message when the input is not an integer. The problem is, the program is giving me error message even if the input is valid integer. Please give me some suggestions to make it run. My code is given below:
I tried using exception clause but that did not work.
class Hotel:
def __init__(self,room,catagory):
if room != int:
raise TypeError ()
self.room = room
self.catagory = catagory
self.catagories = {"A":"Elite","B":"Economy","C":"Regular"}
self.rooms = ["0","1","2","3","4","5"]
def getRoom(self):
return self.room
def getCatagory(self):
return self.catagory
return self.catagories.get(self.catagory)
def __str__(self):
return "%s and %s"%(self.rooms[self.room],self.catagories.get(self.catagory))
try:
room1 = Hotel(a,"A")
room2 = Hotel(1,"A")
print(room1.getRoom())
except:
print("there's an error")
I am expecting:
there's an error
1 and Elite
A
You are checking if room != int . It will give you error always.
You have to check type(room)!= int .
I have corrected the code below
class Hotel:
def __init__(self,room,catagory):
if type(room) != int:
raise TypeError ()
self.room = room
self.catagory = catagory
self.catagories = {"A":"Elite","B":"Economy","C":"Regular"}
self.rooms = ["0","1","2","3","4","5"]
I made this simple decorator which basically puts the decorated function in a try...except.
from functools import wraps
def try_except(on_exception=None, exception=Exception, *args, **kwargs):
from sys import stderr
def decorator(func):
#wraps(func)
def wrapper(*args1, **kwargs1):
try:
return func(*args1, **kwargs1)
except exception as e:
print(repr(e), file=stderr)
if on_exception is not None:
return on_exception(*args, **kwargs)
return wrapper
return decorator
Then, I tried to decorate the following function, so it calls itself if it raises a ValueError:
#try_except(get_int, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
But I get the following error:
Traceback (most recent call last):
File "C:\Python\decorator_test.py", line 9348234, in <module>
#try_except(get_int, ValueError, "Please enter a valid integer!\n>>> ")
NameError: name 'get_int' is not defined
I know I could just put it in a while loop with the try...except in the function, but I was doing this as a learning exercise. Is there any way to have this not happen?
One approach is to define and use a sentinel object to denote "call the same decorated function now executing. I.e, before the def try_except, add:
same = object()
and in the body of the wrapper, after the try/except:
if on_exception is not None:
if on_exception is same:
return decorator(func)(*args, **kwargs)
else:
return on_exception(*args, **kwargs)
Then, the decorated function would be e.g (Python 3, I assume, given the way you use input -- would no doubt be raw_input in Python 2)...:
#try_except(same, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
The best way to fix that is with a function that calls the function.
def _get_int(prompt):
get_int(prompt)
#try_except(_get_int, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
del _get_int
# Or even a lambda
#try_except(lambda p: get_int(p), ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
Because the _get_int returns what get_int returns at the time of call (i.e. runtime), it will change to what get_int currently is.
You may think you would be able to do it without the # syntactic sugar, but that will only call the previous (undecorated) function, so it will not recurse.
Try running the following code:
class Test(object):
def func_accepting_args(self,prop,*args):
msg = "%s getter/setter got called with args %s" % (prop,args)
print msg #this is prented
return msg #Why is None returned?
def __getattr__(self,name):
if name.startswith("get_") or name.startswith("set_"):
prop = name[4:]
def return_method(*args):
self.func_accepting_args(prop,*args)
return return_method
else:
raise AttributeError, name
x = Test()
x.get_prop(50) #will return None, why?!, I was hoping it would return msg from func_accepting_args
Anyone with an explanation as to why None is returned?
return_method() doesn't return anything. It should return the result of the wrapped func_accepting_args():
def return_method(*args):
return self.func_accepting_args(prop,*args)
Because return_method() doesn't return a value. It just falls out the bottom, hence you get None.