blalterman
blalterman

Reputation: 575

Python KeyError and ValueError inconsistency?

I've found an inconsistency between ValueError and KeyError. The former will treat \n as a newline; the latter treats it as raw text. Is this behavior normal/expected?

TeX_dict is a dictionary to convert parts of dictionary keys to TeX formatted strings that are used when generating plots. part is one such part. Here are two examples of part:

When I raise a ValueError, the \n newline characters generate a new line. When I raise a KeyError, they do not.

geo_split = lambda thing: '\&'.join([
                                      TeX_dict[x]
                                      for x in thing.split('&')
                                    ])

try:

    TeX = geo_split(part)

except KeyError:

    msg = ("You have programmed limited functionality for "
           "geometric mean keys. They can only handle species "
           "that are hard coded into "
           "``pccv.TeX_labels.axis_labels``.\n\n" #
           "The following part failed: {}\n"
          ).format(part)

    raise ValueError(msg) # If this is KeyError, the new lines don't print.

Here is a sample output from each:

ValueError: You have programmed limited functionality for geometric mean keys. 
They can only handle species that are hard coded into 
``pccv.TeX_labels.axis_labels``.

KeyError: 'You have programmed limited functionality for geometric mean keys. 
They can only handle species that are hard coded into 
``pccv.TeX_labels.axis_labels``.\n\nThe following part failed: a,p1&p2\n' 

Upvotes: 3

Views: 2540

Answers (1)

engineerC
engineerC

Reputation: 2868

This is a peculiarity of the KeyError implementation.

/* 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__().

You could work around it by passing something that overrides __repr__:

class Wrapper(str):
    def __repr__(self):
        return str(self)

raise KeyError(Wrapper('hello\nthere'))

Upvotes: 4

Related Questions