You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add a convenience flag for upcalling on Exception subclasses #368
If attrs is overriding __init__ then this makes sense; args is filled in by __init__ in 2.x and __new__ in 3.x, but only pulling from the *args and never **kwargs. I discussed this a bit with @markrwilliams but I'm not sure what the best way to handle an attrs-ified exception would be. Maybe it's okay to consider args vestigal.
Mostly I'm raising this on the issue tracker because there are some references to using attrs for exceptions, but only indirectly. It'd be nice to have some documentation on a suggested approach either way.
Is test_exception_init_called_even_with_kw a valid test?
The args attribute on Exception is documented as "The tuple of arguments given to the exception constructor."
And Exception itself doesn't accept kwargs. So I think the behavior in the case of kwargs to init with respect to what goes into the args attribute is… undefined. So I'd have no expectation of that test passing on exception classes generically.
It might not abide strictly by the documentation of Exception that you'd end up with e.args == (e.x, e.y) but I wasn't sure if a case could be made since this is how one would write the class without attrs.
I guess what I'm saying is that it's not clear to me that when one calls the super init, that including the kwargs is a common practice.
That said, I find the args attribute's design to be severely lacking in clarity, basically a "tuple of whatever rando stuff the caller threw in here", so I'm rather sympathetic to the argument that it is vestigal.
The only reason to care about it as far as I'm aware is that it effects str(), and that's true even when using attrs, which leaves something to be desired:
After running into #217 I came up with an @attrs_exception decorator that passes both of your tests on Python 2.7 (and probably 3.6):
importinspectimportattrdefattrs_exception(maybe_cls=None, *args, **kwargs):
r""" A class decorator to eliminate boilerplate when creating Exceptions using :func:`attr.s`. Adds ``__str__`` (because Exceptions don't use ``__repr__``) and an ``__attrs_post_init__`` that calls ``Exception.__init__`` with the class's :func:`attr.ib`\ s. Without this, instances cannot be deepcopied on Python 2. ref: https://github.com/python-attrs/attrs/issues/217 :param args: additional positional arguments to be passed to :func:`attr.s` :param kwargs: additional keyword arguments to be passed to :func:`attr.s` """defwrap(cls):
def_attrs_post_init__(obj):
Exception.__init__(obj, *attr.astuple(obj))
existing_post_init=getattr(cls, '__attrs_post_init__', None)
if (
existing_post_initand (
inspect.getsource(existing_post_init)
!=inspect.getsource(_attrs_post_init__)
)
):
raiseTypeError(
"'%s' already has an '__attrs_post_init__' method"% (cls,),
)
ifnotissubclass(cls, Exception):
raiseTypeError(
"'%s' is not a subclass of Exception! Use 'attr.s' instead"% (cls,),
)
cls.__attrs_post_init__=_attrs_post_init__kwargs['str'] =Truekwargs['slots'] =Truereturnattr.attributes(cls, *args, **kwargs)
# maybe_cls depends on the usage of the decorator. It's a class if it's# used as @attrs_exception but None if it's used as @attrs_exception()ifmaybe_clsisNone:
returnwrapelse:
returnwrap(maybe_cls)
If anyone is interested, I can probably put that (and its accompanying tests) on PyPI.
Activity
wsanchez commentedon Apr 11, 2018
Is
test_exception_init_called_even_with_kwa valid test?The
argsattribute onExceptionis documented as "The tuple of arguments given to the exception constructor."And
Exceptionitself doesn't acceptkwargs. So I think the behavior in the case ofkwargsto init with respect to what goes into theargsattribute is… undefined. So I'd have no expectation of that test passing on exception classes generically.habnabit commentedon Apr 11, 2018
I included it because of the usual attrs isomorphism:
It might not abide strictly by the documentation of
Exceptionthat you'd end up withe.args == (e.x, e.y)but I wasn't sure if a case could be made since this is how one would write the class without attrs.wsanchez commentedon Apr 11, 2018
I guess what I'm saying is that it's not clear to me that when one calls the super init, that including the kwargs is a common practice.
That said, I find the
argsattribute's design to be severely lacking in clarity, basically a "tuple of whatever rando stuff the caller threw in here", so I'm rather sympathetic to the argument that it is vestigal.The only reason to care about it as far as I'm aware is that it effects
str(), and that's true even when usingattrs, which leaves something to be desired:Here
E1is defined as in your example, andCis the same asE1, but without inheriting fromException.rouge8 commentedon May 2, 2018
After running into #217 I came up with an
@attrs_exceptiondecorator that passes both of your tests on Python 2.7 (and probably 3.6):If anyone is interested, I can probably put that (and its accompanying tests) on PyPI.
hynek commentedon Jun 16, 2018
So, what we want here is basically:
@attr.s(str=True)self.args?cmp=False?I’d be sympathetic to add something like
@attr.excsince I use it quite often myself.Hynek is right, this is more correct
glyph commentedon Oct 15, 2018
Just hit this myself, blindly assuming Exceptions would work -
@attr.exc(@attr.err?) would be very handy.Implement first class exception support
Implement first class exception support
Implement first class exception support
Implement first class exception support
hynek commentedon Feb 10, 2019
I took a stab at this in #500.
Please provide feedback so we can close this gaping hole.
Implement first class exception support
Implement first class exception support
Implement first class exception support (#500)