Which exceptions i should catch and which should not in Python - python

For example i have a program with this structure:
Domain logic module -> Settings module -> Settings store backend
Next is a part of Settings module.
def load_from_json(self, json_str):
try:
self.load_from_dict(json.loads(json_str))
except ValueError as e:
raise SettingsLoadDataException('Error loading json')
Need I a custom exception SettingsLoadDataException here, or I could just skip catching json.loads errors?
def load_from_json(self, json_str):
self.load_from_dict(json.loads(json_str))
Update.
Also good variant is:
def load_from_json(self, json_str):
try:
self.load_from_dict(json.loads(json_str))
except ValueError as e:
raise ValueError('Error loading json')

That is a problem only you can answer. You could catch all exceptions, or you could let the program crash if it throws an exception you don't handle. If it is vital that the program doesn't crash, catch the exception. However, you should implement a recovery method then. If the Json doesn't load properly, can your program do anything useful without it ? If it can, I would catch the exception, otherwise you could just display an error and terminate.

You should work with exceptions in such a way, that seeing a stack trace explains the problem to you immediately.
I am no Python expert, but won't you loose the piece of information that it was actually ValueError, that caused program crash? You will see only SettingsLoadDataException in a trace without any real reason of it, right?
Also, if you do not rethrow exceptions, you should catch only those, you know how to deal with. It is always better to have your program crash, than to leave it in an unexpected state.

Related

Python - try-except warning

I've recently had a problem when coding in Python in the PyCharm editor. Whenever I made a try-except statement, I would for some reason get a warning (yellow line beneath the word: except)
Here is an example:
s = "Text"
try:
print(s[2])
except:
print("There is no character at that index")
When I write this exact code in PyCharm, I get a warning. When I hover my mouse over the warning it says:
Too broad exception clause
PEP 8: E722 do not use bare 'except'
Any idea why this happens?
When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.
For example:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException: ).
A good rule of thumb is to limit use of bare 'except' clauses to two cases:
If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise . try...finally can be a better way to handle this case.

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: Make exceptions 'exiting'

In Python, is there any (proper) way to change the the default exception handling behaviour so that any uncaught exception will terminate/exit the program?
I don't want to wrap the entire program in a generic try-except block:
try:
// write code here
except Exception:
sys.exit(1)
For those asking for more specificity and/or claiming this is already the case, it's my understanding that not all Python exceptions are system-exiting: docs
Edit: It looks like I have forked processes complicating matters so won't be posting any specific details about my own mess.
If you're looking for an answer to the original question, Dmitry's comment is interesting and useful, references the 2nd answer to this question
You can use Specific exception instead of Exception because Exception is a Base class for all exceptions. For more details refer Exception tutorial
You can write your script like this-
try:
# write code here
except OverflowError:
raise SystemExit
except ArithmeticError:
sys.exit()
except IOError:
quit()
Try this different approaches to find what is exactly you are missing.
Edit 1 - Maintain Program Execution
In order to maintain your program execution try this one-
consider error_handler function is raising SystemExit exception then In your main method you need to add below code so you can maintain your program execution.
try:
error_handler()
except SystemExit:
print "sys.exit was called but I'm proceeding anyway (so there!-)."

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.

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

Categories

Resources