39

What's wrong with the following code (under Python 2.7.1):

class TestFailed(BaseException):
    def __new__(self, m):
        self.message = m
    def __str__(self):
        return self.message

try:
    raise TestFailed('Oops')
except TestFailed as x:
    print x

When I run it, I get:

Traceback (most recent call last):
  File "x.py", line 9, in <module>
    raise TestFailed('Oops')
TypeError: exceptions must be old-style classes or derived from BaseException, not NoneType

But it looks to me that TestFailed does derive from BaseException.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 6
    For other people who can't figure out why they are getting this error: check to make sure you didn't accidentally do `def MyException(Exception): pass` rather than the required `class MyException(Exception): pass`. Easy mistake to miss. – Rick Jul 21 '17 at 06:57

4 Answers4

33

__new__ is a staticmethod that needs to return an instance.

Instead, use the __init__ method:

class TestFailed(Exception):
    def __init__(self, m):
        self.message = m
    def __str__(self):
        return self.message

try:
    raise TestFailed('Oops')
except TestFailed as x:
    print x
damon
  • 14,485
  • 14
  • 56
  • 75
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
26

Others have shown you how to fix your implementation, but I feel it important to point out that the behavior you are implementing is already the standard behavior of exceptions in Python so most of your code is completely unnecessary. Just derive from Exception (the appropriate base class for runtime exceptions) and put pass as the body.

class TestFailed(Exception):
    pass
kindall
  • 178,883
  • 35
  • 278
  • 309
5

Use __init__() instead of __new__() to "initialize" classes. In most cases overriding __new__ is not necessary. It is called before __init__ during object creation.

See also Python's use of __new__ and __init__?

Community
  • 1
  • 1
Florian
  • 2,562
  • 5
  • 25
  • 35
3

The __new__ implementation should return an instance of the class, but it's currently returning None (by default).

However, it looks like you should be using __init__ here, rather than __new__.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336