diff --git a/coolamqp/attaches/channeler.py b/coolamqp/attaches/channeler.py
index 87f733907555e49b6a5b7b63901744c27af2e5d8..b2c9ac788d7b1f0b8c616f329176ad362ab34ca3 100644
--- a/coolamqp/attaches/channeler.py
+++ b/coolamqp/attaches/channeler.py
@@ -6,6 +6,7 @@ set up and tear down channels
 from __future__ import print_function, absolute_import, division
 
 import logging
+import typing as tp
 
 from coolamqp.framing.definitions import ChannelOpen, ChannelOpenOk, \
     ChannelClose, ChannelCloseOk, BasicCancel, \
@@ -29,7 +30,7 @@ class Attache(object):
         self.state = ST_OFFLINE
         self.connection = None
 
-    def attach(self, connection):
+    def attach(self, connection):  # type (coolamqp.uplink.connection.Connection) -> None
         """
         Attach to a connection.
 
@@ -69,7 +70,7 @@ class Channeler(Attache):
         super(Channeler, self).__init__()
         self.channel_id = None  # channel obtained from Connection
 
-    def attach(self, connection):
+    def attach(self, connection):  # type (coolamqp.uplink.connection.Connection) -> None
         """
         Attach this object to a live Connection.
 
@@ -81,7 +82,7 @@ class Channeler(Attache):
 
     # ------- event handlers
 
-    def on_operational(self, operational):
+    def on_operational(self, operational):  # type: (bool) -> None
         """
         [EXTEND ME] Called by internal methods (on_*) when channel has achieved (or lost) operational status.
 
@@ -97,6 +98,7 @@ class Channeler(Attache):
         """
 
     def on_close(self, payload=None):
+        # type (tp.Optional[coolamqp.framing.base.AMQPMethodPayload) -> None
         """
         [EXTEND ME] Handler for channeler destruction.
 
@@ -161,6 +163,7 @@ class Channeler(Attache):
                          payload.reply_text.tobytes())
 
     def methods(self, payloads):
+        # type: (tp.Iterable[coolamqp.framing.base.AMQPMethodPayload]) -> None
         """
         Syntactic sugar for
 
@@ -177,6 +180,7 @@ class Channeler(Attache):
         self.connection.send(frames)
 
     def method(self, payload):
+        # type: (tp.Iterable[coolamqp.framing.base.AMQPMethodPayload]) -> None
         """
         Syntactic sugar for:
 
@@ -186,6 +190,8 @@ class Channeler(Attache):
 
     def method_and_watch(self, method_payload, method_classes_to_watch,
                          callable):
+        # type: (coolamqp.framing.base.AMQPMethodPayload,
+        # tp.Iterable[type], tp.Callable[[coolamqp.framing.base.AMQPMethodPayload], None]) -> None
         """
         Syntactic sugar for
 
@@ -198,7 +204,7 @@ class Channeler(Attache):
         self.connection.method_and_watch(self.channel_id, method_payload,
                                          method_classes_to_watch, callable)
 
-    def on_setup(self, payload):
+    def on_setup(self, payload):  # type: (coolamqp.framing.base.AMQPMethodPayload) -> None
         """
         [OVERRIDE ME!] Called with a method frame that signifies a part of setup.
 
diff --git a/coolamqp/framing/base.py b/coolamqp/framing/base.py
index 6b224dcb73cf5069e632d59ceb45723502396088..e52f7be306ca3aec9a7bd0d31878e20c0891ee45 100644
--- a/coolamqp/framing/base.py
+++ b/coolamqp/framing/base.py
@@ -1,12 +1,11 @@
 # coding=UTF-8
 from __future__ import absolute_import, division, print_function
 
-import logging
-
-logger = logging.getLogger(__name__)
+import typing as tp
 
 AMQP_HELLO_HEADER = b'AMQP\x00\x00\x09\x01'
 
+
 # name => (length|None, struct ID|None, reserved-field-value : for struct if structable, bytes else, length of default)
 BASIC_TYPES = {u'bit': (None, None, "0", None),  # special case
                u'octet': (1, 'B', "b'\\x00'", 1),
@@ -29,10 +28,10 @@ DYNAMIC_BASIC_TYPES = (u'table', u'longstr', u'shortstr')
 class AMQPFrame(object):  # base class for framing
     FRAME_TYPE = None  # override me!
 
-    def __init__(self, channel):
+    def __init__(self, channel):  # type: (int) -> None
         self.channel = channel
 
-    def write_to(self, buf):
+    def write_to(self, buf):  # type: (io.BinaryIO) -> None
         """
         Write a complete frame to buffer
 
@@ -52,26 +51,29 @@ class AMQPFrame(object):  # base class for framing
         """
         raise NotImplementedError('Override me')
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         """
         Return size of this frame, in bytes, from frame type to frame_end
         :return: int
         """
         raise NotImplementedError('Override me')
 
+    def __str__(self):  # type: () -> str
+        return 'AMQPFrame(%s)' % (self.channel,)
+
 
 class AMQPPayload(object):
     """Payload is something that can write itself to bytes,
     or at least provide a buffer to do it."""
 
-    def write_to(self, buf):
+    def write_to(self, buf):  # type: (buffer) -> None
         """
         Emit itself into a buffer, from length to FRAME_END
 
         :param buf: buffer to write to (will be written using .write)
         """
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         """
         Return size of this payload
         :return: int
@@ -95,10 +97,11 @@ class AMQPContentPropertyList(object):
 
     # todo they are immutable, so they could just serialize themselves...
 
-    def __str__(self):
+    def __str__(self):  # type: () -> str
         return '<AMQPContentPropertyList>'
 
     def get(self, property_name, default=None):
+        # type: (str, str) -> tp.Union[memoryview, bytes]
         """
         Return a particular property, or default if not defined
         :param property_name: property name, unicode
@@ -127,7 +130,7 @@ class AMQPContentPropertyList(object):
         raise Exception(u'This is an abstract method')
 
     @staticmethod
-    def from_buffer(self, buf, start_offset):
+    def from_buffer(self, buf, start_offset):  # type: (buffer, int) -> AMQPContentPropertyList
         """
         Return an instance of self, loaded from a buffer.
 
@@ -137,7 +140,7 @@ class AMQPContentPropertyList(object):
         """
         raise Exception(u'This is an abstract method')
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         """
         How long is property_flags + property_values
         :return: int
@@ -150,7 +153,7 @@ class AMQPMethodPayload(AMQPPayload):
     REPLY_WITH = []
     FIELDS = []
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         """
         Calculate the size of this frame.
 
@@ -162,7 +165,7 @@ class AMQPMethodPayload(AMQPPayload):
 
         raise NotImplementedError()
 
-    def write_arguments(self, buf):
+    def write_arguments(self, buf):  # type: (tp.BinaryIO) -> None
         """
         Write the argument portion of this frame into buffer.
 
@@ -173,7 +176,7 @@ class AMQPMethodPayload(AMQPPayload):
         raise NotImplementedError()
 
     @staticmethod
-    def from_buffer(buf, offset):
+    def from_buffer(buf, offset):  # type: (buffer, int) -> AMQPMethodPayload
         """
         Construct this frame from a buffer
 
diff --git a/coolamqp/framing/field_table.py b/coolamqp/framing/field_table.py
index 98ffe811f180a94e777582a43dba673883b4838a..60cf0dd1ad00800054cebaa6f01c0d5ab8ebf5f7 100644
--- a/coolamqp/framing/field_table.py
+++ b/coolamqp/framing/field_table.py
@@ -15,15 +15,15 @@ NOTE: it's not buffers, it's memoryview all along
 """
 
 import struct
-
+import io
 import six
 
 
-def _tobuf(buf, pattern, *vals):
+def _tobuf(buf, pattern, *vals):  # type: (io.BytesIO, str, *tp.Any) -> int
     return buf.write(struct.pack(pattern, *vals))
 
 
-def _tobufv(buf, value, pattern, *vals):
+def _tobufv(buf, value, pattern, *vals):  # type: (io.BytesIO, bytes, str, *tp.Any) -> None
     _tobuf(buf, pattern, *vals)
     buf.write(value)
 
diff --git a/coolamqp/framing/frames.py b/coolamqp/framing/frames.py
index 092f0b820cb7c7d652c21e6baed24a3260e1dee6..1aa4ea4b117131da1dcf3d93027cd36a8df73c7b 100644
--- a/coolamqp/framing/frames.py
+++ b/coolamqp/framing/frames.py
@@ -18,6 +18,7 @@ class AMQPMethodFrame(AMQPFrame):
     FRAME_TYPE = FRAME_METHOD
 
     def __init__(self, channel, payload):
+        # type: (int, coolamqp.framing.base.AMQPMethodPayload) -> None
         """
         :param channel: channel ID
         :param payload: AMQPMethodPayload instance
@@ -25,7 +26,7 @@ class AMQPMethodFrame(AMQPFrame):
         AMQPFrame.__init__(self, channel)
         self.payload = payload
 
-    def __str__(self):
+    def __str__(self):  # type: () -> str
         return 'AMQPMethodFrame(%s, %s)' % (self.channel, self.payload)
 
     def write_to(self, buf):
@@ -51,7 +52,7 @@ class AMQPMethodFrame(AMQPFrame):
         else:
             return AMQPMethodFrame(channel, payload)
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         # frame_header = (method(1) + channel(2) + length(4) + class(2) + method(2) + payload(N) + frame_end(1))
         return 12 + self.payload.get_size()
 
@@ -60,6 +61,7 @@ class AMQPHeaderFrame(AMQPFrame):
     FRAME_TYPE = FRAME_HEADER
 
     def __init__(self, channel, class_id, weight, body_size, properties):
+        # type: (int, int, int, int, AMQPContentPropertyList) -> None
         """
         :param channel: channel ID
         :param class_id: class ID
@@ -91,11 +93,11 @@ class AMQPHeaderFrame(AMQPFrame):
         return AMQPHeaderFrame(channel, class_id, weight, body_size,
                                properties)
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         # frame header is always 7, frame end is 1, content header is 12 + props
         return 20 + self.properties.get_size()
 
-    def __str__(self):
+    def __str__(self):  # type: () -> str
         return 'AMQPHeaderFrame(%s, %s, %s, %s, %s)' % (self.channel, self.class_id, self.weight,
                                                         self.body_size, self.properties)
 
@@ -105,7 +107,7 @@ class AMQPBodyFrame(AMQPFrame):
 
     FRAME_SIZE_WITHOUT_PAYLOAD = 8
 
-    def __init__(self, channel, data):
+    def __init__(self, channel, data):  # type: (int, bytes) -> None
         """
         :type data: binary
         """
@@ -123,10 +125,10 @@ class AMQPBodyFrame(AMQPFrame):
     def unserialize(channel, payload_as_buffer):
         return AMQPBodyFrame(channel, payload_as_buffer)
 
-    def get_size(self):
+    def get_size(self):  # type: () -> int
         return 8 + len(self.data)
 
-    def __str__(self):
+    def __str__(self):  # type: () -> str
         return '<AMQPBodyFrame of size %s>' % (len(self.data),)
 
 
diff --git a/coolamqp/uplink/connection/connection.py b/coolamqp/uplink/connection/connection.py
index e12e3d2c208bb78d36bcc21dada245e26b9e5ef7..e658836d0caef6fc9f8ec17b2bad4b9a450ab595 100644
--- a/coolamqp/uplink/connection/connection.py
+++ b/coolamqp/uplink/connection/connection.py
@@ -10,6 +10,7 @@ import uuid
 import monotonic
 
 from coolamqp.exceptions import ConnectionDead
+from coolamqp.framing.base import AMQPMethodPayload
 from coolamqp.framing.definitions import ConnectionClose, ConnectionCloseOk
 from coolamqp.framing.frames import AMQPMethodFrame
 from coolamqp.objects import Callable
@@ -344,6 +345,8 @@ class Connection(object):
             self.watches[watch.channel].append(watch)
 
     def watch_for_method(self, channel, method, callback, on_fail=None):
+        # type: (int, AMQPMethodPayload, tp.Callable[[AMQPMethodPayload], None],
+        #   tp.Optional[tp.Callable[[AMQPMethodPayload], None]]) -> MethodWatch
         """
         :param channel: channel to monitor
         :param method: AMQPMethodPayload class or tuple of AMQPMethodPayload classes
diff --git a/docs/conf.py b/docs/conf.py
index 65811d17f4b575726d79ca8ac67c9647cf02d6b8..3ac9cc3d02a257bf17684d8a00ed5449eaaafe30 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -23,7 +23,9 @@ sys.path.insert(0, os.path.abspath('..'))
 source_parsers = {
 }
 
-# -- General configuration ------------------------------------------------
+os.system('pip install sphinx-autodoc-typehints')
+
+# -- General configuration ----------------------------------
 
 # If your documentation needs a minimal Sphinx version, state it here.
 #
@@ -32,7 +34,7 @@ source_parsers = {
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ['sphinx.ext.autodoc']
+extensions = ['sphinx.ext.autodoc', 'sphinx_autodoc_typehints']
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']