Is there a best practice for cascading python exception handlers? - python

TLDR: Is there a good way to cascade a heirarchy of exception handlers similar to what is possible with a series of if statements? e.g. one handler may attempt to handle a problem but throw an exception to be caught by the next handler, or the initial try block throws the second exception directly.
Basic premise: (There may be poory conceived code here, so bear with me) Also may be a duplicate, but I couldn't find it.
I am trying to verify the validity of a url with a head request. If I get a ConnectionError the url is not valid. The head request will helpfully throw a MissingSchema exception for missing "http://" so I added an exception handler to try the url with an "http://". However, if the url is still invalid it throws the expected ConnectionError. Is there a good way to pass that exception back to the exception handler that takes the ConnectionError directly from the try block? This would be similar to how you can cascade if statements. I could solve this particular example with some copy paste or recursion, but I could see both solutions becoming pretty annoying in more complex functions. Sample code below:
def checkURL(url):
try:
resp = requests.head(url)
return True # if request does not raise exception
except requests.exceptions.MissingSchema as exception:
try:
#try url with schema
resp = requests.head('http://' + url)
return True
#if url is still bad it will throw Connection Error
#I would like this to be also handled by the block below
except requests.ConnectionError as exception:
#ConnectionError == bad url
return False
I could solve this by duplicating my ConnectionError handler in the secondary try - except block, but that seems like a bad solution. Or I could recursively call checkURL('http://' + url) in the MissingSchema handler, but I could see that being problematic / inefficient also if there was more work being done in the initial try block. There's a good chance I'm missing something obvious here, but I'd appreciate any feedback.

In this case it would be easier to check the protocol "http://" or "https://" with .startswith() or a regular expression.
Nesting exception handling is rarely a good design choice.
Also your strategy for checking the url by trying the request multiple times can have serious performance issues if you are going to do a lot of checks.
Your best option here would be to check whatever you can without performing any request first, and only then have a single try block with multiple except clauses if you need to address the failures separately.
Edit: in the context of your question, where you want to retry the request in case of failures it is not really helpful and will force you to repeat the code.
If you need some mechanics that keeps retrying some operation then you need to enclose the try-except block inside a loop. For example:
for url in url_variations:
try:
request.head(url)
return url
except BlaBlaError:
continue
return None

Related

Why is exception displaying as a number?

I have a Python script running on a schedule and I have set up a try/except block to catch all exceptions and email me the exception message so that I can be made aware that something has gone wrong.
I am observing some odd behavior. For every execution of my script, an Exception is being caught where the message is simply:
93
This content is the same when I print it to the console as well.
When I remove the try/except block, there aren't any exceptions being thrown by my code. Does anyone know why the presence of the try/except blocks are causing exceptions and why it is just returning digits?
try:
#do something
except Exception as ex:
s = smtplib.SMTP('000.000.000.000',25)
s.starttls()
s.sendmail('email#email.com', 'email#email.com', 'General Exception in final_parse method ' + str(ex.message))
print str(ex.message)
s.quit()
It depends on what you're doing in your try. The exception is created and raised in that code. It is possible to set an exception's message to 93, or to anything else.
Try evaluating the entire exception in your debugger, or stepping through the code you're running in try until you get the the exception, and look at the context in which it is created/raised. This will at least give you an idea of what the code/module was doing when it failed.
My guess is that the code running in try isn't well written or maintained. Try a different module, or post more details about it here.
Update:
If your stack trace is giving you KeyError, then the code you're executing is throwing a KeyError exception that isn't handled by an except block deeper down in the code, which would mean it's either poorly written or being poorly used. The issue is most likely within your 'do something'
Rather than use smtplib.SMTP you should use Yagmail. It's easier to use:
import yagmail
yag = yagmail.SMTP(username, password)
yag.send(emailto, subject = "I now can send an attachment", contents = fileToSend)

Python: Must non-built-in exceptions be imported in order to catch them?

I'm trying to catch some exceptions thrown by the requests library, with the following try-except block:
try:
get = requests.get((requester.batchesUrl)+str(id)+'/', auth=requester.auth)
except (ConnectionRefusedError, ConnectionError, MaxRetryError) as e:
print("CAUGHT ECONNECTION ERROR")
raise type(e)(str(e) + "Additional Info: Method couldn't connect to website, check that your server is running"
).with_traceback(sys.exc_info()[2])
But instead of catching the exceptions and adding "Additional Info:" to the args, I get NameError: global name 'MaxRetryError' is not defined. Now I know MaxRetryError is an exception in urllib3.exceptions.MaxRetryError. Must I import these non-built-in exception in order to catch them? This seems verbose to me considering the number of possible exceptions one is likely to need to watch out for.
Running: Python 3.3, Windows 7.
You must always always always have a name in an accessible scope before you can refer to it without throwing an exception. If that means importing, then so be it.
If you want to handle these three exceptions differently from other exceptions, then yes, you will have to import them. (You already have at least one of them, since it's at the top level of requests, but the others you may not.)
But do you really need to do that? Trying to restrict yourself to the most detailed exception possible can be as bad as just handling everything. Sometimes both extremes are the right thing to do, but think about what you really want to happen.
If you get a RequestException, but it's not a ConnectionError, do you really want that to print a traceback and abort, or do you want to log that CAUGHT ECONNECTION ERROR and reraise it wrapped in your own type? For that matter, what about an OSError that isn't a RequestException?
As a side note, do you really get urllib3.exception.*Errors from requests? I've only seen them wrapped in a requests.exceptions.RequestException. (And from a quick look at the source to HTTPAdapter.send, there's a except MaxRetryError as e: raise ConnectionError(e, request=request), so I think they're supposed to be wrapped, and if you're seeing them unwrapped that may be a bug you need to file.)
As another side note, in Python 3.3, you don't have to hack with exception messages like that anymore; you can chain and wrap exceptions, add arguments, etc. See Exceptions in the docs for more details. But I think what you want here may be to define your own exception type, then do this:
try:
get = requests.get((requester.batchesUrl)+str(id)+'/', auth=requester.auth)
except OSError as e:
print("CAUGHT ECONNECTION ERROR")
raise EConnectionError("Method couldn't connect to website, check that your server is running")
That will put the original exception in the __context__ of your wrapper exception. If you want it in the __cause__ instead, then raise EConnectionError(…) from e. Either way, it'll show up if you format the traceback.
You must import, etc. in order to catch specific exceptions.
Of course you could simply catch everything.
But the real issue may be that you need to understand why you should catch exceptions.
There are really only few cases I can think of.
1) You catch specific exceptions so that you can respond to them effectively -- If you don't know how to respond to them (requiring an understanding of what they mean and how to respond) -- Since these are generally few in number, this is not a real problem in having to import a number of modules.
2) You catch exceptions so that you can continue processing the next transaction, etc. -- though you abandon the current operation, you may still be able to continue processing acceptablely if the transactions are independent.
3) You catch the exception so that you can log detail, etc. Often re-raising the transaction after you have logged it.
4) You have a top-level exception handler so that you can report the problem in a clean manner to the end-user and possibly do some thing like saving work-in-progress before it is lost.
ADDED
You don't just willy nilly catch exceptions so that you can ignore them unless you like pain.

Python Exception Handling - Best Practices

I'm writing a python program the accesses a database. I want to catch three types of exceptions when I make a http request. Timeouts, network errors, and http errors. I'm looking for the best way to deal with this situation. I need to check for these exceptions multiple times in multiple areas of my code, and it will look something like this each time:
try:
//some request
except timeout:
print '\nException: Timeout Error'
except connection error:
print '\nException: Network Error'
except http error, e:
print 'Exception: %s.' % e
Since I have to do this multiple times, at least probably 8 or more, should I make a module to handle these exceptions or no? Also in which of these cases would it be advisable to shut my system down as opposed to just displaying a message?
Thank you.
If you don't want to use decorators, you can also combine all the except statements, and use some function to handle your exception (assuming that your errors are called TimeoutError, ConnectionError, and HttpError...doesn't really matter for clarity) i.e.
try:
# do stuff
except (TimeoutError, ConnectionError, HttpError) as e:
handle_exception(e)

How should I use try...except while defining a function?

I find I've been confused by the problem that when I needn't to use try..except.For last few days it was used in almost every function I defined which I think maybe a bad practice.For example:
class mongodb(object):
def getRecords(self,tname,conditions=''):
try:
col = eval("self.db.%s" %tname)
recs = col.find(condition)
return recs
except Exception,e:
#here make some error log with e.message
What I thought is ,exceptions may be raised everywhere and I have to use try to get them.
And my question is,is it a good practice to use it everywhere when defining functions?If not are there any principles for it?Help would be appreciated!
Regards
That may not be the best thing to do. Whole point of exceptions is that you can catch them on very different level than it's raised. It's best to handle them in the place where you have enough information to make something useful with them (that is very application and context dependent).
For example code below can throw IOError("[Errno 2] No such file or directory"):
def read_data(filename):
return open(filename).read()
In that function you don't have enough information to do something with it, but in place where you actually using this function, in case of such exception, you may decide to try different filename or display error to the user, or something else:
try:
data = read_data('data-file.txt')
except IOError:
data = read_data('another-data-file.txt')
# or
show_error_message("Data file was not found.")
# or something else
This (catching all possible exceptions very broadly) is indeed considered bad practice. You'll mask the real reason for the exception.
Catch only 'explicitely named' types of exceptions (which you expect to happen and you can/will handle gracefully). Let the rest (unexpected ones) bubble as they should.
You can log these (uncaught) exceptions (globally) by overriding sys.excepthook:
import sys
import traceback
# ...
def my_uncaught_exception_hook(exc_type, exc_value, exc_traceback):
msg_exc = "".join( \
traceback.format_exception(exc_type, exc_value, exc_traceback) )
# ... log here...
sys.excepthook = my_uncaught_exception_hook # our uncaught exception hook
You must find a balance between several goals:
An application should recover from as many errors as possible by itself.
An application should report all unrecoverable errors with enough detail to fix the cause of the problem.
Errors can happen everywhere but you don't want to pollute your code with all the error handling code.
Applications shouldn't crash
To solve #3, you can use an exception hook. All unhandled exceptions will cause the current transaction to abort. Catch them at the highest level, roll back the transaction (so the database doesn't become inconsistent) and either throw them again or swallow them (so the app doesn't crash). You should use decorators for this. This solves #4 and #1.
The solution for #2 is experience. You will learn with time what information you need to solve problems. The hard part is to still have the information when an error happens. One solution is to add debug logging calls in the low level methods.
Another solution is a dictionary per thread in which you can store some bits and which you dump when an error happens.
another option is to wrap a large section of code in a try: except: (for instance in a web application, one specific GUI page) and then use sys.exc_info() to print out the error and also the stack where it occurred
import sys
import traceback
try:
#some buggy code
x = ??
except:
print sys.exc_info()[0] #prints the exception class
print sys.exc_info()[1] #prints the error message
print repr(traceback.format_tb(sys.exc_info()[2])) #prints the stack

How should I correctly handle exceptions in Python3

I can't understand what sort of exceptions I should handle 'here and now', and what sort of exceptions I should re-raise or just don't handle here, and what to do with them later (on higher tier). For example: I wrote client/server application using python3 with ssl communication. Client is supposed to verify files on any differences on them, and if diff exists then it should send this 'updated' file to server.
class BasicConnection:
#blablabla
def sendMessage(self, sock, url, port, fileToSend, buffSize):
try:
sock.connect((url, port))
while True:
data = fileToSend.read(buffSize)
if not data: break
sock.send(data)
return True
except socket.timeout as toErr:
raise ConnectionError("TimeOutError trying to send File to remote socket: %s:%d"
% (url,port)) from toErr
except socket.error as sErr:
raise ConnectionError("Error trying to send File to remote socket: %s:%d"
% (url,port)) from sErr
except ssl.SSLError as sslErr:
raise ConnectionError("SSLError trying to send File to remote socket: %s:%d"
% (url,port)) from sslErr
finally:
sock.close()
Is it right way to use exceptions in python? The problem is: what if file.read() throws IOError? Should I handle it here, or just do nothing and catch it later? And many other possible exceptions?
Client use this class (BasicConnection) to send updated files to server:
class PClient():
def __init__(self, DATA):
'''DATA = { 'sendTo' : {'host':'','port':''},
'use_ssl' : {'use_ssl':'', 'fileKey':'', 'fileCert':'', 'fileCaCert':''},
'dirToCheck' : '',
'localStorage': '',
'timeToCheck' : '',
'buffSize' : '',
'logFile' : ''} '''
self._DATA = DATA
self._running = False
self.configureLogging()
def configureLogging(self):
#blablabla
def isRun(self):
return self._running
def initPClient(self):
try:
#blablabla
return True
except ConnectionError as conErr:
self._mainLogger.exception(conErr)
return False
except FileCheckingError as fcErr:
self._mainLogger.exception(fcErr)
return False
except IOError as ioErr:
self._mainLogger.exception(ioErr)
return False
except OSError as osErr:
self._mainLogger.exception(osErr)
return False
def startPClient(self):
try:
self._running = True
while self.isRun():
try :
self._mainLogger.debug("Checking differences")
diffFiles = FileChecker().checkDictionary(self._dict)
if len(diffFiles) != 0:
for fileName in diffFiles:
try:
self._mainLogger.info("Sending updated file: %s to remote socket: %s:%d"
% (fileName,self._DATA['sendTo']['host'],self._DATA['sendTo']['port']))
fileToSend = io.open(fileName, "rb")
result = False
result = BasicConnection().sendMessage(self._sock, self._DATA['sendTo']['host'],
self._DATA['sendTo']['port'], fileToSend, self._DATA['buffSize'])
if result:
self._mainLogger.info("Updated file: %s was successfully delivered to remote socket: %s:%d"
% (fileName,self._DATA['sendTo']['host'],self._DATA['sendTo']['port']))
except ConnectionError as conErr:
self._mainLogger.exception(conErr)
except IOError as ioErr:
self._mainLogger.exception(ioErr)
except OSError as osErr:
self._mainLogger.exception(osErr)
self._mainLogger.debug("Updating localStorage %s from %s " %(self._DATA['localStorage'], self._DATA['dirToCheck']))
FileChecker().updateLocalStorage(self._DATA['dirToCheck'],
self._DATA['localStorage'])
self._mainLogger.info("Directory %s were checked" %(self._DATA['dirToCheck']))
time.sleep(self._DATA['timeToCheck'])
except FileCheckingError as fcErr:
self._mainLogger.exception(fcErr)
except IOError as ioErr:
self._mainLogger.exception(ioErr)
except OSError as osErr:
self._mainLogger.exception(osErr)
except KeyboardInterrupt:
self._mainLogger.info("Shutting down...")
self.stopPClient()
except Exception as exc:
self._mainLogger.exception(exc)
self.stopPClient()
raise RuntimeError("Something goes wrong...") from exc
def stopPClient(self):
self._running = False
Is it correct? May be someone spend his own time and just help me to understand pythonic style of handling exceptions? I can't understand what to do with such exceptions as NameError, TypeError, KeyError, ValueError...and so on.......They could be thrown at any statement, at any time... and what to do with them, if I want to logged everything.
And what information should people usually log? If error occurs, what info about it I should log? All traceback, or just relevant message about it or something else?
I hope somebody helps me.
Thanks a lot.
In general, you should "catch" the exceptions that you expect to happen (because they may be caused by user error, or other environmental problems outside of your program's control), especially if you know what your code might be able to do about them. Just giving more details in an error report is a marginal issue, though some programs' specs may require doing that (e.g. a long-running server that's not supposed to crash due to such problems, but rather log a lot of state information, give the user a summary explanation, and just keep working for future queries).
NameError, TypeError, KeyError, ValueError, SyntaxError, AttributeError, and so on, can be thought of as due to errors in the program -- bugs, not problems outside of the programmer's control. If you're releasing a library or framework, so that your code is going to be called by other code outside of your control, then such bugs may quite likely be in that other code; you should normally let the exception propagate to help the other programmer debug their own bugs. If you're releasing an application, you own the bugs, and you must pick the strategy that helps you find them.
If your bugs show up while an end-user is running the program, you should log a lot of state information, and give the user a summary explanation and apologies (perhaps with a request to send you the log info, if you can't automate that -- or, at least, ask permission before you send anything from the user's machine to yours). You may be able to save some of the user's work so far, but often (in a program that's known to be buggy) that may not work anyway.
Most bugs should show up during your own testing of course; in that case, propagating the exception is useful as you can hook it up to a debugger and explore the bug's details.
Sometimes some exceptions like these show up just because "it's easier to ask forgiveness than permission" (EAFP) -- a perfectly acceptable programming technique in Python. In that case of course you should handle them at once. For example:
try:
return mylist[theindex]
except IndexError:
return None
here you might expect that theindex is generally a valid index into mylist, but occasionally outside of mylist's bounds -- and the latter case, by the semantics of the hypothetic app in which this snippet belongs, is not an error, just a little anomaly to be fixed by considering the list to be conceptually extended on both sides with infinite numbers of Nones. It's easier to just try/except than to properly check for positive and negative values of the index (and faster, if being out of bounds is a truly rare occurrence).
Similarly appropriate cases for KeyError and AttributeError happen less frequently, thanks to the getattr builtin and get method of dicts (which let you provide a default value), collections.defaultdict, etc; but lists have no direct equivalent of those, so the try/except is seen more frequently for IndexError.
Trying to catch syntax errors, type errors, value errors, name errors, etc, is a bit rarer and more controversial -- though it would surely be appropriate if the error was diagnosed in a "plug-in", third-party code outside your control which your framework/application is trying to load and execute dynamically (indeed that's the case where you're supplying a library or the like and need to coexist peacefully with code out of your control which might well be buggy). Type and value errors may sometimes occur within an EAFP pattern -- e.g. when you try to overload a function to accept either a string or a number and behave slightly differently in each case, catching such errors may be better than trying to check types -- but the very concept of functions thus overloaded is more often than not quite dubious.
Back to "user and environmental errors", users will inevitably make mistakes when they give you input, indicate a filename that's not actually around (or that you don't have permission to read, or to write if that's what you're supposed to be doing), and so on: all such errors should of course be caught and result in a clear explanation to the user about what's gone wrong, and another chance to get the input right. Networks sometime go down, databases or other external servers may not respond as expected, and so forth -- sometimes it's worth catching such problems and retrying (maybe after a little wait -- maybe with an indication to the user about what's wrong, e.g. they may have accidentally unplugged a cable and you want to give them a chance to fix things and tell you when to try again), sometimes (especially in unattended long-running programs) there's nothing much you can do except an ordered shutdown (and detailed logging of every possibly-relevant aspect of the environment).
So, in brief, the answer to your Q's title is, "it depends";-). I hope I have been of use in listing many of the situations and aspects on which it can depend, and recommending what's generally the most useful attitude to take towards such issues.
To start with, you don't need any _mainLogger.
If you want to catch any exceptions, maybe to log or send them by email or whatever, do that at the highest possible level -- certainly not inside this class.
Also, you definitely don't want to convert every Exception to a RuntimeError. Let it emerge. The stopClient() method has no purpose right now. When it has, we'll look at it..
You could basically wrap the ConnectionError, IOError and OSError together (like, re-raise as something else), but not much more than that...

Categories

Resources