[tor-commits] [stem/master] Expanding contorller exception types

atagar at torproject.org atagar at torproject.org
Sun Nov 13 19:05:14 UTC 2011


commit efe28987ffd27e69a2c6c566bdad2efc5f16e93e
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Nov 12 15:55:09 2011 -0800

    Expanding contorller exception types
    
    Exception types pretty much mirror what TorCtl has (protocol error, socket
    error, and controller closed) with a base type users can catch instead. One
    difference though is that if stem functions raise a socket.error (without
    documenting that they do) then that's a bug - those errors should cuase a
    stem.types.SocketError instead.
---
 stem/types.py                      |   34 +++++++++++++++++++++-------------
 test/integ/message.py              |   14 +++++++-------
 test/integ/system.py               |    3 ++-
 test/unit/types/control_message.py |    2 +-
 4 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/stem/types.py b/stem/types.py
index e03698c..78e2fd9 100644
--- a/stem/types.py
+++ b/stem/types.py
@@ -2,8 +2,10 @@
 Class representations for a variety of tor objects. These are most commonly
 return values rather than being instantiated by users directly.
 
-ProtocolError - Malformed socket data.
-ControlSocketClosed - Socket terminated.
+ControllerError - Base exception raised when using the controller.
+  |- ProtocolError - Malformed socket data.
+  |- SocketError - Socket used for controller communication errored.
+  +- SocketClosed - Socket terminated.
 
 read_message - Reads a ControlMessage from a control socket.
 ControlMessage - Message from the control socket.
@@ -45,11 +47,18 @@ KEY_ARG = re.compile("^(\S+)=")
 CONTROL_ESCAPES = {r"\\": "\\",  r"\"": "\"",   r"\'": "'",
                    r"\r": "\r",  r"\n": "\n",   r"\t": "\t"}
 
-class ProtocolError(Exception):
+class ControllerError(Exception):
+  "Base error for controller communication issues."
+
+class ProtocolError(ControllerError):
   "Malformed content from the control socket."
   pass
 
-class ControlSocketClosed(Exception):
+class SocketError(ControllerError):
+  "Error arose while communicating with the control socket."
+  pass
+
+class SocketClosed(ControllerError):
   "Control socket was closed before completing the message."
   pass
 
@@ -67,8 +76,7 @@ def read_message(control_file):
   
   Raises:
     ProtocolError the content from the socket is malformed
-    ControlSocketClosed if the socket closes before we receive a complete
-      message
+    SocketClosed if the socket closes before we receive a complete message
   """
   
   parsed_content, raw_content = [], ""
@@ -79,11 +87,11 @@ def read_message(control_file):
       # if the control_file has been closed then we will receive:
       # AttributeError: 'NoneType' object has no attribute 'recv'
       
-      LOGGER.warn("ControlSocketClosed: socket file has been closed")
-      raise ControlSocketClosed("socket file has been closed")
+      LOGGER.warn("SocketClosed: socket file has been closed")
+      raise SocketClosed("socket file has been closed")
     except socket.error, exc:
-      LOGGER.warn("ControlSocketClosed: received an exception (%s)" % exc)
-      raise ControlSocketClosed(exc)
+      LOGGER.warn("SocketClosed: received an exception (%s)" % exc)
+      raise SocketClosed(exc)
     
     raw_content += line
     
@@ -94,8 +102,8 @@ def read_message(control_file):
       # if the socket is disconnected then the readline() method will provide
       # empty content
       
-      LOGGER.warn("ControlSocketClosed: empty socket content")
-      raise ControlSocketClosed("Received empty socket content.")
+      LOGGER.warn("SocketClosed: empty socket content")
+      raise SocketClosed("Received empty socket content.")
     elif len(line) < 4:
       LOGGER.warn("ProtocolError: line too short (%s)" % line)
       raise ProtocolError("Badly formatted reply line: too short")
@@ -125,7 +133,7 @@ def read_message(control_file):
       
       while True:
         try: line = control_file.readline()
-        except socket.error, exc: raise ControlSocketClosed(exc)
+        except socket.error, exc: raise SocketClosed(exc)
         
         raw_content += line
         
diff --git a/test/integ/message.py b/test/integ/message.py
index 531d4a2..a562f86 100644
--- a/test/integ/message.py
+++ b/test/integ/message.py
@@ -40,16 +40,16 @@ class TestMessageFunctions(unittest.TestCase):
     control_socket_file.write("GETINFO version\r\n")
     control_socket_file.flush()
     
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
     
     # Additional socket usage should fail, and pulling more responses will fail
     # with more closed exceptions.
     
     control_socket_file.write("GETINFO version\r\n")
     self.assertRaises(socket.error, control_socket_file.flush)
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
     
     # The socket connection is already broken so calling close shouldn't have
     # an impact.
@@ -57,7 +57,7 @@ class TestMessageFunctions(unittest.TestCase):
     control_socket.close()
     control_socket_file.write("GETINFO version\r\n")
     self.assertRaises(socket.error, control_socket_file.flush)
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
     
     # Closing the file handler, however, will cause a different type of error.
     # This seems to depend on the python version, in 2.6 we get an
@@ -72,8 +72,8 @@ class TestMessageFunctions(unittest.TestCase):
     # receives: AttributeError: 'NoneType' object has no attribute 'sendall'
     self.assertRaises(AttributeError, control_socket_file.flush)
     
-    # receives: stem.types.ControlSocketClosed: socket file has been closed
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
+    # receives: stem.types.SocketClosed: socket file has been closed
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
   
   def test_invalid_command(self):
     """
diff --git a/test/integ/system.py b/test/integ/system.py
index 4aa5d15..09ffd24 100644
--- a/test/integ/system.py
+++ b/test/integ/system.py
@@ -49,7 +49,8 @@ class TestSystemFunctions(unittest.TestCase):
     # tor's pwd will match our process since we started it
     runner = test.runner.get_runner()
     self.assertEquals(os.getcwd(), system.get_cwd(runner.get_pid()))
-    self.assertRaises(IOError, system.get_cwd, 99999)
+    self.assertEquals(None, system.get_cwd(99999, True))
+    self.assertRaises(IOError, system.get_cwd, 99999, False)
   
   def test_get_bsd_jail_id(self):
     """
diff --git a/test/unit/types/control_message.py b/test/unit/types/control_message.py
index 563a0bf..5e9b7bc 100644
--- a/test/unit/types/control_message.py
+++ b/test/unit/types/control_message.py
@@ -156,7 +156,7 @@ class TestControlMessage(unittest.TestCase):
     
     control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     control_socket_file = control_socket.makefile()
-    self.assertRaises(stem.types.ControlSocketClosed, stem.types.read_message, control_socket_file)
+    self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file)
   
   def assert_message_parses(self, controller_reply):
     """





More information about the tor-commits mailing list