MemoryError's message as str is empty in Python - python

This is a very silly question, but I'm running some tasks and catching their errors by:
try:
run_something()
except Exception as e:
handle_error(str(e))
I want the error message as a String because I'm using a UI and I want to display the error in a window.
The problem can be replicated as:
>>> import numpy as np
>>> np.range(1e10)
MemoryError Traceback (most recent call last)
<ipython-input-4-20a59c2069b2> in <module>()
----> 1 np.arange(1e10)
MemoryError:
However, if I try to catch the error and print its message (which I was hoping to be something like "MemoryError":
try:
np.arange(1e10)
except Exception as e:
print(str(e))
print("Catched!")
The only output I get is "Catched!". This is so stupid, I was doing some work with UI's and threading, and took me a while to realise that the problem was a memory error with no message at all.
Is the MemoryError the only Exception that is translated to an empty string? Because if it is the case I can check it. If not, how to get its message as a String?

So you probably want to print the name of the exception class:
try:
np.arange(1e10)
except Exception as e: #not catch...
print(str(e.__class__.__name__))
print("Catched!")
Using str(e) only prints the "message" of the exception, which in your case was empty.
Note that you can obtain the arguments passed to the exception constructor via the args attribute:
In [4]: try:
...: raise ValueError(1,2,3)
...: except ValueError as e:
...: print('arguments:', e.args)
arguments: (1, 2, 3)

When call str(e) it returns the message of the Exception. Take an example -
NameError: name 'a' is not defined
^ ^
name message
The part before : is the name of the exception, whereas the part after it is the message (arguments).
In the case of MemoryError , as you can see in your example -
MemoryError:
does not have an error message , only the name of the exception , hence you get the empty string.
I am not sure if there are other Exceptions that do not have an exception, but I believe it would be very rare to find such exceptions. Maybe you can print both the exception's name as well as the message , if you really want to take care of the MemoryError (and maybe other such rare exceptions without messages) , something like -
print(type(e).__name__ , ':', str(e))

From the Python documentation (Version 2.7, I guess also applies to Python 3.x):
The base class for all built-in exceptions. It is not meant to be directly inherited by user-defined classes (for that, use Exception). If str() or unicode() is called on an instance of this class, the representation of the argument(s) to the instance are returned, or the empty string when there were no arguments.
It seems, that MemoryError gets no arguments, and thus according to this documentation does give an empty string back.
The exception can of course still be catched, because it can be catched by its type.
You can get the name of the exception class and print that.
This makes of course also a lot of sense, since look at that:
a = {}
try:
a['barrel']
except Exception as e:
print str(e)
Will print just 'barrel' -- what is not so helpful, so to add the class name of the exception is really a good idea:
...
except Exception as e:
print(e.__class__.__name + ': ' + (str(e)))

Related

usage of except and store error in a variable

I need to catch all the errors,exceptions, and everything that stops the execution of a code and store it in a variable.
I want something like this:
try:
Error generating code
except as err:
print err
But this doesnt work. Is there any other way to do the same?
except as err: doesn't work because the correct syntax is:
except TypeOfError as somename:
To catch any type of error, use Exception as the type,
it is the common base class for all non-exit exceptions in Python:
try:
# Error generating code
except Exception as err:
print(err)
err will be an instance of the actual exception that was raised,
you can see its correct type with type(err),
and it's attributes and methods with dir(err).
Keep in mind that it's recommended to use the most specific type of exception that may be raised.
See more details in Python's tutorial on error handling.

Python Exception instances can be indexed directly [duplicate]

I have been bitten by something unexpected recently. I wanted to make something like that:
try :
thing.merge(iterable) # this is an iterable so I add it to the list
except TypeError :
thing.append(iterable) # this is not iterable, so I add it
Well, It was working fine until I passed an object inheriting from Exception which was supposed to be added.
Unfortunetly, an Exception is iterable. The following code does not raise any TypeError:
for x in Exception() :
print 1
Does anybody know why?
Note that what is happening is not related to any kind of implicit string conversion etc, but because the Exception class implements __getitem__ to return the values from the args tuple (ex.args). You can see this by the fact that you get the whole string as your first and only item in the iteration, rather than the character-by-character result you'd get if you iterate over the string.
This surprised me too, but thinking about it, I'm guessing it is for backwards compatibility reasons. Python used to (pre-1.5) lack the current class hierarchy of exceptions. Instead, strings were thrown, with (usually) a tuple argument for any details that should be passed to the handling block, i.e:
try:
raise "something failed", (42, "some other details")
except "something failed", args:
errCode, msg = args
print "something failed. error code %d: %s" % (errCode, msg)
It looks like this behavior was put in to avoid breaking pre-1.5 code expecting a tuple of arguments, rather than a non-iterable exception object. There are a couple of examples of this with IOError in the Fatal Breakage section of the above link
String exceptions have been deprecated for a while, and are gone in Python 3. Exception objects are no longer iterable in Python 3:
>>> list(Exception("test"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Exception' object is not iterable
NOT VALID. Check Brian anwser.
Ok, I just got it :
for x in Exception("test") :
print x
....:
....:
test
Don't bother ;-)
Anyway, it's good to know.
EDIT : looking to the comments, I feel like adding some explanations.
An exception contains a message you passed to during instantiation :
raise Exception("test")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: test
It's fair to say that the message is what defines the Exception the best, so str() returns it :
print Exception("test")
test
Now, it happens that Exceptions are implicitly converted to string when used in something else than an Exception context.
So when I do :
for x in Exception("test") :
print x
I am iterating over the string "test".
And when I do :
for x in Exception() :
print x
I do iterate over an empty string. Tricky. Because when it comes to my issue :
try :
thing.merge(ExceptionLikeObject)
except TypeError :
...
This won't raise anything since ExceptionLikeObject is considered as a string.
Well now, we know the HOW, but I still not the WHY. Maybe the built-in Exception inherit from the built-in String ? Because as far as I know :
adding str does not make any object iterable.
I bypassed the problem by overloding iter, making it raising TypeError !
Not a problem anymore, but still a mystery.

How to get exception message in Python properly

What is the best way to get exceptions' messages from components of standard library in Python?
I noticed that in some cases you can get it via message field like this:
try:
pass
except Exception as ex:
print(ex.message)
but in some cases (for example, in case of socket errors) you have to do something like this:
try:
pass
except socket.error as ex:
print(ex)
I wondered is there any standard way to cover most of these situations?
If you look at the documentation for the built-in errors, you'll see that most Exception classes assign their first argument as a message attribute. Not all of them do though.
Notably,EnvironmentError (with subclasses IOError and OSError) has a first argument of errno, second of strerror. There is no message... strerror is roughly analogous to what would normally be a message.
More generally, subclasses of Exception can do whatever they want. They may or may not have a message attribute. Future built-in Exceptions may not have a message attribute. Any Exception subclass imported from third-party libraries or user code may not have a message attribute.
I think the proper way of handling this is to identify the specific Exception subclasses you want to catch, and then catch only those instead of everything with an except Exception, then utilize whatever attributes that specific subclass defines however you want.
If you must print something, I think that printing the caught Exception itself is most likely to do what you want, whether it has a message attribute or not.
You could also check for the message attribute if you wanted, like this, but I wouldn't really suggest it as it just seems messy:
try:
pass
except Exception as e:
# Just print(e) is cleaner and more likely what you want,
# but if you insist on printing message specifically whenever possible...
if hasattr(e, 'message'):
print(e.message)
else:
print(e)
To improve on the answer provided by #artofwarfare, here is what I consider a neater way to check for the message attribute and print it or print the Exception object as a fallback.
try:
pass
except Exception as e:
print getattr(e, 'message', repr(e))
The call to repr is optional, but I find it necessary in some use cases.
Update #1:
Following the comment by #MadPhysicist, here's a proof of why the call to repr might be necessary. Try running the following code in your interpreter:
try:
raise Exception
except Exception as e:
print(getattr(e, 'message', repr(e)))
print(getattr(e, 'message', str(e)))
The repr(e) line will print Exception() and the str(e) line will print an empty string.
Update #2:
Here is a demo with specifics for Python 2.7 and 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533
I too had the same problem. Digging into this I found that the Exception class has an args attribute, which captures the arguments that were used to create the exception. If you narrow the exceptions that except will catch to a subset, you should be able to determine how they were constructed, and thus which argument contains the message.
try:
# do something that may raise an AuthException
except AuthException as ex:
if ex.args[0] == "Authentication Timeout.":
# handle timeout
else:
# generic handling
from traceback import format_exc
try:
fault = 10/0
except ZeroDivision:
print(format_exc())
Another possibility is to use the format_exc() method from the traceback module.
I had the same problem. I think the best solution is to use log.exception, which will automatically print out stack trace and error message, such as:
try:
pass
log.info('Success')
except:
log.exception('Failed')

Catching Python Exceptions and printing out a separate message

I'm currently trying to write code to catch exceptions, and depending upon which exception is thrown, a different module will be imported than when no exception was thrown.
try:
import sge_execution_engine as execution_engine
except ImportError:
print "Use local execution engine because SGE support is missing!"
print sys.exc_info() # Print out the exception message
import local_execution_engine as execution_engine
except RuntimeError:
print "Using local execution engine because SGE support is missing!"
print sys.exc_info()
import local_execution_engine as execution_engine
The first exception, ImportError that is caught, catches the exception thrown when python drmaa module cannot be found during the execution of import sge_execution_engine (inside sge_execution_engine, there is an import drmaa statement). The second exception, RuntimeError, is caught when the drmaa python library is found (likewsie during the execution of the import drmaa statement inside the sge_execution_engine), but the drmaa C library is not installed into the OS. We hope that these two except statements are sufficient to catch all possible exceptions that can be thrown when a user attempts to run this module on a machine that just does not have the python drmaa library, the drmaa C library, or does not have Sun Grid Engine installed. without any of these proceeds, the module proceeds to then import local_execution_engine and so the code can then execute on the user's machine locally. Right now the code works as expected in the sense that it goes to import local when it finds exceptions with sge, but we are still looking to improve the exception handling here to make it more robust.
In my opinion I think having the actual Exception message that was thrown be printed to stdout is good as it will allow the user to know why he was unable to import sge_execution_engine especially if he was not expecting it to fail being imported.
However, instead of using print sys.exc_info() to actually have the actual exception message be printed on screen, I realized that perhaps a better way would be to use the except EXCEPTION as some_variable_name format and then print out print some_variable_name and also call some of the attributes associated with the Exception that is thrown and assigned to some_variable_name.
I saw this being done in the Python tutorial on exceptions where there was this chunk of code:
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as e:
print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
It seems like the except IOError as e chunk is handling the exception message in a fine-grained way by specifically calling on the errno and strerror attributes of the IOError object. However, when I look at the IOError documentation , I do not see these specific attributes being listed out as part of the documentation for the exception. In fact, this is also the case for all the other exceptions under the Python documentation, so it seems there is no way we can figure out what attributes will be associated with a particular exception. If we don't know anything about this, then how will we be able to figure out what attributes to call on the some_variable_name object when we use the import EXCEPTION as some_variable_name syntax to handle our exceptions?
I would appreciate anyone's suggestion on this, and even if your answer is not directly answering my question, but if you have another entirely different suggestion on how I could better handle my exception here, please don't hesitate to make a post!
Thank you very much!
Using a bare except is rarely a good idea, but this is one of those rare times -- primarily because you have a backup that you want to use if, for any reason, you cannot import the system sge:
try:
import sge_execution_engine as execution_engine
except:
print "Use local execution engine because SGE support is missing!"
print sys.exc_info() # Print out the exception message
import local_execution_engine as execution_engine
Notice you now only need one except clause.
The better way to handle getting that information to the user is probably to go ahead and print it out, and then also use the logging module to make a permanent record:
import logging
logger = logging.getLogger()
logger.setLevel(logging.WARNING)
and then in your except clause add:
logger.exception('unable to import sge')
and your message, along with the actual exception, will be saved in a log file.
First you're right that it's better to catch the exception into a variable than to ignore it and then pull it back out with sys.exc_info(). There are a few good reasons to use exc_info (low-level code, code that has to work with both pre-2.6 and 3.x, etc.), but in general, when you get can do it your way, you should.
And this works even for your last bare except. In 2.7, a plain except: means the same thing as except Exception:, so you can write except Exception as e:, and then use the e value.
Also note that if you want to do exactly the same thing for multiple exception types, you can write except (RuntimeError, ImportError) as e:.
As for "making it more robust", that's not an absolute thing. For example, if there's some unexpected exception that's neither a RuntimeError nor an ImportError, do you want to log it and try the fallback code, or quite and dump the traceback? If it's, e.g., a SyntaxError caused by someone checking in a bad edit to your program, you may not want to treat that like a runtime error… or maybe you do; that really depends on your development practices and target userbase.
Meanwhile:
It seems like the except IOError as e chunk is handling the exception message in a fine-grained way by specifically calling on the errno and strerror attributes of the IOError object. However, when I look at the IOError documentation, I do not see these specific attributes being listed out as part of the documentation for the exception.
You need to look up the hierarchy. Notice that IOError is a subclass of EnvironmentError, which does document the errno and strerror attributes. (What these attributes actually mean is only documneted for OSError and its subclasses, but the fact that they exist is documented.)
If you think this is all a bit of a mess… well, it is. It's all cleaned up in Python 3.x, where IOError and EnvironmentError are merged into OSError, which clearly documents its attributes, and where you usually don't have to switch on errno in the first place because common errno values generate a specific subclass like FileNotFoundError, and so on. But as long as you're using 2.7, you don't get the benefits of the last 6 years of improvements to the language.
For example, looking at the hierarchy or ValueError=>StandardError=>Exception (from lowest to highest in the hierarchy), I can't find any attributes about it.
If you dir a ValueError, you'll see that it only has two attributes (besides the usual special stuff like __repr__ and __class_): args and message.
message isn't documented because it was deprecated in 2.5, and only exists in 2.7 to allow some pre-2.5 code to keep running.* But args is documented; you just need to go up one level further, to BaseException:
args
The tuple of arguments given to the exception constructor. Some built-in exceptions (like IOError) expect a certain number of arguments and assign a special meaning to the elements of this tuple, while others are usually called only with a single string giving an error message.
So, the reason you can't find the other attributes in ValueError is that there are no other attributes to find. And the same goes for those other classes. The handful of types that have special attributes (OSError, SyntaxError, maybe a few module-specific types elsewhere in the stdlib) document them explicitly.**
If we are using the except some_exception as e syntax, is doing a print e sufficient to get the exception printed out without calling its attributes
It's sufficient to get some useful form of the exception printed. Again, from the BaseException docs:
If str() or unicode() is called on an instance of this class, the representation of the argument(s) to the instance are returned or the empty string when there were no arguments.
In some cases, that's not what you want. In particular, notice that it doesn't include the type of the exception. You can get that with repr, which gives you something that looks like a constructor call (e.g., ValueError("invalid literal for int() with base 10: 'f'")).
If you want the same output you get in a traceback, you have to put the type and the str or unicode together yourself—e.g., '{}: {}'.format(type(e), e).
If you want to get the actual information out of the exception, like that base 10 or that string 'f'—well, you can't,*** because that information has already been thrown away. You'll have to write your own code to keep track of it, like:
try:
i = int(s, 16)
except ValueError as e:
print '{} is not a base-16 number'.format(s)
* It's as if BaseException.__init__(self, *args) were defined to do self.args = tuple(args); self.message = str(args[0]) if args else ''.
** I believe in 2.5 there were a few exception types that had undocumented attributes as an implementation detail of CPython, but by 2.7 they're all either gone or documented.
*** Well, you could parse the exception string, but needless to say, that's an implementation detail, not something guaranteed to be stable and portable. It could be different in Jython, or on a Spanish-language system, or it may not quote strings the way you expect, etc.

Exception handling in Python

http://docs.python.org/library/imaplib.html states that:
exception IMAP4.error
Exception raised on any errors. The reason for the exception is passed to the constructor as a string.
What does "exception is passed to the constructor as a string" mean? What would the code look like that can print the reason.
Just use print str(exception).
You can specify the reason when constructing the exception yourself, and put it into a variable when catching the exception.
try:
raise imaplib.IMAP4.error('Some exception')
except imaplib.IMAP4.error, error:
print error

Categories