Pyjo.IOLoop.Delay - Manage callbacks and control the flow of events

import Pyjo.IOLoop

# Synchronize multiple events
delay = Pyjo.IOLoop.delay()

@delay.step
def step(delay):
    print('BOOM!')

for i in range(10):
    end = delay.begin()

    def timer_wrap(i):
        def timer_cb(loop):
            print(10 - i)
            end()
        return timer_cb

    Pyjo.IOLoop.timer(timer_wrap(i), i)

delay.wait()

# Sequentialize multiple events
delay = Pyjo.IOLoop.delay()

@delay.step
def step1(delay):
    # First step (simple timer)
    Pyjo.IOLoop.timer(delay.begin(), 2)
    print('Second step in 2 seconds.')

@delay.step
def step2(delay):
    # Second step (concurrent timers)
    Pyjo.IOLoop.timer(delay.begin(), 1)
    Pyjo.IOLoop.timer(delay.begin(), 3)
    print('Third step in 3 seconds.')

@delay.step
def step3(delay):
    print('And done after 5 seconds total.')

delay.wait()

# Handle exceptions in all steps
delay = Pyjo.IOLoop.delay()

@delay.step
def step1(delay):
    raise Exception('Intentional error')

@delay.step
def step2(delay):
    print('Never actually reached.')

@delay.catch
def step3(delay, err):
    print("Something went wrong: {0}".format(err))

delay.wait()

Pyjo.IOLoop.Delay manages callbacks and controls the flow of events for Pyjo.IOLoop, which can help you avoid deep nested closures and memory leaks that often result from continuation-passing style.

Events

Pyjo.IOLoop.Delay inherits all events from Pyjo.EventEmitter and can emit the following new ones.

error

@delay.on
def error(delay, err):
    ...

Emitted if an exception gets thrown in one of the steps, breaking the chain, fatal if unhandled.

finish

@delay.on
def finish(delay, *args):
    ...

Emitted once the active event counter reaches zero and there are no more steps.

Classes

class Pyjo.IOLoop.Delay.Pyjo_IOLoop_Delay(*args, **kwargs)

Pyjo.IOLoop.Delay inherits all attributes and methods from Pyjo.EventEmitter and implements the following new ones.

begin(offset=1, length=0, *args)
cb = delay.begin
cb = delay.begin(offset)
cb = delay.begin(offset, length)

Indicate an active event by incrementing the active event counter, the returned callback needs to be called when the event has completed, to decrement the active event counter again. When all callbacks have been called and the active event counter reached zero, steps() will continue.

# Capture all arguments except for the first one (invocant)
delay = Pyjo.IOLoop.delay()

@delay.step
def step1(delay, err, stream):
    ...

Pyjo.IOLoop.client(delay.begin(), port=3000)
delay.wait()

Arguments passed to the returned callback are sliced with the given offset and length, defaulting to an offset of 1 with no default length. The arguments are then combined in the same order begin() was called, and passed together to the next step or finish event.

# Capture all arguments
delay = Pyjo.IOLoop.delay()

@delay.step
def step2(delay, loop, err, stream):
    ...

Pyjo.IOLoop.client(delay.begin(0), port=3000)
delay.wait()

# Capture only the second argument
delay = Pyjo.IOLoop.delay()

@delay.step
def step3(delay, err):
    ...

Pyjo.IOLoop.client(delay.begin(1, 1), port=3000)
delay.wait()

# Capture and combine arguments
delay = Pyjo.IOLoop.delay()

@delay.step
def step4(delay, three_err, three_stream, four_err, four_stream):
    ...

Pyjo.IOLoop.client(delay.begin(), port=3000)
Pyjo.IOLoop.client(delay.begin(), port=4000)
delay.wait()
data(*args, **kwargs)
data = delay.data()
foo  = delay.data('foo')
delay = delay.data(foo='bar')

Data shared between all steps().

# Remove value
del delay.data()['foo']

# Assign multiple values at once
delay.data(foo='test', bar=23)
ioloop = None
ioloop = delay.ioloop
delay.ioloop = Pyjo.IOLoop.new()

Event loop object to control, defaults to the global Pyjo.IOLoop singleton.

remaining(steps=None)
remaining = delay.remaining()
delay = delay.remaining([])

Remaining steps in chain, stored outside the object to protect from circular references.

The first step runs during next reactor tick after wait() method is called.

step(cb)
delay = delay.step(cb)

Add another step to remaining() steps in chain.

@delay.step
def step1(delay, args*)
    ...
steps(*args)
delay = delay.steps(cb, cb)

Add another steps to remaining() steps in chain.

wait()
delay.wait()

This sequentialize multiple events, every time the active event counter reaches zero a callback will run, the first one automatically runs during the next reactor tick unless it is delayed by incrementing the active event counter. This chain will continue until there are no more callbacks, a callback does not increment the active event counter or an exception gets thrown in a callback.

Also start ioloop and stop it again once an error or finish event gets emitted.

Pyjo.IOLoop.Delay.object

alias of Pyjo_IOLoop_Delay