Pycider Module

Deciders

class pycider.deciders.AdaptDecider(fci: Callable[[C], CO | None], fei: Callable[[E], EO | None], feo: Callable[[EO], E], fsi: Callable[[S], SO], decider: Decider[EO, CO, SO])

A decider that translates from one set of events/commands/states to another.

The AdaptDecider takes in a decider and makes a translation layer between the commands, events, and state internally and a new resulting type of command, event, and map. The purpose of this is to allow a Decider of one type to interact with a Decider of another type through translation.

build() BaseDecider[E, C, S, SO]

Create an adapted decider.

Returns:

A Decider with its functions wrapped by translation functions.

class pycider.deciders.BaseDecider

This decider allows for a different input and output state type.

BaseDecider should only be used when the input and output state type should be different. Otherwise use Decider.

abstract decide(command: C, state: SI) Iterator[E]

Return a set of events from a command and state.

Parameters

command: Action to be performed state: State of the current decider

Returns

An iterator of events resulting from the command.

abstract evolve(state: SI, event: E) SO

Returns an updated state based on the current event.

Paramters

state: State of the current decider event: Event

Returns

An updated state

abstract initial_state() SO

Starting state for a decider.

Returns

The base state a decider

abstract is_terminal(state: SI) bool

Returns if the current state is terminal.

Parameters

state: State of the current decider

Returns

A boolean indicating if the decider is finished.

class pycider.deciders.ComposeDecider(left_dx: Decider[EX, CX, SX], right_dy: Decider[EY, CY, SY])

Combine two deciders into a single decider.

This creates a Decider that is combined into a Left and Right side. There is a type for Left or Right in pycider.types. To execute commands after composing two targets you need to pass in commands in the following shape:

Left(C) or Right(C) where C is the command to be executed. This code will make sure the proper decider receives the command.

build() Decider[Left[EX] | Right[EY], Left[CX] | Right[CY], tuple[SX, SY]]

Given two deciders return a single one.

Returns:

A single decider made of two deciders.

class pycider.deciders.Decider

This is a BaseDecider where the input and output state are the same.

This is the Decider that should preferably be used unless you explcitly need control over a different input and output type for the state.

class pycider.deciders.ManyDecider(identifier_type: Type[I])

Manage many instances of the same Decider using a Identifier.

This Decider is useful if you have multiple of the same Decider that can be differentiated by a unique element. For example a list of transaction Deciders which all have a unique transaction key, or a list of clients that all have a unique client id. Using this you can execute commands by executing with a many decider commands in a tuple of (I, C) where I is the unique identifier and C is the desired command to be executed.

class pycider.deciders.Map2Decider(f: Callable[[SX, SY], S], dx: BaseDecider[E, C, SI, SX], dy: BaseDecider[E, C, SI, SY])
class pycider.deciders.MapDecider(f: Callable[[SA], SB], d: BaseDecider[E, C, SI, SA])

Map allows the translation of a Decider’s state into a different state.

build() BaseDecider[E, C, SI, SB]

Build a whose state is represented as the function f(state).

Returns:

A new Decider where evolve and initial_state both return f(state_operation).

class pycider.deciders.NeutralDecider

For demonostration purposes.

build()

Returns a demonstration neutral decider.

Returns:

A decider which is always terminal and returns nothing.

Processes

class pycider.processes.IProcess

Prototype for Process implementations.

All Processes should be implemented using this prototype.

abstract evolve(state: S, event: E) S

Returns an updated state based on the current event.

Paramters

state: State of the current process event: Event generated from commands procesed

Returns

An updated state.

abstract initial_state() S

Returns the starting state for a process.

Returns

A state representing the start of a process.

abstract is_terminal(state: S) bool

Returns if a process’s state is terminal.

Parameters

state: State of the current process

Returns

A boolean indicating if a process has run till completion.

abstract react(state: S, event: E) Iterator[C]

Returns an iterator of commands as a reaction to an event.

Parameters

state: State of the current process event: Event currently being processed

Returns

An iterator of commands to act on.

abstract resume(state: S) Iterator[C]

Returns an iterator of commands to resume a process from a given state.

Parameters

state: State of the current process

Returns

An iterator of commands to act on.

class pycider.processes.ProcessAdapt(select_event: Callable[[EI], EO | None], convert_command: Callable[[CO], CI], p: IProcess[EO, CO, S])

Adapt process Commands / Events into new output Commands and Events.

build() IProcess[EI, CI, S]

Convert Commands/Events into output variants.

Returns:

A new Process that can given input Events/Commands return new output variants.

class pycider.processes.ProcessCombineWithDecider(proc: IProcess[E, C, PS], decider: Decider[E, C, DS])

Combine a Processor with a Decider together.

build() Decider[E, C, tuple[DS, PS]]

Combine a Process and a Decider into a single Decider.

Results:

A single Decider.

Note: This function’s generated decide function deviates from the model used by the original material. decide in this code takes a command and state tuple.

For each command issued this code will do the following:

  1. create a command list commands initialized as [commands]

  2. create a event list events initialized as []

  3. run decider.decide on a popped entry from commands

  4. append the results to events array

  5. create a copy of state and run decider.evolve on it

  6. run process.react to generate new commands appended to the commands list.

  7. run process.evolve on each new event.

  8. loop back to 2 with remaining commands and the copy of decider’s state.

  9. one commands is empty, return all events collected during the above.

The state of neither process nor decider is actually changed by decide. You will still need to call evolve to reach the final end states.

Utilities

class pycider.utils.InMemory(decider: Decider[E, C, S])

Runs a decider in memory, performing decide and evolving the state.

command(command: C) Iterator[E]

Decide over a command and evolves the internal state.

Parameters:

command – Command to decide over

Returns:

An iterator over the events.

state: S

State of the decider

Types

pycider.types.Either

Combined type representing Left or Right.

alias of Union[Left[TA], Right[TB]]

class pycider.types.Left(value: TA)

Left-hand side container that holds a value.

value

The stored value.

class pycider.types.Right(value: TB)

Right-hand side container that holds a value.

value

The stored value.