pyloxi: include all members in OFClass.members

This preserves ordering, which is important because we can't rely on the offset
field for sorting (it may be -1).

The newly passing show() tests are due to the side effect of removing type
fields from pretty printing.
diff --git a/py_gen/templates/_ofclass.py b/py_gen/templates/_ofclass.py
index ff8b21b..03fe837 100644
--- a/py_gen/templates/_ofclass.py
+++ b/py_gen/templates/_ofclass.py
@@ -1,11 +1,12 @@
-:: nonskip_members = [m for m in ofclass.members if not m.skip]
+:: from py_gen.codegen import Member, LengthMember, TypeMember
+:: normal_members = [m for m in ofclass.members if type(m) == Member and not m.skip]
 class ${ofclass.pyname}(${superclass}):
 :: for m in ofclass.type_members:
     ${m.name} = ${m.value}
 :: #endfor
 
-    def __init__(${', '.join(['self'] + ["%s=None" % m.name for m in nonskip_members])}):
-:: for m in nonskip_members:
+    def __init__(${', '.join(['self'] + ["%s=None" % m.name for m in normal_members])}):
+:: for m in normal_members:
         if ${m.name} != None:
             self.${m.name} = ${m.name}
         else:
@@ -26,7 +27,7 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-:: for m in nonskip_members:
+:: for m in normal_members:
         if self.${m.name} != other.${m.name}: return False
 :: #endfor
         return True
diff --git a/py_gen/templates/_pack.py b/py_gen/templates/_pack.py
index 0d50a38..15645ee 100644
--- a/py_gen/templates/_pack.py
+++ b/py_gen/templates/_pack.py
@@ -26,14 +26,13 @@
 :: # under the EPL.
 ::
 :: # TODO coalesce format strings
-:: all_members = ofclass.members[:]
-:: if ofclass.length_member: all_members.append(ofclass.length_member)
-:: all_members.extend(ofclass.type_members)
-:: all_members.sort(key=lambda x: x.offset)
+:: from py_gen.codegen import Member, LengthMember, TypeMember
+:: length_member = None
 :: length_member_index = None
 :: index = 0
-:: for m in all_members:
-::     if m == ofclass.length_member:
+:: for m in ofclass.members:
+::     if type(m) == LengthMember:
+::         length_member = m
 ::         length_member_index = index
         packed.append(${m.oftype.gen_pack_expr('0')}) # placeholder for ${m.name} at index ${length_member_index}
 ::     else:
@@ -43,5 +42,5 @@
 :: #endfor
 :: if length_member_index != None:
         length = sum([len(x) for x in packed])
-        packed[${length_member_index}] = ${ofclass.length_member.oftype.gen_pack_expr('length')}
+        packed[${length_member_index}] = ${length_member.oftype.gen_pack_expr('length')}
 :: #endif
diff --git a/py_gen/templates/_pretty_print.py b/py_gen/templates/_pretty_print.py
index 604cd94..5d5edee 100644
--- a/py_gen/templates/_pretty_print.py
+++ b/py_gen/templates/_pretty_print.py
@@ -29,9 +29,10 @@
         with q.group():
             with q.indent(2):
                 q.breakable()
+:: from py_gen.codegen import Member, LengthMember, TypeMember
+:: normal_members = [m for m in ofclass.members if type(m) == Member and not m.skip]
 :: first = True
-:: for m in ofclass.members:
-:: if m.name == 'actions_len': continue
+:: for m in normal_members:
 :: if not first:
                 q.text(","); q.breakable()
 :: else:
diff --git a/py_gen/templates/_unpack.py b/py_gen/templates/_unpack.py
index 173ebb5..6003725 100644
--- a/py_gen/templates/_unpack.py
+++ b/py_gen/templates/_unpack.py
@@ -26,13 +26,10 @@
 :: # under the EPL.
 ::
 :: # TODO coalesce format strings
-:: all_members = ofclass.members[:]
-:: if ofclass.length_member: all_members.append(ofclass.length_member)
-:: all_members.extend(ofclass.type_members)
-:: all_members.sort(key=lambda x: x.offset)
-:: for m in all_members:
+:: from py_gen.codegen import Member, LengthMember, TypeMember
+:: for m in ofclass.members:
 ::     unpack_expr = m.oftype.gen_unpack_expr('buf', m.offset)
-::     if m == ofclass.length_member:
+::     if type(m) == LengthMember:
         _length = ${unpack_expr}
         assert(_length == len(buf))
 :: if ofclass.is_fixed_length:
@@ -40,7 +37,7 @@
 :: else:
         if _length < ${ofclass.min_length}: raise loxi.ProtocolError("${ofclass.pyname} length is %d, should be at least ${ofclass.min_length}" % _length)
 :: #endif
-::     elif m in ofclass.type_members:
+::     elif type(m) == TypeMember:
         ${m.name} = ${unpack_expr}
         assert(${m.name} == ${m.value})
 ::     else:
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index de8fb86..8eb051d 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -44,15 +44,17 @@
     xid = None
 
 :: for ofclass in ofclasses:
-:: nonskip_members = [m for m in ofclass.members if not m.skip]
+:: from py_gen.codegen import Member, LengthMember, TypeMember
+:: normal_members = [m for m in ofclass.members if type(m) == Member and not m.skip]
+:: type_members = [m for m in ofclass.members if type(m) == TypeMember]
 class ${ofclass.pyname}(Message):
-:: for m in ofclass.type_members:
+:: for m in type_members:
     ${m.name} = ${m.value}
 :: #endfor
 
-    def __init__(self, ${', '.join(["%s=None" % m.name for m in nonskip_members])}):
+    def __init__(self, ${', '.join(["%s=None" % m.name for m in normal_members])}):
         self.xid = xid
-:: for m in [x for x in nonskip_members if x.name != 'xid']:
+:: for m in [x for x in normal_members if x.name != 'xid']:
         if ${m.name} != None:
             self.${m.name} = ${m.name}
         else:
@@ -83,7 +85,7 @@
         if type(self) != type(other): return False
         if self.version != other.version: return False
         if self.type != other.type: return False
-:: for m in nonskip_members:
+:: for m in normal_members:
         if self.${m.name} != other.${m.name}: return False
 :: #endfor
         return True
diff --git a/py_gen/templates/oxm.py b/py_gen/templates/oxm.py
index c210874..14ea259 100644
--- a/py_gen/templates/oxm.py
+++ b/py_gen/templates/oxm.py
@@ -41,14 +41,16 @@
     pass
 
 :: for ofclass in ofclasses:
-:: nonskip_members = [m for m in ofclass.members if not m.skip]
+:: from py_gen.codegen import Member, LengthMember, TypeMember
+:: normal_members = [m for m in ofclass.members if type(m) == Member and not m.skip]
+:: type_members = [m for m in ofclass.members if type(m) == TypeMember]
 class ${ofclass.pyname}(OXM):
-:: for m in ofclass.type_members:
+:: for m in type_members:
     ${m.name} = ${m.value}
 :: #endfor
 
-    def __init__(self, ${', '.join(["%s=None" % m.name for m in nonskip_members])}):
-:: for m in nonskip_members:
+    def __init__(self, ${', '.join(["%s=None" % m.name for m in normal_members])}):
+:: for m in normal_members:
         if ${m.name} != None:
             self.${m.name} = ${m.name}
         else:
@@ -68,7 +70,7 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-:: for m in nonskip_members:
+:: for m in normal_members:
         if self.${m.name} != other.${m.name}: return False
 :: #endfor
         return True