polycephaly.core.process package

class polycephaly.core.process.Process(*args, **kwargs)

Bases: polycephaly.core.process.actions.Extend, polycephaly.core.process.events.Extend, polycephaly.core.process.info.Extend, polycephaly.core.process.locking.Extend, polycephaly.core.process.messaging.Extend, polycephaly.core.process.setup.Extend, polycephaly.core.process.signals.Extend, polycephaly.core.process.threading.Extend, polycephaly.core.process.timing.Extend

The process class provides the basis for any Process (Main or sub-process) that you want to run.

The overall archiecture is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Process( polycephaly.core.Process ):

    def birth( self ):

        # Set-up is performed here.

        pass # END METHOD : Birth

    def life( self ):

        # Looping is performed here.

        pass # END METHOD : Life

    def death( self ):

        # Tear-down is performed here.

        pass # END METHOD : Death

    pass # END CLASS : PROCESS : Main

Arguments and Keyword Arguments are passed in from Application.addProcess() which Process.__init__() is responsible for handling.

Parameters
  • *args – Variable length argument list passed directly to the process, and accessible as self.args from within the process.

  • **kwargs – Arbitrary keyword arguments passed directly to the process, and accessible as self.kwargs from within the process.

__init__(*args, **kwargs)

This is the constructor of the Process class, which executes private methods in the following order for helping prepare a process to run:

  1. Process._setupVariables( args, kwargs )

  2. Process._setupEvents()

  3. Process._setupFilters()

Parameters
  • *args – Variable length argument list passed directly to the process, and accessible as self.args from within the process.

  • **kwargs – Arbitrary keyword arguments passed directly to the process, and accessible as self.kwargs from within the process.

_active = False

Boolean whose status is retrieved (and set) by Process.isActive(), determines if Process.life() will continue running in Process.main()’s loop, and can also be referred to by any child threads that a process spins up (please see Thread Spinner for an example).

_application = None

Instance of the Application class used by Process.getApp().

_callbacks = None

Dictionary of callbacks registered (key is the event name, and value is the callback method) with Process.registerCallbacks() that are called by Process.callbackEvent() when a specified event occurs.

An example use case is when specific USB hardware tracked by a Manufacturer ID and/or Model ID (which Polycephaly matches from all a list of all connected USB devices queried from the Operating System) experiences one or more of the following events:

  • connected - device plugged in.

  • disconnected - device unplugged.

  • pong - responds to a ping sent by a child thread (any method starting with _thread can be automatically launched by Process.launchThreads() in the Process.birth() method of a process) of a sub-process.

  • commsError - if the device responds to a message with an error letting us know that something went wrong.

  • deviceError - if the device itself experiences an error.

_currFrame = None

Integer used for tracking the progress of frames per second via Process.currentFrame() within the span of 1 second for a process’ execution of Process.life() from the Process.main() loop.

_locks = None

Dictionary of atomic locks for a sub-process to use, which are set by Process.addLocks() and queried by Process.getLocks().

See also

Process._setupEvents() is used to setup a lock for each process that’s added into an application.

_messenger = None

Instance of Polycephaly's Messenger class, and wrapped by methods defined in the process.messaging package.

_ppill = None

String (by default, a UUID) that represents a Poison Pill. When a process receives a message with this unique value as the subject line, the process will invoke its die() method. Also see ebrake() which allows any sub-process to request the Main process to shut down the entire application.

_ranMailman = False

Boolean that’s used for tracking if Process.mailman() was run in Process.life() or not. If not, then Process.mailman() will automatically be executed for this cycle and to ensure that the Poison Pill is received if sent from another process.

_runLevel = None

Integer that indicates the process’ current run level (and a poor copy of how Linux does it) which is retrieved (and set) by Process.runLevel()

_runtime = None

Dictionary of a process’ run-time variables, such as frequency, accessible by getParameter().

_setupEvents()

Used to setup the process for running. Actions taken:

  1. Sets the process’ active flag to true.

  2. Adds a lock for the process’ message queue, which is most often used by Process.waitForReply().

_setupFilters()

Responsible for adding core message filters to be used by all processes:

_setupVariables(args, kwargs)

Sets the Process variables for use by an instantiated process.

_signalsBak = None

Dictionary used by Process.backupSignals() and Process.restoreSignals() where key is the name (e.g. SIGINT) and value is the handler (e.g. <built-in function default_int_handler>).

_signalsUsed = False

Boolean used by Process.signalsUsed() for tracking if any signals have been bound to a callback method with Process.signals().

_threads = None

Dictionary of child threads (key is the name, and value is the thread object representing a dedicated method) that a process may spin up. This is used extensively by the methods in the Process.Threading package.

args = None

Tuple of Arguments that are passed to the sub-process by Application.addProcess().

kwargs = None

Dictionary of Keyword Arguments that are passed to the sub-process by Application.addProcess().

name = None

String that represents the friendly name of a (sub-)process inheriting from this class.

nameMain = None

String that represents the friendly name of the Application’s primary process.

paths = None

Object comprised of namespaces representing the various paths used by the application.

signalEnd = None

If a Signal is received, an integer representing the Signal event responsible for the shutdown (e.g. 2 for SIGINT, 15 for SIGTERM, etc.). Please note, you can pass this value to Process.signalsDict() to obtain the string equivalent.

Submodules

polycephaly.core.process.actions module

class polycephaly.core.process.actions.Extend

Bases: object

cleanup()

Used by the Main process during its run of Process.die() to send the Poison Pill to sub-processes that Process.activeSubProcesses() reports as still active.

die(message=None, **kwargs)

Commonly used as a callback that can detect internal events (Polycephaly messages) and external events (Signals), this is used by a process to shut itself down.

Parameters
  • message (dict, optional) – If called by a Polycephaly's Messenger event, this variable will be populated with the message which allows for a reason to explain the shutdown and optionally responding to the sender to confirm the shutdown sequence.

  • **kwargs

    Allows for other events to pass information for shutdown, which can include but are not limited to:

    • Signals
      • sigNum : (int, optional) - Signal Integer (e.g. 2 for SIGINT, 15 for SIGTERM, etc.)

    • Information
      • currFrame : (frame, optional) - Python stack frame information.

      • reason : (str, optional) - why this process is being shutdown.

Returns

True if successful, False if something went wrong.

Return type

bool

ebrake(reason=None)

Used by a process to request that the entire application be shutdown, which is usually caused by a process encountering an unrecoverable error.

Parameters

reason (str, optional) – Provides an explanation for why a process is requesting that the entire application be shutdown.

polycephaly.core.process.events module

class polycephaly.core.process.events.Extend

Bases: object

birth()

This serves as your process’ constructor, and what you would override when you need to prepare your process for starting up.

callbackEvent(event, *args, **kwargs)

Attempts to run a callback that was registered to an event with Process.registerCallbacks() when a specific event is triggered.

Parameters
  • event (str) – Usually called by a process’ child thread at a specific event, such as (dis)connect or communication/device failure.

  • *args – Passed directly to the callback as arguments.

  • **kwargs – Passed directly to the callback as keyword arguments.

Returns

Results directly from the callback.

Return type

return

An example for triggering an event’s callback:

# System
import time

# Hardware
import myUSBdevice

# Polycephaly
import polycephaly

class Process( polycephaly.core.Process ):

    def _threadBoardPing( self ):

        while self.isActive():

            # Board successfully responded
            if myUSBdevice.ping():

                self.callbackEvent( 'boardPong', time.time(), abc=123, xyz=789 )

                pass # END IF

            # Device failed to respond
            else:

                self.callbackEvent( 'deviceError' )

                pass # END ELSE

            self.freqSleep()

            pass # END WHILE LOOP

        pass # END THREAD : Ping USB board

    def birth( self ):

        self.launchThreads()

        pass # END METHOD : Birth

    pass # END PROCESS

Which would yield:

USB device responded to program ping with pong at 123456.789, abc is 123, and xyz is 789.
death()

This serves as your process’ destructor, and what you would override when you need to prepare your process for shutting down.

life()

This serves as your process’ loop, and what you would override when you need to setup your process for running n times per second, as defined by the frequency.

registerCallbacks(**kwargs)

Used in Process.birth() to register events and their reciprocal callbacks. A callback for a specific event is then called by Process.callbackEvent().

Parameters

**kwargs – An arbitrary number of events and their reciprocal callbacks can be passed to this method as keyword arguments.

An example for registering callbacks related to a USB hardware device:

# Polycephaly
import polycephaly

class Process( polycephaly.core.Process ):

    def connected( self ):
        print( 'USB device connected.' )
        pass # END METHOD : Connected

    def disconnected( self ):
        print( 'USB device disconnected.' )
        pass # END METHOD : Disconnected

    def boardPong( self, time, **kwargs ):
        print( f"USB device responded to program ping with pong at { time }, abc is { kwargs[ 'abc' ] }, and xyz is { kwargs[ 'xyz' ] }." )
        pass # END METHOD : Board pong

    def commsError( self ):
        print( 'USB device reports a communications error.' )
        pass # END METHOD : Communications Error

    def deviceError( self ):
        print( 'USB device is experiencing an error.' )
        pass # END METHOD : Device Error

    def birth( self ):

        self.registerCallbacks(
            connected       =   self.connected,
            disconnected    =   self.disconnected,
            boardPong       =   self.boardPong,
            commsError      =   self.commsError,
            deviceError     =   self.deviceError,
        )

        pass # END METHOD : Birth

    pass # END PROCESS

polycephaly.core.process.info module

class polycephaly.core.process.info.Extend

Bases: object

_procInfoSkel()

This is the basis for aliased methods to query the Main process for information about other processes, and is most commonly used by:

Returns

If process information is found, will return the request, otherwise will return None.

Return type

return, None

activeSubProcesses()

Alias method to show which sub-processes are still active.

Returns

Sub-processes that are still active.

Return type

list

getApp()

Returns the Application instance to a process that’s running in threaded mode.

Returns

If called by a process that’s running in threaded mode, the Application instance will be returned. Otherwise, None will be returned.

Return type

Application, None

getParameter(name)

Used for returning private members of the process, and most commonly used by Application to query a process’ run-time variables.

Parameters

name (str) – Which private member of the process to return, and the most common use is runtime.

Returns

Value of the private member that’s being looked up.

Return type

return

isActive(i=None)

Used for querying or setting the process’ active flag. This method is typically used to control the run of process and child-thread loops, including for the loop of Process.life() in Process.main().

Parameters

i (bool) – Sets the desired state of the process (and optional child threads).

Returns

The current value of Process._active.

Return type

bool

listProcessInstances()

Alias method to show process instances.

Returns

Process instances.

Return type

list

listRecipients()

Alias method to show process message queues.

Returns

Process message queues.

Return type

list

runLevel(i=None)

Used for querying or setting the process’ run level stored at Process._runLevel and within the range defined by Process.runLevels().

As a process runs from Process.birth()Process.life()Process.death(), the run level is updated via this method in Process.main().

Parameters

i (int or str) – Integer value within the defined range (e.g. setting to 1 for indicating BUILDUP level), or a String equivalent (e.g. setting to BUILDUP).

Returns

Run level stored at Process._runLevel

Return type

int

Raises

ValueError – Occurs when i is set out of range.

runLevels(i=None)

Used for looking up a run level by its integer or string value, or listing all available run levels.

Parameters

i (int or str) – Set to the run level to look up, or list to obtain all values.

Returns

  • String if i is set to an integer.

  • Integer if i is set to a string.

  • Dictionary if i is set to list (str).

Return type

str, int, dict

polycephaly.core.process.locking module

class polycephaly.core.process.locking.Extend

Bases: object

addLocks(*args)

Adds 1 or more locks to Process._locks.

Parameters

*args – Variable length of strings.

getLocks(*args)

Retrieves 1 or more locks from Process._locks.

Parameters

*args – Variable length of strings.

Returns

Lock object if a single value is provided, otherwise a dictionary of locks where key is the name and value is the reciprocal lock object.

Return type

lock, dict

polycephaly.core.process.setup module

class polycephaly.core.process.setup.Extend

Bases: object

main(*args, **kwargs)

This method is responsible for the entire run of a process from start to stop, and most notably runs the sequence of:

  1. Process.birth()

  2. Process.life() - runs in a loop so long as Process.isActive() evaluates to True.

  3. Process.death()

Parameters
  • *args – Variable length argument list passed from process setup.

  • **kwargs – Arbitrary keyword arguments passed from process setup. Reserved keywords that are used by this argument are:

    • application (Application) - the application instance is the lowest level of the program, which can be accessed from within a process by Process.getApp().

See also

polycephaly.core.process.signals module

class polycephaly.core.process.signals.Extend

Bases: object

backupSignals()

Used for backing up signals and their reciprocal handlers as a dict to Process._signalsBak, where key is the signal name in all capital letters, and value is the handler.

currSignals(*args)

Used for pulling one or more of the process’ current signal handlers.

Parameters

*args (str) – Signal(s) to retrieve information for.

Returns

If a single argument is given, only a single handler is returned. For multiple arguments given, a dictionary will be returned with the names given and its reciprocal handler.

Return type

handler or dictionary

restoreSignals()

Used for restoring signals and their reciprocal handlers as a dict from Process._signalsBak.

Returns

True if successful, False if there are no signals to restore.

Return type

bool

sigTrap(sigNum, currFrame)

This serves as the process’ signal trap for several default signals (e.g. SIGINT and SIGTERM) set in Process.main() if you didn’t set any in Process.birth().

While you can override this method, you probably won’t ever need to, and can leave this to call upon Process.die(), where your process’ specific shutdown actions are carried out in Process.death().

Parameters
  • sigNum (int) – Signal number (e.g. 2 for SIGINT, or 15 for SIGTERM.)

  • currFrame (frame) – Python Stack frame.

See also

signals(cb, *keys)

Bind a callback to an arbitrary number of signals.

Parameters
  • cb (Function or Method) – Callback that’s executed when a signal occurs that it’s been bound to.

  • *keys (str) – Variable length list of signals to bind callback to.

Returns

True if successful, False if an error occurs.

Return type

bool

An example for registering a callback to multiple signals:

def myCallback( self, sigNum, currFrame ):

    print( f'My callback received sigNum={ sigNum } and currFrame={ currFrame }' )

    pass # END METHOD : My callback

def birth( self ):

    self.signals(
        self.myCallback,
        'SIGINT',   # ^C
        'SIGTERM',  # `kill procID` or `pkill myApp.py` and systemd's default kill signal.
    )

    pass # END METHOD : Birth
signalsDict(k=None)

Used for looking up a signal by its integer or string value, or a dictionary listing of all available signals.

Parameters

k (int or str, optional)

Returns

Returns a dictionary by default, or the desired signal lookup (string if an integer is given, or integer if a string is given).

Return type

int, str, or dict

signalsUsed(i=None)

Used for querying or setting the process’ signals used flag.

Parameters

i (bool, optional) – Value to set the flag to.

Returns

The value of the flag.

Return type

bool

Note

When Process.signals() is called, it uses this method to set the flag to True.

polycephaly.core.process.threading module

class polycephaly.core.process.threading.Extend

Bases: object

addChildThread(name, method, *args, **kwargs)

Simplifies creating (and by default, starting) a child thread running under a process with its index created in Process._threads.

Parameters
  • name (str) – Name of thread that can be used in conjunction with thread-related methods.

  • method (method or function) – Callable that should be run as the thread.

  • *args – Variable length argument list passed directly to the child thread.

  • **kwargs – Arbitrary keyword arguments passed directly to the child thread.

    Please note, there are reserved keywords that are used by this method:

    • daemon (bool, optional, default: True) - Binds thread to process, so when the process exits, the thread does too. You’ll almost always want this turned on.

    • start (bool, optional, default: True) - Start the thread after it’s been setup. Otherwise, you can manually start the thread by using getChildThread() to get the instance, and then execute start() on that instance:

      self.getChildThread( 'hello' ).start()
      
childThreadJanitor()

Automatically removes child threads that are stopped or non-existent, and can be used idempotently in life().

getChildThread(threadName)

Obtains a single instance from Process.getChildThreads().

Parameters

threadName (str) – Name of thread to look up.

Returns

If a thread is found, Thread is returned, otherwise None is.

Return type

Thread or None

getChildThreads(*args)

Obtain child thread instance(s) based on queried names.

Parameters

*args (str) – Variable length argument list of child threads to return from the index located at Process._threads.

Returns

Name of the thread String as the key, and the value is Thread if found in the index or None if not found in the index.

Return type

dict

joinChildThreads()

Used in Process.main() and run immediately before Process.death(), this attempts to join each of the process’ child threads that are still active.

launchThreads()

Locates any methods in the process whose name begins with _thread_, and then uses Process.addChildThread() to add each of these methods as a reciprocal thread, then daemonize and start each thread.

An example for automatically launching threads:

def _thread_Hello( self ):
    while self.isActive():
        print( 'Hello' )
        self.freqSleep()
        pass # END WHILE LOOP
    pass # END METHOD : Hello

def _thread_World( self ):
    while self.isActive():
        print( 'World' )
        self.freqSleep()
        pass # END WHILE LOOP
    pass # END METHOD : World

def birth( self ):
    self.launchThreads()
    pass # END METHOD : Birth

See also

Examples making use of this method:

listChildThreadsLives(*args)

Lists status of life for child thread instance(s) based on queried names.

Parameters

*args (str) – Variable length argument list of child threads to return from the index.

Returns

Will return Boolean if found in the index, or None if not found in the index.

Return type

dict

removeChildThreads(*args)

Used for removing stopped child threads from the process’ child threads index.

Parameters

*args (str) – Variable length of stopped child threads to remove from the process.

Returns

Key is the name of the child thread(s) to remove with a value indicating the status of removal from the index:

  1. True - child thread successfully removed.

  2. False - child thread couldn’t be removed since it’s still active.

  3. None - child thread either doesn’t exist or an error was experienced in removing it.

Return type

dict

polycephaly.core.process.timing module

class polycephaly.core.process.timing.Extend

Bases: object

currentFrame()

Returns the current frame within the span of a second from Process._currFrame, which is constantly updated in Process.main().

For example, if the Process.frequency() of this process is 30 and you’re 0.5 seconds into the run, the current frame would be 15.

Returns

The current frame.

Return type

int

currentTimeFrame()

Similar to Process.currentFrame(), this method attempts to calculate which frame in a second that the process is operating.

Returns

The current frame.

Return type

int

freqSleep(multiplier=1)

Frequency that should sleep

Parameters

multiplier (int, optional) – Multiplier can be used to extend the sleep time without changing the frequency.

Example: if you wanted to double the time, set the value to 2.

frequency(i=None)

Sets or queries the frequency of the process.

Parameters

i (int, optional) – Sets the number of times per second that a process should attempt to run.

Returns

Returns the process’ frequency.

Return type

int

lightSleeper(**kwargs)

Sleep timer that can be interrupted by a condition matched against a callback.

Parameters

**kwargs

  • sleep (int) - number of seconds to sleep.

  • callback (Method or Function) - callback that’s evaluated once per second.

  • conditional (Variable) - when this variable is different from the callback’s return, then sleep will be interrupted.

Returns

True if successful sleep, False if woken up early.

Return type

bool

See also

Thread Spinner in the Examples directory, which makes use of this method in conjunction with Process.isActive().

Module contents