THRIFT-5715 Python Exceptions mutable with slots
In Python 3.11 exceptions generated by the compiler can't be used with a
context manager because they are immutable. As of Python 3.11
`contextlib.contextmanager` sets `exc.__traceback__` in the event that
the code in the context manager errors.
As of Thrift v0.18.1 exceptions are generated as immutable by default.
See [PR#1835](https://github.com/apache/thrift/pull/1835) for more
information about why exceptions were made immutable by default.
This change makes all non-Thrift fields mutable when slots is used
without dynamic. This will allow exceptions to be re-raised properly by
the contextmanager in Python 3.11.
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
index 8a30c3a..61a9c60 100755
--- a/test/py/TestClient.py
+++ b/test/py/TestClient.py
@@ -256,6 +256,35 @@
y = self.client.testMultiException('success', 'foobar')
self.assertEqual(y.string_thing, 'foobar')
+ def testException__traceback__(self):
+ print('testException__traceback__')
+ self.client.testException('Safe')
+ expect_slots = uses_slots = False
+ expect_dynamic = uses_dynamic = False
+ try:
+ self.client.testException('Xception')
+ self.fail("should have gotten exception")
+ except Xception as x:
+ uses_slots = hasattr(x, '__slots__')
+ uses_dynamic = (not isinstance(x, TException))
+ # We set expected values here so that we get clean tracebackes when
+ # the assertions fail.
+ try:
+ x.__traceback__ = x.__traceback__
+ # If `__traceback__` was set without errors than we expect that
+ # the slots option was used and that dynamic classes were not.
+ expect_slots = True
+ expect_dynamic = False
+ except Exception as e:
+ self.assertTrue(isinstance(e, TypeError))
+ # There are no other meaningful tests we can preform because we
+ # are unable to determine the desired state of either `__slots__`
+ # or `dynamic`.
+ return
+
+ self.assertEqual(expect_slots, uses_slots)
+ self.assertEqual(expect_dynamic, uses_dynamic)
+
def testOneway(self):
print('testOneway')
start = time.time()