Skip to content

Commit

Permalink
A simpler, faster alternative constructor.
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonspeed committed Mar 13, 2024
1 parent cb535ae commit a9f8dca
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
21 changes: 21 additions & 0 deletions src/twisted/python/failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
See L{Failure}.
"""

from __future__ import annotations

# System Imports
import builtins
Expand Down Expand Up @@ -457,6 +458,26 @@ def _extrapolate(self, otherFailure):
frames.extend(self.frames)
self.frames = frames

@staticmethod
def without_traceback(value: Exception) -> Failure:
"""
Create a L{Failure} for an exception without a traceback.
By restricting the inputs significantly, this constructor runs much
faster.
"""
result = Failure.__new__(Failure)
global count
count += 1
result.captureVars = False
result.count = count
result.frames = []
result.stack = []
result.value = value
result.type = value.__class__
result.tb = None
return result

def trap(self, *errorTypes):
"""
Trap this failure if its type is in a predetermined list.
Expand Down
17 changes: 17 additions & 0 deletions src/twisted/test/test_failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,3 +1032,20 @@ def generator() -> Generator[None, None, None]:
self._throwIntoGenerator(f, g)
except BaseException:
self.assertIsInstance(failure.Failure().value, IndexError)

def test_failure_without_traceback(self):
"""
C{Failure.without_traceback(exc)} gives the same result as
C{Failure(exc)}.
"""
exc = ZeroDivisionError("hello")
dict1 = failure.Failure(exc).__dict__.copy()
failure2 = failure.Failure.without_traceback(exc)
self.assertIsInstance(failure2, failure.Failure)
dict2 = failure2.__dict__.copy()

# count increments with each new Failure constructed:
self.assertEqual(dict1.pop("count") + 1, dict2.pop("count"))

# The rest of the attributes should be identical:
self.assertEqual(dict1, dict2)
6 changes: 3 additions & 3 deletions src/twisted/web/_newclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,15 +1270,15 @@ def _bodyDataFinished_INITIAL(self, reason=None):
"""
self._state = "DEFERRED_CLOSE"
if reason is None:
reason = Failure(ResponseDone("Response body fully received"))
reason = Failure.without_traceback(ResponseDone("Response body fully received"))
self._reason = reason

def _bodyDataFinished_CONNECTED(self, reason=None):
"""
Disconnect the protocol and move to the C{'FINISHED'} state.
"""
if reason is None:
reason = Failure(ResponseDone("Response body fully received"))
reason = Failure.without_traceback(ResponseDone("Response body fully received"))
self._bodyProtocol.connectionLost(reason)
self._bodyProtocol = None
self._state = "FINISHED"
Expand Down Expand Up @@ -1593,7 +1593,7 @@ def _finishResponse_WAITING(self, rest):
or self._state != "QUIESCENT"
or not self._currentRequest.persistent
):
self._giveUp(Failure(reason))
self._giveUp(Failure.without_traceback(reason))
else:
# Just in case we had paused the transport, resume it before
# considering it quiescent again.
Expand Down

0 comments on commit a9f8dca

Please sign in to comment.