Wild idea: Exception.format

To make Exceptions where some object(s) are involved more useful, it is often necessary to put the objects on the exception *in addition to* formatting them into a string representation for the message. This little classmethod would make that easier:: class BaseException: @classmethod def format(cls, fmt, *args): return cls(fmt.format(*args), *args) Example usage:: ext = 'foo' raise LookupError.format('Extension {0} not registered', ext) 'foo' could then be accessed as ``exc.args[1]``. A similar, but also very useful implementation would be :: def format(cls, fmt, **kwds): exc = cls(fmt.format(**kwds)) exc.__dict__.update(kwds) return exc with example usage being:: raise LookupError.format('Extension {ext} not registered', ext='foo') and 'foo' being accessible as ``exc.ext``. I realize this is probably too obscure for Python core, but I wanted to show it to you anyway, maybe it'll be found useful. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.

How about simplifying creation of a subclass for this pattern:: class NotRegisteredError(LookupError): template = 'Extension {1} not registered' ... raise NotRegisteredError(ext) This is instead of:: class NotRegisteredError(LookupError): def __init__(self, *args): super().__init__('Extension {1} not registered'.format(self, *args), *args) Advantages to having a separate subclass: (1) it can be reused (2) it can be caught separately from LookupError (3) you can list possible exceptions in the beginning of module (4) you can search for functions that raise a specific exception What do you think? Ilya. On Fri, Sep 18, 2009 at 6:07 PM, Georg Brandl <g.brandl@gmx.net> 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) On Fri, Sep 18, 2009 at 10:54 PM, ilya <ilya.nikokoshev@gmail.com> wrote:

Yuvgoog Greenle wrote:
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
Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

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)
(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@gmail.com> wrote:

How about simplifying creation of a subclass for this pattern:: class NotRegisteredError(LookupError): template = 'Extension {1} not registered' ... raise NotRegisteredError(ext) This is instead of:: class NotRegisteredError(LookupError): def __init__(self, *args): super().__init__('Extension {1} not registered'.format(self, *args), *args) Advantages to having a separate subclass: (1) it can be reused (2) it can be caught separately from LookupError (3) you can list possible exceptions in the beginning of module (4) you can search for functions that raise a specific exception What do you think? Ilya. On Fri, Sep 18, 2009 at 6:07 PM, Georg Brandl <g.brandl@gmx.net> 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) On Fri, Sep 18, 2009 at 10:54 PM, ilya <ilya.nikokoshev@gmail.com> wrote:

Yuvgoog Greenle wrote:
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
Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

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)
(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@gmail.com> wrote:
participants (4)
-
Georg Brandl
-
ilya
-
Nick Coghlan
-
Yuvgoog Greenle