From 1921da6eac6231b7bc058b076c0648b2d1b5c042 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sat, 26 Oct 2024 12:20:44 +0100 Subject: [PATCH] allow __suppress_context__ and __notes__ to be mutated on frozen exceptions (#1365) * allow __suppress_context__ to be mutated on frozen exceptions * add changelog * and __notes__! lets' not forget that. * add notes to news * add tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix improt * fix test * fix tests again --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- changelog.d/1365.change.md | 1 + src/attr/_make.py | 6 ++++++ tests/test_next_gen.py | 14 +++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 changelog.d/1365.change.md diff --git a/changelog.d/1365.change.md b/changelog.d/1365.change.md new file mode 100644 index 00000000..24fa6cf8 --- /dev/null +++ b/changelog.d/1365.change.md @@ -0,0 +1 @@ +Allow mutating `__suppress_context__` and `__notes__` on frozen exceptions. diff --git a/src/attr/_make.py b/src/attr/_make.py index 274d4121..f137772a 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -543,6 +543,8 @@ def _frozen_setattrs(self, name, value): "__cause__", "__context__", "__traceback__", + "__suppress_context__", + "__notes__", ): BaseException.__setattr__(self, name, value) return @@ -554,6 +556,10 @@ def _frozen_delattrs(self, name): """ Attached to frozen classes as __delattr__. """ + if isinstance(self, BaseException) and name in ("__notes__",): + BaseException.__delattr__(self, name) + return + raise FrozenInstanceError diff --git a/tests/test_next_gen.py b/tests/test_next_gen.py index a171749a..41e534df 100644 --- a/tests/test_next_gen.py +++ b/tests/test_next_gen.py @@ -14,6 +14,8 @@ import pytest import attr as _attr # don't use it by accident import attrs +from attr._compat import PY_3_11_PLUS + @attrs.define class C: @@ -332,7 +334,7 @@ class TestNextGen: attrs.mutable, ], ) - def test_setting_traceback_on_exception(self, decorator): + def test_setting_exception_mutable_attributes(self, decorator): """ contextlib.contextlib (re-)sets __traceback__ on raised exceptions. @@ -354,6 +356,16 @@ class TestNextGen: # this should not raise an exception either ei.value.__traceback__ = ei.value.__traceback__ + ei.value.__cause__ = ValueError("cause") + ei.value.__context__ = TypeError("context") + ei.value.__suppress_context__ = True + ei.value.__suppress_context__ = False + ei.value.__notes__ = [] + del ei.value.__notes__ + + if PY_3_11_PLUS: + ei.value.add_note("note") + del ei.value.__notes__ def test_converts_and_validates_by_default(self): """