KBUS Python bindings for Messages

KBUS lightweight message system.

Inheritance diagram of Announcement, Request, Reply, Status

Message

class kbus.Message(name, data=None, to=None, from_=None, orig_from=None, final_to=None, in_reply_to=None, flags=None, id=None)

Bases: object

A wrapper for a KBUS message

A Message can be created in a variety of ways. Perhaps most obviously:

>>> msg = Message('$.Fred')
>>> msg
Message('$.Fred')
>>> msg = Message('$.Fred', '1234')
>>> msg
Message('$.Fred', data='1234')
>>> msg = Message('$.Fred', '12345678')
>>> msg
Message('$.Fred', data='12345678')
>>> msg1 = Message('$.Fred', data='1234')
>>> msg1
Message('$.Fred', data='1234')

A Message can be constructed from another message directly:

>>> msg2 = Message.from_message(msg1)
>>> msg2 == msg1
True

or from the tuple returned by extract():

>>> msg3 = Message.from_sequence(msg1.extract())
>>> msg3 == msg1
True

or from an equivalent list:

>>> msg3 = Message.from_sequence(list(msg1.extract()))
>>> msg3 == msg1
True

or one can use a “string” – for instance, as returned by the Ksock.read() method:

>>> msg_as_string = msg1.to_bytes()
>>> msg4 = Message.from_bytes(msg_as_string)
>>> msg4 == msg1
True

Some testing is made on the first argument - a printable string must start with $. (KBUS itself will make a more stringent test when the message is sent):

>>> Message('Fred')
Traceback (most recent call last):
...
ValueError: Message name "Fred" does not start "$."

and a data “string” must be plausible - that is, long enough for the minimal message header:

>>> Message.from_bytes(msg_as_string[:8])
Traceback (most recent call last):
...
ValueError: Cannot form entire message from string "Kbus\x00\x00\x00\x00" of length 8

and starting with a message start guard:

>>> Message.from_bytes('1234'+msg_as_string)
Traceback (most recent call last):
...
ValueError: Cannot form entire message from string "1234Kbus..1234subK" which does not start with message start guard

When constructing a message from another message, one may override particular values (but not the name):

>>> msg5 = Message.from_message(msg1, to=9, in_reply_to=MessageId(0, 3))
>>> msg5
Message('$.Fred', data='1234', to=9L, in_reply_to=MessageId(0, 3))
>>> msg5a = Message.from_message(msg1, to=9, in_reply_to=MessageId(0, 3))
>>> msg5a == msg5
True

However, whilst it is possible to set (for instance) to back to 0 by this method:

>>> msg6 = Message.from_message(msg5, to=0)
>>> msg6
Message('$.Fred', data='1234', in_reply_to=MessageId(0, 3))

(and the same for any of the integer fields), it is not possible to set any of the message id fields to None:

>>> msg6 = Message.from_message(msg5, in_reply_to=None)
>>> msg6
Message('$.Fred', data='1234', to=9L, in_reply_to=MessageId(0, 3))

If you need to do that, go via the extract() method:

>>> (id, in_reply_to, to, from_, orig_from, final_to, flags, name, data) = msg5.extract()
>>> msg6 = Message(name, data, to, from_, None, None, flags, id)
>>> msg6
Message('$.Fred', data='1234', to=9L)

For convenience, the parts of a Message may be retrieved as properties:

>>> print msg1.id
None
>>> msg1.name
'$.Fred'
>>> msg1.to
0L
>>> msg1.from_
0L
>>> print msg1.in_reply_to
None
>>> msg1.flags
0L
>>> msg1.data
'1234'

Message ids are objects if set:

>>> msg1 = Message('$.Fred', data='1234', id=MessageId(0, 33))
>>> msg1
Message('$.Fred', data='1234', id=MessageId(0, 33))
>>> msg1.id
MessageId(0, 33)

The arguments to Message() are:

  • arg – this is the initial argument, and is a message name (a string that starts $.), a Message, or a string representing an “entire” message.

    If arg is a message name, or another Message then the keyword arguments may be used (for another Message, they override the values in that Message). If arg is a message-as-a-string, any keyword arguments will be ignored.

  • data is data for the Message, either None or a Python string.

  • to is the Ksock id for the destination, for use in replies or in stateful messaging. Normally it should be left 0.

  • from_ is the Ksock id of the sender. Normally this should be left 0, as it is assigned by KBUS.

  • if in_reply_to is non-zero, then it is the Ksock id to which the reply shall go (taken from the from_ field in the original message). Setting in_reply_to non-zero indicates that the Message is a reply. See also the Reply class, and especially the reply_to function, which makes constructing replies simpler.

  • flags can be used to set the flags for the message. If all that is wanted is to set the Message.WANT_A_REPLY flag, it is simpler to use the Request class to construct the message.

  • id may be used to set the message id, although unless the network_id field is set, KBUS will ignore this and set the id internally (this can be useful when constructing a message to compare received messages against).

Our internal values are:

  • msg, which is the actual message datastructure.

Note

Message data is always held as the appropriate C datastructure (via ctypes), mainly to try to minimise copying of data in and out of that form. A “pointy” or “entire” form is used as appropriate.

The message fields (inside msg) are readable directly (as properties of Message), but are not directly writable. Setter methods (set_urgent() and set_want_reply()) are provided for those which are likely to be sensible to alter in normal use.

If you need to alter the Message contents, beyond use of the setter methods, then you will need to do so via the internal msg datastructure, with a clear understanding of the KBUS datastructure. If you need an example of doing this, see the Limpet codebase (which changes the id, orig_from and final_to fields, not something normal code should need or want to do).

ALL_OR_FAIL = 512L
ALL_OR_WAIT = 256L
END_GUARD = 1264743795
START_GUARD = 1937072715
SYNTHETIC = 4L
URGENT = 8L
WANT_A_REPLY = 1L
WANT_YOU_TO_REPLY = 2L
cast()

Return (a copy of) ourselves as an appropriate subclass of Message.

Reading from a Ksock returns a Message, whatever the actual message type. Normally, this is OK, but sometimes it would be nice to have an actual message of the correct class.

data

Returns the payload of this KBUS message as a Python string, or None if it is not present.

equivalent(other)

Returns true if the two messages are mostly the same.

For purposes of this comparison, we ignore id, flags, in_reply_to and from_.

extract()

Return our parts as a tuple.

The values are returned in something approximating the order within the message itself:

(id, in_reply_to, to, from_, orig_from, final_to, flags, name, data)

This is not the same order as the keyword arguments to Message().

final_to

The final_to field of the message header. This is of type OrigFrom.

flags

The flags field of the message header.

from_

The from field of the message header.

static from_bytes(arg)

Construct a Message from bytes, as read by Ksock.read_data().

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Message.from_bytes(msg1.to_bytes())
>>> msg2
Message('$.Fred', data='12345678')
static from_message(msg, data=None, to=None, from_=None, orig_from=None, final_to=None, in_reply_to=None, flags=None, id=None)

Construct a Message from another message.

All the values in the old message, except the name, may be changed by specifying new values in the argument list.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Message.from_message(msg1, flags=1)
>>> msg2
Message('$.Fred', data='12345678', flags=0x00000001)
static from_sequence(seq, data=None, to=None, from_=None, orig_from=None, final_to=None, in_reply_to=None, flags=None, id=None)

Construct a Message from a sequence, as returned by extract.

All the values in the old message, except the name, may be changed by specifying new values in the argument list.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Message.from_sequence(msg1.extract(), flags=1)
>>> msg2
Message('$.Fred', data='12345678', flags=0x00000001)
id

The id field of the message header.

in_reply_to

The in_reply_to field of the message header.

is_reply()

A convenience method - are we a Reply?

is_request()

A convenience method - are we a Request?

is_stateful_request()

A convenience method - are we a Stateful Request?

is_synthetic()

Return True if this is a synthetic message - one generated by KBUS.

is_urgent()

Return True if this is an urgent message.

name

The name field of the message header. Any padding bytes are removed.

orig_from

The orig_from field of the message header. This is of type OrigFrom.

set_urgent(value=True)

Set or unset the ‘urgent message’ flag.

set_want_reply(value=True)

Set or unset the ‘we want a reply’ flag.

to

The to field of the message header.

to_bytes()

Return the message as a string.

This returns the entirety of the message as a Python string.

In order to do this, it first coerces the mesage to an “entire” message (so that we don’t have any dangling “pointers” to the name or data).

See the total_length() method for how to determine the “correct” length of this string.

total_length()

Return the total length of this message.

A Message may be held in one of two ways:

  • “pointy” - this is a message header, with references to the message name and data.
  • “entire” - this is a message header with the message name and data (and an extra end guard) appended to it.

Message construction may produce either of these (although construction of a message from a string will always produce an “entire” message). Reading a message from a Ksock returns an “entire” message string.

The actual “pointy” or “entire” message data is held in the msg value of the Message instance.

The to_bytes() method returns the data for an “entire” message. In certain circumstances (typically, on a 64-byte system) the actual length of data returned by to_bytes() may be slightly too long (due to extra padding at the end).

This method calculates the correct length of the equivalent “entire” message for this Message, without any such padding. If you want to write the data returned by to_bytes() into a Ksock, only use the number of bytes indicated by this method.

wants_us_to_reply()

Return True if we (specifically us) are should reply to this message.

Announcement

class kbus.Announcement(name, data=None, to=None, from_=None, flags=None, id=None)

Bases: kbus.messages.Message

A “plain” message, needing no reply

This is intended to be a convenient way of constructing a message that is just aimed at any listeners.

It’s also a terminological convenience - all of the “message” things are clearly messages, so we need a special name for “plain” messages... There’s an argument for just factory functions to create these things, but a class feels a little cleaner to me.

An Announcement can be created in a variety of ways. Perhaps most obviously:

>>> ann1 = Announcement('$.Fred', data='1234')
>>> ann1
Announcement('$.Fred', data='1234')

Since Announcement is a “plain” Message, we expect to be able to use the normal ways of instantiating a Message for an Announcement.

So, an Announcement can be constructed from another message directly:

>>> ann2 = Announcement.from_message(ann1)
>>> ann2 == ann1
True
>>> msg = Announcement.from_message(ann1)
>>> ann2a = Announcement.from_message(msg)
>>> ann2 == ann2a
True

Since it’s an Announcement, there’s no in_reply_to argument

>>> fail = Announcement('$.Fred', in_reply_to=None)
Traceback (most recent call last):
...
TypeError: __init__() got an unexpected keyword argument 'in_reply_to'

and the in_reply_to value in Message objects is ignored:

>>> msg = Message('$.Fred', data='1234', in_reply_to=MessageId(1, 2))
>>> ann = Announcement.from_message(msg)
>>> ann
Announcement('$.Fred', data='1234')
>>> print ann.in_reply_to
None

or from the extract() tuple - again, reply_to will be ignored:

>>> ann3 = Announcement.from_sequence(ann1.extract())
>>> ann3 == ann1
True

or from an equivalent list (and as above for reply_to):

>>> ann3 = Announcement.from_sequence(list(ann1.extract()))
>>> ann3 == ann1
True

Or one can use the same thing represented as a string:

>>> ann_as_string = ann1.to_bytes()
>>> ann4 = Announcement.from_bytes(ann_as_string)
>>> ann4 == ann1
True

For convenience, the parts of an Announcement may be retrieved as properties:

>>> print ann1.id
None
>>> ann1.name
'$.Fred'
>>> ann1.to
0L
>>> ann1.from_
0L
>>> print ann1.in_reply_to # always expected to be None
None
>>> ann1.flags
0L
>>> ann1.data
'1234'

Note that:

  1. An Announcement message is such because it is not a message of another type. There is nothing else special about it.
static from_bytes(arg)

Construct an Announcement from bytes, as read by Ksock.read_data().

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Announcement.from_bytes(msg1.to_bytes())
>>> msg2
Announcement('$.Fred', data='12345678')
static from_message(msg, data=None, to=None, from_=None, flags=None, id=None)

Construct an Announcement from another message.

The optional arguments allow changing the named fields in the new Announcement.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Announcement.from_message(msg1, flags=1)
>>> msg2
Announcement('$.Fred', data='12345678', flags=0x00000001)
static from_sequence(seq, data=None, to=None, from_=None, flags=None, id=None)

Construct an Announcement from a sequence, as returned by extract().

The optional arguments allow changing the named fields in the new Announcement.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Announcement.from_sequence(msg1.extract(), flags=1)
>>> msg2
Announcement('$.Fred', data='12345678', flags=0x00000001)
set_want_reply(value=True)

Announcements are not Requests.

Request and stateful_request

class kbus.Request(name, data=None, to=None, from_=None, final_to=None, flags=None, id=None)

Bases: kbus.messages.Message

A message that wants a reply.

This is intended to be a convenient way of constructing a message that wants a reply.

It doesn’t take an in_reply_to initialisation argument:

>>> fail = Request('$.Fred', in_reply_to=None)
Traceback (most recent call last):
...
TypeError: __init__() got an unexpected keyword argument 'in_reply_to'

And it automatically sets the WANT_A_REPLY flag, but otherwise it behaves just like a Message.

For instance, consider:

>>> msg = Message('$.Fred', data='1234', flags=Message.WANT_A_REPLY)
>>> msg
Message('$.Fred', data='1234', flags=0x00000001)
>>> req = Request('$.Fred', data='1234')
>>> req
Request('$.Fred', data='1234', flags=0x00000001)
>>> req == msg
True

If it is given a to argument, then it is a Stateful Request - it will be an error if it cannot be delivered to that particular Replier (for instance, if the Replier had unbound and someone else had bound as Replier for this message name).

>>> req = Request('$.Fred', data='1234', to=1234)
>>> req
Request('$.Fred', data='1234', to=1234L, flags=0x00000001)

A Stateful Request may also need to supply a final_to argument, if the original Replier is over a (Limpet) network. This should be taken from an earlier Reply from that Replier – see the convenience function stateful_request(). However, it can be done by hand:

>>> req = Request('$.Fred', data='1234', to=1234, final_to=OrigFrom(12, 23), flags=0x00000001)
>>> req
Request('$.Fred', data='1234', to=1234L, final_to=OrigFrom(12, 23), flags=0x00000001)

Note that:

  1. A request message is a request just because it has the Message.WANT_A_REPLY flag set. There is nothing else special about it.
  2. A stateful request message is then a request that has its to flag set.
static from_bytes(arg)

Construct a Request from bytes, as read by Ksock.read_data().

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Request.from_bytes(msg1.to_bytes())
>>> msg2
Request('$.Fred', data='12345678', flags=0x00000001)
static from_message(msg, data=None, to=None, from_=None, final_to=None, flags=None, id=None)

Construct a Request from another message.

The optional arguments allow changing the named fields in the new Request.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Request.from_message(msg1, flags=2)
>>> msg2
Request('$.Fred', data='12345678', flags=0x00000003)
static from_sequence(seq, data=None, to=None, from_=None, final_to=None, flags=None, id=None)

Construct a Request from a sequence, as returned by extract().

The optional arguments allow changing the named fields in the new Request.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Request.from_sequence(msg1.extract(), flags=2)
>>> msg2
Request('$.Fred', data='12345678', flags=0x00000003)
set_want_reply()

Calling this method is an error in this subclass, as by definition a Request always has the WANT_A_REPLY flag set.

kbus.stateful_request(earlier_msg, name, data=None, from_=None, flags=None, id=None)

Construct a stateful Request, based on an earlier Reply or stateful Request.

This is intended to be the normal way of constructing a stateful request.

earlier_msg is either:

  1. an earlier Reply, whose from_ field will be used as the new Request’s to field, and whose orig_from field will be used as the new Request’s final_to field.

    Remember, a Reply is a message whose in_reply_to field is set.

  2. an earlier Stateful Request, whose to and orig_from fields will be copied to the new Request.

    Remember, a Stateful Request is a message with the Message.WANT_A_REPLY flag set (a Request), and whose to field is set (which is to a specific Replier).

The rest of the arguments are the same as for Request(), except that the to and orig_from initialiser arguments are missing.

For instance, in the normal (single network) case:

>>> reply = Reply('$.Fred', to=27, from_=39, in_reply_to=MessageId(0, 132))
>>> reply
Reply('$.Fred', to=27L, from_=39L, in_reply_to=MessageId(0, 132))
>>> request = stateful_request(reply, '$.SomethingElse')
>>> request
Request('$.SomethingElse', to=39L, flags=0x00000001)

or, with a Reply that has come from far away:

>>> reply = Reply('$.Fred', to=27, from_=39, in_reply_to=MessageId(0, 132), orig_from=OrigFrom(19,23))
>>> reply
Reply('$.Fred', to=27L, from_=39L, orig_from=OrigFrom(19, 23), in_reply_to=MessageId(0, 132))
>>> request = stateful_request(reply, '$.SomethingElse')
>>> request
Request('$.SomethingElse', to=39L, final_to=OrigFrom(19, 23), flags=0x00000001)

or, reusing our stateful Request:

>>> request = stateful_request(request, '$.Again', data='Aha!')
>>> request
Request('$.Again', data='Aha!', to=39L, final_to=OrigFrom(19, 23), flags=0x00000001)

Reply and reply_to

class kbus.Reply(name, data=None, to=None, from_=None, orig_from=None, in_reply_to=None, flags=None, id=None)

Bases: kbus.messages.Message

A reply message.

(Note that the constructor for this class does not flip fields (such as id and in_reply_to, or from_ and to) when building the Reply - if you want that behaviour (and you probably do), use the reply_to() function.)

Thus Reply can be used as, for instance:

>>> direct = Reply('$.Fred', to=27, in_reply_to=MessageId(0, 132))
>>> direct
Reply('$.Fred', to=27L, in_reply_to=MessageId(0, 132))
>>> reply = Reply.from_message(direct)
>>> direct == reply
True

Since a Reply is a Message with its in_reply_to set, this must be provided:

>>> msg = Message('$.Fred', data='1234', from_=27, to=99, id=MessageId(0, 132), flags=Message.WANT_A_REPLY)
>>> msg
Message('$.Fred', data='1234', to=99L, from_=27L, flags=0x00000001, id=MessageId(0, 132))
>>> reply = Reply.from_message(msg)
Traceback (most recent call last):
...
ValueError: A Reply must specify in_reply_to
>>> reply = Reply.from_message(msg, in_reply_to=MessageId(0, 5))
>>> reply
Reply('$.Fred', data='1234', to=99L, from_=27L, in_reply_to=MessageId(0, 5), flags=0x00000001, id=MessageId(0, 132))

When Limpet networks are in use, it may be necessary to construct a Reply with its orig_from field set (this should only really be done by a Limpet itself, though):

>>> reply = Reply.from_message(msg, in_reply_to=MessageId(0, 5), orig_from=OrigFrom(23, 92))
>>> reply
Reply('$.Fred', data='1234', to=99L, from_=27L, orig_from=OrigFrom(23, 92), in_reply_to=MessageId(0, 5), flags=0x00000001, id=MessageId(0, 132))

It’s also possible to construct a Reply in most of the other ways a Message can be constructed. For instance:

>>> rep2 = Reply.from_bytes(direct.to_bytes())
>>> rep2 == direct
True
>>> rep4 = Reply.from_sequence(direct.extract())
>>> rep4 == direct
True
static from_bytes(arg)

Construct a Message from bytes, as read by Ksock.read_data().

in_reply_to must be set in the message data.

For instance:

>>> msg1 = Message('$.Fred', '12345678', in_reply_to=MessageId(0,5))
>>> msg1
Message('$.Fred', data='12345678', in_reply_to=MessageId(0, 5))
>>> msg2 = Message.from_bytes(msg1.to_bytes())
>>> msg2
Message('$.Fred', data='12345678', in_reply_to=MessageId(0, 5))
static from_message(msg, data=None, to=None, from_=None, orig_from=None, in_reply_to=None, flags=None, id=None)

Construct a Message from another message.

All the values in the old message, except the name, may be changed by specifying new values in the argument list.

in_reply_to must be specified explicitly, if it is not present in the old/template message.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Reply.from_message(msg1, flags=2, in_reply_to=MessageId(0,5))
>>> msg2
Reply('$.Fred', data='12345678', in_reply_to=MessageId(0, 5), flags=0x00000002)
static from_sequence(seq, data=None, to=None, from_=None, orig_from=None, in_reply_to=None, flags=None, id=None)

Construct a Message from a sequence, as returned by extract().

All the values in the old message, except the name, may be changed by specifying new values in the argument list.

in_reply_to must be specified explicitly, if it is not present in the sequence.

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Reply.from_sequence(msg1.extract(), flags=2, in_reply_to=MessageId(0,5))
>>> msg2
Reply('$.Fred', data='12345678', in_reply_to=MessageId(0, 5), flags=0x00000002)
kbus.reply_to(original, data=None, flags=0)

Return a Reply to the given Message.

This is intended to be the normal way of constructing a reply message.

For instance:

>>> msg = Message('$.Fred', data='1234', from_=27, to=99, id=MessageId(0, 132), flags=Message.WANT_A_REPLY|Message.WANT_YOU_TO_REPLY)
>>> msg
Message('$.Fred', data='1234', to=99L, from_=27L, flags=0x00000003, id=MessageId(0, 132))
>>> reply = reply_to(msg)
>>> reply
Reply('$.Fred', to=27L, in_reply_to=MessageId(0, 132))

Note that:

  1. The message we’re constructing a reply to must be a message that wants a reply. Specifically, this means that it must have the Message.WANT_A_REPLY flag set, and also the Message.WANT_YOU_TO_REPLY flag. This last is because anyone listening to a Request will “see” the Message.WANT_A_REPLY flag, but only the (single) replier will receive the message with Message.WANT_YOU_TO_REPLY set.
  2. A reply message is a reply because it has the in_reply_to field set. This indicates the message id of the original message, the one we’re replying to.
  3. As normal, the Reply’s own message id is unset - KBUS will set this, as for any message.
  4. We give a specific to value, the id of the Ksock that sent the original message, and thus the from value in the original message.
  5. We keep the same message name, but don’t copy the original message’s data. If we want to send data in a reply message, it will be our own data.

The other arguments available are flags (allowing the setting of flags such as Message.ALL_OR_WAIT, for instance), and data, allowing reply data to be added:

>>> rep4 = reply_to(msg, flags=Message.ALL_OR_WAIT, data='1234')
>>> rep4
Reply('$.Fred', data='1234', to=27L, in_reply_to=MessageId(0, 132), flags=0x00000100)

MessageId

class kbus.MessageId

Bases: _ctypes.Structure

A wrapper around a message id.

>>> a = MessageId(1, 2)
>>> a
MessageId(1, 2)
>>> a < MessageId(2, 2) and a < MessageId(1, 3)
True
>>> a == MessageId(1, 2)
True
>>> a > MessageId(0, 2) and a > MessageId(1, 1)
True

We support addition in a limited manner:

>>> a + 3
MessageId(1, 5)

simply to make it convenient to generate unique message ids. This returns a new MessageId - it doesn’t amend the existing one.

network_id

Structure/Union member

serial_num

Structure/Union member

Status

class kbus.Status(original)

Bases: kbus.messages.Message

A status message, from KBUS.

This is provided as a sugar-coating around the messages KBUS sends us. As such, it is not expected that a normal user would want to construct one, and the initialisation mechanisms are correspondingly more restrictive.

For instance:

>>> msg = Message('$.KBUS.Dummy', from_=27, to=99, in_reply_to=MessageId(0, 132))
>>> msg
Message('$.KBUS.Dummy', to=99L, from_=27L, in_reply_to=MessageId(0, 132))
>>> status = Status.from_bytes(msg.to_bytes())
>>> status
Status('$.KBUS.Dummy', to=99L, from_=27L, in_reply_to=MessageId(0, 132))

At the moment it is not possible to construct a Status message in any other way - it is assumed to be strictly for “wrapping” a message read (as bytes) from KBUS. Thus:

>>> msg = Status('$.Fred')
Traceback (most recent call last):
...
NotImplementedError: Use the Status.from_bytes() method to construct a Status

Note that:

  1. A status message is such because it is a (sort of) Reply, with the message name starting with $.KBUS..
static from_bytes(arg)

Construct a Status from bytes, as read by Ksock.read_data().

For instance:

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Status.from_bytes(msg1.to_bytes())
>>> msg2
Status('$.Fred', data='12345678')
static from_message(msg, data=None, to=None, from_=None, orig_from=None, final_to=None, in_reply_to=None, flags=None, id=None)

It is not meaningful to create a Status from another Message.

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Status.from_message(msg1, in_reply_to=MessageId(0,5))
Traceback (most recent call last):
...
NotImplementedError: Status does not support the from_message() static method
static from_sequence(seq, data=None, to=None, from_=None, orig_from=None, final_to=None, in_reply_to=None, flags=None, id=None)

It is not meaningful to create a Status from a sequence.

>>> msg1 = Message('$.Fred', '12345678')
>>> msg1
Message('$.Fred', data='12345678')
>>> msg2 = Status.from_sequence(msg1.extract())
Traceback (most recent call last):
...
NotImplementedError: Status does not support the from_sequence() static method

OrigFrom

class kbus.OrigFrom

Bases: _ctypes.Structure

A wrapper to the underlying C struct kbus_orig_from type. This is the type of Message.orig_from and Message.final_to.

>>> a = OrigFrom(1, 2)
>>> a
OrigFrom(1, 2)
>>> a < OrigFrom(2, 2) and a < OrigFrom(1, 3)
True
>>> a == OrigFrom(1, 2)
True
>>> a > OrigFrom(0, 2) and a > OrigFrom(1, 1)
True
local_id

Structure/Union member

network_id

Structure/Union member

split_replier_bind_event_data

kbus.split_replier_bind_event_data(data)

Split the data from a $.KBUS.ReplierBindEvent message.

Returns a tuple of the form (is_bind, binder, name)