Component 10
Component 10

Reputation: 10497

Python string in exception converted to tuple

Python 2.7.10 appears to be converting my string into a tuple when thrown in an exception. Here's my example:

class MyError(RuntimeError):
   def __init__(self, arg):
      self.args = arg

def raiseMyError():
    errorCode = 29
    errorText = 'Port not ready yet'
    exitCodeMessage = 'ERROR {0}: {1}'.format(errorCode, errorText)
    # print exitCodeMessage  --> print out here and it's a string
    raise MyError(str(exitCodeMessage))

try:
    raiseMyError()

except MyError as e:
    print e.args

I create a string containing the error code and description and use this to construct a purpose built exception class. When I print out the exitCodeMessage variable before the exception is created I get what I'd expect:

ERROR 29: Port not ready yet

However, the trace from within the exception handler gives me the following:

('E', 'R', 'R', 'O', 'R', ' ', '2', '9', ':', ' ', 'P', 'o', 'r', 't', ' ', 'n', 'o', 't',
' ', 'r', 'e', 'a', 'd', 'y', ' ', 'y', 'e', 't')

Can anyone tell me what's going on here and what I can do about it?

Upvotes: 3

Views: 1502

Answers (2)

matino
matino

Reputation: 17725

Actually you don't need to override the __init__ method at all, it's sufficient enough to:

class MyError(RuntimeError):
   pass

Regarding the behaviour - docs state that args is:

The tuple of arguments given to the exception constructor.

When you inherit from Exception class or any of it's children printing e.args will simply print tuple(e.args), since args property is defined in such way in the Exception class (see @advance512 answer).

When you don't inherit from Exception:

class MyError:

    def __init__(self, arg):
        self.args = arg

you don't inherit the "magic" behind the args, thus calling e.args will work as expected.

You could also write like this (note self.arg instead of self.args):

class MyError(RuntimeError):

   def __init__(self, arg):
      self.arg = arg

and calling e.arg will also work as expected.

Upvotes: 3

advance512
advance512

Reputation: 1368

This is because args is a property that is defined in the BaseException class.

Check out exceptions.py:70:

args = property(lambda self: tuple())

Try this:

class MyError(RuntimeError):
   def __init__(self, errorString):
      self._errorString = errorString

def raiseMyError():
    errorCode = 29
    errorText = 'Port not ready yet'
    exitCodeMessage = 'ERROR %s: %s' % (errorCode, errorText)
    # print exitCodeMessage  --> print out here and it's a string
    raise MyError(exitCodeMessage)

try:
    raiseMyError()

except MyError as e:
    print e._errorString
    print e.args

output:

ERROR 29: Port not ready yet
()

Upvotes: 3

Related Questions