)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":38496,"name":"Andressa Cabistani","display_name":"Andressa","email":"acabistani@gmail.com","username":"andressadotpy"},"change_message_id":"449c8e74906ea263a2ec8520ae6ddd051038ce10","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"3a46516f_b5b59818","updated":"2026-06-30 13:38:39.000000000","message":"This is looking pretty good already. Please, take a look at my comment about the `self.previous_timeout is not None`, the only reason for my -1 vote, but after solving that discussion this patch is good to merge.","commit_id":"5dde207a03c391b099d4440583c17793b4a9af79"}],"swift/common/utils/__init__.py":[{"author":{"_account_id":38496,"name":"Andressa Cabistani","display_name":"Andressa","email":"acabistani@gmail.com","username":"andressadotpy"},"change_message_id":"449c8e74906ea263a2ec8520ae6ddd051038ce10","unresolved":true,"context_lines":[{"line_number":5457,"context_line":""},{"line_number":5458,"context_line":"    def __init__(self):"},{"line_number":5459,"context_line":"        self._run_gth \u003d None"},{"line_number":5460,"context_line":"        pass"},{"line_number":5461,"context_line":""},{"line_number":5462,"context_line":"    def start(self, timeout, exc, timeout_at\u003dNone):"},{"line_number":5463,"context_line":"        return 0"}],"source_content_type":"text/x-python","patch_set":9,"id":"9e665e3c_e0d33ce3","line":5460,"updated":"2026-06-30 13:38:39.000000000","message":"Preference: the `pass` is redundant, it could be removed","commit_id":"5dde207a03c391b099d4440583c17793b4a9af79"},{"author":{"_account_id":38496,"name":"Andressa Cabistani","display_name":"Andressa","email":"acabistani@gmail.com","username":"andressadotpy"},"change_message_id":"449c8e74906ea263a2ec8520ae6ddd051038ce10","unresolved":true,"context_lines":[{"line_number":5491,"context_line":""},{"line_number":5492,"context_line":"        :param watchdog: Watchdog instance"},{"line_number":5493,"context_line":"        :param timeout: duration before the timeout expires"},{"line_number":5494,"context_line":"        :param exc: exception class to throw when the timeout expires"},{"line_number":5495,"context_line":"        :param timeout_at: allow to force the expiration timestamp"},{"line_number":5496,"context_line":"        :param socket: optional socket to set timeout"},{"line_number":5497,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":9,"id":"07ccd3ab_41b8a54b","line":5494,"updated":"2026-06-30 13:38:39.000000000","message":"Convention: Python convention uses \"raise\" not \"throw\". Suggestion would be to update the Docstring following Python convention.","commit_id":"5dde207a03c391b099d4440583c17793b4a9af79"},{"author":{"_account_id":38496,"name":"Andressa Cabistani","display_name":"Andressa","email":"acabistani@gmail.com","username":"andressadotpy"},"change_message_id":"449c8e74906ea263a2ec8520ae6ddd051038ce10","unresolved":true,"context_lines":[{"line_number":5511,"context_line":""},{"line_number":5512,"context_line":"    def __exit__(self, exc_type, value, traceback):"},{"line_number":5513,"context_line":"        self.watchdog.stop(self.key)"},{"line_number":5514,"context_line":"        if not USE_EVENTLET:"},{"line_number":5515,"context_line":"            if self.socket is not None and self.previous_timeout is not None:"},{"line_number":5516,"context_line":"                self.socket.settimeout(self.previous_timeout)"},{"line_number":5517,"context_line":"            if exc_type is not None and issubclass("}],"source_content_type":"text/x-python","patch_set":9,"id":"789af0ab_290d4f0f","line":5514,"updated":"2026-06-30 13:38:39.000000000","message":"When a socket is in blocking mode (timeout \u003d None), the `WatchdogTimeout` context manager does not restore the socket to blocking mode after the context exits. This leaves the socket with the temporary timeout value permanently set.\n\nIn Python sockets, `socket.gettimeout()` can return `None`, which means \"blocking mode\" (wait forever). This is a valid and common socket state.\n\nWith the current code `self.previous_timeout is not None` means \"only restore the timeout if it was a number\". But when `previous_timeout \u003d None`, that\u0027s a valid value we need to restore, not \"no value\".\n\nWhat happens:\n1. Socket starts in blocking mode → gettimeout() returns None\n2. Context manager saves previous_timeout \u003d None\n3. Context manager sets socket timeout to 5.0 seconds\n4. Context exits, checks if previous_timeout is not None → False, so restoration is skipped\n5. Socket is stuck with 5.0 second timeout instead of returning to blocking mode\n\nRequirement: The fix would be removing the `is not None` check on `previous_timeout`\n\n```python\n  def __exit__(self, exc_type, value, traceback):\n      self.watchdog.stop(self.key)\n      if not USE_EVENTLET:\n          if self.socket is not None:\n              self.socket.settimeout(self.previous_timeout)\n          if exc_type is not None and issubclass(\n                  exc_type, (TimeoutError, socket.timeout)):\n              raise self.exc(self.timeout)\n```\n\nTest to reproduce in your SAIO machine:\n\n```python\n\n  def test_socket_timeout_restoration_from_blocking_mode(self):\n      watchdog \u003d utils.WatchdogNoOp()\n      mock_socket \u003d mock.Mock()\n\n      # Socket starts in blocking mode (gettimeout returns None)\n      mock_socket.gettimeout.return_value \u003d None\n\n      with mock.patch(\u0027swift.common.utils.USE_EVENTLET\u0027, False):\n          with utils.WatchdogTimeout(\n                  watchdog, 5.0, Exception, socket\u003dmock_socket):\n              # Inside context: timeout should be set to 5.0\n              mock_socket.settimeout.assert_called_with(5.0)\n              mock_socket.reset_mock()\n\n          # After context: should restore to None (blocking mode)\n          # BUG: This assertion fails because settimeout(None) is never called\n          mock_socket.settimeout.assert_called_with(None)\n```","commit_id":"5dde207a03c391b099d4440583c17793b4a9af79"}]}
