ThisGuy
ThisGuy

Reputation: 2883

instantiate subclass from existing superclass

So I'm interacting with a 3rd party library, which raises exceptions someti0mes, but it raises the same exception for basically everything (specifically suds.WebFault. It's possible however to determine the exact type of exception it is from the data on the exception raised. I'm looking to abstract this exception into exceptions that subclass this type, ie:

from suds import WebFault

class MoreSpecificError(WebFault):
    pass

I like the subclassing, because it won't break existing implementations that expect a WebFault. The problem I'm having is passing the data already on the WebFault into the MoreSpecificError. What I would like to do is take the existing exception object and just 'turn it into' the subclass, without any changes or re-running __init__. What I've done so far to accomplish this is something like:

from suds import WebFault

class MoreSpecificError(WebFault):
    # You pass the old WebFault when instantiating this exception.
    # Then it gets poofed into a MoreSpecificError type
    def __new__(cls, internal_fault):
        return internal_fault
    # This is necessary to prevent the parent class' __init__ from being run
    def __init__(self, internal_fault):
        pass

Edit: I now know this doesn't work, the new object will not be of the subclass' type

Which 'works', but the need to put that __init__ that's just a pass feels really gross to me. Not to mention some stuff doesn't like custom __new__ methods (read: deepcopy, it's not a choice, the testing framework we use (lettuce) uses it and we're pretty far invested already).

I'm wondering if there's a better way to do this? I know the ideal way is just to raise the subclass initially, but I'd really rather not start working with a forked copy of this library. I'm really hoping there's some magic somewhere in Python I just don't know yet.

Upvotes: 4

Views: 567

Answers (1)

BrenBarn
BrenBarn

Reputation: 251365

I think this is what you're asking for:

class MoreSpecificError(WebFault):
    def __new__(self, old):
        old.__class__ = MoreSpecificError
        return old

However, it is risky for reasons described here. If all you are doing is catching the exception it should probably work, but no guarantees.

I still think it'd be better to just actually create a new exception object in the normal way. If you're worried about losing the information from the original exception, look in the documentation for that exception to see what information is documented to be part of its public API, and copy that information. Code that was relying on exception info that was not part of the original API is not something you need to support with your new API.

Upvotes: 1

Related Questions