0

I'm trying to create a custom Exception which can inherit from all the Exceptions. I've used a wrapper, here's my code:

def _MyError(_type, message=None, *args, **kwargs):
    class MyError(_type, object):
        def __init__(self, *_args, **_kwargs):
        super(MyError, self).__init__(self, message, *_args, **_kwargs)
        return

    return MyError(*args, **kwargs)


if(__name__ == '__main__'):
    try:
        raise _MyError(KeyError, message="ooops")
    except MyError as e:
        print "MyError occurred. ", e.message
    except BaseException:
        print "MyError not recognized.\n"

    try:
        raise _MyError(IndexError, message="ooops")
    except IndexError as e:
        print "MyError occurred. ", e.message
    except BaseException:
        print "MyError not recognized.\n"
    
    exit

Output:

MyError not recognized.
MyError not recognized.

Suggestions?

1
  • 2
    What problem are you trying to solve by doing this? Commented Feb 17, 2016 at 2:46

4 Answers 4

2

This is a rather tricky problem. The issue is that the very creation of your specialized MyError fails with an IndexError. Because an IndexError is not a KeyError, it passes right through the attempt to catch it and instead is caught as a BaseException.

def _MyError(_type, *args, **kwargs):
    class MyError(_type, object):
        def __init__(self, *_args, **_kwargs):
            super(MyError, self).__init__(self, *_args, **_kwargs)
            # Error on above line (IndexError from kwargs not accepted)

    return MyError(*args, **kwargs) # Error goes through here

try:
    raise _MyError(KeyError, message='hello')
    # raise never gets invoked, IndexError on calling _MyError
except KeyError: # IndexError != KeyError. This clause is skipped
    print 'KeyError'
# except BaseException: 
    # print 'BaseException'
# Commenting out the above lines will throw the error instead of catching it

You should instead create your error like so:

raise _MyError(KeyError, 'hello')
Sign up to request clarification or add additional context in comments.

1 Comment

Check the code... I tried to catch _My(type, args) as MyError and then I tried to catch it as its type...
1

Exceptions does not accept message; causes super(MyError, self).__init__(self, *_args, **_kwargs) fail.

>>> IndexError(message='asdf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: exceptions.IndexError does not take keyword arguments

You need to convert message to positional argument:

def _MyError(_type, *args, **kwargs):
    class MyError(_type, object):
        def __init__(self, message=None):
            super(MyError, self).__init__(self, message)

    return MyError(*args, **kwargs)

1 Comment

@NicholasRoveda, Did you try the code in the answer? asciinema.org/a/0sgbr96z0x9gxpa0ysfnufqve
1

When I try your code in Python 2.7 I get the following error:

Traceback (most recent call last):
  File "test.py", line 13, in <module>
    except MyError as e:
NameError: name 'MyError' is not defined

This is not surprising, because the name MyError does not exist at the file-level scope where you are trying to catch it.

Also consider that you're creating a new class each time you call the _MyError() function. So even if there were a MyError class available to use in the except block, it would almost certainly be the wrong class (albeit with the same name).

I suspect you might want to create a "root" MyError class, and then create a MyCustomError class in your function. You could then catch the MyError (base) class in your exception block and proceed from there.

EDIT

Per your comment, you might be able to do something like this:

class MyError:
    """Marker class for mixin."""
    pass

def my_error(_type, message=None, *args, **kwargs):
    class _MySubclass(_type, MyError):
        def __init__(self, *_args, **_kwargs):
            super(_MySubclass, self).__init__(message, *_args, **_kwargs)

    return _MySubclass(*args, **kwargs)

try:
    raise my_error(KeyError, message="key error")
except MyError as e:
    print "MyError occurred: ", e.message
except BaseException:
    print "Unknown error:", str(e)

try:
    raise my_error(IndexError, message="index error")
except MyError as e:
    print "MyError occurred: ", e.message
except BaseException:
    print "Unknown error:", str(e)

1 Comment

Yeah, I see what u mean... It's also possible to do it only with decorators and direct catch as I'm trying to?
1

I suggest you create a class factory to build your error type dynamically, as explained in the official docs.

def error_factory(name, *base_errors):
    """Dynamically create custom Error class."""
    assert all(issubclass(e, Exception) for e in base_errors)

    return type(name, base_errors, {})


try:
    something()
except KeyError:
    MyError = error_factory("MyError", KeyError)
    raise MyError("A problem occured!")  # this error is also a `KeyError`

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.