New line on error message in KeyError - Python 3.3
Asked Answered
W

2

15

I am using Python 3.3 through the IDLE. While running a code that looks like:

raise KeyError('This is a \n Line break')

it outputs:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise KeyError('This is a \n Line break')
KeyError: 'This is a \n Line break'

I would like it to output the message with the line break like this:

This is a
 Line Break

I have tried to convert it to a string before or using os.linesep but nothing seems to work. Is there any way I can force the message to be correctly shown on the IDLE?


If I raise an Exception (instead of KeyError) then the output is what I want, but I would like to still raise a KeyError if possible.

Widely answered 23/10, 2017 at 14:47 Comment(1)
Please note I wrote "above", i.e. message is shown as "This is a \n Line break" and not as I expect "below" with the new line.Widely
C
16

You problem has nothing to do with IDLE. The behavior you see is all from Python. Running current repository CPython interactively, from a command line, we see the behavior you reported.

Python 3.7.0a2+ (heads/pr_3947:01eae2f721, Oct 22 2017, 14:06:43)
[MSC v.1900 32 bit (Intel)] on win32

>>> raise KeyError('This is a \n Line break')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'This is a \n Line break'
>>> s = 'This is a \n Line break'

>>> s
'This is a \n Line break'
>>> print(s)
This is a
 Line break
>>> raise Exception('This is a \n Line break')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception: This is a
 Line break
>>> raise IndexError(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: This is a
 Line break
>>> try:
...   raise  KeyError('This is a \n Line break')
... except KeyError as e:
...   print(e)

'This is a \n Line break'
>>> try:
...   raise  KeyError('This is a \n Line break')
... except KeyError as e:
...   print(e.args[0])

This is a
 Line break

I don't know why KeyError acts differently from even IndexError, but printing e.args[0] should work for all exceptions.

EDIT

The reason for the difference is given in this old tracker issue, which quotes a comment in the KeyError source code:

/* If args is a tuple of exactly one item, apply repr to args[0].
       This is done so that e.g. the exception raised by {}[''] prints
         KeyError: ''
       rather than the confusing
         KeyError
       alone.  The downside is that if KeyError is raised with an
explanatory
       string, that string will be displayed in quotes.  Too bad.
       If args is anything else, use the default BaseException__str__().
    */

This section appears in the KeyError_str object definition in Objects/exceptions.c of the Python source code.

I will mention your issue as another manifestation of this difference.

Consecrate answered 23/10, 2017 at 21:53 Comment(1)
It's interesting that it only happens for KeyError, not on ValueError or anythingVirendra
H
6

There is a way to get the behavior you want: Simply subclass str and override __repr__:

    class KeyErrorMessage(str):
        def __repr__(self): return str(self)
    msg = KeyErrorMessage('Newline\nin\nkey\nerror')
    raise KeyError(msg)

Prints:

Traceback (most recent call last):
...
File "", line 5, in
raise KeyError(msg)
KeyError: Newline
in
key
error

Hekate answered 25/11, 2021 at 15:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.