To amplify Messa, catch what you expect are failure modes that you know how to recover from. Ian Bicking wrote an article that addresses some of the overarching principles as does Eli Bendersky's note.
The problem with the sample code is that it is not handling errors, just prettifying them and discarding them. Your code does not "know" what to do with a NameError and there isn't much it should do other than pass it up, look at Bicking's re-raise if you feel you must add detail.
IOError and OSError are reasonably "expectable" for a shutil.move but not necessarily handleable. And the caller of your function wanted it to move a file and may itself break if that "contract" that Eli writes of is broken.
Catch what you can fix, adorn and re-raise what you expect but can't fix, and let the caller deal with what you didn't expect, even if the code that "deals" is seven levels up the stack in main.
Python doesn't have a mechanism right now for declaring which exceptions are thrown, unlike (for example) Java. (In Java you have to define exactly which exceptions are thrown by what, and if one of your utility methods needs to throw another exception then you need to add it to all of the methods which call it which gets boring quickly!)
So if you want to discover exactly which exceptions are thrown by any given bit of python then you need to examine the documentation and the source.
However python has a really good exception hierarchy.
If you study the exception hierarchy below you'll see that the error superclass you want to catch is called StandardError - this should catch all the errors that might be generated in normal operations. Turning the error into into a string will give a reasonable idea to the user as to what went wrong, so I'd suggest your code above should look like
from shutil import move
try:
move('somefile.txt', '/tmp/somefile.txt')
except StandardError, e:
print 'Move failed: %s' % e
Exception hierarchy
BaseException
|---Exception
|---|---StandardError
|---|---|---ArithmeticError
|---|---|---|---FloatingPointError
|---|---|---|---OverflowError
|---|---|---|---ZeroDivisionError
|---|---|---AssertionError
|---|---|---AttributeError
|---|---|---BufferError
|---|---|---EOFError
|---|---|---EnvironmentError
|---|---|---|---IOError
|---|---|---|---OSError
|---|---|---ImportError
|---|---|---LookupError
|---|---|---|---IndexError
|---|---|---|---KeyError
|---|---|---MemoryError
|---|---|---NameError
|---|---|---|---UnboundLocalError
|---|---|---ReferenceError
|---|---|---RuntimeError
|---|---|---|---NotImplementedError
|---|---|---SyntaxError
|---|---|---|---IndentationError
|---|---|---|---|---TabError
|---|---|---SystemError
|---|---|---TypeError
|---|---|---ValueError
|---|---|---|---UnicodeError
|---|---|---|---|---UnicodeDecodeError
|---|---|---|---|---UnicodeEncodeError
|---|---|---|---|---UnicodeTranslateError
|---|---StopIteration
|---|---Warning
|---|---|---BytesWarning
|---|---|---DeprecationWarning
|---|---|---FutureWarning
|---|---|---ImportWarning
|---|---|---PendingDeprecationWarning
|---|---|---RuntimeWarning
|---|---|---SyntaxWarning
|---|---|---UnicodeWarning
|---|---|---UserWarning
|---GeneratorExit
|---KeyboardInterrupt
|---SystemExit
This also means that when defining your own exceptions you should base them off StandardError not Exception.
Base class for all standard Python exceptions that do not represent
interpreter exiting.
If the error matches the description of one of the standard python exception classes, then by all means throw it.
Common ones to use are TypeError and ValueError, the list you linked to already is the standard list.
If you want to have application specific ones, then subclassing Exception or one of it's descendants is the way to go.
To reference the examples you gave from .NET
ApplicationException is closest to RuntimeError
ArgumentNullException will probably be an AttributeError (try and call the method you want, let python raise the exception a la duck typing)
AttributeOutOfRange is just a more specific ValueError
InvalidOperationException could be any number of roughly equivalent exceptions form the python standard lib.
Basically, pick one that reflects whatever error it is you're raising based on the descriptions from the http://docs.python.org/library/exceptions.html page.
First, Python raises standard exceptions for you.
It's better to ask forgiveness than to ask permission
Simply attempt the operation and let Python raise the exception. Don't bracket everything with if would_not_work(): raise Exception. Never worth writing. Python already does this in all cases.
If you think you need to raise a standard exception, you're probably writing too much code.
You may have to raise ValueError.
def someFunction( arg1 ):
if arg1 <= 0.0:
raise ValueError( "Guess Again." )
Once in a while, you might need to raise a TypeError, but it's rare.
def someFunctionWithConstraints( arg1 ):
if isinstance(arg1,float):
raise TypeError( "Can't work with float and can't convert to int, either" )
etc.
Second, you almost always want to create your own, unique exceptions.
class MyException( Exception ):
pass
That's all it takes to create something distinctive and unique to your application.
If you're looking for a list of all the builtin exceptions, you can find that in the documentation. The brief description of each kind gives you a basic idea of when they might be used. (Note that third-party libraries can also define their own exceptions, for which you'd need to look at the documentation for those libraries.)
If you want to know what exceptions a particular function might throw, you need to look at the documentation for that function. For instance, the documentation for decode indicates that it might throw a UnicodeError.
The built-in exceptions are listed in the Built-In Exceptions section of the library documentation. Decoding bytes to Unicode would throw the UnicodeDecodeError exception.
You'd also check the documentation for the method you are calling; you are calling bytes.decode() here:
The default for errors is
'strict', meaning that encoding errors raise aUnicodeError.