-
-
Notifications
You must be signed in to change notification settings - Fork 383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a convenience flag for upcalling on Exception subclasses #368
Comments
Is The And |
I included it because of the usual attrs isomorphism: class E1(Exception):
def __init__(self, x, y):
super(E1, self).__init__(x, y)
self.x = x
self.y = y It might not abide strictly by the documentation of |
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 The only reason to care about it as far as I'm aware is that it effects >>> str(C(1,2))
'C(x=1, y=2)'
>>> str(C(x=1,y=2))
'C(x=1, y=2)'
>>> str(E1(1,2))
'(1, 2)'
>>> str(E1(x=1,y=2))
'' Here |
After running into #217 I came up with an import inspect
import attr
def attrs_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`
"""
def wrap(cls):
def _attrs_post_init__(obj):
Exception.__init__(obj, *attr.astuple(obj))
existing_post_init = getattr(cls, '__attrs_post_init__', None)
if (
existing_post_init
and (
inspect.getsource(existing_post_init)
!= inspect.getsource(_attrs_post_init__)
)
):
raise TypeError(
"'%s' already has an '__attrs_post_init__' method" % (cls,),
)
if not issubclass(cls, Exception):
raise TypeError(
"'%s' is not a subclass of Exception! Use 'attr.s' instead" % (cls,),
)
cls.__attrs_post_init__ = _attrs_post_init__
kwargs['str'] = True
kwargs['slots'] = True
return attr.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()
if maybe_cls is None:
return wrap
else:
return wrap(maybe_cls) If anyone is interested, I can probably put that (and its accompanying tests) on PyPI. |
So, what we want here is basically:
I’d be sympathetic to add something like |
See python-attrs/attrs#368 Maybe attrs should do this automatically when subclassing BaseException?
Just hit this myself, blindly assuming Exceptions would work - |
I took a stab at this in #500. Please provide feedback so we can close this gaping hole. |
* Implement first class exception support Fixes #368 * Ensure single-attrib classes work too cf #500 (review) * Call into BaseException to initialiaze self.args * Leave __str__ alone since we upcall Based on Python pizza hallway feedback by @ambv. * remove stray stage * nope
Currently, these tests both fail on 2.7 and only the latter fails on 3.6.
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 considerargs
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.
The text was updated successfully, but these errors were encountered: