From 1aca0727cffc316837b1f678b4a60838fb8cf6ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl>
Date: Wed, 28 Dec 2016 04:29:06 +0100
Subject: [PATCH] ca ira

---
 coolamqp/__init__.py                          |    5 -
 .../authentication.py => cluster/__init__.py} |    2 -
 coolamqp/connection/__init__.py               |    2 +
 .../{uplink/frames => framing}/__init__.py    |    4 +-
 coolamqp/{uplink/frames => framing}/base.py   |   74 +-
 .../compilation/__init__.py                   |    0
 .../compilation/compile_definitions.py        |  276 ++
 .../framing/compilation/content_property.py   |   27 +
 .../framing/compilation/textcode_fields.py    |  225 ++
 .../compilation/utilities.py                  |   91 +-
 .../{uplink/frames => framing}/definitions.py | 2329 +++++------------
 .../{uplink/frames => framing}/field_table.py |    0
 coolamqp/{uplink/frames => framing}/frames.py |   14 +-
 coolamqp/scaffold.py                          |   43 +
 coolamqp/uplink/__init__.py                   |    2 +-
 coolamqp/uplink/commander/__init__.py         |   13 -
 coolamqp/uplink/factory.py                    |   44 -
 coolamqp/uplink/frames/base_definitions.py    |   75 -
 .../frames/compilation/compile_definitions.py |  816 ------
 coolamqp/uplink/iface.py                      |    2 +
 coolamqp/uplink/order.py                      |    2 +-
 .../uplink/{streams => }/reader_thread.py     |    4 +-
 .../recv_formatter.py => recv_framer.py}      |   21 +-
 .../send_operator.py => send_framer.py}       |    6 +-
 coolamqp/uplink/streams/__init__.py           |    9 -
 coolamqp/uplink/uplink.py                     |   58 -
 coolamqp/uplink/{streams => }/watchman.py     |   68 +-
 setup.py                                      |    4 +-
 28 files changed, 1488 insertions(+), 2728 deletions(-)
 rename coolamqp/{uplink/authentication.py => cluster/__init__.py} (70%)
 create mode 100644 coolamqp/connection/__init__.py
 rename coolamqp/{uplink/frames => framing}/__init__.py (59%)
 rename coolamqp/{uplink/frames => framing}/base.py (55%)
 rename coolamqp/{uplink/frames => framing}/compilation/__init__.py (100%)
 create mode 100644 coolamqp/framing/compilation/compile_definitions.py
 create mode 100644 coolamqp/framing/compilation/content_property.py
 create mode 100644 coolamqp/framing/compilation/textcode_fields.py
 rename coolamqp/{uplink/frames => framing}/compilation/utilities.py (77%)
 rename coolamqp/{uplink/frames => framing}/definitions.py (59%)
 rename coolamqp/{uplink/frames => framing}/field_table.py (100%)
 rename coolamqp/{uplink/frames => framing}/frames.py (87%)
 create mode 100644 coolamqp/scaffold.py
 delete mode 100644 coolamqp/uplink/commander/__init__.py
 delete mode 100644 coolamqp/uplink/factory.py
 delete mode 100644 coolamqp/uplink/frames/base_definitions.py
 delete mode 100644 coolamqp/uplink/frames/compilation/compile_definitions.py
 create mode 100644 coolamqp/uplink/iface.py
 rename coolamqp/uplink/{streams => }/reader_thread.py (86%)
 rename coolamqp/uplink/{streams/recv_formatter.py => recv_framer.py} (89%)
 rename coolamqp/uplink/{streams/send_operator.py => send_framer.py} (94%)
 delete mode 100644 coolamqp/uplink/streams/__init__.py
 delete mode 100644 coolamqp/uplink/uplink.py
 rename coolamqp/uplink/{streams => }/watchman.py (55%)

diff --git a/coolamqp/__init__.py b/coolamqp/__init__.py
index 64f8892..9599562 100644
--- a/coolamqp/__init__.py
+++ b/coolamqp/__init__.py
@@ -1,6 +1 @@
 # coding=UTF-8
-from coolamqp.cluster import ClusterNode, Cluster
-from coolamqp.events import ConnectionDown, ConnectionUp, MessageReceived, ConsumerCancelled
-from coolamqp.messages import Message, Exchange, Queue
-from coolamqp.backends.base import Cancelled, Discarded
-
diff --git a/coolamqp/uplink/authentication.py b/coolamqp/cluster/__init__.py
similarity index 70%
rename from coolamqp/uplink/authentication.py
rename to coolamqp/cluster/__init__.py
index 7d799de..9f2b35b 100644
--- a/coolamqp/uplink/authentication.py
+++ b/coolamqp/cluster/__init__.py
@@ -1,4 +1,2 @@
 # coding=UTF-8
-"""All things authentication"""
 from __future__ import absolute_import, division, print_function
-
diff --git a/coolamqp/connection/__init__.py b/coolamqp/connection/__init__.py
new file mode 100644
index 0000000..9f2b35b
--- /dev/null
+++ b/coolamqp/connection/__init__.py
@@ -0,0 +1,2 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
diff --git a/coolamqp/uplink/frames/__init__.py b/coolamqp/framing/__init__.py
similarity index 59%
rename from coolamqp/uplink/frames/__init__.py
rename to coolamqp/framing/__init__.py
index dd8748f..7e413d8 100644
--- a/coolamqp/uplink/frames/__init__.py
+++ b/coolamqp/framing/__init__.py
@@ -2,8 +2,8 @@
 from __future__ import absolute_import, division, print_function
 
 """
-Definitions of frames.
-Mechanisms for serialization/deserialization of AMQP frames and other types.
+Definitions of framing.
+Mechanisms for serialization/deserialization of AMQP framing and other types.
 
 
 definitions.py is machine-generated from AMQP specification.
diff --git a/coolamqp/uplink/frames/base.py b/coolamqp/framing/base.py
similarity index 55%
rename from coolamqp/uplink/frames/base.py
rename to coolamqp/framing/base.py
index 7cd16e1..6ddeddf 100644
--- a/coolamqp/uplink/frames/base.py
+++ b/coolamqp/framing/base.py
@@ -1,8 +1,8 @@
 # coding=UTF-8
 from __future__ import absolute_import, division, print_function
-import struct
+
 import logging
-import six
+import struct
 
 logger = logging.getLogger(__name__)
 
@@ -16,7 +16,7 @@ BASIC_TYPES = {'bit': (None, None, "0", None),          # special case
                'short': (2, 'H', "b'\\x00\\x00'", 2),
                'long': (4, 'I', "b'\\x00\\x00\\x00\\x00'", 4),
                'longlong': (8, 'Q', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8),
-               'timestamp': (8, 'L', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8),
+               'timestamp': (8, 'Q', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8),
                'table': (None, None, "b'\\x00\\x00\\x00\\x00'", 4),          # special case
                'longstr': (None, None, "b'\\x00\\x00\\x00\\x00'", 4),        # special case
                'shortstr': (None, None, "b'\\x00'", 1),                        # special case
@@ -25,8 +25,7 @@ BASIC_TYPES = {'bit': (None, None, "0", None),          # special case
 DYNAMIC_BASIC_TYPES = ('table', 'longstr', 'shortstr')
 
 
-
-class AMQPFrame(object):        # base class for frames
+class AMQPFrame(object):        # base class for framing
     FRAME_TYPE = None   # override me!
 
     def __init__(self, channel):
@@ -75,3 +74,68 @@ class AMQPPayload(object):
         :return: int
         """
         raise NotImplementedError()
+
+
+class AMQPClass(object):
+    """An AMQP class"""
+
+
+class AMQPContentPropertyList(object):
+    """
+    A class is intmately bound with content and content properties
+    """
+    PROPERTIES = []
+
+
+class AMQPMethodPayload(AMQPPayload):
+    RESPONSE_TO = None
+    REPLY_WITH = []
+    FIELDS = []
+
+    def write_to(self, buf):
+        """
+        Write own content to target buffer - starting from LENGTH, ending on FRAME_END
+        :param buf: target buffer
+        """
+        from coolamqp.framing import FRAME_END
+
+        if self.IS_CONTENT_STATIC:
+            buf.write(self.STATIC_CONTENT)
+        else:
+            buf.write(struct.pack('!I', self.get_size()+2))
+            buf.write(self.BINARY_HEADER)
+            self.write_arguments(buf)
+            buf.write(chr(FRAME_END))
+
+    def get_size(self):
+        """
+        Calculate the size of this frame.
+
+        :return: int, size of argument section
+        """
+        raise NotImplementedError()
+
+    def write_arguments(self, buf):
+        """
+        Write the argument portion of this frame into buffer.
+
+        :param buf: buffer to write to
+        :return: how many bytes written
+        :raise ValueError: some field here is invalid!
+        """
+        raise NotImplementedError()
+
+    @staticmethod
+    def from_buffer(buf, offset):
+        """
+        Construct this frame from a buffer
+
+        :param buf: a buffer to construct the frame from
+        :type buf: buffer or memoryview
+        :param offset: offset the argument portion begins at
+        :type offset: int
+        :return: tuple of (an instance of %s, amount of bytes consumed as int)
+        :raise ValueError: invalid data
+        """
+        raise NotImplementedError('')
+
diff --git a/coolamqp/uplink/frames/compilation/__init__.py b/coolamqp/framing/compilation/__init__.py
similarity index 100%
rename from coolamqp/uplink/frames/compilation/__init__.py
rename to coolamqp/framing/compilation/__init__.py
diff --git a/coolamqp/framing/compilation/compile_definitions.py b/coolamqp/framing/compilation/compile_definitions.py
new file mode 100644
index 0000000..1d2f91e
--- /dev/null
+++ b/coolamqp/framing/compilation/compile_definitions.py
@@ -0,0 +1,276 @@
+from __future__ import division
+
+import collections
+import math
+import struct
+from xml.etree import ElementTree
+
+import six
+from coolamqp.framing.base import BASIC_TYPES
+
+from coolamqp.framing.compilation.utilities import get_constants, get_classes, get_domains, \
+    name_class, format_method_class_name, format_field_name, ffmt, to_docstring, pythonify_name, to_code_binary, \
+    frepr, get_size
+
+TYPE_TRANSLATOR = {
+        'shortstr': 'binary type (max length 255)',
+        'longstr': 'binary type',
+        'table': 'table. See coolamqp.uplink.framing.field_table',
+        'bit': 'bool',
+        'octet': 'int, 8 bit unsigned',
+        'short': 'int, 16 bit unsigned',
+        'long': 'int, 32 bit unsigned',
+        'longlong': 'int, 64 bit unsigned',
+        'timestamp': '64 bit signed POSIX timestamp (in seconds)',
+}
+
+def compile_definitions(xml_file='resources/amqp0-9-1.xml', out_file='coolamqp/framing/definitions.py'):
+    """parse resources/amqp-0-9-1.xml into """
+
+    xml = ElementTree.parse(xml_file)
+    out = open(out_file, 'wb')
+
+    out.write('''# coding=UTF-8
+from __future__ import print_function, absolute_import
+"""
+A Python version of the AMQP machine-readable specification.
+
+Generated automatically by CoolAMQP from AMQP machine-readable specification.
+See coolamqp.uplink.framing.compilation for the tool
+
+AMQP is copyright (c) 2016 OASIS
+CoolAMQP is copyright (c) 2016 DMS Serwis s.c.
+"""
+
+import struct
+import collections
+
+from coolamqp.framing.base_definitions import AMQPClass, AMQPMethodPayload, AMQPContentPropertyList
+from coolamqp.framing.field_table import enframe_table, deframe_table, frame_table_size
+
+Field = collections.namedtuple('Field', ('name', 'type', 'reserved'))
+
+''')
+
+    def line(data, *args, **kwargs):
+        out.write(ffmt(data, *args, sane=True))
+
+    # Output core ones
+    FRAME_END = None
+    con_classes = collections.defaultdict(list)
+    line('# Core constants\n')
+    for constant in get_constants(xml):
+        if pythonify_name(constant.name) == 'FRAME_END':
+            FRAME_END = constant.value
+        g = ffmt('%s = %s', pythonify_name(constant.name), constant.value)
+        line(g)
+        if constant.docs:
+            lines = constant.docs.split('\n')
+            line(' # %s\n', lines[0])
+            if len(lines) > 1:
+                for ln in lines[1:]:
+                    line(u' '*len(g))
+                    line(u' # %s\n', ln)
+        else:
+            line('\n')
+
+        if constant.kind:
+            con_classes[constant.kind].append(pythonify_name(constant.name))
+
+    for constant_kind, constants in con_classes.items():
+        line('\n%s = [%s]', pythonify_name(constant_kind), u', '.join(constants))
+
+    # get domains
+    domain_to_basic_type = {}
+    line('\n\n\nDOMAIN_TO_BASIC_TYPE = {\n')
+    for domain in get_domains(xml):
+        line(u'    %s: %s,\n', frepr(domain.name), frepr(None if domain.elementary else domain.type))
+        domain_to_basic_type[domain.name] = domain.type
+
+    line('}\n')
+
+    class_id_to_contentpropertylist = {}
+
+    # Output classes
+    for cls in get_classes(xml):
+
+        cls = cls._replace(properties=[p._replace(basic_type=domain_to_basic_type[p.type]) for p in cls.properties])
+
+        line('''\nclass %s(AMQPClass):
+    """
+    %s
+    """
+    NAME = %s
+    INDEX = %s
+
+''',
+             name_class(cls.name), to_docstring(None, cls.docs), frepr(cls.name), cls.index)
+
+        if len(cls.properties) > 0:
+            class_id_to_contentpropertylist[cls.index] = name_class(cls.name)+'ContentPropertyList'
+
+            line('''\nclass %sContentPropertyList(AMQPContentPropertyList):
+    """
+    %s
+    """
+    FIELDS = [
+''',
+
+                 name_class(cls.name), to_docstring(None, cls.docs), frepr(cls.name), cls.index, name_class(cls.name))
+
+            is_static = all(property.basic_type not in ('table', 'longstr', 'shortstr') for property in cls.properties)
+
+            for property in cls.properties:
+                line('        Field(%s, %s, %s),\n', frepr(property.name), frepr(property.basic_type), repr(property.reserved))
+            line('    ]\n\n')
+
+
+
+
+
+
+
+        # ============================================ Do methods for this class
+        for method in cls.methods:
+            full_class_name = '%s%s' % (name_class(cls.name), format_method_class_name(method.name))
+
+            # annotate types
+            method.fields = [field._replace(basic_type=domain_to_basic_type[field.type]) for field in method.fields]
+
+            is_static = method.is_static()
+            if is_static:
+                static_size = get_size(method.fields)
+
+            is_content_static = len([f for f in method.fields if not f.reserved]) == 0
+
+            line('''\nclass %s(AMQPMethodPayload):
+    """
+    %s
+    """
+    NAME = %s
+
+    INDEX = (%s, %s)          # (Class ID, Method ID)
+    BINARY_HEADER = %s      # CLASS ID + METHOD ID
+
+    SENT_BY_CLIENT, SENT_BY_SERVER = %s, %s
+    REPLY_WITH = [%s]       # methods you can reply with to this one
+
+    IS_SIZE_STATIC = %s     # this means that argument part has always the same length
+    IS_CONTENT_STATIC = %s  # this means that argument part has always the same content
+''',
+                 full_class_name,
+                 to_docstring(method.label, method.docs),
+                 frepr(cls.name + '.' + method.name),
+                 frepr(cls.index), frepr(method.index),
+                 to_code_binary(chr(cls.index)+chr(method.index)),
+                 repr(method.sent_by_client),
+                 repr(method.sent_by_server),
+                 u', '.join([name_class(cls.name) + format_method_class_name(kidname) for kidname in method.response]),
+                 repr(is_static),
+                 repr(is_content_static)
+                 )
+
+
+            if is_content_static:
+
+                line('''    STATIC_CONTENT = %s  # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END
+''',
+                     to_code_binary(struct.pack('!LBB', static_size + 4, cls.index, method.index) + \
+                                    method.get_static_body() + \
+                                    struct.pack('!B', FRAME_END)))
+
+            # Am I a response somewhere?
+            for paren in cls.methods:
+                if method.name in paren.response:
+                    line('    RESPONSE_TO = %s%s # this is sent in response to %s\n', name_class(cls.name), format_method_class_name(paren.name),
+                         cls.name +'.' + paren.name
+                         )
+
+            # fields
+            if len(method.fields) > 0:
+                line('\n    # See constructor pydoc for details\n')
+                line('    FIELDS = [ \n')
+
+                for field in method.fields:
+                    line('        Field(%s, %s, reserved=%s),\n', frepr(field.name), frepr(field.basic_type), repr(field.reserved))
+
+                line('    ]\n')
+
+            non_reserved_fields = [field for field in method.fields if not field.reserved]
+
+            # constructor
+            line('''\n    def __init__(%s):
+        """
+        Create frame %s
+''',
+                 u', '.join(['self'] + [format_field_name(field.name) for field in non_reserved_fields]),
+                 cls.name + '.' + method.name,
+                 )
+
+            if len(non_reserved_fields) > 0:
+                line('\n')
+            for field in non_reserved_fields:
+                if (field.label is not None) or (field.docs is not None):
+                    line('        :param %s: %s\n', format_field_name(field.name),
+                         to_docstring(field.label, field.docs, prefix=12, blank=False))
+
+
+
+                line('        :type %s: %s (%s in AMQP)\n', format_field_name(field.name), TYPE_TRANSLATOR[field.basic_type], field.type)
+
+            line('        """\n')
+
+            for field in non_reserved_fields:
+                line('        self.%s = %s\n', format_field_name(field.name), format_field_name(field.name))
+
+            if len(non_reserved_fields) == 0:
+                line('\n')
+
+            # end
+            if not is_content_static:
+                from coolamqp.framing.compilation.textcode_fields import get_serializer, get_counter, get_from_buffer
+                line('\n    def write_arguments(self, buf):\n')
+                line(get_serializer(method.fields, 'self.', 2))
+
+                line('    def get_size(self):\n')
+                line(get_counter(method.fields, 'self.', 2))
+
+            line('''\n    @staticmethod
+    def from_buffer(buf, start_offset):
+        offset = start_offset
+''')
+
+            line(get_from_buffer(method.fields, '', 2))
+            line("        return %s(%s)",
+                 full_class_name,
+                 u', '.join(format_field_name(field.name) for field in method.fields if not field.reserved))
+
+            line('\n\n')
+
+        # Get me a dict - (classid, methodid) => class of method
+        dct = {}
+        for cls in get_classes(xml):
+            for method in cls.methods:
+                dct[((cls.index, method.index))] = '%s%s' % (name_class(cls.name), format_method_class_name(method.name))
+
+    line('\nIDENT_TO_METHOD = {\n')
+    for k, v in dct.items():
+        line('    %s: %s,\n', repr(k), v)
+    line('}\n\n')
+
+    line('\nBINARY_HEADER_TO_METHOD = {\n')
+    for k, v in dct.items():
+        line('    %s: %s,\n', to_code_binary(struct.pack('!BB', *k)), v)
+    line('}\n\n')
+
+    line('\nCLASS_ID_TO_CONTENT_PROPERTY_LIST = {\n')
+    for k,v in class_id_to_contentpropertylist.items():
+        line('    %s: %s,\n', k, v)
+    line('}\n\n')
+
+
+    out.close()
+
+
+if __name__ == '__main__':
+    compile_definitions()
diff --git a/coolamqp/framing/compilation/content_property.py b/coolamqp/framing/compilation/content_property.py
new file mode 100644
index 0000000..ab85174
--- /dev/null
+++ b/coolamqp/framing/compilation/content_property.py
@@ -0,0 +1,27 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
+"""
+Generate serializers/unserializers/length getters for given property_flags
+"""
+
+class ContentPropertyListCompiler(object):
+    """
+    This produces serializers, unserializers and size getters for any property_flags combinations.
+
+    Sure you could do that by hand, but how much faster is it to have most common messages precompiled?
+    """
+
+    MAX_COMPILERS_TO_KEEP = 8
+
+    def __init__(self, content_property_list_class):
+
+
+def compile_for(fields):
+    """Compile a serializer, unserializer and length calculator for a list of fields"""
+
+    mod = u'''# coding=UTF-8
+import struct
+from coolamqp.framing.field_table import enframe_table, deframe_table, frame_table_size
+
+def write_to(
+'''
\ No newline at end of file
diff --git a/coolamqp/framing/compilation/textcode_fields.py b/coolamqp/framing/compilation/textcode_fields.py
new file mode 100644
index 0000000..551183f
--- /dev/null
+++ b/coolamqp/framing/compilation/textcode_fields.py
@@ -0,0 +1,225 @@
+# coding=UTF-8
+"""
+Return Python code used to serialize/unserialize/get_size of lists of fields.
+
+If you are going to paste the code you get here, note you nede to paste it into
+a module that has following ok:
+
+    * local variables denoted with a list of Field (namedtuple) with optional prefix exist
+    * function header was already emitted
+    * indent_level is in multiple of fours
+    * following imports exists:
+        * import struct
+        * from coolamqp.framing.field_table import enframe_table, deframe_table, frame_table_size
+    * local variables buf and offset exist
+    * local variable start_offset can be created
+
+"""
+from __future__ import absolute_import, division, print_function
+import math
+
+from coolamqp.framing.base import BASIC_TYPES, DYNAMIC_BASIC_TYPES
+from coolamqp.framing.compilation.utilities import format_field_name, get_size
+
+def get_counter(fields, prefix='', indent_level=2):
+    """
+    Emit code that counts how long this struct is.
+
+    :param fields: list of Field instances
+    :param prefix: pass "self." is inside a class
+    :param indent_level: amount of tabs
+    :return: block of code that does that
+    """
+
+    parts = []
+    accumulator = 0
+    bits = 0
+    for field in fields:
+        bt = field.basic_type
+        nam = prefix+format_field_name(field.name)
+
+        if (bits > 0) and (bt != 'bit'):  # sync bits if not
+            accumulator += int(math.ceil(bits / 8))
+            bits = 0
+
+        if field.basic_type == 'bit':
+            bits += 1
+        elif field.reserved:
+            accumulator += BASIC_TYPES[field.basic_type][3]
+        elif BASIC_TYPES[bt][0] is not None:
+            accumulator += BASIC_TYPES[field.basic_type][0]
+        elif bt == 'shortstr':
+            parts.append('len('+nam+')')
+            accumulator += 1
+        elif bt == 'longstr':
+            parts.append('len(' + nam + ')')
+            accumulator += 4
+        elif bt == 'table':
+            parts.append('frame_table_size(' + nam + ')')
+            accumulator += 4
+        else:
+            raise Exception()
+
+    if bits > 0:  # sync bits
+        accumulator += int(math.ceil(bits / 8))
+
+    return (u'    '*indent_level)+u'return '+(u' + '.join([str(accumulator)]+parts))+u'\n'
+
+
+def get_from_buffer(fields, prefix='', indent_level=2):
+    """
+    Emit code that collects values from buf:offset, updating offset as progressing.
+    """
+    code = []
+    def emit(fmt, *args):
+        args = list(args)
+        code.append(u'    '*indent_level)
+        assert fmt.count('%s') == len(args)
+        for arg in args:
+            fmt = fmt.replace('%s', str(arg), 1)
+        code.append(fmt)
+        code.append('\n')
+
+
+    # actually go and load it
+
+    bits = []
+    ln = {'ln': 0}  # so I can modify from outside
+    to_struct = []
+
+    def emit_bits():
+        if all(n == '_' for n in bits):
+            # everything is reserved, lol
+            emit('offset += 1')
+        else:
+            emit("_bit, = struct.unpack_from('!B', buf, offset)")
+
+            for multiplier, bit in enumerate(bits):
+                if bit != '_':
+                    emit("%s = bool(_bit >> %s)", bit, multiplier)
+            emit('offset += 1')
+
+        del bits[:]
+
+    def emit_structures():
+        fffnames = [a for a, b in to_struct if a != u'_'] # skip reserved
+        ffffmts = [b for a, b in to_struct]
+        emit("%s, = struct.unpack_from('!%s', buf, offset)", u', '.join(fffnames), u''.join(ffffmts))
+        emit("offset += %s", ln['ln'])
+        ln['ln'] = 0
+        del to_struct[:]
+
+    for field in fields:
+        fieldname = prefix+format_field_name(field.name)
+
+        if (len(bits) > 0) and (field.basic_type != 'bit'):
+            emit_bits()
+
+        # offset is current start
+        # length is length to read
+        if BASIC_TYPES[field.basic_type][0] is not None:
+            # static type shit has
+            if field.reserved:
+                to_struct.append((u'_', '%sx' % (BASIC_TYPES[field.basic_type][0],)))
+            else:
+                to_struct.append((fieldname, BASIC_TYPES[field.basic_type][1]))
+            ln['ln'] += BASIC_TYPES[field.basic_type][0]
+        elif field.basic_type == u'bit':
+            bits.append('_' if field.reserved else fieldname)
+        elif field.basic_type == u'table': # oh my god
+            emit("%s, delta = deframe_table(buf, offset)", fieldname)
+            emit("offset += delta")
+        else:   # longstr or shortstr
+            f_q, f_l = ('L', 4) if field.basic_type == u'longstr' else ('B', 1)
+            to_struct.append(('s_len', f_q))
+            ln['ln'] += f_l
+            emit_structures()
+            if field.reserved:
+                emit("offset += s_len # reserved field!")
+            else:
+                emit("%s = buf[offset:offset+s_len]", fieldname)
+                emit("offset += s_len")
+
+        # check bits for overflow
+        if len(bits) == 8:
+            emit_bits()
+
+    if len(bits) > 0:
+        emit_bits()
+    if len(to_struct) > 0:
+        emit_structures()
+
+    return u''.join(code)
+
+
+def get_serializer(fields, prefix='', indent_level=2):
+    """
+    Emit code that serializes the fields into buf at offset
+
+    :param fields: list of Field instances
+    :param prefix: pass "self." is inside a class
+    :return: block of code that does that
+    """
+    code = []
+
+    def emit(fmt, *args):
+        args = list(args)
+        code.append(u'    '*indent_level)
+        while len(args) > 0:
+            fmt = fmt.replace('%s', args[0], 1)
+            del args[0]
+        code.append(fmt)
+        code.append('\n')
+
+    formats = []
+    format_args = []
+    bits = []
+
+    def emit_bits():
+        p = []
+        formats.append('B')
+        if all(bit_name == 'False' for bit_name in bits):
+            format_args.append('0')
+        else:
+            for bit_name, modif in zip(bits, range(8)):
+                if bit_name != 'False':
+                    p.append('('+bit_name+' << %s)' % (modif, ))  # yes you can << bools
+            format_args.append(u' | '.join(p))
+        del bits[:]
+
+    def emit_single_struct_pack():
+        emit("buf.write(struct.pack('!%s', %s))", u''.join(formats), u', '.join(format_args))
+        del formats[:]
+        del format_args[:]
+
+    for field in fields:
+        nam = prefix+format_field_name(field.name)
+
+        if (len(bits) == 8) or ((len(bits) > 0) and field.basic_type != 'bit'):
+            emit_bits()
+
+        if field.basic_type == 'bit':
+            if field.reserved:
+                bits.append("False")
+            else:
+                bits.append(nam)
+        elif field.basic_type in ('shortstr', 'longstr'):
+            formats.append('B' if field.basic_type == 'shortstr' else 'I')
+            format_args.append('len('+nam+')')
+            emit_single_struct_pack()
+            emit('buf.write(%s)', nam)
+        elif field.basic_type == 'table':
+            emit('enframe_table(buf, %s)', nam)
+        else:
+            formats.append(BASIC_TYPES[field.basic_type][1])
+            format_args.append(nam)
+
+    if len(bits) > 0:
+        emit_bits()
+    if len(formats) > 0:
+        emit_single_struct_pack()
+
+    emit('')    # eol
+
+    return u''.join(code)
+
diff --git a/coolamqp/uplink/frames/compilation/utilities.py b/coolamqp/framing/compilation/utilities.py
similarity index 77%
rename from coolamqp/uplink/frames/compilation/utilities.py
rename to coolamqp/framing/compilation/utilities.py
index 90c8c22..f847007 100644
--- a/coolamqp/uplink/frames/compilation/utilities.py
+++ b/coolamqp/framing/compilation/utilities.py
@@ -1,25 +1,27 @@
 # coding=UTF-8
 from __future__ import absolute_import, division, print_function
+
+import math
 from collections import namedtuple
+
 import six
-import math
 
-from coolamqp.uplink.frames.base import BASIC_TYPES, DYNAMIC_BASIC_TYPES
+from coolamqp.framing.base import BASIC_TYPES, DYNAMIC_BASIC_TYPES
 
 # docs may be None
 
+
+
 Constant = namedtuple('Constant', ('name', 'value', 'kind', 'docs'))  # kind is AMQP constant class # value is int
 Field = namedtuple('Field', ('name', 'type', 'label', 'docs', 'reserved', 'basic_type')) # reserved is bool
 Method = namedtuple('Method', ('name', 'synchronous', 'index', 'label', 'docs', 'fields', 'response',
                                'sent_by_client', 'sent_by_server', 'constant'))
         # synchronous is bool, constant is bool
         # repponse is a list of method.name
-Property = namedtuple('Property', ('name', 'type', 'label', 'basic_type', 'reserved'))
-Class_ = namedtuple('Class_', ('name', 'index', 'docs', 'methods', 'content_properties'))   # label is int
+Class_ = namedtuple('Class_', ('name', 'index', 'docs', 'methods', 'properties'))   # label is int
 Domain = namedtuple('Domain', ('name', 'type', 'elementary'))   # elementary is bool
 
 
-
 class Method(object):
     def __init__(self, name, synchronous, index, label, docs, fields, response, sent_by_client, sent_by_server):
         self.name = name
@@ -49,36 +51,34 @@ class Method(object):
                 body.append(eval(BASIC_TYPES[field.basic_type][2]))
         return b''.join(body)
 
-    def get_size(self, domain_to_type=None): # for static methods
-        size = 0
-        bits = 0
+    def is_static(self, domain_to_type=None):    # is size constant?
         for field in self.fields:
+            if field.basic_type in DYNAMIC_BASIC_TYPES:
+                return False
+        return True
 
-            if (bits > 0) and (field.basic_type != 'bit'):  # sync bits
-                size += int(math.ceil(bits / 8))
-                bits = 0
 
-            if BASIC_TYPES[field.basic_type][0] is None:
-                if field.basic_type == 'bit':
-                    bits += 1
-                else:
-                    size += len(BASIC_TYPES[field.basic_type][2])   # default minimum entry
-            else:
-                size += BASIC_TYPES[field.basic_type][0]
+def get_size(fields):   # assume all fields have static length
+    size = 0
+    bits = 0
+    for field in fields:
 
-        if bits > 0:    # sync bits
+        if (bits > 0) and (field.basic_type != 'bit'):  # sync bits
             size += int(math.ceil(bits / 8))
+            bits = 0
 
-        return size
+        if BASIC_TYPES[field.basic_type][0] is None:
+            if field.basic_type == 'bit':
+                bits += 1
+            else:
+                size += len(BASIC_TYPES[field.basic_type][2])   # default minimum entry
+        else:
+            size += BASIC_TYPES[field.basic_type][0]
 
-    def is_static(self, domain_to_type=None):    # is size constant?
-        for field in self.fields:
-            if field.basic_type in DYNAMIC_BASIC_TYPES:
-                return False
-        return True
+    if bits > 0:    # sync bits
+        size += int(math.ceil(bits / 8))
 
-    def get_minimum_size(self, domain_to_type=None):
-        return self.get_size()
+    return size
 
 
 def get_docs(elem):
@@ -98,7 +98,7 @@ def for_domain(elem):
     return Domain(six.text_type(a['name']), a['type'], a['type'] == a['name'])
 
 
-def for_method_field(elem): # for <field> in <method>
+def for_field(elem): # for <field> in <method>
     a = elem.attrib
     return Field(six.text_type(a['name']), a['domain'] if 'domain' in a else a['type'],
                  a.get('label', None),
@@ -106,16 +106,10 @@ def for_method_field(elem): # for <field> in <method>
                  a.get('reserved', '0') == '1',
                  None)
 
-
-def for_content_property(elem):
-    a = elem.attrib
-    return Property(a['name'], a['domain'], a.get('label', ''), None, 'reserved' in a['name'])
-
-
 def for_method(elem):       # for <method>
     a = elem.attrib
     return Method(six.text_type(a['name']), bool(int(a.get('synchronous', '0'))), int(a['index']), a['label'], get_docs(elem),
-                  [for_method_field(fie) for fie in elem.getchildren() if fie.tag == 'field'],
+                  [for_field(fie) for fie in elem.getchildren() if fie.tag == 'field'],
                   [e.attrib['name'] for e in elem.findall('response')],
                   # if chassis=server that means server has to accept it
                   any([e.attrib.get('name', '') == 'server' for e in elem.getchildren() if e.tag == 'chassis']),
@@ -126,7 +120,7 @@ def for_class(elem):        # for <class>
     a = elem.attrib
     methods = sorted([for_method(me) for me in elem.getchildren() if me.tag == 'method'], key=lambda m: (m.name.strip('-')[0], -len(m.response)))
     return Class_(six.text_type(a['name']), int(a['index']), get_docs(elem) or a['label'], methods,
-                  [for_content_property(e) for e in elem.getchildren() if e.tag == 'field'])
+                  [for_field(e) for e in elem.getchildren() if e.tag == 'field'])
 
 def for_constant(elem):     # for <constant>
     a = elem.attrib
@@ -143,30 +137,31 @@ def get_domains(xml):
     return [for_domain(e) for e in xml.findall('domain')]
 
 
-def a_text(callable):
+def as_unicode(callable):
     def roll(*args, **kwargs):
         return six.text_type(callable(*args, **kwargs))
     return roll
 
-def byname(list_of_things):
+def to_dict_by_name(list_of_things):
     return dict((a.name, a) for a in list_of_things)
 
-@a_text
+@as_unicode
 def name_class(classname):
     """Change AMQP class name to Python class name"""
     return classname.capitalize()
 
-@a_text
-def name_method(methodname):
+@as_unicode
+def format_method_class_name(methodname):
     if '-' in methodname:
         i = methodname.find('-')
         return methodname[0:i].capitalize() + methodname[i+1].upper() + methodname[i+2:]
     else:
         return methodname.capitalize()
 
-@a_text
-def name_field(field):
-    if field in ('global', ):
+@as_unicode
+def format_field_name(field):
+    print(repr(field))
+    if field in (u'global', u'type'):
         field = field + '_'
     return field.replace('-', '_')
 
@@ -180,7 +175,7 @@ def frepr(p, sop=six.text_type):
     else:
         return s
 
-def as_nice_escaped_string(p):
+def to_code_binary(p):
     body = []
     for q in p:
         z = (hex(ord(q))[2:].upper())
@@ -189,16 +184,16 @@ def as_nice_escaped_string(p):
         body.append(u'\\x' + z)
     return u"b'"+(u''.join(body))+u"'"
 
-def normname(p):
+def pythonify_name(p):
     return p.strip().replace('-', '_').upper()
 
-def infertype(p):
+def try_to_int(p):
     try:
         return int(p)
     except ValueError:
         return p
 
-def doxify(label, doc, prefix=4, blank=True): # output a full docstring section
+def to_docstring(label, doc, prefix=4, blank=True): # output a full docstring section
     label = [] if label is None else [label]
     doc = [] if doc is None else [q.strip() for q in doc.split(u'\n') if len(q.strip()) > 0]
     pre = u' '*prefix
diff --git a/coolamqp/uplink/frames/definitions.py b/coolamqp/framing/definitions.py
similarity index 59%
rename from coolamqp/uplink/frames/definitions.py
rename to coolamqp/framing/definitions.py
index b369497..c7a5d57 100644
--- a/coolamqp/uplink/frames/definitions.py
+++ b/coolamqp/framing/definitions.py
@@ -4,16 +4,19 @@ from __future__ import print_function, absolute_import
 A Python version of the AMQP machine-readable specification.
 
 Generated automatically by CoolAMQP from AMQP machine-readable specification.
-See coolamqp.uplink.frames.compilation for the tool
+See coolamqp.uplink.framing.compilation for the tool
 
 AMQP is copyright (c) 2016 OASIS
 CoolAMQP is copyright (c) 2016 DMS Serwis s.c.
 """
 
 import struct
+import collections
 
-from coolamqp.uplink.frames.base_definitions import AMQPClass, AMQPMethodPayload, AMQPContentPropertyList
-from coolamqp.uplink.frames.field_table import enframe_table, deframe_table, frame_table_size
+from coolamqp.framing.base_definitions import AMQPClass, AMQPMethodPayload, AMQPContentPropertyList
+from coolamqp.framing.field_table import enframe_table, deframe_table, frame_table_size
+
+Field = collections.namedtuple('Field', ('name', 'type', 'reserved'))
 
 # Core constants
 FRAME_METHOD = 1
@@ -104,37 +107,6 @@ class Connection(AMQPClass):
     INDEX = 10
 
 
-class ConnectionContentPropertyList(AMQPContentPropertyList):
-    """
-    The connection class provides methods for a client to establish a network connection to
-    
-    a server, and for both peers to operate the connection thereafter.
-    """
-    CLASS_NAME = u'connection'
-    CLASS_INDEX = 10
-    CLASS = Connection
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-    ]
-
-    def __init__(self):
-        """
-        Create the property list.
-
-        """
-
-    def write_arguments(self, buf):
-        pass # this has a frame, but its only default shortstrs
-
-    @staticmethod
-    def from_buffer(buf, start_offset):
-        return ConnectionContentPropertyList()
-
-    def get_size(self):
-        return 0
-
-
 class ConnectionClose(AMQPMethodPayload):
     """
     Request a connection close
@@ -144,34 +116,23 @@ class ConnectionClose(AMQPMethodPayload):
     a specific method, i.e. an exception. When a close is due to an exception, the
     sender provides the class and method id of the method which caused the exception.
     """
-    CLASS = Connection
-    NAME = u'close'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.close'
+    NAME = u'connection.close'
 
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
-
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 50
-    METHOD_INDEX_BINARY = b'\x32'
+    INDEX = (10, 50)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x32'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ConnectionCloseOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 13 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, True
+    REPLY_WITH = [ConnectionCloseOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reply-code', u'reply-code', u'short', False), 
-        (u'reply-text', u'reply-text', u'shortstr', False), 
-        (u'class-id', u'class-id', u'short', False),  # failing method class
-        (u'method-id', u'method-id', u'short', False),  # failing method ID
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reply-code', u'short', reserved=False),
+        Field(u'reply-text', u'shortstr', reserved=False),
+        Field(u'class-id', u'short', reserved=False),
+        Field(u'method-id', u'short', reserved=False),
     ]
 
     def __init__(self, reply_code, reply_text, class_id, method_id):
@@ -197,14 +158,13 @@ class ConnectionClose(AMQPMethodPayload):
         buf.write(struct.pack('!HB', self.reply_code, len(self.reply_text)))
         buf.write(self.reply_text)
         buf.write(struct.pack('!HH', self.class_id, self.method_id))
-
+        
     def get_size(self):
-        return len(self.reply_text) + 7
+        return 7 + len(self.reply_text)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionClose.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         reply_code, s_len, = struct.unpack_from('!HB', buf, offset)
         offset += 3
         reply_text = buf[offset:offset+s_len]
@@ -221,26 +181,13 @@ class ConnectionCloseOk(AMQPMethodPayload):
     This method confirms a Connection.Close method and tells the recipient that it is
     safe to release resources for the connection and close the socket.
     """
-    CLASS = Connection
-    NAME = u'close-ok'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.close-ok'
+    NAME = u'connection.close-ok'
 
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
-
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 51
-    METHOD_INDEX_BINARY = b'\x33'
+    INDEX = (10, 51)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x33'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -252,10 +199,10 @@ class ConnectionCloseOk(AMQPMethodPayload):
         Create frame connection.close-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return ConnectionCloseOk()
 
 
@@ -268,33 +215,22 @@ class ConnectionOpen(AMQPMethodPayload):
     The server may apply arbitrary limits per virtual host, such as the number
     of each type of entity that may be used, per connection and/or in total.
     """
-    CLASS = Connection
-    NAME = u'open'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.open'
-
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
+    NAME = u'connection.open'
 
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 40
-    METHOD_INDEX_BINARY = b'\x28'
+    INDEX = (10, 40)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x28'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ConnectionOpenOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 15 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [ConnectionOpenOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'virtual-host', u'path', u'shortstr', False),  # virtual host name
-        (u'reserved-1', u'shortstr', u'shortstr', True), 
-        (u'reserved-2', u'bit', u'bit', True), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'virtual-host', u'shortstr', reserved=False),
+        Field(u'reserved-1', u'shortstr', reserved=True),
+        Field(u'reserved-2', u'bit', reserved=True),
     ]
 
     def __init__(self, virtual_host):
@@ -310,23 +246,23 @@ class ConnectionOpen(AMQPMethodPayload):
     def write_arguments(self, buf):
         buf.write(struct.pack('!B', len(self.virtual_host)))
         buf.write(self.virtual_host)
-        buf.write(b'\x00')
-        buf.write(struct.pack('!B', ))
-
+        buf.write(struct.pack('!B', len(self.reserved_1)))
+        buf.write(self.reserved_1)
+        buf.write(struct.pack('!B', 0))
+        
     def get_size(self):
-        return len(self.virtual_host) + 3
+        return 3 + len(self.virtual_host)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionOpen.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
         virtual_host = buf[offset:offset+s_len]
         offset += s_len
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
-        offset += s_len
+        offset += s_len # reserved field!
         offset += 1
         return ConnectionOpen(virtual_host)
 
@@ -337,33 +273,22 @@ class ConnectionOpenOk(AMQPMethodPayload):
     
     This method signals to the client that the connection is ready for use.
     """
-    CLASS = Connection
-    NAME = u'open-ok'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.open-ok'
+    NAME = u'connection.open-ok'
 
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
-
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 41
-    METHOD_INDEX_BINARY = b'\x29'
+    INDEX = (10, 41)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x29'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 7 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
     STATIC_CONTENT = b'\x00\x00\x00\x04\x0A\x29\x00\xCE'  # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END
     RESPONSE_TO = ConnectionOpen # this is sent in response to connection.open
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'shortstr', u'shortstr', True), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'shortstr', reserved=True),
     ]
 
     def __init__(self):
@@ -371,10 +296,13 @@ class ConnectionOpenOk(AMQPMethodPayload):
         Create frame connection.open-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
+        s_len, = struct.unpack_from('!B', buf, offset)
+        offset += 1
+        offset += s_len # reserved field!
         return ConnectionOpenOk()
 
 
@@ -386,35 +314,24 @@ class ConnectionStart(AMQPMethodPayload):
     protocol version that the server proposes, along with a list of security mechanisms
     which the client can use for authentication.
     """
-    CLASS = Connection
-    NAME = u'start'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.start'
-
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
+    NAME = u'connection.start'
 
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 10
-    METHOD_INDEX_BINARY = b'\x0A'
+    INDEX = (10, 10)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x0A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ConnectionStartOk]
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 59 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = [ConnectionStartOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'version-major', u'octet', u'octet', False),  # protocol major version
-        (u'version-minor', u'octet', u'octet', False),  # protocol minor version
-        (u'server-properties', u'peer-properties', u'table', False),  # server properties
-        (u'mechanisms', u'longstr', u'longstr', False),  # available security mechanisms
-        (u'locales', u'longstr', u'longstr', False),  # available message locales
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'version-major', u'octet', reserved=False),
+        Field(u'version-minor', u'octet', reserved=False),
+        Field(u'server-properties', u'table', reserved=False),
+        Field(u'mechanisms', u'longstr', reserved=False),
+        Field(u'locales', u'longstr', reserved=False),
     ]
 
     def __init__(self, version_major, version_minor, server_properties, mechanisms, locales):
@@ -435,7 +352,7 @@ class ConnectionStart(AMQPMethodPayload):
             "version", giving the name of the server version, "platform", giving the name
             of the operating system, "copyright", if appropriate, and "information", giving
             other general information.
-        :type server_properties: table. See coolamqp.uplink.frames.field_table (peer-properties in AMQP)
+        :type server_properties: table. See coolamqp.uplink.framing.field_table (peer-properties in AMQP)
         :param mechanisms: Available security mechanisms
             A list of the security mechanisms that the server supports, delimited by spaces.
         :type mechanisms: binary type (longstr in AMQP)
@@ -451,20 +368,18 @@ class ConnectionStart(AMQPMethodPayload):
         self.locales = locales
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!BB', self.version_major, self.version_minor))
         enframe_table(buf, self.server_properties)
-        buf.write(struct.pack('!L', len(self.mechanisms)))
+        buf.write(struct.pack('!BBI', self.version_major, self.version_minor, len(self.mechanisms)))
         buf.write(self.mechanisms)
-        buf.write(struct.pack('!L', len(self.locales)))
+        buf.write(struct.pack('!I', len(self.locales)))
         buf.write(self.locales)
-
+        
     def get_size(self):
-        return frame_table_size(self.server_properties) + len(self.mechanisms) + len(self.locales) + 14
+        return 14 + frame_table_size(self.server_properties) + len(self.mechanisms) + len(self.locales)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionStart.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         server_properties, delta = deframe_table(buf, offset)
         offset += delta
         version_major, version_minor, s_len, = struct.unpack_from('!BBL', buf, offset)
@@ -486,31 +401,20 @@ class ConnectionSecure(AMQPMethodPayload):
     received sufficient information to authenticate each other. This method challenges
     the client to provide more information.
     """
-    CLASS = Connection
-    NAME = u'secure'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.secure'
-
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
+    NAME = u'connection.secure'
 
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 20
-    METHOD_INDEX_BINARY = b'\x14'
+    INDEX = (10, 20)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x14'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ConnectionSecureOk]
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 19 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = [ConnectionSecureOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'challenge', u'longstr', u'longstr', False),  # security challenge data
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'challenge', u'longstr', reserved=False),
     ]
 
     def __init__(self, challenge):
@@ -525,16 +429,15 @@ class ConnectionSecure(AMQPMethodPayload):
         self.challenge = challenge
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!L', len(self.challenge)))
+        buf.write(struct.pack('!I', len(self.challenge)))
         buf.write(self.challenge)
-
+        
     def get_size(self):
-        return len(self.challenge) + 4
+        return 4 + len(self.challenge)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionSecure.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!L', buf, offset)
         offset += 4
         challenge = buf[offset:offset+s_len]
@@ -548,35 +451,24 @@ class ConnectionStartOk(AMQPMethodPayload):
     
     This method selects a SASL security mechanism.
     """
-    CLASS = Connection
-    NAME = u'start-ok'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.start-ok'
-
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
+    NAME = u'connection.start-ok'
 
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 11
-    METHOD_INDEX_BINARY = b'\x0B'
+    INDEX = (10, 11)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x0B'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 52 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = ConnectionStart # this is sent in response to connection.start
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'client-properties', u'peer-properties', u'table', False),  # client properties
-        (u'mechanism', u'shortstr', u'shortstr', False),  # selected security mechanism
-        (u'response', u'longstr', u'longstr', False),  # security response data
-        (u'locale', u'shortstr', u'shortstr', False),  # selected message locale
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'client-properties', u'table', reserved=False),
+        Field(u'mechanism', u'shortstr', reserved=False),
+        Field(u'response', u'longstr', reserved=False),
+        Field(u'locale', u'shortstr', reserved=False),
     ]
 
     def __init__(self, client_properties, mechanism, response, locale):
@@ -588,7 +480,7 @@ class ConnectionStartOk(AMQPMethodPayload):
             of the client product, "version", giving the name of the client version, "platform",
             giving the name of the operating system, "copyright", if appropriate, and
             "information", giving other general information.
-        :type client_properties: table. See coolamqp.uplink.frames.field_table (peer-properties in AMQP)
+        :type client_properties: table. See coolamqp.uplink.framing.field_table (peer-properties in AMQP)
         :param mechanism: Selected security mechanism
             A single security mechanisms selected by the client, which must be one of those
             specified by the server.
@@ -611,18 +503,17 @@ class ConnectionStartOk(AMQPMethodPayload):
         enframe_table(buf, self.client_properties)
         buf.write(struct.pack('!B', len(self.mechanism)))
         buf.write(self.mechanism)
-        buf.write(struct.pack('!L', len(self.response)))
+        buf.write(struct.pack('!I', len(self.response)))
         buf.write(self.response)
         buf.write(struct.pack('!B', len(self.locale)))
         buf.write(self.locale)
-
+        
     def get_size(self):
-        return frame_table_size(self.client_properties) + len(self.mechanism) + len(self.response) + len(self.locale) + 10
+        return 10 + frame_table_size(self.client_properties) + len(self.mechanism) + len(self.response) + len(self.locale)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionStartOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         client_properties, delta = deframe_table(buf, offset)
         offset += delta
         s_len, = struct.unpack_from('!B', buf, offset)
@@ -647,32 +538,21 @@ class ConnectionSecureOk(AMQPMethodPayload):
     This method attempts to authenticate, passing a block of SASL data for the security
     mechanism at the server side.
     """
-    CLASS = Connection
-    NAME = u'secure-ok'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.secure-ok'
-
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
+    NAME = u'connection.secure-ok'
 
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 21
-    METHOD_INDEX_BINARY = b'\x15'
+    INDEX = (10, 21)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x15'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 19 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = ConnectionSecure # this is sent in response to connection.secure
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'response', u'longstr', u'longstr', False),  # security response data
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'response', u'longstr', reserved=False),
     ]
 
     def __init__(self, response):
@@ -687,16 +567,15 @@ class ConnectionSecureOk(AMQPMethodPayload):
         self.response = response
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!L', len(self.response)))
+        buf.write(struct.pack('!I', len(self.response)))
         buf.write(self.response)
-
+        
     def get_size(self):
-        return len(self.response) + 4
+        return 4 + len(self.response)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionSecureOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!L', buf, offset)
         offset += 4
         response = buf[offset:offset+s_len]
@@ -711,33 +590,22 @@ class ConnectionTune(AMQPMethodPayload):
     This method proposes a set of connection configuration values to the client. The
     client can accept and/or adjust these.
     """
-    CLASS = Connection
-    NAME = u'tune'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.tune'
-
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
+    NAME = u'connection.tune'
 
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 30
-    METHOD_INDEX_BINARY = b'\x1E'
+    INDEX = (10, 30)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x1E'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ConnectionTuneOk]
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 8 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = [ConnectionTuneOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'channel-max', u'short', u'short', False),  # proposed maximum channels
-        (u'frame-max', u'long', u'long', False),  # proposed maximum frame size
-        (u'heartbeat', u'short', u'short', False),  # desired heartbeat delay
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'channel-max', u'short', reserved=False),
+        Field(u'frame-max', u'long', reserved=False),
+        Field(u'heartbeat', u'short', reserved=False),
     ]
 
     def __init__(self, channel_max, frame_max, heartbeat):
@@ -765,15 +633,15 @@ class ConnectionTune(AMQPMethodPayload):
 
     def write_arguments(self, buf):
         buf.write(struct.pack('!HIH', self.channel_max, self.frame_max, self.heartbeat))
-
+        
     def get_size(self):
         return 8
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionTune.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         channel_max, frame_max, heartbeat, = struct.unpack_from('!HIH', buf, offset)
+        offset += 8
         return ConnectionTune(channel_max, frame_max, heartbeat)
 
 
@@ -784,34 +652,23 @@ class ConnectionTuneOk(AMQPMethodPayload):
     This method sends the client's connection tuning parameters to the server.
     Certain fields are negotiated, others provide capability information.
     """
-    CLASS = Connection
-    NAME = u'tune-ok'
-    CLASSNAME = u'connection'
-    FULLNAME = u'connection.tune-ok'
+    NAME = u'connection.tune-ok'
 
-    CONTENT_PROPERTY_LIST = ConnectionContentPropertyList
-
-    CLASS_INDEX = 10
-    CLASS_INDEX_BINARY = b'\x0A'
-    METHOD_INDEX = 31
-    METHOD_INDEX_BINARY = b'\x1F'
+    INDEX = (10, 31)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x0A\x1F'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 8 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = ConnectionTune # this is sent in response to connection.tune
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'channel-max', u'short', u'short', False),  # negotiated maximum channels
-        (u'frame-max', u'long', u'long', False),  # negotiated maximum frame size
-        (u'heartbeat', u'short', u'short', False),  # desired heartbeat delay
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'channel-max', u'short', reserved=False),
+        Field(u'frame-max', u'long', reserved=False),
+        Field(u'heartbeat', u'short', reserved=False),
     ]
 
     def __init__(self, channel_max, frame_max, heartbeat):
@@ -839,15 +696,15 @@ class ConnectionTuneOk(AMQPMethodPayload):
 
     def write_arguments(self, buf):
         buf.write(struct.pack('!HIH', self.channel_max, self.frame_max, self.heartbeat))
-
+        
     def get_size(self):
         return 8
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ConnectionTuneOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         channel_max, frame_max, heartbeat, = struct.unpack_from('!HIH', buf, offset)
+        offset += 8
         return ConnectionTuneOk(channel_max, frame_max, heartbeat)
 
 
@@ -861,37 +718,6 @@ class Channel(AMQPClass):
     INDEX = 20
 
 
-class ChannelContentPropertyList(AMQPContentPropertyList):
-    """
-    The channel class provides methods for a client to establish a channel to a
-    
-    server and for both peers to operate the channel thereafter.
-    """
-    CLASS_NAME = u'channel'
-    CLASS_INDEX = 20
-    CLASS = Channel
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-    ]
-
-    def __init__(self):
-        """
-        Create the property list.
-
-        """
-
-    def write_arguments(self, buf):
-        pass # this has a frame, but its only default shortstrs
-
-    @staticmethod
-    def from_buffer(buf, start_offset):
-        return ChannelContentPropertyList()
-
-    def get_size(self):
-        return 0
-
-
 class ChannelClose(AMQPMethodPayload):
     """
     Request a channel close
@@ -901,34 +727,23 @@ class ChannelClose(AMQPMethodPayload):
     method, i.e. an exception. When a close is due to an exception, the sender provides
     the class and method id of the method which caused the exception.
     """
-    CLASS = Channel
-    NAME = u'close'
-    CLASSNAME = u'channel'
-    FULLNAME = u'channel.close'
-
-    CONTENT_PROPERTY_LIST = ChannelContentPropertyList
+    NAME = u'channel.close'
 
-    CLASS_INDEX = 20
-    CLASS_INDEX_BINARY = b'\x14'
-    METHOD_INDEX = 40
-    METHOD_INDEX_BINARY = b'\x28'
+    INDEX = (20, 40)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x14\x28'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ChannelCloseOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 13 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, True
+    REPLY_WITH = [ChannelCloseOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reply-code', u'reply-code', u'short', False), 
-        (u'reply-text', u'reply-text', u'shortstr', False), 
-        (u'class-id', u'class-id', u'short', False),  # failing method class
-        (u'method-id', u'method-id', u'short', False),  # failing method ID
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reply-code', u'short', reserved=False),
+        Field(u'reply-text', u'shortstr', reserved=False),
+        Field(u'class-id', u'short', reserved=False),
+        Field(u'method-id', u'short', reserved=False),
     ]
 
     def __init__(self, reply_code, reply_text, class_id, method_id):
@@ -954,14 +769,13 @@ class ChannelClose(AMQPMethodPayload):
         buf.write(struct.pack('!HB', self.reply_code, len(self.reply_text)))
         buf.write(self.reply_text)
         buf.write(struct.pack('!HH', self.class_id, self.method_id))
-
+        
     def get_size(self):
-        return len(self.reply_text) + 7
+        return 7 + len(self.reply_text)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ChannelClose.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         reply_code, s_len, = struct.unpack_from('!HB', buf, offset)
         offset += 3
         reply_text = buf[offset:offset+s_len]
@@ -978,26 +792,13 @@ class ChannelCloseOk(AMQPMethodPayload):
     This method confirms a Channel.Close method and tells the recipient that it is safe
     to release resources for the channel.
     """
-    CLASS = Channel
-    NAME = u'close-ok'
-    CLASSNAME = u'channel'
-    FULLNAME = u'channel.close-ok'
-
-    CONTENT_PROPERTY_LIST = ChannelContentPropertyList
+    NAME = u'channel.close-ok'
 
-    CLASS_INDEX = 20
-    CLASS_INDEX_BINARY = b'\x14'
-    METHOD_INDEX = 41
-    METHOD_INDEX_BINARY = b'\x29'
+    INDEX = (20, 41)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x14\x29'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -1009,10 +810,10 @@ class ChannelCloseOk(AMQPMethodPayload):
         Create frame channel.close-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return ChannelCloseOk()
 
 
@@ -1026,31 +827,20 @@ class ChannelFlow(AMQPMethodPayload):
     it can process. Note that this method is not intended for window control. It does
     not affect contents returned by Basic.Get-Ok methods.
     """
-    CLASS = Channel
-    NAME = u'flow'
-    CLASSNAME = u'channel'
-    FULLNAME = u'channel.flow'
-
-    CONTENT_PROPERTY_LIST = ChannelContentPropertyList
+    NAME = u'channel.flow'
 
-    CLASS_INDEX = 20
-    CLASS_INDEX_BINARY = b'\x14'
-    METHOD_INDEX = 20
-    METHOD_INDEX_BINARY = b'\x14'
+    INDEX = (20, 20)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x14\x14'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ChannelFlowOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 1 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, True
+    REPLY_WITH = [ChannelFlowOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'active', u'bit', u'bit', False),  # start/stop content frames
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'active', u'bit', reserved=False),
     ]
 
     def __init__(self, active):
@@ -1065,17 +855,17 @@ class ChannelFlow(AMQPMethodPayload):
         self.active = active
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!B', (int(self.active) << 0)))
-
+        buf.write(struct.pack('!B', (self.active << 0)))
+        
     def get_size(self):
         return 1
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ChannelFlow.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        _bit_0, = struct.unpack_from('!B', buf, offset)
-        active = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        active = bool(_bit >> 0)
+        offset += 1
         return ChannelFlow(active)
 
 
@@ -1085,32 +875,21 @@ class ChannelFlowOk(AMQPMethodPayload):
     
     Confirms to the peer that a flow command was received and processed.
     """
-    CLASS = Channel
-    NAME = u'flow-ok'
-    CLASSNAME = u'channel'
-    FULLNAME = u'channel.flow-ok'
-
-    CONTENT_PROPERTY_LIST = ChannelContentPropertyList
+    NAME = u'channel.flow-ok'
 
-    CLASS_INDEX = 20
-    CLASS_INDEX_BINARY = b'\x14'
-    METHOD_INDEX = 21
-    METHOD_INDEX_BINARY = b'\x15'
+    INDEX = (20, 21)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x14\x15'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 1 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = ChannelFlow # this is sent in response to channel.flow
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'active', u'bit', u'bit', False),  # current flow setting
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'active', u'bit', reserved=False),
     ]
 
     def __init__(self, active):
@@ -1125,17 +904,17 @@ class ChannelFlowOk(AMQPMethodPayload):
         self.active = active
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!B', (int(self.active) << 0)))
-
+        buf.write(struct.pack('!B', (self.active << 0)))
+        
     def get_size(self):
         return 1
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ChannelFlowOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        _bit_0, = struct.unpack_from('!B', buf, offset)
-        active = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        active = bool(_bit >> 0)
+        offset += 1
         return ChannelFlowOk(active)
 
 
@@ -1145,32 +924,21 @@ class ChannelOpen(AMQPMethodPayload):
     
     This method opens a channel to the server.
     """
-    CLASS = Channel
-    NAME = u'open'
-    CLASSNAME = u'channel'
-    FULLNAME = u'channel.open'
-
-    CONTENT_PROPERTY_LIST = ChannelContentPropertyList
+    NAME = u'channel.open'
 
-    CLASS_INDEX = 20
-    CLASS_INDEX_BINARY = b'\x14'
-    METHOD_INDEX = 10
-    METHOD_INDEX_BINARY = b'\x0A'
+    INDEX = (20, 10)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x14\x0A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ChannelOpenOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 7 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [ChannelOpenOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
     STATIC_CONTENT = b'\x00\x00\x00\x05\x14\x0A\x00\xCE'  # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'shortstr', u'shortstr', True), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'shortstr', reserved=True),
     ]
 
     def __init__(self):
@@ -1178,10 +946,13 @@ class ChannelOpen(AMQPMethodPayload):
         Create frame channel.open
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
+        s_len, = struct.unpack_from('!B', buf, offset)
+        offset += 1
+        offset += s_len # reserved field!
         return ChannelOpen()
 
 
@@ -1191,33 +962,22 @@ class ChannelOpenOk(AMQPMethodPayload):
     
     This method signals to the client that the channel is ready for use.
     """
-    CLASS = Channel
-    NAME = u'open-ok'
-    CLASSNAME = u'channel'
-    FULLNAME = u'channel.open-ok'
+    NAME = u'channel.open-ok'
 
-    CONTENT_PROPERTY_LIST = ChannelContentPropertyList
-
-    CLASS_INDEX = 20
-    CLASS_INDEX_BINARY = b'\x14'
-    METHOD_INDEX = 11
-    METHOD_INDEX_BINARY = b'\x0B'
+    INDEX = (20, 11)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x14\x0B'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 19 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
     STATIC_CONTENT = b'\x00\x00\x00\x05\x14\x0B\x00\x00\x00\x00\xCE'  # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END
     RESPONSE_TO = ChannelOpen # this is sent in response to channel.open
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'longstr', u'longstr', True), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'longstr', reserved=True),
     ]
 
     def __init__(self):
@@ -1225,10 +985,13 @@ class ChannelOpenOk(AMQPMethodPayload):
         Create frame channel.open-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
+        s_len, = struct.unpack_from('!L', buf, offset)
+        offset += 4
+        offset += s_len # reserved field!
         return ChannelOpenOk()
 
 
@@ -1242,37 +1005,6 @@ class Exchange(AMQPClass):
     INDEX = 40
 
 
-class ExchangeContentPropertyList(AMQPContentPropertyList):
-    """
-    Exchanges match and distribute messages across queues. exchanges can be configured in
-    
-    the server or declared at runtime.
-    """
-    CLASS_NAME = u'exchange'
-    CLASS_INDEX = 40
-    CLASS = Exchange
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-    ]
-
-    def __init__(self):
-        """
-        Create the property list.
-
-        """
-
-    def write_arguments(self, buf):
-        pass # this has a frame, but its only default shortstrs
-
-    @staticmethod
-    def from_buffer(buf, start_offset):
-        return ExchangeContentPropertyList()
-
-    def get_size(self):
-        return 0
-
-
 class ExchangeDeclare(AMQPMethodPayload):
     """
     Verify exchange exists, create if needed
@@ -1280,42 +1012,31 @@ class ExchangeDeclare(AMQPMethodPayload):
     This method creates an exchange if it does not already exist, and if the exchange
     exists, verifies that it is of the correct and expected class.
     """
-    CLASS = Exchange
-    NAME = u'declare'
-    CLASSNAME = u'exchange'
-    FULLNAME = u'exchange.declare'
-
-    CONTENT_PROPERTY_LIST = ExchangeContentPropertyList
+    NAME = u'exchange.declare'
 
-    CLASS_INDEX = 40
-    CLASS_INDEX_BINARY = b'\x28'
-    METHOD_INDEX = 10
-    METHOD_INDEX_BINARY = b'\x0A'
+    INDEX = (40, 10)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x28\x0A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ExchangeDeclareOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 36 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [ExchangeDeclareOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'type', u'shortstr', u'shortstr', False),  # exchange type
-        (u'passive', u'bit', u'bit', False),  # do not create exchange
-        (u'durable', u'bit', u'bit', False),  # request a durable exchange
-        (u'reserved-2', u'bit', u'bit', True), 
-        (u'reserved-3', u'bit', u'bit', True), 
-        (u'no-wait', u'no-wait', u'bit', False), 
-        (u'arguments', u'table', u'table', False),  # arguments for declaration
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'type', u'shortstr', reserved=False),
+        Field(u'passive', u'bit', reserved=False),
+        Field(u'durable', u'bit', reserved=False),
+        Field(u'reserved-2', u'bit', reserved=True),
+        Field(u'reserved-3', u'bit', reserved=True),
+        Field(u'no-wait', u'bit', reserved=False),
+        Field(u'arguments', u'table', reserved=False),
     ]
 
-    def __init__(self, exchange, type, passive, durable, no_wait, arguments):
+    def __init__(self, exchange, type_, passive, durable, no_wait, arguments):
         """
         Create frame exchange.declare
 
@@ -1323,12 +1044,12 @@ class ExchangeDeclare(AMQPMethodPayload):
             standardised exchanges. The client MAY declare an exchange starting with
             "amq." if the passive option is set, or the exchange already exists.
         :type exchange: binary type (max length 255) (exchange-name in AMQP)
-        :param type: Exchange type
+        :param type_: Exchange type
             Each exchange belongs to one of a set of exchange types implemented by the
             server. The exchange types define the functionality of the exchange - i.e. how
             messages are routed through it. It is not valid or meaningful to attempt to
             change the type of an existing exchange.
-        :type type: binary type (max length 255) (shortstr in AMQP)
+        :type type_: binary type (max length 255) (shortstr in AMQP)
         :param passive: Do not create exchange
             If set, the server will reply with Declare-Ok if the exchange already
             exists with the same name, and raise an error if not.  The client can
@@ -1346,47 +1067,45 @@ class ExchangeDeclare(AMQPMethodPayload):
         :param arguments: Arguments for declaration
             A set of arguments for the declaration. The syntax and semantics of these
             arguments depends on the server implementation.
-        :type arguments: table. See coolamqp.uplink.frames.field_table (table in AMQP)
+        :type arguments: table. See coolamqp.uplink.framing.field_table (table in AMQP)
         """
         self.exchange = exchange
-        self.type = type
+        self.type_ = type_
         self.passive = passive
         self.durable = durable
         self.no_wait = no_wait
         self.arguments = arguments
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.exchange)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.exchange)))
         buf.write(self.exchange)
-        buf.write(struct.pack('!B', len(self.type)))
-        buf.write(self.type)
-        buf.write(struct.pack('!B', (int(self.passive) << 0) | (int(self.durable) << 1) | (int(self.no_wait) << 2)))
+        buf.write(struct.pack('!B', len(self.type_)))
+        buf.write(self.type_)
         enframe_table(buf, self.arguments)
-
+        buf.write(struct.pack('!B', (self.passive << 0) | (self.durable << 1) | (self.no_wait << 4)))
+        
     def get_size(self):
-        return len(self.exchange) + len(self.type) + frame_table_size(self.arguments) + 9
+        return 9 + len(self.exchange) + len(self.type_) + frame_table_size(self.arguments)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ExchangeDeclare.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         exchange = buf[offset:offset+s_len]
         offset += s_len
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
-        type = buf[offset:offset+s_len]
+        type_ = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        passive = bool(_bit >> 0)
+        durable = bool(_bit >> 1)
+        no_wait = bool(_bit >> 4)
         offset += 1
-        passive = bool(_bit & 1)
-        durable = bool(_bit & 2)
-        no_wait = bool(_bit & 16)
         arguments, delta = deframe_table(buf, offset)
         offset += delta
-        return ExchangeDeclare(exchange, type, passive, durable, no_wait, arguments)
+        return ExchangeDeclare(exchange, type_, passive, durable, no_wait, arguments)
 
 
 class ExchangeDelete(AMQPMethodPayload):
@@ -1396,34 +1115,23 @@ class ExchangeDelete(AMQPMethodPayload):
     This method deletes an exchange. When an exchange is deleted all queue bindings on
     the exchange are cancelled.
     """
-    CLASS = Exchange
-    NAME = u'delete'
-    CLASSNAME = u'exchange'
-    FULLNAME = u'exchange.delete'
-
-    CONTENT_PROPERTY_LIST = ExchangeContentPropertyList
+    NAME = u'exchange.delete'
 
-    CLASS_INDEX = 40
-    CLASS_INDEX_BINARY = b'\x28'
-    METHOD_INDEX = 20
-    METHOD_INDEX_BINARY = b'\x14'
+    INDEX = (40, 20)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x28\x14'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [ExchangeDeleteOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 10 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [ExchangeDeleteOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'if-unused', u'bit', u'bit', False),  # delete only if unused
-        (u'no-wait', u'no-wait', u'bit', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'if-unused', u'bit', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
     ]
 
     def __init__(self, exchange, if_unused, no_wait):
@@ -1444,26 +1152,24 @@ class ExchangeDelete(AMQPMethodPayload):
         self.no_wait = no_wait
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.exchange)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.exchange)))
         buf.write(self.exchange)
-        buf.write(struct.pack('!B', (int(self.if_unused) << 0) | (int(self.no_wait) << 1)))
-
+        buf.write(struct.pack('!B', (self.if_unused << 0) | (self.no_wait << 1)))
+        
     def get_size(self):
-        return len(self.exchange) + 4
+        return 4 + len(self.exchange)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= ExchangeDelete.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         exchange = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        if_unused = bool(_bit >> 0)
+        no_wait = bool(_bit >> 1)
         offset += 1
-        if_unused = bool(_bit & 1)
-        no_wait = bool(_bit & 2)
         return ExchangeDelete(exchange, if_unused, no_wait)
 
 
@@ -1474,26 +1180,13 @@ class ExchangeDeclareOk(AMQPMethodPayload):
     This method confirms a Declare method and confirms the name of the exchange,
     essential for automatically-named exchanges.
     """
-    CLASS = Exchange
-    NAME = u'declare-ok'
-    CLASSNAME = u'exchange'
-    FULLNAME = u'exchange.declare-ok'
+    NAME = u'exchange.declare-ok'
 
-    CONTENT_PROPERTY_LIST = ExchangeContentPropertyList
-
-    CLASS_INDEX = 40
-    CLASS_INDEX_BINARY = b'\x28'
-    METHOD_INDEX = 11
-    METHOD_INDEX_BINARY = b'\x0B'
+    INDEX = (40, 11)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x28\x0B'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -1505,10 +1198,10 @@ class ExchangeDeclareOk(AMQPMethodPayload):
         Create frame exchange.declare-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return ExchangeDeclareOk()
 
 
@@ -1518,26 +1211,13 @@ class ExchangeDeleteOk(AMQPMethodPayload):
     
     This method confirms the deletion of an exchange.
     """
-    CLASS = Exchange
-    NAME = u'delete-ok'
-    CLASSNAME = u'exchange'
-    FULLNAME = u'exchange.delete-ok'
-
-    CONTENT_PROPERTY_LIST = ExchangeContentPropertyList
+    NAME = u'exchange.delete-ok'
 
-    CLASS_INDEX = 40
-    CLASS_INDEX_BINARY = b'\x28'
-    METHOD_INDEX = 21
-    METHOD_INDEX_BINARY = b'\x15'
+    INDEX = (40, 21)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x28\x15'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -1549,10 +1229,10 @@ class ExchangeDeleteOk(AMQPMethodPayload):
         Create frame exchange.delete-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return ExchangeDeleteOk()
 
 
@@ -1567,38 +1247,6 @@ class Queue(AMQPClass):
     INDEX = 50
 
 
-class QueueContentPropertyList(AMQPContentPropertyList):
-    """
-    Queues store and forward messages. queues can be configured in the server or created at
-    
-    runtime. Queues must be attached to at least one exchange in order to receive messages
-    from publishers.
-    """
-    CLASS_NAME = u'queue'
-    CLASS_INDEX = 50
-    CLASS = Queue
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-    ]
-
-    def __init__(self):
-        """
-        Create the property list.
-
-        """
-
-    def write_arguments(self, buf):
-        pass # this has a frame, but its only default shortstrs
-
-    @staticmethod
-    def from_buffer(buf, start_offset):
-        return QueueContentPropertyList()
-
-    def get_size(self):
-        return 0
-
-
 class QueueBind(AMQPMethodPayload):
     """
     Bind queue to an exchange
@@ -1608,36 +1256,25 @@ class QueueBind(AMQPMethodPayload):
     are bound to a direct exchange and subscription queues are bound to a topic
     exchange.
     """
-    CLASS = Queue
-    NAME = u'bind'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.bind'
+    NAME = u'queue.bind'
 
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
-
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 20
-    METHOD_INDEX_BINARY = b'\x14'
+    INDEX = (50, 20)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x14'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [QueueBindOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 43 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [QueueBindOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'exchange', u'exchange-name', u'shortstr', False),  # name of the exchange to bind to
-        (u'routing-key', u'shortstr', u'shortstr', False),  # message routing key
-        (u'no-wait', u'no-wait', u'bit', False), 
-        (u'arguments', u'table', u'table', False),  # arguments for binding
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'routing-key', u'shortstr', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
+        Field(u'arguments', u'table', reserved=False),
     ]
 
     def __init__(self, queue, exchange, routing_key, no_wait, arguments):
@@ -1663,7 +1300,7 @@ class QueueBind(AMQPMethodPayload):
         :param arguments: Arguments for binding
             A set of arguments for the binding. The syntax and semantics of these arguments
             depends on the exchange class.
-        :type arguments: table. See coolamqp.uplink.frames.field_table (table in AMQP)
+        :type arguments: table. See coolamqp.uplink.framing.field_table (table in AMQP)
         """
         self.queue = queue
         self.exchange = exchange
@@ -1672,23 +1309,21 @@ class QueueBind(AMQPMethodPayload):
         self.arguments = arguments
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
         buf.write(struct.pack('!B', len(self.exchange)))
         buf.write(self.exchange)
         buf.write(struct.pack('!B', len(self.routing_key)))
         buf.write(self.routing_key)
-        buf.write(struct.pack('!B', (int(self.no_wait) << 0)))
         enframe_table(buf, self.arguments)
-
+        buf.write(struct.pack('!B', (self.no_wait << 0)))
+        
     def get_size(self):
-        return len(self.queue) + len(self.exchange) + len(self.routing_key) + frame_table_size(self.arguments) + 10
+        return 10 + len(self.queue) + len(self.exchange) + len(self.routing_key) + frame_table_size(self.arguments)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueBind.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
@@ -1702,8 +1337,8 @@ class QueueBind(AMQPMethodPayload):
         routing_key = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        no_wait = bool(_bit >> 0)
         offset += 1
-        no_wait = bool(_bit & 1)
         arguments, delta = deframe_table(buf, offset)
         offset += delta
         return QueueBind(queue, exchange, routing_key, no_wait, arguments)
@@ -1715,26 +1350,13 @@ class QueueBindOk(AMQPMethodPayload):
     
     This method confirms that the bind was successful.
     """
-    CLASS = Queue
-    NAME = u'bind-ok'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.bind-ok'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.bind-ok'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 21
-    METHOD_INDEX_BINARY = b'\x15'
+    INDEX = (50, 21)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x15'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -1746,10 +1368,10 @@ class QueueBindOk(AMQPMethodPayload):
         Create frame queue.bind-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return QueueBindOk()
 
 
@@ -1761,38 +1383,27 @@ class QueueDeclare(AMQPMethodPayload):
     specify various properties that control the durability of the queue and its
     contents, and the level of sharing for the queue.
     """
-    CLASS = Queue
-    NAME = u'declare'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.declare'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.declare'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 10
-    METHOD_INDEX_BINARY = b'\x0A'
+    INDEX = (50, 10)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x0A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [QueueDeclareOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 29 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [QueueDeclareOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'passive', u'bit', u'bit', False),  # do not create queue
-        (u'durable', u'bit', u'bit', False),  # request a durable queue
-        (u'exclusive', u'bit', u'bit', False),  # request an exclusive queue
-        (u'auto-delete', u'bit', u'bit', False),  # auto-delete queue when unused
-        (u'no-wait', u'no-wait', u'bit', False), 
-        (u'arguments', u'table', u'table', False),  # arguments for declaration
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'passive', u'bit', reserved=False),
+        Field(u'durable', u'bit', reserved=False),
+        Field(u'exclusive', u'bit', reserved=False),
+        Field(u'auto-delete', u'bit', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
+        Field(u'arguments', u'table', reserved=False),
     ]
 
     def __init__(self, queue, passive, durable, exclusive, auto_delete, no_wait, arguments):
@@ -1833,7 +1444,7 @@ class QueueDeclare(AMQPMethodPayload):
         :param arguments: Arguments for declaration
             A set of arguments for the declaration. The syntax and semantics of these
             arguments depends on the server implementation.
-        :type arguments: table. See coolamqp.uplink.frames.field_table (table in AMQP)
+        :type arguments: table. See coolamqp.uplink.framing.field_table (table in AMQP)
         """
         self.queue = queue
         self.passive = passive
@@ -1844,30 +1455,28 @@ class QueueDeclare(AMQPMethodPayload):
         self.arguments = arguments
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
-        buf.write(struct.pack('!B', (int(self.passive) << 0) | (int(self.durable) << 1) | (int(self.exclusive) << 2) | (int(self.auto_delete) << 3) | (int(self.no_wait) << 4)))
         enframe_table(buf, self.arguments)
-
+        buf.write(struct.pack('!B', (self.passive << 0) | (self.durable << 1) | (self.exclusive << 2) | (self.auto_delete << 3) | (self.no_wait << 4)))
+        
     def get_size(self):
-        return len(self.queue) + frame_table_size(self.arguments) + 8
+        return 8 + len(self.queue) + frame_table_size(self.arguments)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueDeclare.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        passive = bool(_bit >> 0)
+        durable = bool(_bit >> 1)
+        exclusive = bool(_bit >> 2)
+        auto_delete = bool(_bit >> 3)
+        no_wait = bool(_bit >> 4)
         offset += 1
-        passive = bool(_bit & 1)
-        durable = bool(_bit & 2)
-        exclusive = bool(_bit & 4)
-        auto_delete = bool(_bit & 8)
-        no_wait = bool(_bit & 16)
         arguments, delta = deframe_table(buf, offset)
         offset += delta
         return QueueDeclare(queue, passive, durable, exclusive, auto_delete, no_wait, arguments)
@@ -1881,35 +1490,24 @@ class QueueDelete(AMQPMethodPayload):
     to a dead-letter queue if this is defined in the server configuration, and all
     consumers on the queue are cancelled.
     """
-    CLASS = Queue
-    NAME = u'delete'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.delete'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.delete'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 40
-    METHOD_INDEX_BINARY = b'\x28'
+    INDEX = (50, 40)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x28'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [QueueDeleteOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 10 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [QueueDeleteOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'if-unused', u'bit', u'bit', False),  # delete only if unused
-        (u'if-empty', u'bit', u'bit', False),  # delete only if empty
-        (u'no-wait', u'no-wait', u'bit', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'if-unused', u'bit', reserved=False),
+        Field(u'if-empty', u'bit', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
     ]
 
     def __init__(self, queue, if_unused, if_empty, no_wait):
@@ -1934,27 +1532,25 @@ class QueueDelete(AMQPMethodPayload):
         self.no_wait = no_wait
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
-        buf.write(struct.pack('!B', (int(self.if_unused) << 0) | (int(self.if_empty) << 1) | (int(self.no_wait) << 2)))
-
+        buf.write(struct.pack('!B', (self.if_unused << 0) | (self.if_empty << 1) | (self.no_wait << 2)))
+        
     def get_size(self):
-        return len(self.queue) + 4
+        return 4 + len(self.queue)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueDelete.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        if_unused = bool(_bit >> 0)
+        if_empty = bool(_bit >> 1)
+        no_wait = bool(_bit >> 2)
         offset += 1
-        if_unused = bool(_bit & 1)
-        if_empty = bool(_bit & 2)
-        no_wait = bool(_bit & 4)
         return QueueDelete(queue, if_unused, if_empty, no_wait)
 
 
@@ -1965,34 +1561,23 @@ class QueueDeclareOk(AMQPMethodPayload):
     This method confirms a Declare method and confirms the name of the queue, essential
     for automatically-named queues.
     """
-    CLASS = Queue
-    NAME = u'declare-ok'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.declare-ok'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.declare-ok'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 11
-    METHOD_INDEX_BINARY = b'\x0B'
+    INDEX = (50, 11)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x0B'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 15 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = QueueDeclare # this is sent in response to queue.declare
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'message-count', u'message-count', u'long', False), 
-        (u'consumer-count', u'long', u'long', False),  # number of consumers
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'message-count', u'long', reserved=False),
+        Field(u'consumer-count', u'long', reserved=False),
     ]
 
     def __init__(self, queue, message_count, consumer_count):
@@ -2016,14 +1601,13 @@ class QueueDeclareOk(AMQPMethodPayload):
         buf.write(struct.pack('!B', len(self.queue)))
         buf.write(self.queue)
         buf.write(struct.pack('!II', self.message_count, self.consumer_count))
-
+        
     def get_size(self):
-        return len(self.queue) + 9
+        return 9 + len(self.queue)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueDeclareOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
         queue = buf[offset:offset+s_len]
@@ -2039,32 +1623,21 @@ class QueueDeleteOk(AMQPMethodPayload):
     
     This method confirms the deletion of a queue.
     """
-    CLASS = Queue
-    NAME = u'delete-ok'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.delete-ok'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.delete-ok'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 41
-    METHOD_INDEX_BINARY = b'\x29'
+    INDEX = (50, 41)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x29'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 4 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = QueueDelete # this is sent in response to queue.delete
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'message-count', u'message-count', u'long', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'message-count', u'long', reserved=False),
     ]
 
     def __init__(self, message_count):
@@ -2078,15 +1651,15 @@ class QueueDeleteOk(AMQPMethodPayload):
 
     def write_arguments(self, buf):
         buf.write(struct.pack('!I', self.message_count))
-
+        
     def get_size(self):
         return 4
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueDeleteOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         message_count, = struct.unpack_from('!I', buf, offset)
+        offset += 4
         return QueueDeleteOk(message_count)
 
 
@@ -2097,33 +1670,22 @@ class QueuePurge(AMQPMethodPayload):
     This method removes all messages from a queue which are not awaiting
     acknowledgment.
     """
-    CLASS = Queue
-    NAME = u'purge'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.purge'
+    NAME = u'queue.purge'
 
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
-
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 30
-    METHOD_INDEX_BINARY = b'\x1E'
+    INDEX = (50, 30)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x1E'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [QueuePurgeOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 10 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [QueuePurgeOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'no-wait', u'no-wait', u'bit', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
     ]
 
     def __init__(self, queue, no_wait):
@@ -2138,25 +1700,23 @@ class QueuePurge(AMQPMethodPayload):
         self.no_wait = no_wait
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
-        buf.write(struct.pack('!B', (int(self.no_wait) << 0)))
-
+        buf.write(struct.pack('!B', (self.no_wait << 0)))
+        
     def get_size(self):
-        return len(self.queue) + 4
+        return 4 + len(self.queue)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueuePurge.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        no_wait = bool(_bit >> 0)
         offset += 1
-        no_wait = bool(_bit & 1)
         return QueuePurge(queue, no_wait)
 
 
@@ -2166,32 +1726,21 @@ class QueuePurgeOk(AMQPMethodPayload):
     
     This method confirms the purge of a queue.
     """
-    CLASS = Queue
-    NAME = u'purge-ok'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.purge-ok'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.purge-ok'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 31
-    METHOD_INDEX_BINARY = b'\x1F'
+    INDEX = (50, 31)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x1F'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 4 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = QueuePurge # this is sent in response to queue.purge
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'message-count', u'message-count', u'long', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'message-count', u'long', reserved=False),
     ]
 
     def __init__(self, message_count):
@@ -2205,15 +1754,15 @@ class QueuePurgeOk(AMQPMethodPayload):
 
     def write_arguments(self, buf):
         buf.write(struct.pack('!I', self.message_count))
-
+        
     def get_size(self):
         return 4
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueuePurgeOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         message_count, = struct.unpack_from('!I', buf, offset)
+        offset += 4
         return QueuePurgeOk(message_count)
 
 
@@ -2223,35 +1772,24 @@ class QueueUnbind(AMQPMethodPayload):
     
     This method unbinds a queue from an exchange.
     """
-    CLASS = Queue
-    NAME = u'unbind'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.unbind'
+    NAME = u'queue.unbind'
 
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
-
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 50
-    METHOD_INDEX_BINARY = b'\x32'
+    INDEX = (50, 50)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x32'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [QueueUnbindOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 42 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [QueueUnbindOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'routing-key', u'shortstr', u'shortstr', False),  # routing key of binding
-        (u'arguments', u'table', u'table', False),  # arguments of binding
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'routing-key', u'shortstr', reserved=False),
+        Field(u'arguments', u'table', reserved=False),
     ]
 
     def __init__(self, queue, exchange, routing_key, arguments):
@@ -2267,7 +1805,7 @@ class QueueUnbind(AMQPMethodPayload):
         :type routing_key: binary type (max length 255) (shortstr in AMQP)
         :param arguments: Arguments of binding
             Specifies the arguments of the binding to unbind.
-        :type arguments: table. See coolamqp.uplink.frames.field_table (table in AMQP)
+        :type arguments: table. See coolamqp.uplink.framing.field_table (table in AMQP)
         """
         self.queue = queue
         self.exchange = exchange
@@ -2275,22 +1813,20 @@ class QueueUnbind(AMQPMethodPayload):
         self.arguments = arguments
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
         buf.write(struct.pack('!B', len(self.exchange)))
         buf.write(self.exchange)
         buf.write(struct.pack('!B', len(self.routing_key)))
         buf.write(self.routing_key)
         enframe_table(buf, self.arguments)
-
+        
     def get_size(self):
-        return len(self.queue) + len(self.exchange) + len(self.routing_key) + frame_table_size(self.arguments) + 9
+        return 9 + len(self.queue) + len(self.exchange) + len(self.routing_key) + frame_table_size(self.arguments)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueUnbind.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
@@ -2314,26 +1850,13 @@ class QueueUnbindOk(AMQPMethodPayload):
     
     This method confirms that the unbind was successful.
     """
-    CLASS = Queue
-    NAME = u'unbind-ok'
-    CLASSNAME = u'queue'
-    FULLNAME = u'queue.unbind-ok'
-
-    CONTENT_PROPERTY_LIST = QueueContentPropertyList
+    NAME = u'queue.unbind-ok'
 
-    CLASS_INDEX = 50
-    CLASS_INDEX_BINARY = b'\x32'
-    METHOD_INDEX = 51
-    METHOD_INDEX_BINARY = b'\x33'
+    INDEX = (50, 51)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x32\x33'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -2345,10 +1868,10 @@ class QueueUnbindOk(AMQPMethodPayload):
         Create frame queue.unbind-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return QueueUnbindOk()
 
 
@@ -2364,145 +1887,23 @@ class BasicContentPropertyList(AMQPContentPropertyList):
     """
     The basic class provides methods that support an industry-standard messaging model.
     """
-    CLASS_NAME = u'basic'
-    CLASS_INDEX = 60
-    CLASS = Basic
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-        (u'content-type', u'shortstr', u'shortstr'), # u'MIME content type'
-        (u'content-encoding', u'shortstr', u'shortstr'), # u'MIME content encoding'
-        (u'headers', u'table', u'table'), # u'message header field table'
-        (u'delivery-mode', u'octet', u'octet'), # u'non-persistent (1) or persistent (2)'
-        (u'priority', u'octet', u'octet'), # u'message priority, 0 to 9'
-        (u'correlation-id', u'shortstr', u'shortstr'), # u'application correlation identifier'
-        (u'reply-to', u'shortstr', u'shortstr'), # u'address to reply to'
-        (u'expiration', u'shortstr', u'shortstr'), # u'message expiration specification'
-        (u'message-id', u'shortstr', u'shortstr'), # u'application message identifier'
-        (u'timestamp', u'timestamp', u'timestamp'), # u'message timestamp'
-        (u'type', u'shortstr', u'shortstr'), # u'message type name'
-        (u'user-id', u'shortstr', u'shortstr'), # u'creating user id'
-        (u'app-id', u'shortstr', u'shortstr'), # u'creating application id'
-        (u'reserved', u'shortstr', u'shortstr'), # u'reserved, must be empty'
+    FIELDS = [
+        Field(u'content-type', u'shortstr', False),
+        Field(u'content-encoding', u'shortstr', False),
+        Field(u'headers', u'table', False),
+        Field(u'delivery-mode', u'octet', False),
+        Field(u'priority', u'octet', False),
+        Field(u'correlation-id', u'shortstr', False),
+        Field(u'reply-to', u'shortstr', False),
+        Field(u'expiration', u'shortstr', False),
+        Field(u'message-id', u'shortstr', False),
+        Field(u'timestamp', u'timestamp', False),
+        Field(u'type', u'shortstr', False),
+        Field(u'user-id', u'shortstr', False),
+        Field(u'app-id', u'shortstr', False),
+        Field(u'reserved', u'shortstr', False),
     ]
 
-    def __init__(self, content_type, content_encoding, headers, delivery_mode, priority, correlation_id, reply_to, expiration, message_id, timestamp, type, user_id, app_id):
-        """
-        Create the property list.
-
-        :param content_type: MIME content type
-        :type content_type: binary type (max length 255) (shortstr in AMQP)
-        :param content_encoding: MIME content encoding
-        :type content_encoding: binary type (max length 255) (shortstr in AMQP)
-        :param headers: message header field table
-        :type headers: table. See coolamqp.uplink.frames.field_table (table in AMQP)
-        :param delivery_mode: non-persistent (1) or persistent (2)
-        :type delivery_mode: int, 8 bit unsigned (octet in AMQP)
-        :param priority: message priority, 0 to 9
-        :type priority: int, 8 bit unsigned (octet in AMQP)
-        :param correlation_id: application correlation identifier
-        :type correlation_id: binary type (max length 255) (shortstr in AMQP)
-        :param reply_to: address to reply to
-        :type reply_to: binary type (max length 255) (shortstr in AMQP)
-        :param expiration: message expiration specification
-        :type expiration: binary type (max length 255) (shortstr in AMQP)
-        :param message_id: application message identifier
-        :type message_id: binary type (max length 255) (shortstr in AMQP)
-        :param timestamp: message timestamp
-        :type timestamp: 64 bit signed POSIX timestamp (in seconds) (timestamp in AMQP)
-        :param type: message type name
-        :type type: binary type (max length 255) (shortstr in AMQP)
-        :param user_id: creating user id
-        :type user_id: binary type (max length 255) (shortstr in AMQP)
-        :param app_id: creating application id
-        :type app_id: binary type (max length 255) (shortstr in AMQP)
-        """
-        self.content_type = content_type # MIME content type
-        self.content_encoding = content_encoding # MIME content encoding
-        self.headers = headers # message header field table
-        self.delivery_mode = delivery_mode # non-persistent (1) or persistent (2)
-        self.priority = priority # message priority, 0 to 9
-        self.correlation_id = correlation_id # application correlation identifier
-        self.reply_to = reply_to # address to reply to
-        self.expiration = expiration # message expiration specification
-        self.message_id = message_id # application message identifier
-        self.timestamp = timestamp # message timestamp
-        self.type = type # message type name
-        self.user_id = user_id # creating user id
-        self.app_id = app_id # creating application id
-
-    def write_arguments(self, buf):
-        buf.write(struct.pack('!B', len(self.content_type)))
-        buf.write(self.content_type)
-        buf.write(struct.pack('!B', len(self.content_encoding)))
-        buf.write(self.content_encoding)
-        enframe_table(buf, self.headers)
-        buf.write(struct.pack('!BBB', self.delivery_mode, self.priority, len(self.correlation_id)))
-        buf.write(self.correlation_id)
-        buf.write(struct.pack('!B', len(self.reply_to)))
-        buf.write(self.reply_to)
-        buf.write(struct.pack('!B', len(self.expiration)))
-        buf.write(self.expiration)
-        buf.write(struct.pack('!B', len(self.message_id)))
-        buf.write(self.message_id)
-        buf.write(struct.pack('!LB', self.timestamp, len(self.type)))
-        buf.write(self.type)
-        buf.write(struct.pack('!B', len(self.user_id)))
-        buf.write(self.user_id)
-        buf.write(struct.pack('!B', len(self.app_id)))
-        buf.write(self.app_id)
-        buf.write(b'\x00')
-
-    @staticmethod
-    def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= QueueUnbindOk.MINIMUM_SIZE, 'Content property list too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        content_type = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        content_encoding = buf[offset:offset+s_len]
-        offset += s_len
-        headers, delta = deframe_table(buf, offset)
-        offset += delta
-        delivery_mode, priority, s_len, = struct.unpack_from('!BBB', buf, offset)
-        offset += 3
-        correlation_id = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        reply_to = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        expiration = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        message_id = buf[offset:offset+s_len]
-        offset += s_len
-        timestamp, s_len, = struct.unpack_from('!LB', buf, offset)
-        offset += 9
-        type = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        user_id = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        app_id = buf[offset:offset+s_len]
-        offset += s_len
-        s_len, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-        offset += s_len
-        return BasicContentPropertyList(content_type, content_encoding, headers, delivery_mode, priority, correlation_id, reply_to, expiration, message_id, timestamp, type, user_id, app_id)
-
-    def get_size(self):
-        return len(self.content_type) + len(self.content_encoding) + frame_table_size(self.headers) + len(self.correlation_id) + len(self.reply_to) + len(self.expiration) + len(self.message_id) + len(self.type) + len(self.user_id) + len(self.app_id) + 24
-
 
 class BasicAck(AMQPMethodPayload):
     """
@@ -2512,32 +1913,21 @@ class BasicAck(AMQPMethodPayload):
     methods. The client can ask to confirm a single message or a set of messages up to
     and including a specific message.
     """
-    CLASS = Basic
-    NAME = u'ack'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.ack'
+    NAME = u'basic.ack'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 80
-    METHOD_INDEX_BINARY = b'\x50'
+    INDEX = (60, 80)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x50'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 9 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'delivery-tag', u'delivery-tag', u'longlong', False), 
-        (u'multiple', u'bit', u'bit', False),  # acknowledge multiple messages
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'delivery-tag', u'longlong', reserved=False),
+        Field(u'multiple', u'bit', reserved=False),
     ]
 
     def __init__(self, delivery_tag, multiple):
@@ -2556,18 +1946,19 @@ class BasicAck(AMQPMethodPayload):
         self.multiple = multiple
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!Q', self.delivery_tag))
-        buf.write(struct.pack('!B', (int(self.multiple) << 0)))
-
+        buf.write(struct.pack('!QB', self.delivery_tag, (self.multiple << 0)))
+        
     def get_size(self):
         return 9
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicAck.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        delivery_tag, _bit_0, = struct.unpack_from('!QB', buf, offset)
-        multiple = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        multiple = bool(_bit >> 0)
+        offset += 1
+        delivery_tag, = struct.unpack_from('!Q', buf, offset)
+        offset += 8
         return BasicAck(delivery_tag, multiple)
 
 
@@ -2579,38 +1970,27 @@ class BasicConsume(AMQPMethodPayload):
     messages from a specific queue. Consumers last as long as the channel they were
     declared on, or until the client cancels them.
     """
-    CLASS = Basic
-    NAME = u'consume'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.consume'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.consume'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 20
-    METHOD_INDEX_BINARY = b'\x14'
+    INDEX = (60, 20)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x14'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [BasicConsumeOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 36 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [BasicConsumeOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'consumer-tag', u'consumer-tag', u'shortstr', False), 
-        (u'no-local', u'no-local', u'bit', False), 
-        (u'no-ack', u'no-ack', u'bit', False), 
-        (u'exclusive', u'bit', u'bit', False),  # request exclusive access
-        (u'no-wait', u'no-wait', u'bit', False), 
-        (u'arguments', u'table', u'table', False),  # arguments for declaration
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'consumer-tag', u'shortstr', reserved=False),
+        Field(u'no-local', u'bit', reserved=False),
+        Field(u'no-ack', u'bit', reserved=False),
+        Field(u'exclusive', u'bit', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
+        Field(u'arguments', u'table', reserved=False),
     ]
 
     def __init__(self, queue, consumer_tag, no_local, no_ack, exclusive, no_wait, arguments):
@@ -2633,7 +2013,7 @@ class BasicConsume(AMQPMethodPayload):
         :param arguments: Arguments for declaration
             A set of arguments for the consume. The syntax and semantics of these
             arguments depends on the server implementation.
-        :type arguments: table. See coolamqp.uplink.frames.field_table (table in AMQP)
+        :type arguments: table. See coolamqp.uplink.framing.field_table (table in AMQP)
         """
         self.queue = queue
         self.consumer_tag = consumer_tag
@@ -2644,21 +2024,19 @@ class BasicConsume(AMQPMethodPayload):
         self.arguments = arguments
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
         buf.write(struct.pack('!B', len(self.consumer_tag)))
         buf.write(self.consumer_tag)
-        buf.write(struct.pack('!B', (int(self.no_local) << 0) | (int(self.no_ack) << 1) | (int(self.exclusive) << 2) | (int(self.no_wait) << 3)))
         enframe_table(buf, self.arguments)
-
+        buf.write(struct.pack('!B', (self.no_local << 0) | (self.no_ack << 1) | (self.exclusive << 2) | (self.no_wait << 3)))
+        
     def get_size(self):
-        return len(self.queue) + len(self.consumer_tag) + frame_table_size(self.arguments) + 9
+        return 9 + len(self.queue) + len(self.consumer_tag) + frame_table_size(self.arguments)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicConsume.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
@@ -2668,11 +2046,11 @@ class BasicConsume(AMQPMethodPayload):
         consumer_tag = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        no_local = bool(_bit >> 0)
+        no_ack = bool(_bit >> 1)
+        exclusive = bool(_bit >> 2)
+        no_wait = bool(_bit >> 3)
         offset += 1
-        no_local = bool(_bit & 1)
-        no_ack = bool(_bit & 2)
-        exclusive = bool(_bit & 4)
-        no_wait = bool(_bit & 8)
         arguments, delta = deframe_table(buf, offset)
         offset += delta
         return BasicConsume(queue, consumer_tag, no_local, no_ack, exclusive, no_wait, arguments)
@@ -2687,32 +2065,21 @@ class BasicCancel(AMQPMethodPayload):
     that consumer. The client may receive an arbitrary number of messages in
     between sending the cancel method and receiving the cancel-ok reply.
     """
-    CLASS = Basic
-    NAME = u'cancel'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.cancel'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.cancel'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 30
-    METHOD_INDEX_BINARY = b'\x1E'
+    INDEX = (60, 30)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x1E'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [BasicCancelOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 8 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [BasicCancelOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'consumer-tag', u'consumer-tag', u'shortstr', False), 
-        (u'no-wait', u'no-wait', u'bit', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'consumer-tag', u'shortstr', reserved=False),
+        Field(u'no-wait', u'bit', reserved=False),
     ]
 
     def __init__(self, consumer_tag, no_wait):
@@ -2728,22 +2095,21 @@ class BasicCancel(AMQPMethodPayload):
     def write_arguments(self, buf):
         buf.write(struct.pack('!B', len(self.consumer_tag)))
         buf.write(self.consumer_tag)
-        buf.write(struct.pack('!B', (int(self.no_wait) << 0)))
-
+        buf.write(struct.pack('!B', (self.no_wait << 0)))
+        
     def get_size(self):
-        return len(self.consumer_tag) + 2
+        return 2 + len(self.consumer_tag)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicCancel.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
         consumer_tag = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        no_wait = bool(_bit >> 0)
         offset += 1
-        no_wait = bool(_bit & 1)
         return BasicCancel(consumer_tag, no_wait)
 
 
@@ -2754,32 +2120,21 @@ class BasicConsumeOk(AMQPMethodPayload):
     The server provides the client with a consumer tag, which is used by the client
     for methods called on the consumer at a later stage.
     """
-    CLASS = Basic
-    NAME = u'consume-ok'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.consume-ok'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.consume-ok'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 21
-    METHOD_INDEX_BINARY = b'\x15'
+    INDEX = (60, 21)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x15'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 7 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = BasicConsume # this is sent in response to basic.consume
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'consumer-tag', u'consumer-tag', u'shortstr', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'consumer-tag', u'shortstr', reserved=False),
     ]
 
     def __init__(self, consumer_tag):
@@ -2794,14 +2149,13 @@ class BasicConsumeOk(AMQPMethodPayload):
     def write_arguments(self, buf):
         buf.write(struct.pack('!B', len(self.consumer_tag)))
         buf.write(self.consumer_tag)
-
+        
     def get_size(self):
-        return len(self.consumer_tag) + 1
+        return 1 + len(self.consumer_tag)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicConsumeOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
         consumer_tag = buf[offset:offset+s_len]
@@ -2815,32 +2169,21 @@ class BasicCancelOk(AMQPMethodPayload):
     
     This method confirms that the cancellation was completed.
     """
-    CLASS = Basic
-    NAME = u'cancel-ok'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.cancel-ok'
+    NAME = u'basic.cancel-ok'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 31
-    METHOD_INDEX_BINARY = b'\x1F'
+    INDEX = (60, 31)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x1F'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 7 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = BasicCancel # this is sent in response to basic.cancel
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'consumer-tag', u'consumer-tag', u'shortstr', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'consumer-tag', u'shortstr', reserved=False),
     ]
 
     def __init__(self, consumer_tag):
@@ -2854,14 +2197,13 @@ class BasicCancelOk(AMQPMethodPayload):
     def write_arguments(self, buf):
         buf.write(struct.pack('!B', len(self.consumer_tag)))
         buf.write(self.consumer_tag)
-
+        
     def get_size(self):
-        return len(self.consumer_tag) + 1
+        return 1 + len(self.consumer_tag)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicCancelOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
         consumer_tag = buf[offset:offset+s_len]
@@ -2878,35 +2220,24 @@ class BasicDeliver(AMQPMethodPayload):
     the server responds with Deliver methods as and when messages arrive for that
     consumer.
     """
-    CLASS = Basic
-    NAME = u'deliver'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.deliver'
+    NAME = u'basic.deliver'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 60
-    METHOD_INDEX_BINARY = b'\x3C'
+    INDEX = (60, 60)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x3C'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 30 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'consumer-tag', u'consumer-tag', u'shortstr', False), 
-        (u'delivery-tag', u'delivery-tag', u'longlong', False), 
-        (u'redelivered', u'redelivered', u'bit', False), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'routing-key', u'shortstr', u'shortstr', False),  # Message routing key
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'consumer-tag', u'shortstr', reserved=False),
+        Field(u'delivery-tag', u'longlong', reserved=False),
+        Field(u'redelivered', u'bit', reserved=False),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'routing-key', u'shortstr', reserved=False),
     ]
 
     def __init__(self, consumer_tag, delivery_tag, redelivered, exchange, routing_key):
@@ -2932,26 +2263,24 @@ class BasicDeliver(AMQPMethodPayload):
     def write_arguments(self, buf):
         buf.write(struct.pack('!B', len(self.consumer_tag)))
         buf.write(self.consumer_tag)
-        buf.write(struct.pack('!B', (int(self.redelivered) << 0)))
-        buf.write(struct.pack('!QB', self.delivery_tag, len(self.exchange)))
+        buf.write(struct.pack('!QBB', self.delivery_tag, (self.redelivered << 0), len(self.exchange)))
         buf.write(self.exchange)
         buf.write(struct.pack('!B', len(self.routing_key)))
         buf.write(self.routing_key)
-
+        
     def get_size(self):
-        return len(self.consumer_tag) + len(self.exchange) + len(self.routing_key) + 12
+        return 12 + len(self.consumer_tag) + len(self.exchange) + len(self.routing_key)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicDeliver.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!B', buf, offset)
         offset += 1
         consumer_tag = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        redelivered = bool(_bit >> 0)
         offset += 1
-        redelivered = bool(_bit & 1)
         delivery_tag, s_len, = struct.unpack_from('!QB', buf, offset)
         offset += 9
         exchange = buf[offset:offset+s_len]
@@ -2971,33 +2300,22 @@ class BasicGet(AMQPMethodPayload):
     dialogue that is designed for specific types of application where synchronous
     functionality is more important than performance.
     """
-    CLASS = Basic
-    NAME = u'get'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.get'
+    NAME = u'basic.get'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 70
-    METHOD_INDEX_BINARY = b'\x46'
+    INDEX = (60, 70)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x46'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [BasicGetOk, BasicGetEmpty]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 10 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [BasicGetOk, BasicGetEmpty]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'queue', u'queue-name', u'shortstr', False), 
-        (u'no-ack', u'no-ack', u'bit', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'queue', u'shortstr', reserved=False),
+        Field(u'no-ack', u'bit', reserved=False),
     ]
 
     def __init__(self, queue, no_ack):
@@ -3012,25 +2330,23 @@ class BasicGet(AMQPMethodPayload):
         self.no_ack = no_ack
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.queue)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.queue)))
         buf.write(self.queue)
-        buf.write(struct.pack('!B', (int(self.no_ack) << 0)))
-
+        buf.write(struct.pack('!B', (self.no_ack << 0)))
+        
     def get_size(self):
-        return len(self.queue) + 4
+        return 4 + len(self.queue)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicGet.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         queue = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        no_ack = bool(_bit >> 0)
         offset += 1
-        no_ack = bool(_bit & 1)
         return BasicGet(queue, no_ack)
 
 
@@ -3042,36 +2358,25 @@ class BasicGetOk(AMQPMethodPayload):
     delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the
     get method.
     """
-    CLASS = Basic
-    NAME = u'get-ok'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.get-ok'
+    NAME = u'basic.get-ok'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 71
-    METHOD_INDEX_BINARY = b'\x47'
+    INDEX = (60, 71)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x47'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 27 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
     RESPONSE_TO = BasicGet # this is sent in response to basic.get
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'delivery-tag', u'delivery-tag', u'longlong', False), 
-        (u'redelivered', u'redelivered', u'bit', False), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'routing-key', u'shortstr', u'shortstr', False),  # Message routing key
-        (u'message-count', u'message-count', u'long', False), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'delivery-tag', u'longlong', reserved=False),
+        Field(u'redelivered', u'bit', reserved=False),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'routing-key', u'shortstr', reserved=False),
+        Field(u'message-count', u'long', reserved=False),
     ]
 
     def __init__(self, delivery_tag, redelivered, exchange, routing_key, message_count):
@@ -3095,23 +2400,21 @@ class BasicGetOk(AMQPMethodPayload):
         self.message_count = message_count
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!B', (int(self.redelivered) << 0)))
-        buf.write(struct.pack('!QB', self.delivery_tag, len(self.exchange)))
+        buf.write(struct.pack('!QBB', self.delivery_tag, (self.redelivered << 0), len(self.exchange)))
         buf.write(self.exchange)
         buf.write(struct.pack('!B', len(self.routing_key)))
         buf.write(self.routing_key)
         buf.write(struct.pack('!I', self.message_count))
-
+        
     def get_size(self):
-        return len(self.exchange) + len(self.routing_key) + 15
+        return 15 + len(self.exchange) + len(self.routing_key)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicGetOk.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         _bit, = struct.unpack_from('!B', buf, offset)
+        redelivered = bool(_bit >> 0)
         offset += 1
-        redelivered = bool(_bit & 1)
         delivery_tag, s_len, = struct.unpack_from('!QB', buf, offset)
         offset += 9
         exchange = buf[offset:offset+s_len]
@@ -3132,33 +2435,22 @@ class BasicGetEmpty(AMQPMethodPayload):
     This method tells the client that the queue has no messages available for the
     client.
     """
-    CLASS = Basic
-    NAME = u'get-empty'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.get-empty'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.get-empty'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 72
-    METHOD_INDEX_BINARY = b'\x48'
+    INDEX = (60, 72)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x48'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 7 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
     STATIC_CONTENT = b'\x00\x00\x00\x0D\x3C\x48\x00\xCE'  # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END
     RESPONSE_TO = BasicGet # this is sent in response to basic.get
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'shortstr', u'shortstr', True), 
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'shortstr', reserved=True),
     ]
 
     def __init__(self):
@@ -3166,10 +2458,13 @@ class BasicGetEmpty(AMQPMethodPayload):
         Create frame basic.get-empty
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
+        s_len, = struct.unpack_from('!B', buf, offset)
+        offset += 1
+        offset += s_len # reserved field!
         return BasicGetEmpty()
 
 
@@ -3181,35 +2476,24 @@ class BasicPublish(AMQPMethodPayload):
     to queues as defined by the exchange configuration and distributed to any active
     consumers when the transaction, if any, is committed.
     """
-    CLASS = Basic
-    NAME = u'publish'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.publish'
+    NAME = u'basic.publish'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 40
-    METHOD_INDEX_BINARY = b'\x28'
+    INDEX = (60, 40)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x28'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 17 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reserved-1', u'short', u'short', True), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'routing-key', u'shortstr', u'shortstr', False),  # Message routing key
-        (u'mandatory', u'bit', u'bit', False),  # indicate mandatory routing
-        (u'immediate', u'bit', u'bit', False),  # request immediate delivery
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reserved-1', u'short', reserved=True),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'routing-key', u'shortstr', reserved=False),
+        Field(u'mandatory', u'bit', reserved=False),
+        Field(u'immediate', u'bit', reserved=False),
     ]
 
     def __init__(self, exchange, routing_key, mandatory, immediate):
@@ -3242,20 +2526,18 @@ class BasicPublish(AMQPMethodPayload):
         self.immediate = immediate
 
     def write_arguments(self, buf):
-        buf.write(b'\x00\x00')
-        buf.write(struct.pack('!B', len(self.exchange)))
+        buf.write(struct.pack('!HB', self.reserved_1, len(self.exchange)))
         buf.write(self.exchange)
         buf.write(struct.pack('!B', len(self.routing_key)))
         buf.write(self.routing_key)
-        buf.write(struct.pack('!B', (int(self.mandatory) << 0) | (int(self.immediate) << 1)))
-
+        buf.write(struct.pack('!B', (self.mandatory << 0) | (self.immediate << 1)))
+        
     def get_size(self):
-        return len(self.exchange) + len(self.routing_key) + 5
+        return 5 + len(self.exchange) + len(self.routing_key)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicPublish.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         s_len, = struct.unpack_from('!2xB', buf, offset)
         offset += 3
         exchange = buf[offset:offset+s_len]
@@ -3265,9 +2547,9 @@ class BasicPublish(AMQPMethodPayload):
         routing_key = buf[offset:offset+s_len]
         offset += s_len
         _bit, = struct.unpack_from('!B', buf, offset)
+        mandatory = bool(_bit >> 0)
+        immediate = bool(_bit >> 1)
         offset += 1
-        mandatory = bool(_bit & 1)
-        immediate = bool(_bit & 2)
         return BasicPublish(exchange, routing_key, mandatory, immediate)
 
 
@@ -3281,33 +2563,22 @@ class BasicQos(AMQPMethodPayload):
     qos method could in principle apply to both peers, it is currently meaningful only
     for the server.
     """
-    CLASS = Basic
-    NAME = u'qos'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.qos'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.qos'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 10
-    METHOD_INDEX_BINARY = b'\x0A'
+    INDEX = (60, 10)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x0A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [BasicQosOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 7 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [BasicQosOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'prefetch-size', u'long', u'long', False),  # prefetch window in octets
-        (u'prefetch-count', u'short', u'short', False),  # prefetch window in messages
-        (u'global', u'bit', u'bit', False),  # apply to entire connection
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'prefetch-size', u'long', reserved=False),
+        Field(u'prefetch-count', u'short', reserved=False),
+        Field(u'global', u'bit', reserved=False),
     ]
 
     def __init__(self, prefetch_size, prefetch_count, global_):
@@ -3340,18 +2611,19 @@ class BasicQos(AMQPMethodPayload):
         self.global_ = global_
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!IH', self.prefetch_size, self.prefetch_count))
-        buf.write(struct.pack('!B', (int(self.global_) << 0)))
-
+        buf.write(struct.pack('!IHB', self.prefetch_size, self.prefetch_count, (self.global_ << 0)))
+        
     def get_size(self):
         return 7
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicQos.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        prefetch_size, prefetch_count, _bit_0, = struct.unpack_from('!IHB', buf, offset)
-        global_ = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        global_ = bool(_bit >> 0)
+        offset += 1
+        prefetch_size, prefetch_count, = struct.unpack_from('!IH', buf, offset)
+        offset += 6
         return BasicQos(prefetch_size, prefetch_count, global_)
 
 
@@ -3363,26 +2635,13 @@ class BasicQosOk(AMQPMethodPayload):
     server. The requested QoS applies to all active consumers until a new QoS is
     defined.
     """
-    CLASS = Basic
-    NAME = u'qos-ok'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.qos-ok'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.qos-ok'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 11
-    METHOD_INDEX_BINARY = b'\x0B'
+    INDEX = (60, 11)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x0B'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3394,10 +2653,10 @@ class BasicQosOk(AMQPMethodPayload):
         Create frame basic.qos-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return BasicQosOk()
 
 
@@ -3410,34 +2669,23 @@ class BasicReturn(AMQPMethodPayload):
     reply code and text provide information about the reason that the message was
     undeliverable.
     """
-    CLASS = Basic
-    NAME = u'return'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.return'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.return'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 50
-    METHOD_INDEX_BINARY = b'\x32'
+    INDEX = (60, 50)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x32'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 23 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = False     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'reply-code', u'reply-code', u'short', False), 
-        (u'reply-text', u'reply-text', u'shortstr', False), 
-        (u'exchange', u'exchange-name', u'shortstr', False), 
-        (u'routing-key', u'shortstr', u'shortstr', False),  # Message routing key
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'reply-code', u'short', reserved=False),
+        Field(u'reply-text', u'shortstr', reserved=False),
+        Field(u'exchange', u'shortstr', reserved=False),
+        Field(u'routing-key', u'shortstr', reserved=False),
     ]
 
     def __init__(self, reply_code, reply_text, exchange, routing_key):
@@ -3465,14 +2713,13 @@ class BasicReturn(AMQPMethodPayload):
         buf.write(self.exchange)
         buf.write(struct.pack('!B', len(self.routing_key)))
         buf.write(self.routing_key)
-
+        
     def get_size(self):
-        return len(self.reply_text) + len(self.exchange) + len(self.routing_key) + 5
+        return 5 + len(self.reply_text) + len(self.exchange) + len(self.routing_key)
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicReturn.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
+        offset = start_offset
         reply_code, s_len, = struct.unpack_from('!HB', buf, offset)
         offset += 3
         reply_text = buf[offset:offset+s_len]
@@ -3496,32 +2743,21 @@ class BasicReject(AMQPMethodPayload):
     cancel large incoming messages, or return untreatable messages to their original
     queue.
     """
-    CLASS = Basic
-    NAME = u'reject'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.reject'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.reject'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 90
-    METHOD_INDEX_BINARY = b'\x5A'
+    INDEX = (60, 90)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x5A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 9 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'delivery-tag', u'delivery-tag', u'longlong', False), 
-        (u'requeue', u'bit', u'bit', False),  # requeue the message
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'delivery-tag', u'longlong', reserved=False),
+        Field(u'requeue', u'bit', reserved=False),
     ]
 
     def __init__(self, delivery_tag, requeue):
@@ -3538,18 +2774,19 @@ class BasicReject(AMQPMethodPayload):
         self.requeue = requeue
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!Q', self.delivery_tag))
-        buf.write(struct.pack('!B', (int(self.requeue) << 0)))
-
+        buf.write(struct.pack('!QB', self.delivery_tag, (self.requeue << 0)))
+        
     def get_size(self):
         return 9
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicReject.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        delivery_tag, _bit_0, = struct.unpack_from('!QB', buf, offset)
-        requeue = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        requeue = bool(_bit >> 0)
+        offset += 1
+        delivery_tag, = struct.unpack_from('!Q', buf, offset)
+        offset += 8
         return BasicReject(delivery_tag, requeue)
 
 
@@ -3561,31 +2798,20 @@ class BasicRecoverAsync(AMQPMethodPayload):
     specified channel. Zero or more messages may be redelivered.  This method
     is deprecated in favour of the synchronous Recover/Recover-Ok.
     """
-    CLASS = Basic
-    NAME = u'recover-async'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.recover-async'
+    NAME = u'basic.recover-async'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 100
-    METHOD_INDEX_BINARY = b'\x64'
+    INDEX = (60, 100)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x64'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 1 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'requeue', u'bit', u'bit', False),  # requeue the message
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'requeue', u'bit', reserved=False),
     ]
 
     def __init__(self, requeue):
@@ -3601,17 +2827,17 @@ class BasicRecoverAsync(AMQPMethodPayload):
         self.requeue = requeue
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!B', (int(self.requeue) << 0)))
-
+        buf.write(struct.pack('!B', (self.requeue << 0)))
+        
     def get_size(self):
         return 1
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicRecoverAsync.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        _bit_0, = struct.unpack_from('!B', buf, offset)
-        requeue = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        requeue = bool(_bit >> 0)
+        offset += 1
         return BasicRecoverAsync(requeue)
 
 
@@ -3623,31 +2849,20 @@ class BasicRecover(AMQPMethodPayload):
     specified channel. Zero or more messages may be redelivered.  This method
     replaces the asynchronous Recover.
     """
-    CLASS = Basic
-    NAME = u'recover'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.recover'
+    NAME = u'basic.recover'
 
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
-
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 110
-    METHOD_INDEX_BINARY = b'\x6E'
+    INDEX = (60, 110)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x6E'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = False        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 1 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = False  # this means that argument part has always the same content
-    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)
-        (u'requeue', u'bit', u'bit', False),  # requeue the message
+
+    # See constructor pydoc for details
+    FIELDS = [ 
+        Field(u'requeue', u'bit', reserved=False),
     ]
 
     def __init__(self, requeue):
@@ -3663,17 +2878,17 @@ class BasicRecover(AMQPMethodPayload):
         self.requeue = requeue
 
     def write_arguments(self, buf):
-        buf.write(struct.pack('!B', (int(self.requeue) << 0)))
-
+        buf.write(struct.pack('!B', (self.requeue << 0)))
+        
     def get_size(self):
         return 1
 
     @staticmethod
     def from_buffer(buf, start_offset):
-        assert (len(buf) - start_offset) >= BasicRecover.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-        _bit_0, = struct.unpack_from('!B', buf, offset)
-        requeue = bool(_bit_0 & 1)
+        offset = start_offset
+        _bit, = struct.unpack_from('!B', buf, offset)
+        requeue = bool(_bit >> 0)
+        offset += 1
         return BasicRecover(requeue)
 
 
@@ -3683,26 +2898,13 @@ class BasicRecoverOk(AMQPMethodPayload):
     
     This method acknowledges a Basic.Recover method.
     """
-    CLASS = Basic
-    NAME = u'recover-ok'
-    CLASSNAME = u'basic'
-    FULLNAME = u'basic.recover-ok'
-
-    CONTENT_PROPERTY_LIST = BasicContentPropertyList
+    NAME = u'basic.recover-ok'
 
-    CLASS_INDEX = 60
-    CLASS_INDEX_BINARY = b'\x3C'
-    METHOD_INDEX = 111
-    METHOD_INDEX_BINARY = b'\x6F'
+    INDEX = (60, 111)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x3C\x6F'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3713,10 +2915,10 @@ class BasicRecoverOk(AMQPMethodPayload):
         Create frame basic.recover-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return BasicRecoverOk()
 
 
@@ -3737,44 +2939,6 @@ class Tx(AMQPClass):
     INDEX = 90
 
 
-class TxContentPropertyList(AMQPContentPropertyList):
-    """
-    The tx class allows publish and ack operations to be batched into atomic
-    
-    units of work.  The intention is that all publish and ack requests issued
-    within a transaction will complete successfully or none of them will.
-    Servers SHOULD implement atomic transactions at least where all publish
-    or ack requests affect a single queue.  Transactions that cover multiple
-    queues may be non-atomic, given that queues can be created and destroyed
-    asynchronously, and such events do not form part of any transaction.
-    Further, the behaviour of transactions with respect to the immediate and
-    mandatory flags on Basic.Publish methods is not defined.
-    """
-    CLASS_NAME = u'tx'
-    CLASS_INDEX = 90
-    CLASS = Tx
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-    ]
-
-    def __init__(self):
-        """
-        Create the property list.
-
-        """
-
-    def write_arguments(self, buf):
-        pass # this has a frame, but its only default shortstrs
-
-    @staticmethod
-    def from_buffer(buf, start_offset):
-        return TxContentPropertyList()
-
-    def get_size(self):
-        return 0
-
-
 class TxCommit(AMQPMethodPayload):
     """
     Commit the current transaction
@@ -3782,26 +2946,13 @@ class TxCommit(AMQPMethodPayload):
     This method commits all message publications and acknowledgments performed in
     the current transaction.  A new transaction starts immediately after a commit.
     """
-    CLASS = Tx
-    NAME = u'commit'
-    CLASSNAME = u'tx'
-    FULLNAME = u'tx.commit'
-
-    CONTENT_PROPERTY_LIST = TxContentPropertyList
+    NAME = u'tx.commit'
 
-    CLASS_INDEX = 90
-    CLASS_INDEX_BINARY = b'\x5A'
-    METHOD_INDEX = 20
-    METHOD_INDEX_BINARY = b'\x14'
+    INDEX = (90, 20)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x5A\x14'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [TxCommitOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [TxCommitOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3812,10 +2963,10 @@ class TxCommit(AMQPMethodPayload):
         Create frame tx.commit
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return TxCommit()
 
 
@@ -3826,26 +2977,13 @@ class TxCommitOk(AMQPMethodPayload):
     This method confirms to the client that the commit succeeded. Note that if a commit
     fails, the server raises a channel exception.
     """
-    CLASS = Tx
-    NAME = u'commit-ok'
-    CLASSNAME = u'tx'
-    FULLNAME = u'tx.commit-ok'
+    NAME = u'tx.commit-ok'
 
-    CONTENT_PROPERTY_LIST = TxContentPropertyList
-
-    CLASS_INDEX = 90
-    CLASS_INDEX_BINARY = b'\x5A'
-    METHOD_INDEX = 21
-    METHOD_INDEX_BINARY = b'\x15'
+    INDEX = (90, 21)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x5A\x15'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3857,10 +2995,10 @@ class TxCommitOk(AMQPMethodPayload):
         Create frame tx.commit-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return TxCommitOk()
 
 
@@ -3873,26 +3011,13 @@ class TxRollback(AMQPMethodPayload):
     Note that unacked messages will not be automatically redelivered by rollback;
     if that is required an explicit recover call should be issued.
     """
-    CLASS = Tx
-    NAME = u'rollback'
-    CLASSNAME = u'tx'
-    FULLNAME = u'tx.rollback'
-
-    CONTENT_PROPERTY_LIST = TxContentPropertyList
+    NAME = u'tx.rollback'
 
-    CLASS_INDEX = 90
-    CLASS_INDEX_BINARY = b'\x5A'
-    METHOD_INDEX = 30
-    METHOD_INDEX_BINARY = b'\x1E'
+    INDEX = (90, 30)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x5A\x1E'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [TxRollbackOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [TxRollbackOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3903,10 +3028,10 @@ class TxRollback(AMQPMethodPayload):
         Create frame tx.rollback
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return TxRollback()
 
 
@@ -3917,26 +3042,13 @@ class TxRollbackOk(AMQPMethodPayload):
     This method confirms to the client that the rollback succeeded. Note that if an
     rollback fails, the server raises a channel exception.
     """
-    CLASS = Tx
-    NAME = u'rollback-ok'
-    CLASSNAME = u'tx'
-    FULLNAME = u'tx.rollback-ok'
-
-    CONTENT_PROPERTY_LIST = TxContentPropertyList
+    NAME = u'tx.rollback-ok'
 
-    CLASS_INDEX = 90
-    CLASS_INDEX_BINARY = b'\x5A'
-    METHOD_INDEX = 31
-    METHOD_INDEX_BINARY = b'\x1F'
+    INDEX = (90, 31)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x5A\x1F'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3948,10 +3060,10 @@ class TxRollbackOk(AMQPMethodPayload):
         Create frame tx.rollback-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return TxRollbackOk()
 
 
@@ -3962,26 +3074,13 @@ class TxSelect(AMQPMethodPayload):
     This method sets the channel to use standard transactions. The client must use this
     method at least once on a channel before using the Commit or Rollback methods.
     """
-    CLASS = Tx
-    NAME = u'select'
-    CLASSNAME = u'tx'
-    FULLNAME = u'tx.select'
+    NAME = u'tx.select'
 
-    CONTENT_PROPERTY_LIST = TxContentPropertyList
-
-    CLASS_INDEX = 90
-    CLASS_INDEX_BINARY = b'\x5A'
-    METHOD_INDEX = 10
-    METHOD_INDEX_BINARY = b'\x0A'
+    INDEX = (90, 10)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x5A\x0A'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = [TxSelectOk]
-
-    SENT_BY_CLIENT = True
-    SENT_BY_SERVER = False
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = True, False
+    REPLY_WITH = [TxSelectOk]       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -3992,10 +3091,10 @@ class TxSelect(AMQPMethodPayload):
         Create frame tx.select
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return TxSelect()
 
 
@@ -4006,26 +3105,13 @@ class TxSelectOk(AMQPMethodPayload):
     This method confirms to the client that the channel was successfully set to use
     standard transactions.
     """
-    CLASS = Tx
-    NAME = u'select-ok'
-    CLASSNAME = u'tx'
-    FULLNAME = u'tx.select-ok'
+    NAME = u'tx.select-ok'
 
-    CONTENT_PROPERTY_LIST = TxContentPropertyList
-
-    CLASS_INDEX = 90
-    CLASS_INDEX_BINARY = b'\x5A'
-    METHOD_INDEX = 11
-    METHOD_INDEX_BINARY = b'\x0B'
+    INDEX = (90, 11)          # (Class ID, Method ID)
     BINARY_HEADER = b'\x5A\x0B'      # CLASS ID + METHOD ID
 
-    SYNCHRONOUS = True        # does this message imply other one?
-    REPLY_WITH = []
-
-    SENT_BY_CLIENT = False
-    SENT_BY_SERVER = True
-
-    MINIMUM_SIZE = 0 # arguments part can never be shorter than this
+    SENT_BY_CLIENT, SENT_BY_SERVER = False, True
+    REPLY_WITH = []       # methods you can reply with to this one
 
     IS_SIZE_STATIC = True     # this means that argument part has always the same length
     IS_CONTENT_STATIC = True  # this means that argument part has always the same content
@@ -4037,10 +3123,10 @@ class TxSelectOk(AMQPMethodPayload):
         Create frame tx.select-ok
         """
 
-    # not generating write_arguments - this method has static content!
 
     @staticmethod
     def from_buffer(buf, start_offset):
+        offset = start_offset
         return TxSelectOk()
 
 
@@ -4157,3 +3243,8 @@ BINARY_HEADER_TO_METHOD = {
     b'\x32\x0A': QueueDeclare,
 }
 
+
+CLASS_ID_TO_CONTENT_PROPERTY_LIST = {
+    60: BasicContentPropertyList,
+}
+
diff --git a/coolamqp/uplink/frames/field_table.py b/coolamqp/framing/field_table.py
similarity index 100%
rename from coolamqp/uplink/frames/field_table.py
rename to coolamqp/framing/field_table.py
diff --git a/coolamqp/uplink/frames/frames.py b/coolamqp/framing/frames.py
similarity index 87%
rename from coolamqp/uplink/frames/frames.py
rename to coolamqp/framing/frames.py
index 84a74c8..dad0c7d 100644
--- a/coolamqp/uplink/frames/frames.py
+++ b/coolamqp/framing/frames.py
@@ -6,9 +6,9 @@ from __future__ import absolute_import, division, print_function
 
 import struct
 
-from coolamqp.uplink.frames.base import AMQPFrame
-from coolamqp.uplink.frames.definitions import FRAME_METHOD, FRAME_HEARTBEAT, FRAME_BODY, FRAME_HEADER, FRAME_END, \
-    IDENT_TO_METHOD
+from coolamqp.framing.base import AMQPFrame
+from coolamqp.framing.definitions import FRAME_METHOD, FRAME_HEARTBEAT, FRAME_BODY, FRAME_HEADER, FRAME_END, \
+    IDENT_TO_METHOD, CLASS_ID_TO_CONTENT_PROPERTY_LIST
 
 
 class AMQPMethodFrame(AMQPFrame):
@@ -48,10 +48,10 @@ class AMQPHeaderFrame(AMQPFrame):
 
     def __init__(self, channel, class_id, weight, body_size, property_flags, property_list):
         """
-        :param channel:
-        :param class_id:
-        :param weight:
-        :param body_size:
+        :param channel: channel ID
+        :param class_id: class ID
+        :param weight: weight (lol wut?)
+        :param body_size: size of the body to follow
         :param property_flags:
         :param property_list:
         """
diff --git a/coolamqp/scaffold.py b/coolamqp/scaffold.py
new file mode 100644
index 0000000..7c3d245
--- /dev/null
+++ b/coolamqp/scaffold.py
@@ -0,0 +1,43 @@
+# coding=UTF-8
+"""
+Utilities for building the CoolAMQP engine
+"""
+from __future__ import absolute_import, division, print_function
+import functools
+import threading
+
+
+class Synchronized(object):
+    """Protects access to methods with a lock"""
+    def __init__(self):
+        self.lock = threading.Lock()
+
+    def protect(self):
+        """Make the function body lock-protected"""
+        def outer(fun):
+            @functools.wraps(fun)
+            def inner(*args, **kwargs):
+                with self.lock:
+                    return fun(*args, **kwargs)
+            return inner
+        return outer
+
+
+class AcceptsFrames(object):
+    """Base class for objects that accept AMQP frames"""
+
+    def on_frame(self, amqp_frame):
+        """
+        :type amqp_frame: AMQPFrame object
+        """
+
+
+class EmitsFrames(object):
+    """Base class for objects that send AMQP frames somewhere"""
+
+    def wire_frame_to(self, acceptor):
+        """
+        Configure this object to send frames somewhere.
+
+        :param acceptor: an AcceptsFrames instance or callable(AMQPMethod instance)
+        """
\ No newline at end of file
diff --git a/coolamqp/uplink/__init__.py b/coolamqp/uplink/__init__.py
index ff76c6b..3fb71d5 100644
--- a/coolamqp/uplink/__init__.py
+++ b/coolamqp/uplink/__init__.py
@@ -1,7 +1,7 @@
 # coding=UTF-8
 """
 The layer that:
-    - manages serialization/deserializtion (frames)
+    - manages serialization/deserializtion (framing)
     - manages low-level data sending (streams)
     - sets up connection to AMQP
     - reacts and allows sending low-level AMQP commands
diff --git a/coolamqp/uplink/commander/__init__.py b/coolamqp/uplink/commander/__init__.py
deleted file mode 100644
index 129d19e..0000000
--- a/coolamqp/uplink/commander/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# coding=UTF-8
-"""
-Classes that control what Uplink does
-"""
-from __future__ import absolute_import, division, print_function
-
-
-class BaseCommander(object):
-    """
-
-
-    This is invoked by user
-    """
\ No newline at end of file
diff --git a/coolamqp/uplink/factory.py b/coolamqp/uplink/factory.py
deleted file mode 100644
index 337659b..0000000
--- a/coolamqp/uplink/factory.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# coding=UTF-8
-"""
-Set of objects and functions whose job is to construct an Uplink
-instance capable of further action and bootstrap.
-"""
-from __future__ import absolute_import, division, print_function
-
-from coolamqp.uplink.frames.base import AMQP_HELLO_HEADER
-
-import socket
-
-
-def connect(host, port, connect_timeout=10,
-                        general_timeout=5):
-    """
-    Return a TCP socket connected to broker.
-
-    Socket should be in the state of 'Awaiting Connection.Start'
-
-    This may block for up to connect_timeout seconds.
-
-    When returned, this socket will be in the state of awaiting
-    an
-
-    :param host: host to connect to
-    :type host: text
-    :param port: port to connect to
-    :type port: int
-    :return: a CONNECTED socket or None, if connection failed.
-    """
-
-    try:
-        s = socket(socket.AF_INET, socket.SOCK_STREAM)
-        s.settimeout(connect_timeout)
-        s.setsockopt(socket.SOL_SOCKET, socket.TCP_NODELAY, 1)
-        s.connect((host, port))
-        s.send(AMQP_HELLO_HEADER)
-        s.settimeout(0)
-    except (IOError, socket.error, socket.timeout):
-        try:
-            s.close()
-        except:
-            pass
-        return None
diff --git a/coolamqp/uplink/frames/base_definitions.py b/coolamqp/uplink/frames/base_definitions.py
deleted file mode 100644
index befb642..0000000
--- a/coolamqp/uplink/frames/base_definitions.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# coding=UTF-8
-"""
-Used for definitions
-"""
-from __future__ import absolute_import, division, print_function
-
-import struct
-
-from coolamqp.uplink.frames.base import AMQPPayload
-
-
-
-class AMQPClass(object):
-    """An AMQP class"""
-
-
-class AMQPContentPropertyList(object):
-    """
-    A class is intmately bound with content and content properties
-    """
-    PROPERTIES = []
-
-
-class AMQPMethodPayload(AMQPPayload):
-    RESPONSE_TO = None
-    REPLY_WITH = []
-    FIELDS = []
-
-    def write_to(self, buf):
-        """
-        Write own content to target buffer - starting from LENGTH, ending on FRAME_END
-        :param buf: target buffer
-        """
-        from coolamqp.uplink.frames.definitions import FRAME_END
-
-        if self.IS_CONTENT_STATIC:
-            buf.write(self.STATIC_CONTENT)
-        else:
-            buf.write(struct.pack('!I', self.get_size()+2))
-            buf.write(self.BINARY_HEADER)
-            self.write_arguments(buf)
-            buf.write(chr(FRAME_END))
-
-    def get_size(self):
-        """
-        Calculate the size of this frame.
-
-        :return: int, size of argument section
-        """
-        raise NotImplementedError()
-
-    def write_arguments(self, buf):
-        """
-        Write the argument portion of this frame into buffer.
-
-        :param buf: buffer to write to
-        :return: how many bytes written
-        :raise ValueError: some field here is invalid!
-        """
-        raise NotImplementedError()
-
-    @staticmethod
-    def from_buffer(buf, offset):
-        """
-        Construct this frame from a buffer
-
-        :param buf: a buffer to construct the frame from
-        :type buf: buffer or memoryview
-        :param offset: offset the argument portion begins at
-        :type offset: int
-        :return: tuple of (an instance of %s, amount of bytes consumed as int)
-        :raise ValueError: invalid data
-        """
-        raise NotImplementedError('')
-
diff --git a/coolamqp/uplink/frames/compilation/compile_definitions.py b/coolamqp/uplink/frames/compilation/compile_definitions.py
deleted file mode 100644
index 56ec91b..0000000
--- a/coolamqp/uplink/frames/compilation/compile_definitions.py
+++ /dev/null
@@ -1,816 +0,0 @@
-from __future__ import division
-from xml.etree import ElementTree
-import collections
-import struct
-import six
-import math
-
-from coolamqp.uplink.frames.compilation.utilities import get_constants, get_classes, get_domains, \
-    byname, name_class, name_method, name_field, ffmt, doxify, infertype, normname, as_nice_escaped_string, \
-    frepr
-from coolamqp.uplink.frames.base import BASIC_TYPES
-
-TYPE_TRANSLATOR = {
-        'shortstr': 'binary type (max length 255)',
-        'longstr': 'binary type',
-        'table': 'table. See coolamqp.uplink.frames.field_table',
-        'bit': 'bool',
-        'octet': 'int, 8 bit unsigned',
-        'short': 'int, 16 bit unsigned',
-        'long': 'int, 32 bit unsigned',
-        'longlong': 'int, 64 bit unsigned',
-        'timestamp': '64 bit signed POSIX timestamp (in seconds)',
-}
-
-def compile_definitions(xml_file='resources/amqp0-9-1.xml', out_file='coolamqp/uplink/frames/definitions.py'):
-    """parse resources/amqp-0-9-1.xml into """
-
-    xml = ElementTree.parse(xml_file)
-    out = open(out_file, 'wb')
-
-    out.write('''# coding=UTF-8
-from __future__ import print_function, absolute_import
-"""
-A Python version of the AMQP machine-readable specification.
-
-Generated automatically by CoolAMQP from AMQP machine-readable specification.
-See coolamqp.uplink.frames.compilation for the tool
-
-AMQP is copyright (c) 2016 OASIS
-CoolAMQP is copyright (c) 2016 DMS Serwis s.c.
-"""
-
-import struct
-
-from coolamqp.uplink.frames.base_definitions import AMQPClass, AMQPMethodPayload, AMQPContentPropertyList
-from coolamqp.uplink.frames.field_table import enframe_table, deframe_table, frame_table_size
-
-''')
-
-    def line(data, *args, **kwargs):
-        out.write(ffmt(data, *args, sane=True))
-
-    # Output core ones
-    FRAME_END = None
-    con_classes = collections.defaultdict(list)
-    line('# Core constants\n')
-    for constant in get_constants(xml):
-        if normname(constant.name) == 'FRAME_END':
-            FRAME_END = constant.value
-        g = ffmt('%s = %s', normname(constant.name), constant.value)
-        line(g)
-        if constant.docs:
-            lines = constant.docs.split('\n')
-            line(' # %s\n', lines[0])
-            if len(lines) > 1:
-                for ln in lines[1:]:
-                    line(u' '*len(g))
-                    line(u' # %s\n', ln)
-        else:
-            line('\n')
-
-        if constant.kind:
-            con_classes[constant.kind].append(normname(constant.name))
-
-    for constant_kind, constants in con_classes.items():
-        line('\n%s = [%s]', normname(constant_kind), u', '.join(constants))
-
-    # get domains
-    domain_to_basic_type = {}
-    line('\n\n\nDOMAIN_TO_BASIC_TYPE = {\n')
-    for domain in get_domains(xml):
-        line(u'    %s: %s,\n', frepr(domain.name), frepr(None if domain.elementary else domain.type))
-        domain_to_basic_type[domain.name] = domain.type
-
-    line('}\n')
-
-    # Output classes
-    for cls in get_classes(xml):
-
-        cls = cls._replace(content_properties=[p._replace(basic_type=domain_to_basic_type[p.type]) for p in cls.content_properties])
-
-        line('''\nclass %s(AMQPClass):
-    """
-    %s
-    """
-    NAME = %s
-    INDEX = %s
-
-''',
-             name_class(cls.name), doxify(None, cls.docs), frepr(cls.name), cls.index)
-
-        line('''\nclass %sContentPropertyList(AMQPContentPropertyList):
-    """
-    %s
-    """
-    CLASS_NAME = %s
-    CLASS_INDEX = %s
-    CLASS = %s
-
-    CONTENT_PROPERTIES = [  # tuple of (name, domain, type)
-
-''',
-
-           name_class(cls.name), doxify(None, cls.docs), frepr(cls.name), cls.index, name_class(cls.name))
-
-        is_static = all(property.basic_type not in ('table', 'longstr', 'shortstr') for property in cls.content_properties)
-
-        for property in cls.content_properties:
-            line('        (%s, %s, %s), # %s\n', frepr(property.name), frepr(property.type), frepr(property.basic_type),
-                 frepr(property.label))
-        line('    ]\n\n')
-
-
-        line('''    def __init__(%s):
-        """
-        Create the property list.
-
-''',
-             u', '.join(['self'] + [name_field(property.name) for property in cls.content_properties if not property.reserved])
-             )
-
-        for property in (p for p in cls.content_properties if not p.reserved):
-            line('''        :param %s: %s
-        :type %s: %s (%s in AMQP)
-''',
-                 name_field(property.name), property.label, name_field(property.name), TYPE_TRANSLATOR[property.basic_type], property.type)
-        line('''        """
-''')
-
-        for property in (p for p in cls.content_properties if not p.reserved):
-
-            line('        self.%s = %s # %s\n', name_field(property.name), name_field(property.name), property.label)
-        line('''\n    def write_arguments(self, buf):
-''')
-
-        def emit_structs(su):
-            if len(su) == 0:
-                return
-            line("        buf.write(struct.pack('!")
-            line(''.join(a for a, b in su))
-            line("', ")
-            line(', '.join(b for a, b in su))
-            line('))\n')
-
-        def emit_bits(bits):
-            bits = [b for b in bits if b != '0']  # reserved values are out :>
-
-            line("        buf.write(struct.pack('!B', %s))\n",
-                 u' | '.join((u'(int(%s) << %s)' % (bit, position)) for position, bit in enumerate(bits))
-                 )
-
-        good_structs = []
-        written = False
-        bits = []
-        for property in cls.content_properties:
-            val = 'self.' + name_field(property.name) if not property.reserved else BASIC_TYPES[property.basic_type][2]
-
-            if (len(bits) == 8) or ((property.basic_type != 'bit') and len(bits) > 0):
-                emit_bits(bits)
-                bits = []
-                written = True
-
-            if property.basic_type == 'bit':
-                bits.append(val)
-            elif property.reserved:
-                line("        buf.write(" + BASIC_TYPES[property.basic_type][2] + ")\n")
-                written = True
-                continue
-            elif BASIC_TYPES[property.basic_type][1] is None:
-                # struct can't do it
-
-                if property.basic_type == 'longstr':
-                    good_structs.append(('L', 'len(%s)' % (val,)))
-
-                elif property.basic_type == 'shortstr':
-                    good_structs.append(('B', 'len(%s)' % (val,)))
-
-                emit_structs(good_structs)
-                good_structs = []
-
-                if property.basic_type == 'table':
-                    line('        enframe_table(buf, %s)\n' % (val,))
-                    written = True
-                else:
-                    # emit ours
-                    line('        buf.write(' + val + ')\n')
-                    written = True
-            else:
-                # special case - empty string
-                if property.basic_type == 'shortstr' and property.reserved:
-                    continue  # just skip :)
-
-                val = ('self.' + name_field(property.name)) if not property.reserved else frepr(
-                    BASIC_TYPES[property.basic_type][2], sop=six.binary_type)
-
-                good_structs.append((BASIC_TYPES[property.basic_type][1], val))
-                written = True
-        written = written or len(good_structs) > 0
-        emit_structs(good_structs)
-        if len(bits) > 0:
-            emit_bits(bits)
-            written = True
-            bits = []
-
-        if not written:
-            line('        pass # this has a frame, but it''s only default shortstrs\n')
-        line('\n')
-
-        line('''    @staticmethod
-    def from_buffer(buf, start_offset):
-''')
-
-        if len([f for f in cls.content_properties if not f.reserved]) == 0:
-            line("        return %sContentPropertyList()\n\n", name_class(cls.name))
-        else:
-            line("""        assert (len(buf) - start_offset) >= %s.MINIMUM_SIZE, 'Content property list too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-""",
-                 full_class_name)
-            # The simple, or the painful way?
-            has_nonstruct_fields = False
-            for property in cls.content_properties:
-                if BASIC_TYPES[property.basic_type][1] is None:
-                    has_nonstruct_fields = True
-
-            if len(cls.content_properties) == 0:
-                line('        return %s(), 0\n', full_class_name)
-            elif is_static:
-                fieldnames = []
-                formats = []
-
-                bits = []
-                bit_id = 0
-                bits_to_sync_later = {}  # bit_0 => [fLSB, fMSB]
-
-                for property in cls.content_properties:
-                    if property.basic_type == 'bit':
-                        bits.append(None if property.reserved else name_field(property.name))
-
-                        if len(bits) == 8:
-                            fieldnames.append('_bit_%s' % (bit_id,))
-                            formats.append('B')
-                            bits_to_sync_later['_bit_%s' % (bit_id,)] = bits
-                            bits = []
-                            bit_id += 1
-
-                    elif property.reserved:
-                        formats.append('%sx' % (BASIC_TYPES[property.basic_type][0],))
-                    else:
-                        fieldnames.append(name_field(property.name))
-                        formats.append(BASIC_TYPES[property.basic_type][1])
-
-                # sync bits
-                if len(bits) > 0:
-                    fieldnames.append('_bit_%s' % (bit_id,))
-                    formats.append('B')
-                    bits_to_sync_later['_bit_%s' % (bit_id,)] = bits
-
-                line("        %s, = struct.unpack_from('!%s', buf, offset)\n",
-                     u', '.join(fieldnames),
-                     u''.join(formats)
-                     )
-
-                # If there were any bits, unpack them now
-                for var_name, bits in bits_to_sync_later.items():
-                    for bitname, multiplier in zip(bits, (1, 2, 4, 8, 16, 32, 64, 128)):
-                        line("        %s = bool(%s & %s)\n", bitname, var_name, multiplier)
-
-                line("        return %s(%s)", full_class_name, u', '.join([
-                                                                              name_field(property.name) for field in
-                                                                              cls.content_properties if not property.reserved
-                                                                              ]))
-
-            else:
-                def emit_bits(bits):
-
-                    if all(n == '_' for n in bits):
-                        # everything is reserved, lol
-                        line("""        offset += 1
-""")
-                        return
-
-                    line("""        _bit, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-""")
-                    for bit, multiplier in zip(bits, (1, 2, 4, 8, 16, 32, 64, 128)):
-                        if bit != '_':
-                            line("""        %s = bool(_bit & %s)
-""",
-                                 bit, multiplier)
-
-                def emit_structures(ss, ln):
-                    line("""        %s, = struct.unpack_from('!%s', buf, offset)
-        offset += %s
-""",
-                         u', '.join([a[0] for a in ss if not (a[0] == '_' and a[1][-1] == 'x')]),
-                         ''.join([a[1] for a in ss]),
-                         ln
-                         )
-
-                # we'll be counting bytes
-                to_struct = []  # accumulate static field, (var name, struct_code)
-                cur_struct_len = 0  # length of current struct
-
-                bits = []
-                bit_id = 0
-
-                for property in cls.content_properties:
-                    fieldname = '_' if property.reserved else name_field(property.name)
-
-                    if (len(bits) > 0) and (property.basic_type != 'bit'):
-                        emit_bits(bits)
-                        bits = []
-
-                    # offset is current start
-                    # length is length to read
-                    if BASIC_TYPES[property.basic_type][0] is not None:
-                        if property.reserved:
-                            to_struct.append(('_', '%sx' % (BASIC_TYPES[property.basic_type][0],)))
-                        else:
-                            to_struct.append((fieldname, BASIC_TYPES[property.basic_type][1]))
-                        cur_struct_len += BASIC_TYPES[property.basic_type][0]
-                    elif property.basic_type == 'bit':
-                        bits.append(fieldname)
-                    else:
-                        if property.basic_type == 'table':  # oh my god
-                            line("""        %s, delta = deframe_table(buf, offset)
-        offset += delta
-""", name_field(property.name))
-                        else:  # longstr or shortstr
-                            f_q, f_l = ('L', 4) if property.basic_type == 'longstr' else ('B', 1)
-                            to_struct.append(('s_len', f_q))
-                            cur_struct_len += f_l
-                            emit_structures(to_struct, cur_struct_len)
-                            to_struct, cur_struct_len = [], 0
-                            if property.reserved:
-                                line("        offset += s_len\n")
-                            else:
-                                line("        %s = buf[offset:offset+s_len]\n        offset += s_len\n",
-                                     fieldname)
-
-                    # check bits for overflow
-                    if len(bits) == 8:
-                        emit_bits(bits)
-                        bits = []
-
-                if len(bits) > 0:
-                    emit_bits(bits)
-                elif len(to_struct) > 0:
-                    emit_structures(to_struct, cur_struct_len)
-
-                line("        return %sContentPropertyList(%s)",
-                     name_class(cls.name),
-                     u', '.join(name_field(property.name) for property in cls.content_properties if not property.reserved))
-
-            line('\n\n')
-
-        line('    def get_size(self):\n        return ')
-        parts = []
-        accumulator = 0
-        bits = 0
-        for property in cls.content_properties:
-            bt = property.basic_type
-
-            if (bits > 0) and (bt != 'bit'):  # sync bits if not
-                accumulator += int(math.ceil(bits / 8))
-                bits = 0
-
-            if property.basic_type == 'bit':
-                bits += 1
-            elif property.reserved:
-                accumulator += BASIC_TYPES[property.basic_type][3]
-            elif BASIC_TYPES[bt][0] is not None:
-                accumulator += BASIC_TYPES[property.basic_type][0]
-            elif bt == 'shortstr':
-                parts.append('len(self.' + name_field(property.name) + ')')
-                accumulator += 1
-            elif bt == 'longstr':
-                parts.append('len(self.' + name_field(property.name) + ')')
-                accumulator += 4
-            elif bt == 'table':
-                parts.append('frame_table_size(self.' + name_field(property.name) + ')')
-                accumulator += 4
-            else:
-                raise Exception()
-
-        if bits > 0:  # sync bits
-            accumulator += int(math.ceil(bits / 8))
-            bits = 0
-
-        parts.append(repr(accumulator))
-        line(u' + '.join(parts))
-        line('\n\n')
-
-        # ============================================ Do methods for this class
-        for method in cls.methods:
-            full_class_name = '%s%s' % (name_class(cls.name), name_method(method.name))
-
-            # annotate types
-            method.fields = [field._replace(basic_type=domain_to_basic_type[field.type]) for field in method.fields]
-
-            is_static = method.is_static()
-            if is_static:
-                static_size = method.get_size()
-
-            is_content_static = len([f for f in method.fields if not f.reserved]) == 0
-
-            line('''\nclass %s(AMQPMethodPayload):
-    """
-    %s
-    """
-    CLASS = %s
-    NAME = %s
-    CLASSNAME = %s
-    FULLNAME = %s
-
-    CONTENT_PROPERTY_LIST = %sContentPropertyList
-
-    CLASS_INDEX = %s
-    CLASS_INDEX_BINARY = %s
-    METHOD_INDEX = %s
-    METHOD_INDEX_BINARY = %s
-    BINARY_HEADER = %s      # CLASS ID + METHOD ID
-
-    SYNCHRONOUS = %s        # does this message imply other one?
-    REPLY_WITH = [%s]
-
-    SENT_BY_CLIENT = %s
-    SENT_BY_SERVER = %s
-
-    MINIMUM_SIZE = %s # arguments part can never be shorter than this
-
-    IS_SIZE_STATIC = %s     # this means that argument part has always the same length
-    IS_CONTENT_STATIC = %s  # this means that argument part has always the same content
-''',
-                 full_class_name,
-                 doxify(method.label, method.docs),
-                 name_class(cls.name),
-                 frepr(method.name),
-                 frepr(cls.name),
-                 frepr(cls.name + '.' + method.name),
-                 name_class(cls.name),
-                 frepr(cls.index),
-                 as_nice_escaped_string(chr(cls.index)),
-                 frepr(method.index),
-                 as_nice_escaped_string(chr(method.index)),
-                 as_nice_escaped_string(chr(cls.index)+chr(method.index)),
-                 repr(method.synchronous),
-                 u', '.join([name_class(cls.name)+name_method(kidname) for kidname in method.response]),
-                 repr(method.sent_by_client),
-                 repr(method.sent_by_server),
-                 repr(method.get_minimum_size(domain_to_basic_type)),
-                 repr(is_static),
-                 repr(is_content_static)
-                 )
-
-
-            if is_content_static:
-
-                line('''    STATIC_CONTENT = %s  # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END
-''',
-                     as_nice_escaped_string(struct.pack('!LBB', static_size+4, cls.index, method.index)+\
-                                            method.get_static_body()+\
-                                            struct.pack('!B', FRAME_END)))
-
-            # Am I a response somewhere?
-            for paren in cls.methods:
-                if method.name in paren.response:
-                    line('    RESPONSE_TO = %s%s # this is sent in response to %s\n', name_class(cls.name), name_method(paren.name),
-                         cls.name+'.'+paren.name
-                         )
-
-            # fields
-            if len(method.fields) > 0:
-                line('    FIELDS = [ # tuples of (field name, field domain, basic type used, is_reserved)')
-
-                for field in method.fields:
-                    line('\n        (%s, %s, %s, %s), ', frepr(field.name), frepr(field.type),
-                         frepr(field.basic_type), repr(field.reserved))
-                    if field.label:
-                        line(' # '+field.label)
-
-                line('\n    ]\n')
-
-            non_reserved_fields = [field for field in method.fields if not field.reserved]
-
-            # constructor
-            line('''\n    def __init__(%s):
-        """
-        Create frame %s
-''',
-                 u', '.join(['self'] + [name_field(field.name) for field in non_reserved_fields]),
-                 cls.name + '.' + method.name,
-                 )
-
-            if len(non_reserved_fields) > 0:
-                line('\n')
-            for field in non_reserved_fields:
-                if (field.label is not None) or (field.docs is not None):
-                    line('        :param %s: %s\n', name_field(field.name),
-                         doxify(field.label, field.docs, prefix=12, blank=False))
-
-
-
-                line('        :type %s: %s (%s in AMQP)\n', name_field(field.name), TYPE_TRANSLATOR[field.basic_type], field.type)
-
-            line('        """\n')
-
-            for field in non_reserved_fields:
-                line('        self.%s = %s\n', name_field(field.name), name_field(field.name))
-
-            if len(non_reserved_fields) == 0:
-                line('\n')
-
-            # end
-            if not is_content_static:
-                line('''\n    def write_arguments(self, buf):
-''')
-                def emit_structs(su):
-                    if len(su) == 0:
-                        return
-                    line("        buf.write(struct.pack('!")
-                    line(''.join(a for a, b in su))
-                    line("', ")
-                    line(', '.join(b for a, b in su))
-                    line('))\n')
-
-                def emit_bits(bits):
-                    bits = [b for b in bits if b != '0']    # reserved values are out :>
-
-                    line("        buf.write(struct.pack('!B', %s))\n",
-                         u' | '.join((u'(int(%s) << %s)' % (bit, position)) for position, bit in enumerate(bits))
-                         )
-
-                good_structs = []
-                written = False
-                bits = []
-                for field in method.fields:
-                    val = 'self.' + name_field(field.name) if not field.reserved else BASIC_TYPES[field.basic_type][2]
-
-                    if (len(bits) == 8) or ((field.basic_type != 'bit') and len(bits) > 0):
-                        emit_bits(bits)
-                        bits = []
-                        written = True
-
-                    if field.basic_type == 'bit':
-                        bits.append(val)
-                    elif field.reserved:
-                        line("        buf.write("+BASIC_TYPES[field.basic_type][2]+")\n")
-                        written = True
-                        continue
-                    elif BASIC_TYPES[field.basic_type][1] is None:
-                        # struct can't do it
-
-                        if field.basic_type == 'longstr':
-                            good_structs.append(('L', 'len(%s)' % (val, )))
-
-                        elif field.basic_type == 'shortstr':
-                            good_structs.append(('B', 'len(%s)' % (val, )))
-
-                        emit_structs(good_structs)
-                        good_structs = []
-
-                        if field.basic_type == 'table':
-                            line('        enframe_table(buf, %s)\n' % (val, ))
-                            written = True
-                        else:
-                            # emit ours
-                            line('        buf.write('+val+')\n')
-                            written = True
-                    else:
-                        # special case - empty string
-                        if field.basic_type == 'shortstr' and field.reserved:
-                            continue    # just skip :)
-
-                        val = ('self.'+name_field(field.name)) if not field.reserved else frepr(BASIC_TYPES[field.basic_type][2], sop=six.binary_type)
-
-                        good_structs.append((BASIC_TYPES[field.basic_type][1], val))
-                        written = True
-                written = written or len(good_structs) > 0
-                emit_structs(good_structs)
-                if len(bits) > 0:
-                    emit_bits(bits)
-                    written = True
-                    bits = []
-
-                if not written:
-                    line('        pass # this has a frame, but it''s only default shortstrs\n')
-                line('\n')
-
-                line('    def get_size(self):\n        return ')
-                parts = []
-                accumulator = 0
-                bits = 0
-                for field in method.fields:
-                    bt = field.basic_type
-
-                    if (bits > 0) and (bt != 'bit'):    # sync bits if not
-                        accumulator += int(math.ceil(bits / 8))
-                        bits = 0
-
-                    if field.basic_type == 'bit':
-                        bits += 1
-                    elif field.reserved:
-                        accumulator += BASIC_TYPES[field.basic_type][3]
-                    elif BASIC_TYPES[bt][0] is not None:
-                        accumulator += BASIC_TYPES[field.basic_type][0]
-                    elif bt == 'shortstr':
-                        parts.append('len(self.'+name_field(field.name)+')')
-                        accumulator += 1
-                    elif bt == 'longstr':
-                        parts.append('len(self.'+name_field(field.name)+')')
-                        accumulator += 4
-                    elif bt == 'table':
-                        parts.append('frame_table_size(self.'+name_field(field.name)+')')
-                        accumulator += 4
-                    else:
-                        raise Exception()
-
-                if bits > 0:    # sync bits
-                    accumulator += int(math.ceil(bits / 8))
-                    bits = 0
-
-                parts.append(repr(accumulator))
-                line(u' + '.join(parts))
-                line('\n')
-            else:
-                line('    # not generating write_arguments - this method has static content!\n')
-            line('\n')
-
-            line('''    @staticmethod
-    def from_buffer(buf, start_offset):
-''',
-                 full_class_name)
-
-            if is_content_static:
-                line("        return %s()\n\n", full_class_name)
-            else:
-                line("""        assert (len(buf) - start_offset) >= %s.MINIMUM_SIZE, 'Frame too short!'
-        offset = start_offset   # we will use it to count consumed bytes
-""",
-                     full_class_name)
-                # The simple, or the painful way?
-                has_nonstruct_fields = False
-                for field in method.fields:
-                    if BASIC_TYPES[field.basic_type][1] is None:
-                        has_nonstruct_fields = True
-
-                if len(method.fields) == 0:
-                    line('        return %s(), 0\n', full_class_name)
-                elif is_static:
-                    fieldnames = []
-                    formats = []
-
-                    bits = []
-                    bit_id = 0
-                    bits_to_sync_later = {} # bit_0 => [fLSB, fMSB]
-
-                    for field in method.fields:
-                        if field.basic_type == 'bit':
-                            bits.append(None if field.reserved else name_field(field.name))
-
-                            if len(bits) == 8:
-                                fieldnames.append('_bit_%s' % (bit_id, ))
-                                formats.append('B')
-                                bits_to_sync_later['_bit_%s' % (bit_id, )] = bits
-                                bits = []
-                                bit_id += 1
-
-                        elif field.reserved:
-                            formats.append('%sx' % (BASIC_TYPES[field.basic_type][0],))
-                        else:
-                            fieldnames.append(name_field(field.name))
-                            formats.append(BASIC_TYPES[field.basic_type][1])
-
-                    # sync bits
-                    if len(bits) > 0:
-                        fieldnames.append('_bit_%s' % (bit_id,))
-                        formats.append('B')
-                        bits_to_sync_later['_bit_%s' % (bit_id,)] = bits
-
-                    line("        %s, = struct.unpack_from('!%s', buf, offset)\n",
-                         u', '.join(fieldnames),
-                         u''.join(formats)
-                         )
-
-                    # If there were any bits, unpack them now
-                    for var_name, bits in bits_to_sync_later.items():
-                        for bitname, multiplier in zip(bits, (1, 2, 4, 8, 16, 32, 64, 128)):
-                            line("        %s = bool(%s & %s)\n", bitname, var_name, multiplier)
-
-
-                    line("        return %s(%s)", full_class_name, u', '.join([
-                        name_field(field.name) for field in method.fields if not field.reserved
-                                                                                  ]))
-
-                else:
-                    def emit_bits(bits):
-
-                        if all(n == '_' for n in bits):
-                            # everything is reserved, lol
-                            line("""        offset += 1
-""")
-                            return
-
-                        line("""        _bit, = struct.unpack_from('!B', buf, offset)
-        offset += 1
-""")
-                        for bit, multiplier in zip(bits, (1,2,4,8,16,32,64,128)):
-                            if bit != '_':
-                                line("""        %s = bool(_bit & %s)
-""",
-                                     bit, multiplier)
-
-                    def emit_structures(ss, ln):
-                        line("""        %s, = struct.unpack_from('!%s', buf, offset)
-        offset += %s
-""",
-                             u', '.join([a[0] for a in ss if not (a[0] == '_' and a[1][-1] == 'x')]),
-                             ''.join([a[1] for a in ss]),
-                             ln
-                             )
-
-                    # we'll be counting bytes
-                    to_struct = []  # accumulate static field, (var name, struct_code)
-                    cur_struct_len = 0  # length of current struct
-
-                    bits = []
-                    bit_id = 0
-
-                    for field in method.fields:
-                        fieldname = '_' if field.reserved else name_field(field.name)
-
-                        if (len(bits) > 0) and (field.basic_type != 'bit'):
-                            emit_bits(bits)
-                            bits = []
-
-                        # offset is current start
-                        # length is length to read
-                        if BASIC_TYPES[field.basic_type][0] is not None:
-                            if field.reserved:
-                                to_struct.append(('_', '%sx' % (BASIC_TYPES[field.basic_type][0],)))
-                            else:
-                                to_struct.append((fieldname, BASIC_TYPES[field.basic_type][1]))
-                            cur_struct_len += BASIC_TYPES[field.basic_type][0]
-                        elif field.basic_type == 'bit':
-                            bits.append(fieldname)
-                        else:
-                            if field.basic_type == 'table': # oh my god
-                                line("""        %s, delta = deframe_table(buf, offset)
-        offset += delta
-""", name_field(field.name))
-                            else:   # longstr or shortstr
-                                f_q, f_l = ('L', 4) if field.basic_type == 'longstr' else ('B', 1)
-                                to_struct.append(('s_len', f_q))
-                                cur_struct_len += f_l
-                                emit_structures(to_struct, cur_struct_len)
-                                to_struct, cur_struct_len = [], 0
-                                if field.reserved:
-                                    line("        offset += s_len\n")
-                                else:
-                                    line("        %s = buf[offset:offset+s_len]\n        offset += s_len\n",
-                                         fieldname)
-
-                        # check bits for overflow
-                        if len(bits) == 8:
-                            emit_bits(bits)
-                            bits = []
-
-                    if len(bits) > 0:
-                        emit_bits(bits)
-                    elif len(to_struct) > 0:
-                        emit_structures(to_struct, cur_struct_len)
-
-
-
-                    line("        return %s(%s)",
-                         full_class_name,
-                         u', '.join(name_field(field.name) for field in method.fields if not field.reserved))
-
-
-                line('\n\n')
-
-
-        # Get me a dict - (classid, methodid) => class of method
-        dct = {}
-        for cls in get_classes(xml):
-            for method in cls.methods:
-                dct[((cls.index, method.index))] = '%s%s' % (name_class(cls.name), name_method(method.name))
-
-    line('\nIDENT_TO_METHOD = {\n')
-    for k, v in dct.items():
-        line('    %s: %s,\n', repr(k), v)
-    line('}\n\n')
-
-    line('\nBINARY_HEADER_TO_METHOD = {\n')
-    for k, v in dct.items():
-        line('    %s: %s,\n', as_nice_escaped_string(struct.pack('!BB', *k)), v)
-    line('}\n\n')
-
-
-    out.close()
-
-
-if __name__ == '__main__':
-    compile_definitions()
diff --git a/coolamqp/uplink/iface.py b/coolamqp/uplink/iface.py
new file mode 100644
index 0000000..9f2b35b
--- /dev/null
+++ b/coolamqp/uplink/iface.py
@@ -0,0 +1,2 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
diff --git a/coolamqp/uplink/order.py b/coolamqp/uplink/order.py
index 74486d4..9eaf45c 100644
--- a/coolamqp/uplink/order.py
+++ b/coolamqp/uplink/order.py
@@ -13,7 +13,7 @@ class MethodTransaction(object):
 
 class SyncOrder(Order):
     """
-    This means "send a method frame, optionally some other frames,
+    This means "send a method frame, optionally some other framing,
     and run a callback with the returned thing.
 
     Possible responses are registered for.
diff --git a/coolamqp/uplink/streams/reader_thread.py b/coolamqp/uplink/reader_thread.py
similarity index 86%
rename from coolamqp/uplink/streams/reader_thread.py
rename to coolamqp/uplink/reader_thread.py
index f5870f3..ae333b5 100644
--- a/coolamqp/uplink/streams/reader_thread.py
+++ b/coolamqp/uplink/reader_thread.py
@@ -6,7 +6,7 @@ import threading
 
 class ReaderThread(threading.Thread):
     """
-    A thread, whose job is to receive AMQP frames from AMQP TCP socket.
+    A thread, whose job is to receive AMQP framing from AMQP TCP socket.
 
     Thread may inform Uplink of socket's lossage via on_socket_failed(exception). It should exit afterwards at once.
     """
@@ -26,7 +26,7 @@ class ReaderThread(threading.Thread):
 
     def on_cancel(self):
         """
-        Called by Uplink when it decides that we should not report any more frames, and should just die.
+        Called by Uplink when it decides that we should not report any more framing, and should just die.
         """
         self.is_cancelled = True
 
diff --git a/coolamqp/uplink/streams/recv_formatter.py b/coolamqp/uplink/recv_framer.py
similarity index 89%
rename from coolamqp/uplink/streams/recv_formatter.py
rename to coolamqp/uplink/recv_framer.py
index 528cfcb..69e0f07 100644
--- a/coolamqp/uplink/streams/recv_formatter.py
+++ b/coolamqp/uplink/recv_framer.py
@@ -1,15 +1,12 @@
 # coding=UTF-8
 from __future__ import absolute_import, division, print_function
-import struct
-import io
-import six
-import collections
-import socket
 
-from coolamqp.uplink.frames.definitions import FRAME_HEADER, FRAME_HEARTBEAT, FRAME_END, FRAME_METHOD, FRAME_BODY
-from coolamqp.uplink.frames.frames import AMQPBodyFrame, AMQPHeaderFrame, AMQPHeartbeatFrame, AMQPMethodFrame
-from coolamqp.uplink.streams.exceptions import InvalidDataError
+import collections
+import io
+import struct
 
+from coolamqp.framing import AMQPBodyFrame, AMQPHeaderFrame, AMQPHeartbeatFrame, AMQPMethodFrame
+from coolamqp.framing import FRAME_HEADER, FRAME_HEARTBEAT, FRAME_END, FRAME_METHOD, FRAME_BODY
 
 FRAME_TYPES = {
     FRAME_HEADER: AMQPHeaderFrame,
@@ -20,9 +17,9 @@ FRAME_TYPES = {
 
 class ReceivingFormatter(object):
     """
-    Assembles AMQP frames from received data.
+    Assembles AMQP framing from received data.
 
-    Just call with .put(data) and get frames by iterator .frames().
+    Just call with .put(data) and get framing by iterator .framing().
 
     Not thread safe.
 
@@ -54,10 +51,10 @@ class ReceivingFormatter(object):
 
     def get_frames(self):   # -> iterator of AMQPFrame, raises ValueError
         """
-        An iterator to return frames pending for read.
+        An iterator to return framing pending for read.
 
         :raises ValueError: invalid frame readed, kill the connection.
-        :return: iterator with frames
+        :return: iterator with framing
         """
         while self._statemachine():
             pass
diff --git a/coolamqp/uplink/streams/send_operator.py b/coolamqp/uplink/send_framer.py
similarity index 94%
rename from coolamqp/uplink/streams/send_operator.py
rename to coolamqp/uplink/send_framer.py
index b76a0f6..49c88a2 100644
--- a/coolamqp/uplink/streams/send_operator.py
+++ b/coolamqp/uplink/send_framer.py
@@ -9,9 +9,9 @@ import socket
 
 class SendingOperator(object):
     """
-    Assembles AMQP frames from received data and orchestrates their upload via a socket.
+    Assembles AMQP framing from received data and orchestrates their upload via a socket.
 
-    Just call with .put(data) and get frames by iterator .frames().
+    Just call with .put(data) and get framing by iterator .framing().
 
     Not thread safe.
 
@@ -77,7 +77,7 @@ class SendingOperator(object):
 
     def send(self, frames, on_done=None, on_fail=None):
         """
-        Schedule to send some frames.
+        Schedule to send some framing.
         :param frames: list of AMQPFrame instances
         :param on_done: callable/0 to call when this is done (frame_end of last frame has just left this PC)
         :param on_fail: callable(Exception) to call when something broke before the data could be sent.
diff --git a/coolamqp/uplink/streams/__init__.py b/coolamqp/uplink/streams/__init__.py
deleted file mode 100644
index 772cb44..0000000
--- a/coolamqp/uplink/streams/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# coding=UTF-8
-"""
-Classes that allow to receive and send frames
-REASONABLY FAST, because they use buffers and stuff.
-"""
-from __future__ import absolute_import, division, print_function
-
-from coolamqp.uplink.streams.recv_formatter import ReceivingFormatter
-from coolamqp.uplink.streams.send_operator import SendingOperator
diff --git a/coolamqp/uplink/uplink.py b/coolamqp/uplink/uplink.py
deleted file mode 100644
index 905e5f4..0000000
--- a/coolamqp/uplink/uplink.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# coding=UTF-8
-from __future__ import absolute_import, division, print_function
-import collections
-from six.moves import queue
-
-
-from coolamqp.uplink.frames.base_definitions import AMQPMethodPayload
-
-
-class Uplink(object):
-    """
-    Uplink, the frame relay manager.
-
-    It coordinates the joint effort of all the classes in this module.
-
-    Uplink brings a thread to life - reader_thread - those job is to recv() on socket.
-
-
-
-    There are two principal threads that can call Uplink.
-    1) CoolAMQP frontend thread: this is the one processing events in the system. This thread
-       is the only one allowed to send(), and will frequently block on it.
-
-       Well, you can't process more tasks if you are hanging on send, are you.
-
-    2) Reader thread, spawned and managed by Uplink. This is the thread running recv() on the socket,
-       calling the callbacks that you register, and so on.
-
-    """
-
-    def __init__(self):
-        #                       Watchers
-        # Watcher is a one-time trigger set on one (or more) method frames.
-        self.watchers_to_register = queue.Queue()
-        pass
-
-
-
-    def listen_for_method_frame(self, frames, on_frame=lambda f: None, on_dead=None):
-        """
-        Register a one-time listener for a particular method frame (or may kinds of frame).
-
-        When one matching frame arrives, on_frame will be called and rest of subscriptions will be evicted.
-
-        The callback will be executed in Uplink's internal thread context.
-
-        :param frames:
-        :param on_frame:
-        :param on_dead:
-        :return:
-        """
-
-    def
-
-
-
-    def on_socket_failed(self, exc):
-        """Called by ReaderThread when it detects that socket has failed"""
\ No newline at end of file
diff --git a/coolamqp/uplink/streams/watchman.py b/coolamqp/uplink/watchman.py
similarity index 55%
rename from coolamqp/uplink/streams/watchman.py
rename to coolamqp/uplink/watchman.py
index e244fe4..b82bc03 100644
--- a/coolamqp/uplink/streams/watchman.py
+++ b/coolamqp/uplink/watchman.py
@@ -4,9 +4,69 @@ import collections
 from six.moves import queue
 
 
-class Watchman(object):
+from coolamqp.uplink.exceptions import called_by
+from coolamqp.scaffold import AcceptsFrames, RelaysFrames, Synchronized
+
+from coolamqp.framing.frames import AMQPMethodFrame, AMQPHeartbeatFrame, AMQPBodyFrame, AMQPHeaderFrame
+
+
+class Watch(object):
+    def __init__(self, channel, on_frame, predicate):
+        """
+        :type predicate: callable(AMQPFrame object) -> should_trigger::bool
+        """
+        self.channel = channel
+        self.on_frame = on_frame
+        self.predicate = predicate
+
+
+
+
+class Watchman(AcceptsFrames, RelaysFrames, Synchronized):
+    """
+    Watchman is the guy, who:
+
+    - Receives frames from RecvFramer
+    - Executes in the context of the Listener
+    - You can ask to trigger, when a particular frame is received from server
     """
-    Watchman is a guy that you can:
+
+    def __init__(self):
+        super(Watchman, self).__init__(self)
+        self.watches = collections.defaultdict(collections.deque)
+        self.on_frame = lambda frame: None
+
+    def wire_frame_to(self, on_frame):
+        """
+        Set this Watchman to pass non-triggered frames to some callable.
+
+        Called by: Uplink factory
+
+        :param callable: callable(AMQPMethodPayload object)
+        """
+        self.on_frame = on_frame
+
+    @
+    def trigger_methods(self, channel, frame_payload_types, on_frame):
+        """
+        Register a one-shot trigger on an AMQP method.
+
+        After triggering upon any of method frame payload types, you'll get a callback with
+        AMQPMethodPayload instance. This will prevent it from being relayed further.
+
+        Called by: frontend, listener
+
+        :param channel: channel ID
+        :param frame_payload_types: list of AMQPMethodPayload classes
+        :param on_frame: callable(AMQPMethodPayload instance) -> n/a
+        """
+        def predicate(frame):
+            if not isinstance(frame, )
+        m = Watch(channel, on_frame, lambda frame: isinstance(frame.payload ))
+        with self.lock:
+
+
+
 
      - If you are ReaderThread, ask "hey, this frame just arrived,
      is someone interested in it?"
@@ -14,7 +74,7 @@ class Watchman(object):
      when a particular frame arrives (or a bunch of them, if your request
      expects a bunch).
 
-    Since Watchman receives all frames from ReaderThread, it also knows about:
+    Since Watchman receives all framing from ReaderThread, it also knows about:
     - channels being opened
     - channels being closed by exception
     -
@@ -51,7 +111,7 @@ class Watchman(object):
     def on_frame(self, frame):
         """
         A frame arrived. If this triggers a watch, trigger it and remove.
-        All frames received by ReaderThread go thru here.
+        All framing received by ReaderThread go thru here.
 
         TO BE CALLED BY READER THREAD
 
diff --git a/setup.py b/setup.py
index 03c8c95..4b387b7 100644
--- a/setup.py
+++ b/setup.py
@@ -14,8 +14,8 @@ setup(name='CoolAMQP',
           'coolamqp',
           'coolamqp.backends',
           'coolamqp.uplink',
-          'coolamqp.uplink.frames',
-          'coolamqp.uplink.frames.compilation',
+          'coolamqp.uplink.framing',
+          'coolamqp.uplink.framing.compilation',
           'coolamqp.uplink.streams',
 
       ],
-- 
GitLab