[Python-ideas] Wild idea: Exception.format
ilya
ilya.nikokoshev at gmail.com
Sat Sep 19 09:29:30 CEST 2009
I think there's a way to define an exception subclass with message as
a one-liner::
# Simple syntax to define exception classes.
_ = BaseFormattedException
class RegisterError(_, LookupError): 'Extension "{0}" not registered.'
class ExtensionError(_, ValueError): 'Extension "{0}" returns wrong data.'
# Another way to define exception classes --- factory function.
MissingError = _.formatted(IndexError, 'No extension named "{0}"')
SomeOtherError = _.formatted(Exception)
>>> raise RegisterError('test')
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
raise RegisterError('test')
exceptions.RegisterError: Extension "test" not registered.
>>> raise MissingError('test')
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
raise MissingError('test')
exceptions.IndexError: No extension named "test"
(Note the difference between two methods above: RegisterError has its
separate __name__ while still being a subclass of IndexError, while
MissingError doesn't have its own __name__)
The trick is in defining the `BaseFormattedException` which harvests
(the first line of a) docstring to provide template (I figured out for
a small, locally-used exception class there may be no difference
between what it prints and its docstring).
The whole example is at http://web.mit.edu/~unknot/www/exceptions.py
How does that sound?
On Sat, Sep 19, 2009 at 5:43 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Yuvgoog Greenle wrote:
>> I fail to see why you can't have both args and kwargs...
>>
>> class BaseException:
>> @classmethod
>> def format(cls, fmt, *args, **kwargs):
>> return cls(fmt.format(*args, **kwargs), *args, **kwargs)
>>
>> And concerning Gerog's actual question, I think this is a not uncommon
>> pattern, but
>> raise Exception.format(...)
>> doesn't sound good. It's not really as readable as
>> raise Exception(fmt.format(ext), ext)
>>
>> ilya suggested an almost ok direction but he doesn't define formats at
>> runtime. So maybe instead we can make a factory for formatted exceptions.
>>
>> def formatted_exception(exception):
>> def format_and_return(fmt, *args, **kwargs):
>> return exception(fmt.format(*args, **kwargs), *args, **kwargs)
>> return format_and_return
>>
>> @formatted_exception
>> class NotRegisteredError(LookupError): pass
>>
>> then the usage becomes:
>> raise NotRegisteredError("Extension {0} not registered.", ext)
>
> I like the class decorator idea (to avoid namespace conflicts on the
> exception objects - cf. the dramas with ex.message). However, the above
> would break exception handling since NotRegisteredError would refer to
> the factory function instead of the exception that is actually thrown.
>
> Combining it with Ilya's idea (by having the class decorator return a
> new subclass rather than a factory function) gives something that should
> work in practice:
>
> def formatted_exception(exc):
> class FormattedExc(exc):
> def __init__(*args, **kwds):
> self, fmt, args = args[0], args[1], args[2:]
> super(FormattedExc, self).__init__(
> fmt.format(*args, **kwds), *args, **kwds)
> def __str__(self):
> return self.args[0]
> __name__ = exc.__name__
> __doc__ = exc.__doc__
> __module__ = exc.__module__
> return FormattedExc
>
> @formatted_exception
> class ExampleError(Exception): pass
>
>>>> try:
> ... raise ExampleError("Format: {}", "Value")
> ... except ExampleError as ex:
> ... saved = ex
> ...
>>>> saved
> FormattedExc('Format: Value', 'Value')
>>>> print(saved)
> Format: Value
>>>> saved.args[1]
> 'Value'
>>>> saved.__name__
> 'ExampleError'
>
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
> ---------------------------------------------------------------
>
More information about the Python-ideas
mailing list