SimService API

simservice.service_function(func: Callable, function_name: Optional[str] = None)

Service function registrator: makes ad-hoc modifications to the client-side interface

This can be used within service specification to make an internal method available as a method on a client-side service proxy

E.g., if MyServiceWrap defines a service wrap, the underlying service of which makes the following specification

def f():
    print("Hello from the server side!")

Then f() can be made available on a proxy of the service on the client side by declaring inside the service,

service_function(f)

Then on the client side, the following can then be performed:

my_service = MyServiceWrap()
my_service.run()
my_service.f()

Note that the availability of a service function depends on the specification of the underlying service. At various stages of usage, a service may or may not have yet made a service function available.

Parameters:
  • func (Callable) – function to make available

  • function_name (str) – optional name assignment; if not specified, then the proxy method will be named the same as the registered function. Useful for attaching to methods of the same name to the same service as a service function

Returns:

None

simservice.close_service(_s) None

Closes a service completely

Parameters:

_s – service proxy

class simservice.ExecutionContext(_proxy, run: bool = True, init: bool = True, start: bool = True, finish: bool = True, close: bool = True)

A context to automate much of the mundane details of managing simple services

simservice.close()

Closes module managers

Returns:

None

basics

Defines basic library standard definitions

simservice.basics.name_mangler(process_name: str, name: str) str

Standard name mangling of this module by process name

Parameters:
  • process_name (str) – process name (e.g., hex( os.getpid() ) )

  • name (str) – name to mangle

Returns:

mangled name

Return type:

str

simservice.basics.standard_process_name() str

Get standard process name

Returns:

standard process name

Return type:

str

managers

Defines service managers

class simservice.managers.ServiceManagerLocal

Manager for locally-hosted services

function_registry: Dict[str, Callable] = {}

Register of functions

classmethod is_registered(_name) bool

Tests if a service has been registered

Parameters:

_name (str) – name of service or function

Returns:

True if passed name is found in registry

Return type:

bool

manager: Optional[_ServiceManagerLocal] = None

Underlying manager

classmethod register_function(_function_name, _func)

Registers a function with the manager

Parameters:
  • _function_name (str) – name of function

  • _func (Callable) – function to register

Returns:

None

classmethod register_service(_service_name, _service_wrap)

Registers a service wrap with the manager

Parameters:
Returns:

None

service_registry = {}

Registry of services

type: Dict[str, service_wraps.TypeProcessWrap]

classmethod shutdown()

Shuts down the manager

classmethod start(*args, **kwargs)

Simple wrap of BaseManager.start

started: bool = False

Flag for whether the manager has been started

simservice.managers.close_services()

Closes all service managers

Returns:

None

messages

Defines messages and inter-process message-passing structures

class simservice.messages.ConnectionMessage(_command, *args, **kwargs)

Standard message class for function calling between processes via a Pipe

Parameters:
  • _command (str or None) – command name

  • args (tuple) – command positional arguments

  • kwargs (dict) – command keyword arguments

TERMINATOR = 'ConnectionMessageTerminator'

Signal code to terminate connection

property is_terminator: bool
Returns:

True if this is a terminator message

Return type:

bool

static terminator()
Returns:

standard message to predicate connection termination

Return type:

ConnectionMessage

class simservice.messages.Functor

A callable object

class simservice.messages.RemoteFunctionEvaluator(conn, func=None)

Safe way to evaluate a function in a different process

Parameters:
  • conn (multiprocessing.connection.Connection) – RemoteFunctionEvaluator-RemoteFunctionWorker connection, RemoteFunctionEvaluator side

  • func (Callable or None) – function to evaluate; optional

class simservice.messages.RemoteFunctionWorker(conn, func, daemon: bool = False)

Safe way to send function evaluations to a different process

Note: this is safer than deriving from multiprocessing.Process, since potential applications include instantiation during bootstrap phase of parent processes

Parameters:
  • conn (multiprocessing.connection.Connection) – RemoteFunctionEvaluator-RemoteFunctionWorker connection, RemoteFunctionWorker side

  • func (Callable) – function to evaluate

  • daemon (bool) – daemon argument to base Thread class

run() None

Runs the thread

class simservice.messages.ServiceFunctionConnectionMessage(service_name: str, function_name: str, evaluator: RemoteFunctionEvaluator)

Standard message class for service function callbacks with a RemoteFunctionEvaluator - RemoteFunctionWorker pair

Parameters:
  • service_name (str) – service name

  • function_name (str) – function name

  • evaluator (RemoteFunctionEvaluator) – evaluator

simservice.messages.connection_terminator = <simservice.messages.ConnectionMessage object>

A connection terminator message

simservice.messages.dispatch_terminate(conn) None

Generic communication protocol: terminate worker side

Parameters:

conn (multiprocessing.connection.Connection) – dispatcher-worker connection, dispatcher side

Returns:

None

simservice.messages.dispatch_transmit(conn, _cmd, *args, **kwargs) Any

Generic communication protocol: dispatcher side

Parameters:
  • conn (multiprocessing.connection.Connection) – dispatcher-worker connection, dispatcher side

  • _cmd (str or None) – function name

  • args (tuple) – function positional arguments

  • kwargs (dict) – function keyword arguments

Returns:

function return value

Return type:

Any

simservice.messages.remote_function_factory(_func, daemon: bool = False) Tuple[RemoteFunctionEvaluator, RemoteFunctionWorker]

Generate a pipe to evaluate a function in a different process

Should be generated in the process that defines the function, from which the evaluator can be piped elsewhere

Safe so long as the function and its returned data can be serialized

Parameters:
  • _func (Callable) – function

  • daemon (bool) – daemon argument to RemoteFunctionWorker instance

Returns:

evaluator-worker pair

Return type:

Tuple[RemoteFunctionEvaluator, RemoteFunctionWorker]

simservice.messages.safe_transmit(conn=None) Callable

Wrap to do communication protocol with safe handling of common exceptions

Parameters:

conn (multiprocessing.connection.Connection or None; default None) – connection

Returns:

function wrapper

simservice.messages.worker_transmit(conn, func) None

Generic communication protocol: worker side

Blocks until routine is terminated by dispatcher

Parameters:
  • conn (multiprocessing.connection.Connection) – dispatcher-worker connection, worker side

  • func (Functor) – functor with supporting evaluation by ConnectionMessage

Returns:

None

PySimService

Defines the base class for simulation services

class simservice.PySimService.PySimService(sim_name: str = '', *args, **kwargs)

Client-side interface for simulation service processes Implementations should derive a wrap for an underlying service from this class

Basic usage is

sim = PySimService()
sim.run()
sim.init()
sim.start()
for s in range(S):
    sim.step()
sim.finish()

Status reporting is as follows

  • sim = PySimService() : sim.status -> SimStatus.REGISTERED

  • sim.run() : sim.status -> SimStatus.SIM_LOADED

  • sim.init() : sim.status -> SimStatus.SIM_INITIALIZED

  • sim.start() : sim.status -> SimStatus.SIM_STARTED

  • sim.step() : sim.status -> SimStatus.SIM_RUNNING

  • sim.finish() : sim.status -> SimStatus.SIM_FINISHED

  • sim.stop() : sim.status -> SimStatus.SIM_STOPPED

  • sim.stop(terminate_sim=False) : sim.status -> SimStatus.SIM_FINISHED

beginning_step: int

First simulaton step

property current_step: int

Current simulation step

property error_message: Optional[str]

Error message to report on demand, if any

finish() None

Execute underlying simulation finish

Returns:

None

init() bool

Initialize underlying simulation

Returns:

True if started; False if further start calls are required

Return type:

bool

static inside_run(self) None

Called inside run; this supports parallel applications

To support running a service in parallel, overload this or set it via set_inside_run with what to do when this service acts without further control from the calling process

Parameters:

self (PySimService) – this service instance

Returns:

None

property profiler_report: str

Return on-demand profiling information about simulation service

Returns:

profiling information

Return type:

str

run()

Initialize underlying simulation

All prep for the underlying simulation is complete after this call

Returned dictionary contains

  • name: the name of the simulation

  • sim: this servce instance

Returns:

name and reference of this service instance

set_inside_run(_inside_run_func) None

Set inside run function

Parameters:

_inside_run_func ((PySimService) -> None) – inside run function

Returns:

None

set_sim_name(_sim_name: str) None

Set simulation name after instantiation

Parameters:

_sim_name (str) – name of the simulation

Returns:

None

start() bool

After simulation and before stepping

Returns:

True if started; False if further start calls are required

Return type:

bool

status: SimStatus

Current serivce status

steer() bool

Execute steering; calling signal for ad-hoc changes to service and underlying simulation data

Returns:

True if OK, False if something went wrong

Return type:

bool

step() bool

Execute a step of the underlying simulation

Returns:

True if successful, False if something failed

Return type:

bool

stop(terminate_sim: bool = True) None

Execute underlying stop

Parameters:

terminate_sim (bool) – Terminates simulation if True; default True

Returns:

None

class simservice.PySimService.SimStatus(value)

Simulation status enum

service_containers

Defines containers for service processes

class simservice.service_containers.ProcessContainer(_conn, _process_cls, *args, **kwargs)

Basic container for a service process

An instance of this class instantiates a service environment and spawns an underlying service process

Parameters:
  • _conn (multiprocessing.connection.Connection) – X-process connection, process side

  • _process_cls – process-launching class; args and kwargs are passed to this to instantiate the process

  • args – process-launching positional arguments

  • kwargs – process-launching keyword arguments

run()

Runs the process

service_factory

Defines a factory method for instantiating services

class simservice.service_factory.ProcessRegistry

A registry of process info

Acts as a dictionary, where each key is the name of a registered service, and each value is a tuple of the following,

  • the service process

  • the service wrap

  • connection to the service process

  • connection to service function receiver

simservice.service_factory.close_service(_s) None

Closes a service completely

Parameters:

_s – service proxy

simservice.service_factory.connect_properties(_client_process, _server_wrap_class) None

Connect properties of a wrapped service class to a client process class

Wrapped service class should present a list of properties via a method _property_names() and corresponding getter and setter methods.

E.g., for p in cls._property_names(), cls.get_p() and cls.set_p() are defined

Parameters:
  • _client_process – client-side service proxy instance

  • _server_wrap_class – server-side wrapped service class

Returns:

None

simservice.service_factory.get_proxy_by_process_name(_process_name: str)

Returns a process by name

Parameters:

_process_name (str) – name of process

Returns:

Return type:

simservice.service_factory.process_factory(_service_name: str, *args, **kwargs)

Main template service process proxy generator for local services

Implementations should work through this when presenting a service proxy

Parameters:
  • _service_name (str) – basic name of service; the factory will generate a unique name for each instance

  • args – service constructor position arguments

  • kwargs – service constructor keyword arguments

Returns:

service proxy instance

service_wraps

Defines service wraps

class simservice.service_wraps.TypeProcessWrap(_return_conn, *args, **kwargs)

Process wrap base class

Client service proxies are generated from this wrap

Service implementations should derive a wrap from this and register it with an appropriate service manager

Service wraps with method and property names that collide with those defined on this class will be ignored when generating a client-side proxy class

close()

Closes the proxy

process_name() str

Reserved function for uniquely identifying a service process

Do not override

Returns:

unique process name

Return type:

str

simservice.service_wraps.proxy_function_factory(_cmd: str, _conn) partial

Service proxy dispatcher function factory

Generated function goes on client proxy wrap and dispatches commands to service ProcessContainer instance

Parameters:
  • _cmd (str) – function name defined on server-side service wrap

  • _conn (multiprocessing.connection.Connection) – manager-process connection, manager side

Returns:

serial-safe dispatch transmiter

Return type:

functools.partial

simservice.service_wraps.proxy_property_accessor_factory(_name: str, _conn)

Service proxy dispatcher property factory

Parameters:
  • _name (str) – property name

  • _conn (multiprocessing.connection.Connection) – manager-process connection, manager side

Returns:

property getter, setter

ServiceFunctionReceiver

Defines structures for connecting service functions

class simservice.ServiceFunctionReceiver.ServiceFunctionReceiver

Handles callbacks for instantiating service functions of service proxies

Service process sends registered service functions via Pipe

Processing generates service function containers for accessing underlying service function on the client side

Processing is invoked by workers that monitor pipes between the registry in the service process and the receiver in the main process

KEY_CONN = 'Connection'

Key for connection in container storage dictionary

KEY_CONT = 'Container'

Key for container in container storage dictionary

classmethod disconnect_service(service_proxy) None

Remove a service from the receiver.

Parameters:

service_proxy – service proxy instance

Returns:

None

classmethod register_service(service_proxy, service_conn) None

Register service with receiver

A service process should be registered before being deployed, since the receiver must be ready to handle service function callbacks during service process activity

Parameters:
  • service_proxy – service proxy instance

  • service_conn (multiprocessing.connection.Connection) – service function callback connection; receiver side

Returns:

None

service_containers = {}

Service container storage

type: Dict[str, Dict[str, Union[multiprocessing.connection.Connection, _ServiceFunctionContainer]]]

workers: Dict[str, _ServiceFunctionConnectionWorker] = {}

Service function connection worker storage

ServiceFunctionRegistry

Defines the service function interface

exception simservice.ServiceFunctionRegistry.NotAServiceError

Raised when attempts are made to register a service function outside of a simservice environment

class simservice.ServiceFunctionRegistry.ServiceFunctionRegistry

Registers service function on service process side and relays them to receiver in main process

parent = None

Service process; set by parent process during environment setup

If this isn’t set, then this class is being improperly accessed

process_name: Optional[str] = None

Name of this process; set by parent process during environment setup

receiver_conn = None

Connection to main process service function receiver; set by parent process during environment setup

type: multiprocessing.connection.Connection

classmethod register_function(func: Callable, function_name: Optional[str] = None) None

Registers a service function

Parameters:
  • func (Callable) – function to register

  • function_name (str) – name of function on proxy; optional

Returns:

None

workers = {}

Worker storage by function name

These calculate service functions on demand by the client side and send them back with threading

type: Dict[str, Tuple[Callable, messages.RemoteFunctionWorker]]

simservice.ServiceFunctionRegistry.service_function(func: Callable, function_name: Optional[str] = None)

Service function registrator: makes ad-hoc modifications to the client-side interface

This can be used within service specification to make an internal method available as a method on a client-side service proxy

E.g., if MyServiceWrap defines a service wrap, the underlying service of which makes the following specification

def f():
    print("Hello from the server side!")

Then f() can be made available on a proxy of the service on the client side by declaring inside the service,

service_function(f)

Then on the client side, the following can then be performed:

my_service = MyServiceWrap()
my_service.run()
my_service.f()

Note that the availability of a service function depends on the specification of the underlying service. At various stages of usage, a service may or may not have yet made a service function available.

Parameters:
  • func (Callable) – function to make available

  • function_name (str) – optional name assignment; if not specified, then the proxy method will be named the same as the registered function. Useful for attaching to methods of the same name to the same service as a service function

Returns:

None

utils

Defines utility features

class simservice.utils.ExecutionContext(_proxy, run: bool = True, init: bool = True, start: bool = True, finish: bool = True, close: bool = True)

A context to automate much of the mundane details of managing simple services

class simservice.utils.NonDaemonicContext

A non-daemonic context

Process

alias of NonDaemonicProcess

class simservice.utils.NonDaemonicPool(*args, **kwargs)
class simservice.utils.NonDaemonicProcess(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

A non-daemonic process

property daemon

Return whether process is a daemon