I am trying to avoid the BaseException issue here . My requirement is i have a custom exception . when the custom exception is raised, i need to do some commands and need to abort a job.
class custom_exp(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
try:
#calculating a threshold value
# if( above threshold):
raise custom_exp("hello")
except custom_exp as x:
# have some code to store the bad records
raise(message) # this line written to fail the job
except Exception as e:
# have some code to store the bad records
raise(str(e)) # this line written to fail the job
here is the output
File "C:\Users\gopia\OneDrive - VW Credit\Desktop\untitled1.py", line 11, in <module>
raise(message)
TypeError: exceptions must derive from BaseException
You could do something like this
class CustomExp(Exception):
pass
try:
# calculating a threshold value
# if above threshold:
raise CustomExp("hello")
except CustomExp as e:
# store the records
raise e
except Exception as e:
# store the records
raise e
Related
Suppose that:
TEF is a try-except-finally block.
an exception is raised from within the try clause of TEF
The finally clause, F of block T contains a return statement
TEF contains an except clause E
an exception e is raised inside of E
How can we catch e from outside of clause F and outside of clause E?
If that was confusing, then some code is shown below:
def e():
out = "hello world"
try:
raise ValueError("my name is Sarah")
except BaseException as exc:
# HOW DO I CATCH THE FIRST OF THE FOLLOWING
# exceptions from outside of this, current,
# except clause?
raise ValueError("secret info it would be good to know")
raise AttributeError
raise type("Hell", (Exception,), dict())()
[0, 1, 2][99999]
class AnythingYouCanThinkOf(Exception):
pass
raise AnythingYouCanThinkOf
out = "definitely not `hello world`"
finally:
return out
print(e())
print("No error!!! wowza!")
The code above prints:
hello world
No error!!! wowza!
If we comment out the line out = "hello world" then we get UnboundLocalError: local variable 'out' referenced before assignment. However, I am still not sure how to recover ValueError("secret info it would be good to know")
Also, if you put almost the same code outside of the function e, you get very different results. Why?
if True:
out = "hello world"
try:
raise ValueError("my name is Bob")
except BaseException as exc:
# HOW DO I CATCH THE FIRST OF THE FOLLOWING
# exceptions from outside of this, current,
# except clause?
raise ValueError("what is this madness?")
class AnythingYouCanThinkOf(Exception):
pass
raise AnythingYouCanThinkOf
out = "definitely not `hello world`"
finally:
print(out)
The above results in unhandled exception ValueError: what is this madness? before, we got No error!!! wowza!
I am trying to learn Python and I want to know if it is possible to pass a variable to an Exception? This is the code I have:
try:
staffId = int(row['staffId'])
openingSalary = int(row['initialSalary'])
monthsWorked = float(row['monthsWorked'])
except CutomException:
pass
class CustomException(ValueError): # raised if data conversion fails
def __init__(self):
print("There was a problem converting data")
I want to pass staffId to the exception so that I can print something like:
print("There was a problem converting data for staff Id: ", staffId)
I tried this with no success: How to pass a variable to an exception when raised and retrieve it when excepted?
The caller of the exception, e.g. the one that raise exception will have to pass an argument to the constructor.
class CustomException(ValueError): # raised if data conversion fails
def __init__(self, message):
self.message = message;
print("There was a problem converting data")
try:
try:
staffId = int(row['staffId'])
openingSalary = int(row['initialSalary'])
monthsWorked = float(row['monthsWorked'])
except ValueError as e:
raise CustomException(e);
except CustomException:
pass
The custom exception will need to be raise'd conditionally by the try block to include the staffId variable. As an example, when the staffId is a str and not an int.
try:
# conditionalize a scenario where you'd want to raise an error
# (e.g. the variable is a string)
if type(staffId) is str:
raise CustomException(staffId)
else:
staffId = int(row['staffId'])
openingSalary = int(row['initialSalary'])
monthsWorked = float(row['monthsWorked'])
except CutomException:
pass
class CustomException(ValueError): # raised if data conversion fails
def __init__(self, id):
print("There was a problem converting data %s" % id)
I think you should handle the exception in the except block and not inside the exception class.
try:
raise CustomException(foo)
except CutomException as e:
print(e.args)
handle_exception()
class CustomException(Exception):
def __init__(self, foo):
super().__init__(foo, bar)
I am using tornado to create a rest handler.. Here i have some common exceptions like InvalidRequest, InvalidToken etc. So i wanted to know how i can create a sort of super exception handler for these and handle the rest in the same function itself.. Part of the example code
class RestRegisterHandler(RestHandler):
#gen.coroutine
def post(self):
self.raw_data = None
try:
yield self.validate_user()
self.raw_data = json_decode(self.request.body)
logger.debug(self.raw_data)
model_object = self.model(self.raw_data)
model_object.validate()
logger.debug("Inseting to database")
yield model_object.insert(self.db)
except InvalidRequest:
self.write_error(404, 'Invalid request')
except InvalidToken:
self.write_error(404, 'Token Validation Failed')
except ModelValidationError as error:
logger.error("Unknown Validation error: '{0}'".format(error))
raise utils.errors.ValidationError(400, error_messages=error.messages)
except DuplicateKeyError:
logger.debug("User already exists")
self.write_error(404, 'User already exists')
except Exception as e:
logger.error(e)
self.write_error(404, 'Invalid request')
else:
logger.debug("db saved")
self.write("Registered succesfully")
return
Something like
class RestHandler():
def super_exception():
except InvalidToken:
print()
except InvalidRequest:
print()
# the rest of exceptions should be handled by post function
Something like this?
class RestHandler(object):
# "default" exception handling in the super class
def handle_exception(self, e):
logger.error('Default error handling caught a "%s"' % e)
class RestRegisterHandler(RestHandler):
# "specific" exception handling in the child class
def handle_exception(self, e):
# Just an idea, you can implement this in different ways
WRITE_ERROR = (InvalidRequest, InvalidToken, DuplicateKeyError)
WRITE_ERROR_WITH_LOGGER = (Exception,)
RAISE_VALIDATION_ERROR = (ModelValidationError,)
if e in WRITE_ERROR:
self.write_error(404, str(e))
elif e in WRITE_ERROR_WITH_LOGGER:
logger.error(e)
self.write_error(404, str(e))
elif e in RAISE_VALIDATION_ERROR:
logger.error("Unknown Validation error: '{0}'".format(e))
raise utils.errors.ValidationError(400, error_messages=e.messages)
else:
# if couldn't be handled here, fallback to the default implementation
super(RestHandler, self).handle_exception(e)
#gen.coroutine
def post(self):
self.raw_data = None
try:
yield self.validate_user()
self.raw_data = json_decode(self.request.body)
logger.debug(self.raw_data)
model_object = self.model(self.raw_data)
model_object.validate()
logger.debug("Inseting to database")
yield model_object.insert(self.db)
except Exception as e:
self.handle_exception(e)
else:
logger.debug("db saved")
self.write("Registered succesfully")
return
The general solution for this is to override RequestHandler.write_error (and don't call write_error yourself, just let the errors escape the handler function). write_error will get an exc_info keyword argument that lets you see the exception that caused the request to fail.
I would like to add context to an exception like this:
def process(vals):
for key in vals:
try:
do_something(vals[key])
except Exception as ex: # base class. Not sure what to expect.
raise # with context regarding the key that was being processed.
I found a way that is uncharacteristically long winded for Python. Is there a better way than this?
try:
do_something(vals[key])
except Exception as ex:
args = list(ex.args)
if len(args) > 1:
args[0] = "{}: {}".format(key, args[0])
ex.args = tuple(args)
raise # Will re-trhow ValueError with new args[0]
The first item in ex.args is always the message -- if there is any. (Note for some exceptions, such as the one raised by assert False, ex.args is an empty tuple.)
I don't know of a cleaner way to modify the message than reassigning a new tuple to ex.args. (We can't modify the tuple since tuples are immutable).
The code below is similar to yours, except it constructs the tuple without using an intermediate list, it handles the case when ex.args is empty, and to make the code more readable, it hides the boilerplate inside a context manager:
import contextlib
def process(val):
with context(val):
do_something(val)
def do_something(val):
# assert False
return 1/val
#contextlib.contextmanager
def context(msg):
try:
yield
except Exception as ex:
msg = '{}: {}'.format(msg, ex.args[0]) if ex.args else str(msg)
ex.args = (msg,) + ex.args[1:]
raise
process(0)
yields a stack trace with this as the final message:
ZeroDivisionError: 0: division by zero
You could just raise a new exception:
def process(vals):
for key in vals:
try:
do_something(vals[key])
except Exception as ex:
raise Error(key, context=ex)
On Python 3 you don't need to provide the old exception explicitly, it will be available as __context__ attribute on the new exception object and the default exception handler will report it automatically:
def process(vals):
for key in vals:
try:
do_something(vals[key])
except Exception:
raise Error(key)
In you case, you should probably use the explicit raise Error(key) from ex syntax that sets __cause__ attribute on the new exception, see Exception Chaining and Embedded Tracebacks.
If the only issue is the verbosity of the message-amending code in your question; you could encapsulate it in a function:
try:
do_something(vals[key])
except Exception:
reraise_with_context(key=key) # reraise with extra info
where:
import inspect
import sys
def reraise_with_context(**context):
ex = sys.exc_info()[1]
if not context: # use locals from the caller scope
context = inspect.currentframe().f_back.f_locals
extra_info = ", ".join("%s=%s" % item for item in context.items())
amend_message(ex, extra_info)
raise
def amend_message(ex, extra):
msg = '{} with context: {}'.format(ex.args[0], extra) if ex.args else extra
ex.args = (msg,) + ex.args[1:]
I'm really new in Python and a have no experience with exceptions but I've read all the documentation and couldn't find an answer ... so I'm looking for a deeper view in except's semantics.
When we have for example:
try:
x = 2
except GreaterThanOne:
print("The value is greater than one")
In this case I want the message to be printed.Is there a way for the GreaterThanOne class(exception) to be defined to raise when the entered value is greater than one ?
Ok, let me be more specific ...
Every error raises by a specific rule which should be add in the error attributes, am I right ?
For example:
try:
myvalue = x / y
except ZeroDivisionError:
print("Some error message printed ...")
So when I use this code and enter for y to be 0 the exception ZeroDivisionError will raise ... Can I for example redefine ZeroDivisionError to raise like this but if y is set to be ... 2 or 3 or any other value ?
Input:
x = 10
y = 2
try:
myvalue = x / y
except ZeroDivisionError:
print("division by 2")
Output: division by 2
Here's an example that should help you understand. Run this in your Python interpreter and watch how the exception is raised and caught (or not caught) when you call set_val(2).
# Defining our Exception subclass:
class GreaterThanOne(Exception):
pass
# The global value we pretend to care about:
val = 0
# Function to set a value but possibly raise our new Exception
def set_val(new_val):
if new_val > 1:
raise GreaterThanOne("%d > 1" % new_val)
val = new_val
# Catching exception:
try:
set_val(0)
set_val(1)
set_val(2)
except GreaterThanOne:
print "Whoops - one of those values was greater than one"
# Not catching exception:
set_val(0)
set_val(1)
set_val(2)
set_val(3)
an try-except block catches exception in this block.
try:
#some stuff here
except ExceptionClass as e:
#Exception handling here
the class after the except keyword indicates which kind of exception you want to catch. Usually you give a specific class, like ValueError or KeyError. You can also use the Exception class, to catch any exception. Because all the other exceptionclasses inhert from Exception.
so if you want to use this construct, an exception needs to be raised, Either by a function / method you call, or you raise it yourself with the raise keyword.
like this:
try:
raise KeyError('Just for test')
except KeyError as e:
#Exception handling here
The try except doesn't automagically inspect the whole code between it, it just looks for exceptions... Or to be more specific, it looks for those exceptions you tell it to look for.
Of course you can also inspect the exception instance.
try:
raise KeyError('Just for test')
except KeyError as e:
print e.args
For more information, please see:
http://docs.python.org/2/tutorial/errors.html