currently I have some code like this
try:
somecode
except Exception as Error:
fallbackcode
Now i want to add another fallback to the fallbackcode
Whats is the best practice to make a nested try/catch in python?
try:
somecode
except Exception as Error:
try:
fallbackcode
except Exception as Error:
nextfallbackcode
produces intendation errors
You should be able to do nested try/except blocks exactly how you have it implemented in your question.
Here's another example:
import os
def touch_file(file_to_touch):
"""
This method accepts a file path as a parameter and
returns true/false if it successfully 'touched' the file
:param '/path/to/file/'
:return: True/False
"""
file_touched = True
try:
os.utime(file_to_touch, None)
except EnvironmentError:
try:
open(file_to_touch, 'a').close()
except EnvironmentError:
file_touched = False
return file_touched
You can rewrite the logic using a loop provided all your callbacks and fallbacks have same API interface
for code in [somecode, fallbackcode, nextfallbackcode]:
try:
code(*args, **kwargs)
break
except Exception as Error:
continue
else:
raise HardException
This would be the preferred way instead of multiple level of nested exception blocks.
you can use functions to handle errors :
def func0():
try:
somecode
except:
other_func()
def func1():
try:
somecode
except:
func0()
You could have change it like this:
try:
try:
somecode
except Exception as Error:
fallbackcode
except Exception as Error:
nextfallbackcode
Related
May be a little confused on how flask handles errors. Working on adding error handling to a DB backend. I essentially have a worker script, a router, and error handling script.
The error handling is pretty basic. I have a separate module with the following classes. They inherit from exception so there is not much added to them
class EmptyQueryError(Exception):
pass
class BadURLError(Exception):
pass
My main route method is as follows, and calls a method which takes care of post process/etc.
def queryJobData(projectId, jobId):
try:
dbv.jobData(projectId, jobId)
except EmptyQueryError as e:
abort(400, "An unexpected Exception Occurred: {}".format(e))
except Exception as e:
abort(400, "An unexpected Exception Occurred: {}".format(e))
Lastly, the main driver function is contained in the dbv object from about. The flow of this works properly, as for when I pass in valued project and job ids, the query is successful and it returns a document as I aim to. However, when I purposely insert errors to get an exception to raise, that's where issues occur. Here is the handler function:
def jobData(self, projectId, jobId):
try:
print("[Querying the job data]")
if (request.method == "GET"):
qData = [x for x in self.collection.find({"projectId": projectId, "jobId": jobId})]
# input(qData)
if (len(qData) == 0):
raise EmptyQueryError("EmptyQueryError: The url you attempted to query did not return any data")
pp.data = qData
unrolled_data = pp.unrollData()
df = pd.DataFrame(unrolled_data)
pps = PostProcessSummary(df)
table_test = pps.pivot_summary()
return dumps(table_test)
except Exception as e:
print(e)
finally:
pass
I purposely did not import the "request" module so it raises an error. I can see it gets caught by "jobData":
However, it never enters one of the exception blocks in "queryJobData", where the handle "jobData" is called.
To say the least this has thrown me a for a loop. Almost all other pieces of software I've built would handle this exception accordingly. (ie it follows the pattern where if one exception is raised elsewhere, it should be handled by the parent calling the child generating the exception). First time using Flask so I imagine I'm missing something obvious I can't find in documentation.
edit:
The exception in jobData() gets caught and it exists back into queryJobData() as if nothing happens. For instance in this block it goes directly to the return and not to handle the raised exception
try:
dbv_ret = dbv.jobData(projectId, jobId)
return dbv_ret
except TypeError:
abort(400, "TypeError Occurred")
except EmptyQueryError:
print("[ARE WE HERE?!]")
abort(404, "Empty Query")
except BadURLError:
abort(404, "Bad URL")
except Exception as e:
abort(404, "An unexptec exception has occurred: {}".format(e))
You a catching all exceptions in you function, so anything that happens inside the try/except block will be caught inside your except block, and then your finally block will be executed.
If you want to pass the EmptyQueryError and BadURLError exceptions to the calling function, raise it outside the try/except block. Or, if you want, re-raise it inside your except block
class EmptyQueryError(Exception):
pass
class BadURLError(Exception):
pass
def jobData():
try:
print("[Querying the job data]")
# this will be caught by the except block
raise EmptyQueryError("EmptyQueryError: The url you attempted to query did not return any data")
except Exception as e:
# catching all exceptions. Including the ones you are raising.
# if you don't re-raise the exception here, no error will be passed
print("Wow, exception")
print(e)
finally:
print("I'm in finally block ;)")
# not returning anything
pass
if __name__ == "__main__":
try:
returned_value = jobData()
# will print None
print(returned_value)
except EmptyQueryError as query_err:
# will never be caught
print("Got a EmptyQueryError")
except BadURLError as url_err:
# will never be caught
print("Got a BadURLError")
The sequence of prints will be:
[Querying the job data]
Wow, exception
EmptyQueryError: The url you attempted to query did not return any data
I'm in finally block ;)
None
You can do something like:
def jobData(data):
if len(data) == 0:
raise EmptyQueryError("EmptyQueryError: The url you attempted to query did not return any data")
try:
# do your thing here
pass
except Exception as e:
print(e)
finally:
print("I'm in finally block ;)")
# not returning anything
pass
Now the EmptyQueryError will be caught by the calling function.
I have a try/except where I repeat the except portion frequently in my code. This led me to believe that it would be better to separate the except portion into a function.
Below is my use case:
try:
...
except api.error.ReadError as e:
...
except api.error.APIConnectionError as e:
...
except Exception as e:
...
How would I go about separating this logic into a function so I can do something as simple as:
try:
...
except:
my_error_handling_function(e)
Just define the function:
def my_error_handling(e):
#Do stuff
...and pass in the exception object as the parameter:
try:
#some code
except Exception as e:
my_error_handling(e)
Using just a generic Exception type will allow you to have a single except clause and handle and test for different error types within your handling function.
In order to check for the name of the caught exception, you can get it by doing:
type(e).__name__
Which will print the name, such as ValueError, IOError, etc.
I would suggest refactoring your code so the try/except block is only present in a single location.
For instance, an API class with a send() method, seems like a reasonable candidate for containing the error handling logic you have described in your question.
Define your function:
def my_error_handling(e):
#Handle exception
And do what you're proposing:
try:
...
except Exception as e:
my_error_handling_function(e)
You can handle logic by getting the type of the exception 'e' within your function. See: python: How do I know what type of exception occurred?
If you don't like try-catch statement, you can use exception-decouple package and decorator.
from exception_decouple import redirect_exceptions
def my_error_handling(arg, e):
#Do stuff
#redirect_exceptions(my_error_handling, api.error.ReadError, api.error.APIConnectionError)
def foo(arg):
...
Lets say I have this:
try:
result = call_external_service()
if not result == expected:
raise MyException()
except MyException as ex:
# bubble up
raise ex
except Exception:
# unexpected exceptions from calling external service
do_some_logging()
Due to my limited python knowledge, I cannot think of an elegant way to bubble up the MyException exception, I was hoping I can do something like:
try:
result = call_external_service()
if not result == expected:
raise MyException()
except Exception, exclude(MyException):
# unexpected exceptions from calling external service
do_some_logging()
Your problem seems to be that you are wrapping too much code in your try block. What about this?:
try:
result = call_external_service()
except Exception:
# unexpected exceptions from calling external service
do_some_logging()
if result != expected:
raise MyException()
My django view goes through a list , uses regex to detect specific elements in the list and finally returns a dict of the contents.
Both IndexError and ValueError can occur while parsing the list.
I need to handle the exceptions in this case.I tried like this
def parse_list(oldlist):
try:
newlist=create_newlist(oldlist)
except Exception as e:
logger.debug(str(e))
else:
mydict = make_dict(newlist)
def create_newlist(oldlist):
mydict = {}
for elem in oldlist:
if re.match('somepattern',elem[0]):
mydict['somekey']=int(elem[0].strip())
else:
raise ValueError(elem[0],' expects an integer')
...
return mydict
Is using the Exception class in except Exception as e: the correct way to handle any exception originating from the above function?
when I wrote a unit test method
def test_me(self):
dl = parse_list(self.somelist)
print 'dl=\n',dl
self.assertTrue(len(dl),0)
I got the console output as
ERROR: test_me (myapp.tests.ParseTest)
..
IndexError: list index out of range
Why is the exception not logged by logger?
Is using the Exception class in except Exception as e: the correct way
to handle any exception originating from the above function?
When handling exceptions you should try to be as specific as possible. In your case, you should catch IndexError and ValueError instead of a general Exception:
try:
...
except (ValueError, IndexError) as e:
...
Your other question:
Why is the exception not logged by logger?
It depends on the configuration of the logger. You're printing a 'debug' message but it could be set to only log/display messages with level 'error' or higher. See logging documentation in Python for more information.
I need to have a file deleted if not all the operations that must be done on it were successful (that is, if an exception is raised). It could have been as simple as using except:, deleting the file and then re-raising the exception, but in that case the original exception would be lost if the file cannot be deleted in the except clause for whatever arcane reason.
The best that I have been able to come up with is this:
try:
file_path = "whatever.jpg"
# do stuff with file
except:
exception_raised = True
raise
finally:
try:
if exception_raised:
os.unlink(file_path)
except:
pass
return file_path # everything OK
Does anybody know of a better, more Pythonic approach?
Another option is to simply store the exception if you don't want to lose it:
Python 3.x version:
try:
file_path = "whatever.jpg"
# do stuff with file
except BaseException as e:
try:
os.unlink(file_path)
except Exception:
traceback.print_exc()
raise e
The Python 2.x version is slightly more complex since you need to store the complete exception information manually (otherwise you'd lose the traceback):
try:
file_path = "whatever.jpg"
# do stuff with file
except:
e = sys.exc_info()
try:
os.unlink(file_path)
except Exception:
traceback.print_exc()
raise e[0], e[1], e[2]
Edit: Only catch subclasses of Exception in the inner try block, since you don't want do catch SystemExit or KeyboardInterrupt here. Also report any excpetion that occurred during unlinking instead of just dropping it.