[tor-commits] [stem/master] Provide classes from by_name and by_value

atagar at torproject.org atagar at torproject.org
Sun Jan 21 02:04:04 UTC 2018


commit 53fd66a3fb21f5dcf946da3264ac0b206f2c0bbc
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Jan 9 12:09:41 2018 -0800

    Provide classes from by_name and by_value
    
    Now that attributes are included as class constants we can swap these functions
    to provide them. This drops our pack unit test since you can no longer call it
    on the base Pack class. We'll add a test for the VersionCell pack method
    instead.
---
 stem/client/cell.py      | 80 +++++++++++++++++++++++-------------------------
 test/unit/client/cell.py | 34 ++++++--------------
 2 files changed, 48 insertions(+), 66 deletions(-)

diff --git a/stem/client/cell.py b/stem/client/cell.py
index f1917805..9a6e6788 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -40,12 +40,9 @@ class Cell(collections.namedtuple('Cell', ['name', 'value', 'fixed_size', 'for_c
     :raise: **ValueError** if cell type is invalid
     """
 
-    if name == 'NETINFO':
-      return NetinfoCell
-
-    for cell_type in CELL_TYPES:
-      if name == cell_type.name:
-        return cell_type
+    for cls in CELL_TYPES:
+      if name == cls.NAME:
+        return cls
 
     raise ValueError("'%s' isn't a valid cell type" % name)
 
@@ -59,14 +56,14 @@ class Cell(collections.namedtuple('Cell', ['name', 'value', 'fixed_size', 'for_c
     :raise: **ValueError** if cell type is invalid
     """
 
-    for cell_type in CELL_TYPES:
-      if value == cell_type.value:
-        return cell_type
+    for cls in CELL_TYPES:
+      if value == cls.VALUE:
+        return cls
 
     raise ValueError("'%s' isn't a valid cell value" % value)
 
-  @staticmethod
-  def pack(name, link_version, payload, circ_id = None):
+  @classmethod
+  def _pack(cls, link_version, payload, circ_id = None):
     """
     Provides bytes that can be used on the wire for these cell attributes.
 
@@ -80,35 +77,34 @@ class Cell(collections.namedtuple('Cell', ['name', 'value', 'fixed_size', 'for_c
       * payload is too large
     """
 
-    attr = Cell.by_name(name)
     circ_id_len = Pack.LONG if link_version > 3 else Pack.SHORT
 
-    if attr.for_circuit and circ_id is None:
-      if name.startswith('CREATE'):
+    if cls.IS_FOR_CIRCUIT and circ_id is None:
+      if cls.NAME.startswith('CREATE'):
         # Since we're initiating the circuit we pick any value from a range
         # that's determined by our link version.
 
         circ_id = 0x80000000 if link_version > 3 else 0x01
       else:
-        raise ValueError('%s cells require a circ_id' % name)
-    elif not attr.for_circuit:
+        raise ValueError('%s cells require a circ_id' % cls.NAME)
+    elif not cls.IS_FOR_CIRCUIT:
       if circ_id:
-        raise ValueError("%s cells don't concern circuits, circ_id is unused" % name)
+        raise ValueError("%s cells don't concern circuits, circ_id is unused" % cls.NAME)
 
       circ_id = 0  # field is still mandatory for all cells
 
     packed_circ_id = struct.pack(circ_id_len, circ_id)
-    packed_command = struct.pack(Pack.CHAR, attr.value)
-    packed_size = b'' if attr.fixed_size else struct.pack(Pack.SHORT, len(payload))
+    packed_command = struct.pack(Pack.CHAR, cls.VALUE)
+    packed_size = b'' if cls.IS_FIXED_SIZE else struct.pack(Pack.SHORT, len(payload))
     cell = b''.join((packed_circ_id, packed_command, packed_size, payload))
 
     # pad fixed sized cells to the required length
 
-    if attr.fixed_size:
+    if cls.IS_FIXED_SIZE:
       fixed_cell_len = 514 if link_version > 3 else 512
 
       if len(cell) > fixed_cell_len:
-        raise ValueError('Payload of %s is too large (%i bytes), must be less than %i' % (name, len(cell), fixed_cell_len))
+        raise ValueError('Payload of %s is too large (%i bytes), must be less than %i' % (cls.NAME, len(cell), fixed_cell_len))
 
       cell += ZERO * (fixed_cell_len - len(cell))
 
@@ -174,8 +170,8 @@ class VersionsCell(Cell):
   IS_FIXED_SIZE = False
   IS_FOR_CIRCUIT = False
 
-  @staticmethod
-  def pack(versions):
+  @classmethod
+  def pack(cls, versions):
     """
     Provides the payload for a series of link versions.
 
@@ -188,7 +184,7 @@ class VersionsCell(Cell):
     # since VERSION cells avoid most version dependent attributes.
 
     payload = b''.join([struct.pack(Pack.SHORT, v) for v in versions])
-    return Cell.pack('VERSIONS', 3, payload)
+    return cls._pack('VERSIONS', 3, payload)
 
 
 class NetinfoCell(Cell):
@@ -262,22 +258,22 @@ class AuthorizeCell(Cell):
 
 
 CELL_TYPES = (
-  Cell('PADDING', 0, True, False),              # Padding                  (section 7.2)
-  Cell('CREATE', 1, True, True),                # Create a circuit         (section 5.1)
-  Cell('CREATED', 2, True, True),               # Acknowledge create       (section 5.1)
-  Cell('RELAY', 3, True, True),                 # End-to-end data          (section 5.5 and 6)
-  Cell('DESTROY', 4, True, True),               # Stop using a circuit     (section 5.4)
-  Cell('CREATE_FAST', 5, True, True),           # Create a circuit, no PK  (section 5.1)
-  Cell('CREATED_FAST', 6, True, True),          # Circuit created, no PK   (section 5.1)
-  Cell('VERSIONS', 7, False, False),            # Negotiate proto version  (section 4)
-  Cell('NETINFO', 8, True, False),              # Time and address info    (section 4.5)
-  Cell('RELAY_EARLY', 9, True, True),           # End-to-end data; limited (section 5.6)
-  Cell('CREATE2', 10, True, True),              # Extended CREATE cell     (section 5.1)
-  Cell('CREATED2', 11, True, True),             # Extended CREATED cell    (section 5.1)
-  Cell('PADDING_NEGOTIATE', 12, True, False),   # Padding negotiation      (section 7.2)
-  Cell('VPADDING', 128, False, False),          # Variable-length padding  (section 7.2)
-  Cell('CERTS', 129, False, False),             # Certificates             (section 4.2)
-  Cell('AUTH_CHALLENGE', 130, False, False),    # Challenge value          (section 4.3)
-  Cell('AUTHENTICATE', 131, False, False),      # Client authentication    (section 4.5)
-  Cell('AUTHORIZE', 132, False, False),         # Client authorization     (not yet used)
+  PaddingCell,            # Padding                  (section 7.2)
+  CreateCell,             # Create a circuit         (section 5.1)
+  CreatedCell,            # Acknowledge create       (section 5.1)
+  RelayCell,              # End-to-end data          (section 5.5 and 6)
+  DestroyCell,            # Stop using a circuit     (section 5.4)
+  CreateFastCell,         # Create a circuit, no PK  (section 5.1)
+  CreatedFastCell,        # Circuit created, no PK   (section 5.1)
+  VersionsCell,           # Negotiate proto version  (section 4)
+  NetinfoCell,            # Time and address info    (section 4.5)
+  RelayEarlyCell,         # End-to-end data; limited (section 5.6)
+  Create2Cell,            # Extended CREATE cell     (section 5.1)
+  Created2Cell,           # Extended CREATED cell    (section 5.1)
+  PaddingNegotiateCell,   # Padding negotiation      (section 7.2)
+  VPaddingCell,           # Variable-length padding  (section 7.2)
+  CertsCell,              # Certificates             (section 4.2)
+  AuthChallengeCell,      # Challenge value          (section 4.3)
+  AuthenticateCell,       # Client authentication    (section 4.5)
+  AuthorizeCell,          # Client authorization     (not yet used)
 )
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index 8a461aba..188fd773 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -2,44 +2,30 @@
 Unit tests for the stem.client.cell.
 """
 
-import struct
 import unittest
 
-from stem.client import Pack
 from stem.client.cell import Cell
 
 
 class TestCell(unittest.TestCase):
   def test_by_name(self):
-    cell = Cell.by_name('NETINFO')
-    self.assertEqual('NETINFO', cell.NAME)
-    self.assertEqual(8, cell.VALUE)
-    self.assertEqual(True, cell.IS_FIXED_SIZE)
-    self.assertEqual(False, cell.IS_FOR_CIRCUIT)
+    cls = Cell.by_name('NETINFO')
+    self.assertEqual('NETINFO', cls.NAME)
+    self.assertEqual(8, cls.VALUE)
+    self.assertEqual(True, cls.IS_FIXED_SIZE)
+    self.assertEqual(False, cls.IS_FOR_CIRCUIT)
 
     self.assertRaises(ValueError, Cell.by_name, 'NOPE')
     self.assertRaises(ValueError, Cell.by_name, 85)
     self.assertRaises(ValueError, Cell.by_name, None)
 
   def test_by_value(self):
-    cell = Cell.by_value(8)
-    self.assertEqual('NETINFO', cell.name)
-    self.assertEqual(8, cell.value)
-    self.assertEqual(True, cell.fixed_size)
-    self.assertEqual(False, cell.for_circuit)
+    cls = Cell.by_value(8)
+    self.assertEqual('NETINFO', cls.NAME)
+    self.assertEqual(8, cls.VALUE)
+    self.assertEqual(True, cls.IS_FIXED_SIZE)
+    self.assertEqual(False, cls.IS_FOR_CIRCUIT)
 
     self.assertRaises(ValueError, Cell.by_value, 'NOPE')
     self.assertRaises(ValueError, Cell.by_value, 85)
     self.assertRaises(ValueError, Cell.by_value, None)
-
-  def test_pack(self):
-    version_payload = struct.pack(Pack.SHORT, 2)
-
-    # basic link v2 and v4 VERSIONS cell
-
-    self.assertEqual('\x00\x00\x07\x00\x02\x00\x02', Cell.pack('VERSIONS', 2, version_payload))
-    self.assertEqual('\x00\x00\x00\x00\x07\x00\x02\x00\x02', Cell.pack('VERSIONS', 4, version_payload))
-
-    self.assertRaisesRegexp(ValueError, "'NOPE' isn't a valid cell type", Cell.pack, 'NOPE', 2, version_payload)
-    self.assertRaisesRegexp(ValueError, "VERSIONS cells don't concern circuits, circ_id is unused", Cell.pack, 'VERSIONS', 2, version_payload, circ_id = 5)
-    self.assertRaisesRegexp(ValueError, 'RELAY_EARLY cells require a circ_id', Cell.pack, 'RELAY_EARLY', 2, version_payload)





More information about the tor-commits mailing list