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']