1

I want to patch a library to catch the built-in ConnectionError (which inherits from OSError).

So far so good. As it happens, the library has a "self-defined" Exception that is also called ConnectionError:

class LibraryError(Exception):
    pass


class ConnectionError(LibraryError):
    pass

I guess, if I now tried to catch a ConnectionError, doing something like

try:
    do_something()
except ConnectionError as e:
    try_to_get_it_right_again()

I would only catch the self-defined ConnectionError, which inherits from LibraryError. (Disclaimer: I have to admit, I haven't tested that myself, as I didn't know how).

How would I get Python to catch the built-in ConnectionError?

speendo
  • 13,045
  • 22
  • 71
  • 107
  • 1
    About your disclaimer part, its about scope resolution, so you are right as the built-ins are checked last. Take a look at this [SO answer](http://stackoverflow.com/a/292502/5050917) if you want. – mgc Jan 22 '16 at 19:43

2 Answers2

3

Use the builtins module, the explicit name for the namespace where built-in names like int and ConnectionError live.

import builtins

try:
    ...
except builtins.ConnectionError:
    ...

In Python 2, this would be __builtin__, although Python 2 doesn't have ConnectionError. Note that __builtins__ is its own weird thing; even if it looks like what you want, it's not.


If you want code that works in both Python 2 and Python 3... well, the exception hierarchy looks pretty different in Python 2, and ConnectionError doesn't even exist, so it's not as simple as deciding whether to use builtins or __builtin__. The builtins/__builtin__ thing is easy enough to solve, at least.

To import the right module depending on Python version, you can catch the ImportError and import the other module:

try:
    import builtins
except ImportError:
    import __builtin__ as builtins

Pretending for a moment that Python 2 has ConnectionError, you could save a reference to the built-in ConnectionError before shadowing the name:

_builtin_ConnectionError = ConnectionError

class ConnectionError(LibraryError):
    ...
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Thank you. Another problem is that the original author wrote the library to run in Python2 *and* in Python3 - so I probably couldn't `import builtins` without breaking Python2 support :( – speendo Jan 22 '16 at 19:39
  • 1
    @speendo: `try: import builtins` `except ImportError: import __builtin__ as builtins`. Catching ImportError is pretty standard when a module might or might not exist. Alternatively, you can save a reference to the builtin `ConnectionError` before shadowing the name: `_builtin_ConnectionError = ConnectionError`. – user2357112 Jan 22 '16 at 19:41
  • oh, the last option would be a great way to deal with it without hacking around too much! Still, I will ask the original author if he would like to rename his ConnectionError, which would improve readability even more :) – speendo Jan 22 '16 at 19:43
  • @speendo: Wait, if you need code that works on both Python 2 and Python 3, you're just going to be catching OSError instead of ConnectionError either way, since Python 2 doesn't have ConnectionError. – user2357112 Jan 22 '16 at 19:45
  • in Python 2 I catch [socket.error](https://docs.python.org/2/library/socket.html#socket.error) at the moment. Would you recommend catching OSError? It seems too "general" to me. – speendo Jan 22 '16 at 19:47
  • 1
    @speendo: Actually, catching OSError wouldn't work, since the exception hierarchy changed in more ways than I realized. In Python 2, `socket.error` doesn't even descend from OSError. – user2357112 Jan 22 '16 at 19:57
2

Use the the ConnectionError defined along with the other exceptions in the builtins library:

import builtins

try:
    # connection error raised
except builtins.ConnectionError as conerr:
    # handle stuff
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253