[Python-ideas] Arguments to exceptions
Steven D'Aprano
steve at pearwood.info
Tue Jul 4 11:33:12 EDT 2017
On Sun, Jul 02, 2017 at 12:19:54PM -0700, Ken Kundert wrote:
> class BaseException:
> def __init__(self, *args, **kwargs):
> self.args = args
> self.kwargs = kwargs
>
> def __str__(self):
> template = self.kwargs.get('template')
> if template is None:
> sep = self.kwargs.get('sep', ' ')
> return sep.join(str(a) for a in self.args)
> else:
> return template.format(*self.args, **self.kwargs)
I think this API is too general. It accepts arbitrary keyword arguments
and stores them in the exception. I think that makes for a poor
experience for the caller:
try:
something()
except MyParsingError as err:
if 'column' in err.kwargs:
...
elif 'col' in err.kwargs:
...
elif 'x' in err.kwargs: # 'x' is the column, or is it the row?
...
The problem here is, unless the exception class offers a real API
for extracting the column, how do you know what key to use? You can't expect
BaseException to force the user of MyParsingError to be consistent:
raise MyParsingError(17, 45, template='Error at line {} column {}')
raise MyParsingError(45, 17, template='Error at column {} line {}')
raise MyParsingError(45, 17, temlpate='Error at col {} row {}') # oops
raise MyParsingError(17, template='Error at line {}')
raise MyParsingError(99, 45, 17, template='Error code {} at column {} line {}')
Unless MyParsingError offers a consistent (preferably using named
attributes) API for extracting the data, pulling it out of args is just
as much of a hack as scraping it from the error message.
It seems to me that we can't solve this problem at BaseException. It has
to be tackled by each exception class. Only the author of each exception
class knows what information it carries and should be provided via named
attributes.
I think OSError has a good approach.
https://docs.python.org/3/library/exceptions.html#OSError
For backwards compatibility, when you raise OSError with a single
argument, it looks like this:
raise OSError('spam is my problem')
=> OSError: spam is my problem
When you offer two or up to five arguments, they get formatted into a
nicer error message, and stored into named attributes:
raise OSError(99, 'spam is my problem', 'xxx', 123, 'yyy')
=> OSError: [Errno 99] foo is my problem: 'xxx' -> 'yyy'
Missing arguments default to None.
I don't think there is a generic recipe that will work for all
exceptions, or even all exceptions in the standard exception heirarchy,
that can make that pleasant. Perhaps I'm insufficiently imaginative, but
I don't think this problem can be solved with a quick hack of the
BaseException class.
--
Steve
More information about the Python-ideas
mailing list