Skip to content

Commit

Permalink
Give up on immutable Failures.
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonspeed committed Mar 13, 2024
1 parent ccf9ba6 commit 53431dc
Show file tree
Hide file tree
Showing 3 changed files with 5 additions and 66 deletions.
29 changes: 0 additions & 29 deletions src/twisted/python/failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,35 +754,6 @@ def printDetailedTraceback(self, file=None, elideFrameworkCode=0):
"""
self.printTraceback(file, elideFrameworkCode, detail="verbose")

def _freeze(self) -> "_FrozenFailure":
"""
Create a frozen instance, consuming this one.
"""
result = _FrozenFailure.__new__(_FrozenFailure)
result.__dict__ = self.__dict__
# Destroy this failure, just to be sure:
self.__dict__ = {}
return result


class _FrozenFailure(Failure):
"""
A L{Failure} that shouldn't be mutated.
"""

def __setattr__(self, key, value):
if key == "__dict__":
object.__setattr__(self, key, value)
return
raise RuntimeError(
f"Tried to set {key} to {value}, but this object should not be mutated"
)

def __delattr__(self, key):
raise RuntimeError(
f"Tried to delete attribute {key}, but this object should not be mutated"
)


def _safeReprVars(varsDictItems):
"""
Expand Down
25 changes: 0 additions & 25 deletions src/twisted/test/test_failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1040,28 +1040,3 @@ def generator() -> Generator[None, None, None]:
self._throwIntoGenerator(f, g)
except BaseException:
self.assertIsInstance(failure.Failure().value, IndexError)


class FrozenFailureTests(SynchronousTestCase):
"""
Tests for C{_FrozenFailure}.
"""

def test_immutable(self) -> None:
"""
L{failure.Failure._freeze} returns a C{_FrozenFailure} that can't be trivially
mutated.
"""
frozen = getDivisionFailure()._freeze()
self.assertIsInstance(frozen, failure.Failure)
self.assertIsInstance(frozen.value, ZeroDivisionError)

# Can't set:
with self.assertRaises(RuntimeError):
frozen.value = 3
self.assertIsInstance(frozen.value, ZeroDivisionError)

# Can't delete:
with self.assertRaises(RuntimeError):
del frozen.value
self.assertIsInstance(frozen.value, ZeroDivisionError)
17 changes: 5 additions & 12 deletions src/twisted/web/_newclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,9 +1051,6 @@ def dispatcher(self, *args, **kwargs):
# IClientRequest.
_ClientRequestProxy = proxyForInterface(IClientRequest)

# Pre-create this since it gets created for every response.
_RESPONSE_DONE_FAILURE = Failure(ResponseDone("Response body fully received"))._freeze()


@implementer(IResponse)
class Response:
Expand Down Expand Up @@ -1273,15 +1270,15 @@ def _bodyDataFinished_INITIAL(self, reason=None):
"""
self._state = "DEFERRED_CLOSE"
if reason is None:
reason = _RESPONSE_DONE_FAILURE
reason = Failure(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 = _RESPONSE_DONE_FAILURE
reason = Failure(ResponseDone("Response body fully received"))
self._bodyProtocol.connectionLost(reason)
self._bodyProtocol = None
self._state = "FINISHED"
Expand Down Expand Up @@ -1408,11 +1405,6 @@ def loseConnection(self):
self._producer.loseConnection()


# Pre-created error and failure, since they are used for every request:
_DONE = ConnectionDone("synthetic!")
_DONE_FAILURE = Failure(_DONE)._freeze()


class HTTP11ClientProtocol(Protocol):
"""
L{HTTP11ClientProtocol} is an implementation of the HTTP 1.1 client
Expand Down Expand Up @@ -1594,13 +1586,14 @@ def _finishResponse_WAITING(self, rest):
if self._parser is None:
return

reason = ConnectionDone("synthetic!")
connHeaders = self._parser.connHeaders.getRawHeaders(b"connection", ())
if (
(b"close" in connHeaders)
or self._state != "QUIESCENT"
or not self._currentRequest.persistent
):
self._giveUp(_DONE_FAILURE)
self._giveUp(Failure(reason))
else:
# Just in case we had paused the transport, resume it before
# considering it quiescent again.
Expand All @@ -1615,7 +1608,7 @@ def _finishResponse_WAITING(self, rest):
# keeping persistent connections around is an optimisation:
self._log.failure("")
self.transport.loseConnection()
self._disconnectParser(_DONE)
self._disconnectParser(reason)

_finishResponse_TRANSMITTING = _finishResponse_WAITING

Expand Down

0 comments on commit 53431dc

Please sign in to comment.