pyziggy.message_loop

Classes synchronizing the various pyziggy tasks across threads.

When pyziggy runs it enters an infinite loop in which it waits for MQTT messages. The thread on which this infinite loop is executed is referred to as the message thread.

Code that wants to interact with the pyziggy.parameters needs to do this on the message thread. This module contains the tools to make this synchronization easy.

Parameter change callbacks are called on the message thread, so they can safely access other parameters. Callbacks of the MessageLoopTimer are also called on the message thread.

Using MessageLoop.post_message() one can transfer a call happening on any thread to the message thread. This is used in the Flask examples to transfer an HTTP call handler to the message thread so that it can modify parameters.

Module Attributes

message_loop

This is the module singleton object that all code directly interacting with the message loop should use.

time_source

A TimeSource object that's used by all MessageLoopTimer objects.

Classes

AsyncCallback(callback)

Helper class that wraps a callback into an AsyncUpdater.

AsyncUpdater()

Helper class to transfer execution from any thread to the message thread.

FastForwardTimeSource()

This source forwards all its calls to the functions of the same name in the time and datetime modules, with the twist, that you can call the fast_forward_by() function to increment an internal time quantity that is added to all returned values.

MessageLoop(*args, **kwargs)

Class responsible for maintaining a queue of callbacks to be executed on the message thread.

MessageLoopTimer(callback)

Simple timer class that repeatedly calls the provided function on the message thread.

SystemTimeSource()

This source forwards all its calls to the functions of the same name in the time and datetime modules.

TimeSource()

Base class for the time_source object used by the MessageLoopTimer.

class pyziggy.message_loop.AsyncCallback(callback: Callable[[], None])

Bases: AsyncUpdater

Helper class that wraps a callback into an AsyncUpdater. The callback is called once on the message thread after the trigger_async_update() function has been called on any thread.

trigger_async_update() None

Triggers a callback. Can be called from any thread.

class pyziggy.message_loop.AsyncUpdater

Bases: object

Helper class to transfer execution from any thread to the message thread.

Inherit from AsyncUpdater and override _handle_async_update(). You can call _trigger_async_update() from any thread, and this will queue a message that will call _handle_async_update() on the message thread.

class pyziggy.message_loop.FastForwardTimeSource

Bases: TimeSource

This source forwards all its calls to the functions of the same name in the time and datetime modules, with the twist, that you can call the fast_forward_by() function to increment an internal time quantity that is added to all returned values.

fast_forward_by(seconds: float) None

Increments the internal quantity that’s added to all returned values. Calling this once with a parameter of 5 means, that all other member functions will return times that are 5 seconds ahead of the system time.

final now() datetime
final perf_counter() float
final time() float
class pyziggy.message_loop.MessageLoop(*args, **kwargs)

Bases: object

Class responsible for maintaining a queue of callbacks to be executed on the message thread.

Must be used as a singleton. To interact with the message loop import the pyziggy.message_loop.message_loop object in your code.

post_message(message: Callable[[], None]) None

Queues the callback for execution on the message thread.

run() int

Enters an infinite loop queuing and dispatching messages. To exit the loop call stop().

A minimal self-contained example of this is as follows:

from pyziggy import message_loop as ml

def start():
    mt.message_loop.stop()

ml.message_loop.post_message(start)
ml.message_loop.run()
stop(return_code: int = 0) None

Exits the infinite message loop and allows clean termination of the program.

stop_after_a_second(return_code: int = 0) None

One second after the call, exits the infinite message loop and allows clean termination of the program. This allows communicating MQTT messages that originate from the same call stack as this call.

class pyziggy.message_loop.MessageLoopTimer(callback: Callable[[MessageLoopTimer], None])

Bases: object

Simple timer class that repeatedly calls the provided function on the message thread.

MessageLoopTimer objects should only be created, started and stopped on the message thread.

It’s not super accurate, and since all timer’s callbacks are called on the same thread, a long-running callback can delay calling the others.

start(duration_sec: float) None

Starts the timer.

Parameters:

duration_sec – The period between two callbacks. The first callback also occurs after this time after this duration elapses.

stop() None

Call this function if you want to stop receiving callbacks.

class pyziggy.message_loop.SystemTimeSource

Bases: TimeSource

This source forwards all its calls to the functions of the same name in the time and datetime modules.

final now() datetime
final perf_counter() float
final time() float
class pyziggy.message_loop.TimeSource

Bases: object

Base class for the time_source object used by the MessageLoopTimer.

abstractmethod now() datetime
abstractmethod perf_counter() float
abstractmethod time() float
pyziggy.message_loop.message_loop = <pyziggy.message_loop.MessageLoop object>

This is the module singleton object that all code directly interacting with the message loop should use. You can import this object and call pyziggy.message_loop.MessageLoop.post_message() from any thread to schedule a callback to be executed on the message thread. You can also call the pyziggy.message_loop.MessageLoop.stop() if you wish to terminate your program early.

pyziggy.message_loop.time_source: TimeSource = <pyziggy.message_loop.SystemTimeSource object>

A TimeSource object that’s used by all MessageLoopTimer objects. By default this reference points to an instance of SystemTimeSource, but you can point it to a FastForwardTimeSource instead. The pyziggy unit tests use this technique to execute tests quickly even if they contain timers and waiting.

User code should generally not need to access this object, but it may be handy for unit tests that use MessageLoopTimer.