pyloxi: move list unpack functions into util

The goal is to make all module templates identical.
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 605d5be..b13022a 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -109,12 +109,12 @@
     'list(of_oxm_t)': OFTypeData(
         init='[]',
         pack='util.pack_list(%s)',
-        unpack='oxm.unpack_list(%s.slice(_length-4))'),
+        unpack='util.unpack_list_oxm(%s.slice(_length-4))'),
 
     'of_oxm_t': OFTypeData(
         init='None',
         pack='%s.pack()',
-        unpack='oxm.unpack(%s)'),
+        unpack='oxm.oxm.unpack(%s)'),
 
     # TODO implement unpack
     'list(of_table_features_t)': OFTypeData(
@@ -171,17 +171,17 @@
 
 # Map from list class name to list deserializer
 variable_elem_len_lists = {
-    'list(of_action_t)': 'action.unpack_list',
-    'list(of_bucket_t)': 'common.unpack_list_bucket',
-    'list(of_flow_stats_entry_t)': 'common.unpack_list_flow_stats_entry',
-    'list(of_group_desc_stats_entry_t)': 'common.unpack_list_group_desc_stats_entry',
-    'list(of_group_stats_entry_t)': 'common.unpack_list_group_stats_entry',
-    'list(of_hello_elem_t)': 'common.unpack_list_hello_elem',
-    'list(of_instruction_t)': 'instruction.unpack_list',
-    'list(of_meter_band_t)': 'meter_band.unpack_list',
-    'list(of_meter_stats_t)': 'common.unpack_list_meter_stats',
-    'list(of_packet_queue_t)': 'common.unpack_list_packet_queue',
-    'list(of_queue_prop_t)': 'common.unpack_list_queue_prop',
+    'list(of_action_t)': 'util.unpack_list_action',
+    'list(of_bucket_t)': 'util.unpack_list_bucket',
+    'list(of_flow_stats_entry_t)': 'util.unpack_list_flow_stats_entry',
+    'list(of_group_desc_stats_entry_t)': 'util.unpack_list_group_desc_stats_entry',
+    'list(of_group_stats_entry_t)': 'util.unpack_list_group_stats_entry',
+    'list(of_hello_elem_t)': 'util.unpack_list_hello_elem',
+    'list(of_instruction_t)': 'util.unpack_list_instruction',
+    'list(of_meter_band_t)': 'util.unpack_list_meter_band',
+    'list(of_meter_stats_t)': 'util.unpack_list_meter_stats',
+    'list(of_packet_queue_t)': 'util.unpack_list_packet_queue',
+    'list(of_queue_prop_t)': 'util.unpack_list_queue_prop',
 }
 
 for (cls, deserializer) in variable_elem_len_lists.items():
diff --git a/py_gen/templates/action.py b/py_gen/templates/action.py
index 9f80243..dfd832d 100644
--- a/py_gen/templates/action.py
+++ b/py_gen/templates/action.py
@@ -41,11 +41,6 @@
 import oxm # for unpack
 :: #endif
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        return action.unpack(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
-
 :: for ofclass in ofclasses:
 :: if ofclass.virtual:
 :: include('_virtual_ofclass.py', ofclass=ofclass)
diff --git a/py_gen/templates/common.py b/py_gen/templates/common.py
index 6569c77..f222e9b 100644
--- a/py_gen/templates/common.py
+++ b/py_gen/templates/common.py
@@ -49,43 +49,6 @@
 # HACK make this module visible as 'common' to simplify code generation
 common = sys.modules[__name__]
 
-def unpack_list_flow_stats_entry(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, flow_stats_entry.unpack)
-
-def unpack_list_queue_prop(reader):
-    def deserializer(reader, typ):
-        return queue_prop.unpack(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
-
-def unpack_list_packet_queue(reader):
-    def wrapper(reader):
-        length, = reader.peek('!4xH')
-        return packet_queue.unpack(reader.slice(length))
-    return loxi.generic_util.unpack_list(reader, wrapper)
-
-def unpack_list_hello_elem(reader):
-    def deserializer(reader, typ):
-        try:
-            return hello_elem.unpack(reader)
-        except loxi.ProtocolError:
-            return None
-    return [x for x in loxi.generic_util.unpack_list_tlv16(reader, deserializer) if x != None]
-
-def unpack_list_bucket(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, bucket.unpack)
-
-def unpack_list_group_desc_stats_entry(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, group_desc_stats_entry.unpack)
-
-def unpack_list_group_stats_entry(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, group_stats_entry.unpack)
-
-def unpack_list_meter_stats(reader):
-    def wrapper(reader):
-        length, = reader.peek('!4xH')
-        return meter_stats.unpack(reader.slice(length))
-    return loxi.generic_util.unpack_list(reader, wrapper)
-
 :: for ofclass in ofclasses:
 :: if ofclass.virtual:
 :: include('_virtual_ofclass.py', ofclass=ofclass)
diff --git a/py_gen/templates/instruction.py b/py_gen/templates/instruction.py
index 9842f95..da91b76 100644
--- a/py_gen/templates/instruction.py
+++ b/py_gen/templates/instruction.py
@@ -38,11 +38,6 @@
 import loxi.generic_util
 import loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        return instruction.unpack(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
-
 :: for ofclass in ofclasses:
 :: if ofclass.virtual:
 :: include('_virtual_ofclass.py', ofclass=ofclass)
diff --git a/py_gen/templates/meter_band.py b/py_gen/templates/meter_band.py
index 38607e7..24c1f2c 100644
--- a/py_gen/templates/meter_band.py
+++ b/py_gen/templates/meter_band.py
@@ -37,11 +37,6 @@
 import loxi.generic_util
 import loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        return meter_band.unpack(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
-
 :: for ofclass in ofclasses:
 :: if ofclass.virtual:
 :: include('_virtual_ofclass.py', ofclass=ofclass)
diff --git a/py_gen/templates/oxm.py b/py_gen/templates/oxm.py
index 71bf7df..5de771c 100644
--- a/py_gen/templates/oxm.py
+++ b/py_gen/templates/oxm.py
@@ -37,12 +37,6 @@
 import loxi.generic_util
 import loxi
 
-def unpack(reader):
-    return oxm.unpack(reader)
-
-def unpack_list(reader):
-    return loxi.generic_util.unpack_list(reader, unpack)
-
 :: for ofclass in ofclasses:
 :: if ofclass.virtual:
 :: include('_virtual_ofclass.py', ofclass=ofclass)
diff --git a/py_gen/templates/util.py b/py_gen/templates/util.py
index 50a64db..73da0ea 100644
--- a/py_gen/templates/util.py
+++ b/py_gen/templates/util.py
@@ -29,9 +29,20 @@
 :: from loxi_globals import OFVersions
 :: include('_autogen.py')
 
+import struct
 import loxi
 import const
-import struct
+import common
+import action
+:: if version >= OFVersions.VERSION_1_1:
+import instruction
+:: #endif
+:: if version >= OFVersions.VERSION_1_2:
+import oxm
+:: #endif
+:: if version >= OFVersions.VERSION_1_3:
+import meter_band
+:: #endif
 
 def pretty_mac(mac):
     return ':'.join(["%02x" % x for x in mac])
@@ -162,3 +173,58 @@
         i += 1
         x >>= 1
     return value
+
+def unpack_list_flow_stats_entry(reader):
+    return loxi.generic_util.unpack_list_lv16(reader, common.flow_stats_entry.unpack)
+
+def unpack_list_queue_prop(reader):
+    def deserializer(reader, typ):
+        return common.queue_prop.unpack(reader)
+    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+
+def unpack_list_packet_queue(reader):
+    def wrapper(reader):
+        length, = reader.peek('!4xH')
+        return common.packet_queue.unpack(reader.slice(length))
+    return loxi.generic_util.unpack_list(reader, wrapper)
+
+def unpack_list_hello_elem(reader):
+    def deserializer(reader, typ):
+        try:
+            return common.hello_elem.unpack(reader)
+        except loxi.ProtocolError:
+            return None
+    return [x for x in loxi.generic_util.unpack_list_tlv16(reader, deserializer) if x != None]
+
+def unpack_list_bucket(reader):
+    return loxi.generic_util.unpack_list_lv16(reader, common.bucket.unpack)
+
+def unpack_list_group_desc_stats_entry(reader):
+    return loxi.generic_util.unpack_list_lv16(reader, common.group_desc_stats_entry.unpack)
+
+def unpack_list_group_stats_entry(reader):
+    return loxi.generic_util.unpack_list_lv16(reader, common.group_stats_entry.unpack)
+
+def unpack_list_meter_stats(reader):
+    def wrapper(reader):
+        length, = reader.peek('!4xH')
+        return common.meter_stats.unpack(reader.slice(length))
+    return loxi.generic_util.unpack_list(reader, wrapper)
+
+def unpack_list_action(reader):
+    def deserializer(reader, typ):
+        return action.action.unpack(reader)
+    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+
+def unpack_list_instruction(reader):
+    def deserializer(reader, typ):
+        return instruction.instruction.unpack(reader)
+    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+
+def unpack_list_meter_band(reader):
+    def deserializer(reader, typ):
+        return meter_band.meter_band.unpack(reader)
+    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+
+def unpack_list_oxm(reader):
+    return loxi.generic_util.unpack_list(reader, oxm.oxm.unpack)
diff --git a/py_gen/tests/of10.py b/py_gen/tests/of10.py
index 876926e..74f3d2c 100644
--- a/py_gen/tests/of10.py
+++ b/py_gen/tests/of10.py
@@ -88,34 +88,34 @@
         add(ofp.action.bsn_set_tunnel_dst(dst=0x12345678))
         add(ofp.action.nicira_dec_ttl())
 
-        actions = ofp.action.unpack_list(OFReader(''.join(bufs)))
+        actions = ofp.util.unpack_list_action(OFReader(''.join(bufs)))
         self.assertEquals(actions, expected)
 
     def test_empty_list(self):
-        self.assertEquals(ofp.action.unpack_list(OFReader('')), [])
+        self.assertEquals(ofp.util.unpack_list_action(OFReader('')), [])
 
     def test_invalid_list_length(self):
         buf = '\x00' * 9
         with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
-            ofp.action.unpack_list(OFReader(buf))
+            ofp.util.unpack_list_action(OFReader(buf))
 
     def test_invalid_action_length(self):
         buf = '\x00' * 8
         with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
-            ofp.action.unpack_list(OFReader(buf))
+            ofp.util.unpack_list_action(OFReader(buf))
 
         buf = '\x00\x00\x00\x04'
         with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
-            ofp.action.unpack_list(OFReader(buf))
+            ofp.util.unpack_list_action(OFReader(buf))
 
         buf = '\x00\x00\x00\x10\x00\x00\x00\x00'
         with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
-            ofp.action.unpack_list(OFReader(buf))
+            ofp.util.unpack_list_action(OFReader(buf))
 
     def test_invalid_action_type(self):
         buf = '\xff\xfe\x00\x08\x00\x00\x00\x00'
         with self.assertRaisesRegexp(ofp.ProtocolError, 'unknown action subtype'):
-            ofp.action.unpack_list(OFReader(buf))
+            ofp.util.unpack_list_action(OFReader(buf))
 
 class TestConstants(unittest.TestCase):
     def test_ports(self):
diff --git a/py_gen/tests/of13.py b/py_gen/tests/of13.py
index 07b0ef0..503a307 100644
--- a/py_gen/tests/of13.py
+++ b/py_gen/tests/of13.py
@@ -67,7 +67,7 @@
             '\x00\x00\x00\x04', # unknown type
             '\x00\x01\x00\x04', # versionbitmap
         ])
-        l = ofp.unpack_list_hello_elem(OFReader(buf))
+        l = ofp.util.unpack_list_hello_elem(OFReader(buf))
         self.assertEquals(len(l), 2)
         self.assertTrue(isinstance(l[0], ofp.hello_elem_versionbitmap))
         self.assertTrue(isinstance(l[1], ofp.hello_elem_versionbitmap))