Graph-IT

supcon.intf module

This module contains the classes to describe interfaces on the supcon bus, a base class Implementation to implemet those interfaces and the abstract class Node which contains methods to interact with the supcon bus.

# -*- coding: utf-8 -*-
"""
This module contains the classes to describe interfaces on the supcon bus,
a base class `supcon.intf.Implementation` to implemet those interfaces and the
abstract class `supcon.intf.Node` which contains methods to interact with the
supcon bus.
"""

import re
import abc
import itertools
import traceback

import twisted.internet.defer as defer

import supcon.util

class Named(supcon.util.Named):
  """A base class for objects with a name.
  """

  regex = None
  """re.RegexObject: a regular expression, the name must conform to"""

  def __init__(self, name):
    """Initializes the NamedAndDescribed instance

    Args:
      name (str): the name of the argument
    """
    self.__name = self.toName(name)

  @property
  def name(self) -> str:
    """str: the name"""
    return self.__name

  @classmethod
  def toName(cls, value) -> str:
    """Converts the value into a name. If this is impossible a ValueError is
    raised.

    Args:
      value (any): the value
    Raises:
      ValueError
    """
    value = str(value)
    if not cls.regex.fullmatch(value):
      raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
    return value

class NamedAndDescribed(Named):
  """A base class for the interface describing classes `supcon.intf.Argument`,
  `supcon.intf.Event`, `supcon.intf.Method` and `supcon.intf.Interface` that
  all have the properties name and description."""

  def __init__(self, name, description=''):
    """Initializes the NamedAndDescribed instance

    Args:
      name (str): the name of the argument
      description (str): a description of the argument
    """
    Named.__init__(self, name)
    self.__description = self.toDescription(description)

  @property
  def description(self) -> str:
    """str: a description"""
    return self.__description

  @classmethod
  def toDescription(cls, value) -> str:
    """Converts the value into a description. If this is impossible a ValueError
    is raised.

    Args:
      value (any): the value
    Raises:
      ValueError
    """
    return str(value)

class DArgument(supcon.util.Dumpable, NamedAndDescribed):
  """Describes an input or output argument of a `supcon.intf.DMethod` or an
  argument of a `supcon.intf.DEvent`"""

  regex = re.compile('[a-zA-Z0-9]+')

  def validate(self, argument):
    """Validates the given argument value. Raises an ValueError if validation
    fails.
    """
    pass

  def dump(self):
    data = {'name': self.name}
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

class DArguments(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DArgument` instances"""
  vtype = DArgument

class DEvent(supcon.util.Dumpable, NamedAndDescribed):
  """Describes an event that can be emitted by an implementation on the bus"""

  regex = re.compile('[a-zA-Z0-9]+')

  def __init__(self, name, args=DArguments(), description=''):
    """Initializes the Event

    Args:
      name (str): the name of the event
      args (DArguments): the list of arguments of the event
      description (str): a description of the event
    """
    NamedAndDescribed.__init__(self, name, description)
    self.__args = DArguments.to(args)

  @property
  def args(self) -> DArguments:
    """DArguments: the list of arguments of the event"""
    return self.__args

  def validateArgs(self, args):
    """Validates the given argument map. Raises an ValueError if validation
    fails.
    """
    for arg in args:
      if arg not in self.__args:
        raise ValueError('event {} has no argument {}'.format(self.name, arg))
      self.__args[arg].validate(args[arg])
    for arg in self.__args:
      if arg not in args:
        raise ValueError('event {} needs argument {}'.format(self.name, arg))

  def dump(self):
    data = {'name': self.name}
    if self.args:
      data['args'] = self.args.dump()
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

class DEvents(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DEvent` instances"""
  vtype = DEvent

class DMethod(supcon.util.Dumpable, NamedAndDescribed):
  """A DMethod that can be called on an Object on the Bus"""

  regex = re.compile('[a-zA-Z0-9]+')

  def __init__(self, name, inArgs=DArguments(), outArgs=DArguments(), description=''):
    """Initializes the Event

    Args:
      name (str): the name of the method
      inArgs (DArguments): the list of input arguments of the method
      outArgs (DArguments): the list of output arguments of the method
      description (str): a description of the method
    """
    NamedAndDescribed.__init__(self, name, description)
    self.__inArgs = DArguments.to(inArgs)#
    self.__outArgs = DArguments.to(outArgs)

  @property
  def inArgs(self) -> DArguments:
    """DArguments: The input arguments of the method"""
    return self.__inArgs

  @property
  def outArgs(self) -> DArguments:
    """DArguments: The output arguments of the method"""
    return self.__outArgs

  def validateInArgs(self, inArgs):
    """Validates the given argument Mapping. Raises an ValueError if validation fails
    """
    for arg in inArgs:
      if arg not in self.__inArgs:
        raise ValueError('method {} has no input argument {}'.format(self.name, arg))
      self.__inArgs[arg].validate(inArgs[arg])
    for arg in self.__inArgs:
      if arg not in inArgs:
        raise ValueError('method {} needs input argument {}'.format(self.name, arg))

  def validateOutArgs(self, outArgs):
    """Validates the given argument Mapping. Raises an ValueError if validation fails
    """
    for arg in outArgs:
      if arg not in self.__outArgs:
        raise ValueError('method {} has no output argument {}'.format(self.name, arg))
      self.__outArgs[arg].validate(outArgs[arg])
    for arg in self.__outArgs:
      if arg not in outArgs:
        raise ValueError('method {} needs output argument {}'.format(self.name, arg))

  def dump(self):
    data = {'name': self.name}
    if self.inArgs:
      data['inArgs'] = self.inArgs.dump()
    if self.outArgs:
      data['outArgs'] = self.outArgs.dump()
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

class DMethods(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DMethod` instances"""
  vtype = DMethod

class DInterface(supcon.util.Dumpable, NamedAndDescribed):
  """An Interface that is implemented by an Object on the Bus"""

  regex = re.compile('([a-zA-Z0-9_]+\\.)*[a-zA-Z0-9_]+')

  def __init__(self, name, events=DEvents(), methods=DMethods(), description=''):
    """Initializes the Event

    Args:
      name (str): the name of the interface
      events (DEvents): the list of events of the interface
      methods (DMethods): the list of methods of the interface
      description (str): a description of the interface
    """
    NamedAndDescribed.__init__(self, name, description)
    self.__events = DEvents.to(events)
    self.__methods = DMethods.to(methods)

  @property
  def events(self) -> DEvents:
    """DEvent: the list of events this interface can emit"""
    return self.__events

  @property
  def methods(self) -> DMethods:
    """DMethods: the list of methods this interface provides"""
    return self.__methods

  def validateEvent(self, event, args):
    """Validates that the given event is an event of this interface and that
    the given arguments are arguments of the event

    Args:
      event (str): the event
      args (dict): the arguments
    Raises:
      ValueError
    """
    event = str(event)
    if event not in self.__events:
      raise ValueError('event {} is unknown'.format(event))
    self.__events[event].validateArgs(args)

  def validateCall(self, method, inArgs):
    """Asserts that the given method is a method of this interface and that
    the given arguments are input arguments of the method

    Args:
      event (str): the event
      inArgs (dict): the input arguments
    Raises:
      AssertationError
    """
    method = str(method)
    if method not in self.__methods:
      raise ValueError('method {} is unknown'.format(method))
    self.__methods[method].validateInArgs(inArgs)

  def validateReturn(self, method, outArgs):
    """Asserts that the given method is a method of this interface and that
    the given arguments are output arguments of the method

    Args:
      event (str): the event
      outArgs (dict): the output arguments
    Raises:
      AssertationError
    """
    method = str(method)
    if method not in self.__methods:
      raise ValueError('method {} is unknown'.format(method))
    self.__methods[method].validateOutArgs(outArgs)

  def dump(self):
    data = {'name': self.name}
    if self.events:
      data['events'] = self.events.dump()
    if self.methods:
      data['methods'] = self.methods.dump()
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

class DInterfaces(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DInterface` instances"""
  vtype = DInterface

class DPath(Named, supcon.util.NamedList):
  """A named readonly map of `supcon.intf.DInterface` instances"""

  vtype = DInterface
  regex = re.compile('/(([a-zA-Z0-9_]+/)*[a-zA-Z0-9_]+)?')

  def __init__(self, name, interfaces=None):
    """Initializes the Path instance

    Args:
      name (str): the name of the argument
      interfaces (): ...
    """
    if interfaces is None:
      interfaces = []
    Named.__init__(self, name)
    supcon.util.NamedList.__init__(self, interfaces)

  def dump(self):
    return {
      'name': self.name,
      'interfaces': [value.dump() for value in self.values()]
    }

  @classmethod
  def load(cls, data) -> 'DPath':
    return cls(**data)

  def addInterface(self, interface: DInterface) -> 'DPath':
    if interface.name in self:
      raise ValueError('interface {} at path {} already exists'.format(interface.name, self.name))
    interfaces = itertools.chain(self.values(), [interface])
    return DPath(self.name, interfaces)

  def delInterface(self, interface: DInterface) -> 'DPath':
    if interface.name not in self:
      raise ValueError('interface {} at path {} does not exist'.format(interface.name, self.name))
    interfaces = (v for v in self.values() if v.name != interface.name)
    return DPath(self.name, interfaces)

class DNode(Named, supcon.util.NamedList):
  """A named readonly map of `supcon.intf.DPath` instances"""

  vtype = DPath
  regex = re.compile('.+')

  def __init__(self, name, paths=None):
    """Initializes the Path instance

    Args:
      name (str): the name of the argument
      paths (): ...
    """
    if paths is None:
      paths = []

    Named.__init__(self, name)
    supcon.util.NamedList.__init__(self, paths)

  def dump(self):
    return {
      'name': self.name,
      'paths': [value.dump() for value in self.values()]
    }

  @classmethod
  def load(cls, data) -> 'DPath':
    return cls(**data)

  def hasPath(self, path: str) -> bool:
    return path in self

  def hasIntf(self, path: str, intf: str) -> bool:
    return path in self and intf in self[path]

  def addPath(self, path: str) -> 'DNode':
    if path in self:
      raise ValueError('path {} on node {} already exists'.format(path, self.name))
    paths = itertools.chain(self.values(), [DPath(path)])
    return DNode(self.name, paths)

  def delPath(self, path: str) -> 'DNode':
    if path not in self:
      raise ValueError('path {} on node {} does not exist'.format(path, self.name))
    if self[path]:
      raise ValueError('path {} on node {} is not empty'.format(path, self.name))
    paths = (v for v in self.values() if v.name != path)
    return DNode(self.name, paths)

  def addInterface(self, path: str, interface: DInterface) -> 'DNode':
    if path not in self:
      raise ValueError('path {} on node {} does not exist'.format(path, self.name))
    if interface.name in self[path]:
      raise ValueError('interface {} at path {} on node {} already exists'.format(interface.name, path, self.name))
    paths = (v for v in self.values() if v.name != path)
    paths = itertools.chain(paths, [self[path].addInterface(interface)])
    return DNode(self.name, paths)

  def delInterface(self, path: str, interface: DInterface) -> 'DNode':
    if path not in self:
      raise ValueError('path {} on node {} does not exist'.format(path, self.name))
    if interface.name not in self[path]:
      raise ValueError('interface {} at path {} on node {} does not exist'.format(interface.name, path, self.name))
    paths = (v for v in self.values() if v.name != path)
    paths = itertools.chain(paths, [self[path].delInterface(interface)])
    return DNode(self.name, paths)

class DNodes(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DNode` instances"""
  vtype = DNode

  def hasNode(self, node: str) -> bool:
    return node in self

  def hasPath(self, node: str, path: str) -> bool:
    return node in self and path in self[node]

  def hasIntf(self, node: str, path: str, intf: str) -> bool:
    return node in self and path in self[node] and intf in self[node][path]

  def addNode(self, node: str) -> 'DNodes':
    if node in self:
      raise ValueError('node {} already exists'.format(node))
    nodes = itertools.chain(self.values(), [DNode(node)])
    return DNodes(nodes)

  def delNode(self, node: str) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    if self[node]:
      raise ValueError('node {} is not empty'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    return DNodes(nodes)

  def addPath(self, node: str, path: str) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].addPath(path)])
    return DNodes(nodes)

  def delPath(self, node: str, path: str) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].delPath(path)])
    return DNodes(nodes)

  def addInterface(self, node: str, path: str, interface: DInterface) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].addInterface(path, interface)])
    return DNodes(nodes)

  def delInterface(self, node: str, path: str, interface: DInterface) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].delInterface(path, interface)])
    return DNodes(nodes)

class Implementation(object):
  """The base class for interface implementations"""

  def __init__(self, interface: DInterface):
    """
    Args:
      interface (DInterface): the interface that is implemented by this Implementation
    """
    if not isinstance(interface, DInterface):
      raise ValueError('interface must be an instance of {}'.format(DInterface))
    self.__interface = interface

    self.__callCbs = {}
    self.__fireCbs = []

  @property
  def intf(self) -> str:
    """str: The name of the implemented interface"""
    return self.__interface.name

  @property
  def interface(self) -> DInterface:
    """Interface: The implemented interface"""
    return self.__interface

  def setCallCb(self, method: str, cb):
    """Sets a callback for the given method. The method must be a method of the
    interface this Implementation implements. The callback must implement the
    given method. The callback gets called by calls to Implementation.call()

    Args:
      method (str): the interface method that the callback implements
      cb (callable): the callback
    """
    method = DMethod.toName(method)
    if method in self.__callCbs:
      raise ValueError('Callback for method {} is already set!'.format(method))
    if method not in self.__interface.methods:
      raise ValueError('Interface has no method {}!'.format(method))
    self.__callCbs[method] = cb

  def call(self, method: str, inArgs) -> defer.Deferred:
    """Calls the given interface method with the given arguments. This method
    calls the callback set by Implementation.setCallCb()

    Args:
      method (str): the called interface method
      inArgs (Mapping): a map of input arguments
    Returns:
      defer.Deferred: Resolves with the result of the called method
    """
    def validateReturn(outArgs):
      self.__interface.validateReturn(method, outArgs)
      return outArgs

    try:
      self.__interface.validateCall(method, inArgs)
      if method not in self.__callCbs:
        raise ValueError('Callback for method {} is not set!'.format(method))

      d = self.__callCbs[method](**inArgs)
      if not isinstance(d, defer.Deferred):
        d = defer.succeed(d)
      d.addCallback(validateReturn)
    except BaseException as e:
      traceback.print_exc()
      d = defer.fail(e)

    return d

  def addFireCb(self, cb):
    """Adds a callback that gets called, when this Implementation fires an
    event.

    Args:
      cb (callable): the callback
    """
    self.__fireCbs.append(cb)

  def delFireCb(self, cb):
    """Removes a callback that gets called, when this Implementation fires an
    event.

    Args:
      cb (callable): the callback
    """
    self.__fireCbs.remove(cb)

  def fire(self, event: str, args):
    """Fires the given event with the given arguments.

    Args:
      event (str): the event name
      args (collecion.Mapping): the event arguments
    """
    self.__interface.validateEvent(event, args)

    for cb in self.__fireCbs:
      cb(event, args)

class Object(object):

  def __init__(self, interfaces=None):
    """
    Args:
      interfaces (DInterfaces): the interfaces that are implemented by this Object
    """
    if interfaces is None:
      interfaces = []

    self.__intfs = {}
    self.__impls = {}

    def getCallCb(intf):
      return lambda method, inArgs: self.__call(intf, method, inArgs)

    for interface in interfaces:
      if not isinstance(interface, DInterface):
        raise ValueError('interface must be an instance of {}'.format(DInterface))
      self.__intfs[interface.name] = interface

      implementation = Implementation(interface)
      callCb = getCallCb(implementation.intf)
      for method in interface.methods:
        implementation.setCallCb(method, callCb)
      self.__impls[implementation.intf] = implementation

  @property
  def interfaces(self):
    return self.__intfs.values()

  @property
  def implementations(self):
    return self.__impls.values()

  def interface(self, intf):
    return self.__intfs[intf]

  def implementation(self, intf):
    return self.__impls[intf]

  def __call(self, intf: str, method: str, inArgs) -> defer.Deferred:
    pass

class Node(abc.ABC):
  """The Node Interface. This class defines the methods that participants can
  use to access the supcon bus."""

  def __init__(self, name):
    super().__init__()
    self.__name = self.toName(name)

  @property
  def name(self) -> str:
    """str: The name of the node on the bus"""
    return self.__name

  @classmethod
  def toName(cls, value) -> str:
    return DNode.toName(value)

  @abc.abstractmethod
  def nodes(self) -> DNodes:
    """list[str]: The currently connected nodes"""
    raise NotImplementedError()

  @abc.abstractmethod
  def connect(self, endpoint):
    """Connects the node to the given endpoint.

    If the connection failes or closes the connection gets reestablished with an
    exponential timeout up to two minutes.

    Args:
      endpoint (twisted.internet.interfaces.IStreamClientEndpoint):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def listen(self, endpoint):
    """Listens at the given endpoint for incoming connections

    Args:
      endpoint (twisted.internet.interfaces.IStreamServerEndpoint):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def register(self, path: str, impl: Implementation):
    """Registers an implementation with the node

    Args:
      impl (Implementation):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def unregister(self, path: str, impl: Implementation):
    """Removes an implementation from the node

    Args:
      impl (supcon.intf.Implementation):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def call(self, node: str, path: str, intf: str, method: str, args: dict) -> defer.Deferred:
    """Calls a method on the bus

    Args:
      node (str): a node on the bus
      path (str): a path on the given node
      intf (str): an interface at the given path
      method (str): a method of the given interface
      args (dict): a dict of method arguments

    Returns:
      defer.Deferred:
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def on(self, node: str, path: str, intf: str, event: str, cb):
    """Registers a callback for an event on the bus

    Args:
      node (str): a node on the bus
      path (str): a path on the given node
      intf (str): an interface at the given path
      event (str): a method of the given interface
      cb (callable): a callable that gets called with a dict of event arguments
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def off(self, node: str, path: str, intf: str, event: str, cb):
    """Unregisters a callback for an event on the bus

    Args:
      node (str): a node on the bus
      path (str): a path on the given node
      intf (str): an interface at the given path
      event (str): a method of the given interface
      cb (callable): a callable that gets called with a dict of event arguments
    """
    raise NotImplementedError()

Classes

class DArgument

Describes an input or output argument of a DMethod or an argument of a DEvent

class DArgument(supcon.util.Dumpable, NamedAndDescribed):
  """Describes an input or output argument of a `supcon.intf.DMethod` or an
  argument of a `supcon.intf.DEvent`"""

  regex = re.compile('[a-zA-Z0-9]+')

  def validate(self, argument):
    """Validates the given argument value. Raises an ValueError if validation
    fails.
    """
    pass

  def dump(self):
    data = {'name': self.name}
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

Ancestors (in MRO)

Class variables

var regex

Class Methods

def load(

cls, data)

@classmethod
def load(cls, data):
  return cls(**data)

def toDescription(

cls, value)

Converts the value into a description. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toDescription(cls, value) -> str:
  """Converts the value into a description. If this is impossible a ValueError
  is raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  return str(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var description

Inheritance: NamedAndDescribed.description

str: a description

var name

Inheritance: Named.name

str: the name

Methods

def __init__(

self, name, description='')

Initializes the NamedAndDescribed instance

Args: name (str): the name of the argument description (str): a description of the argument

def __init__(self, name, description=''):
  """Initializes the NamedAndDescribed instance
  Args:
    name (str): the name of the argument
    description (str): a description of the argument
  """
  Named.__init__(self, name)
  self.__description = self.toDescription(description)

def dump(

self)

Converts the supcon.util.Dumpable into a 'simple' datastructure.

def dump(self):
  data = {'name': self.name}
  if self.description != '':
    data['description'] = self.description
  return data

def validate(

self, argument)

Validates the given argument value. Raises an ValueError if validation fails.

def validate(self, argument):
  """Validates the given argument value. Raises an ValueError if validation
  fails.
  """
  pass

class DArguments

A readonly map of DArgument instances

class DArguments(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DArgument` instances"""
  vtype = DArgument

Ancestors (in MRO)

  • DArguments
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var vtype

Class Methods

def load(

cls, data)

Converts the given list of 'simple' datastructures data into an instance of cls, a subclass of supcon.util.NamedList.

@classmethod
def load(cls, data):
  """
  Converts the given list of 'simple' datastructures **data** into an instance
  of **cls**, a subclass of `supcon.util.NamedList`.
  """
  return cls(data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

Methods

def __init__(

self, values=None)

Initializes the supcon.util.NamedList with the given list of values.

An element of values must be of type supcon.util.NamedList.vtype or a 'simple' datastructure that can be converted to an instance of supcon.util.NamedList.vtype by supcon.util.NamedList.vtype.load().

def __init__(self, values=None):
  """
  Initializes the `supcon.util.NamedList` with the given list of **values**.
  An element of **values** must be of type `supcon.util.NamedList.vtype` or a
  'simple' datastructure that can be converted to an instance of
  `supcon.util.NamedList.vtype` by `supcon.util.NamedList.vtype`.load().
  """
  if values is None:
    values = []
  if not issubclass(self.vtype, Named):
    raise ValueError('the value type must be a subclass of Named')
  if not issubclass(self.vtype, Dumpable):
    raise ValueError('the value type must be a subclass of Dumpable')
  self.__values = collections.OrderedDict()
  for value in values:
    if not isinstance(value, self.vtype):
      value = self.vtype.load(value)
    if value.name in self.__values:
      raise ValueError('value.name must be unique in the given list of values')
    self.__values[value.name] = value

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  """
  Converts the `supcon.util.NamedList` into a list of 'simple' datastructures.
  """
  return [value.dump() for value in self.values()]

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class DEvent

Describes an event that can be emitted by an implementation on the bus

class DEvent(supcon.util.Dumpable, NamedAndDescribed):
  """Describes an event that can be emitted by an implementation on the bus"""

  regex = re.compile('[a-zA-Z0-9]+')

  def __init__(self, name, args=DArguments(), description=''):
    """Initializes the Event

    Args:
      name (str): the name of the event
      args (DArguments): the list of arguments of the event
      description (str): a description of the event
    """
    NamedAndDescribed.__init__(self, name, description)
    self.__args = DArguments.to(args)

  @property
  def args(self) -> DArguments:
    """DArguments: the list of arguments of the event"""
    return self.__args

  def validateArgs(self, args):
    """Validates the given argument map. Raises an ValueError if validation
    fails.
    """
    for arg in args:
      if arg not in self.__args:
        raise ValueError('event {} has no argument {}'.format(self.name, arg))
      self.__args[arg].validate(args[arg])
    for arg in self.__args:
      if arg not in args:
        raise ValueError('event {} needs argument {}'.format(self.name, arg))

  def dump(self):
    data = {'name': self.name}
    if self.args:
      data['args'] = self.args.dump()
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

Ancestors (in MRO)

Class variables

var regex

Class Methods

def load(

cls, data)

@classmethod
def load(cls, data):
  return cls(**data)

def toDescription(

cls, value)

Converts the value into a description. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toDescription(cls, value) -> str:
  """Converts the value into a description. If this is impossible a ValueError
  is raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  return str(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var args

DArguments: the list of arguments of the event

var description

str: a description

var name

str: the name

Methods

def __init__(

self, name, args=supcon.intf.DArguments(), description='')

Initializes the Event

Args: name (str): the name of the event args (DArguments): the list of arguments of the event description (str): a description of the event

def __init__(self, name, args=DArguments(), description=''):
  """Initializes the Event
  Args:
    name (str): the name of the event
    args (DArguments): the list of arguments of the event
    description (str): a description of the event
  """
  NamedAndDescribed.__init__(self, name, description)
  self.__args = DArguments.to(args)

def dump(

self)

Converts the supcon.util.Dumpable into a 'simple' datastructure.

def dump(self):
  data = {'name': self.name}
  if self.args:
    data['args'] = self.args.dump()
  if self.description != '':
    data['description'] = self.description
  return data

def validateArgs(

self, args)

Validates the given argument map. Raises an ValueError if validation fails.

def validateArgs(self, args):
  """Validates the given argument map. Raises an ValueError if validation
  fails.
  """
  for arg in args:
    if arg not in self.__args:
      raise ValueError('event {} has no argument {}'.format(self.name, arg))
    self.__args[arg].validate(args[arg])
  for arg in self.__args:
    if arg not in args:
      raise ValueError('event {} needs argument {}'.format(self.name, arg))

class DEvents

A readonly map of DEvent instances

class DEvents(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DEvent` instances"""
  vtype = DEvent

Ancestors (in MRO)

  • DEvents
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var vtype

Class Methods

def load(

cls, data)

Converts the given list of 'simple' datastructures data into an instance of cls, a subclass of supcon.util.NamedList.

@classmethod
def load(cls, data):
  """
  Converts the given list of 'simple' datastructures **data** into an instance
  of **cls**, a subclass of `supcon.util.NamedList`.
  """
  return cls(data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

Methods

def __init__(

self, values=None)

Initializes the supcon.util.NamedList with the given list of values.

An element of values must be of type supcon.util.NamedList.vtype or a 'simple' datastructure that can be converted to an instance of supcon.util.NamedList.vtype by supcon.util.NamedList.vtype.load().

def __init__(self, values=None):
  """
  Initializes the `supcon.util.NamedList` with the given list of **values**.
  An element of **values** must be of type `supcon.util.NamedList.vtype` or a
  'simple' datastructure that can be converted to an instance of
  `supcon.util.NamedList.vtype` by `supcon.util.NamedList.vtype`.load().
  """
  if values is None:
    values = []
  if not issubclass(self.vtype, Named):
    raise ValueError('the value type must be a subclass of Named')
  if not issubclass(self.vtype, Dumpable):
    raise ValueError('the value type must be a subclass of Dumpable')
  self.__values = collections.OrderedDict()
  for value in values:
    if not isinstance(value, self.vtype):
      value = self.vtype.load(value)
    if value.name in self.__values:
      raise ValueError('value.name must be unique in the given list of values')
    self.__values[value.name] = value

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  """
  Converts the `supcon.util.NamedList` into a list of 'simple' datastructures.
  """
  return [value.dump() for value in self.values()]

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class DInterface

An Interface that is implemented by an Object on the Bus

class DInterface(supcon.util.Dumpable, NamedAndDescribed):
  """An Interface that is implemented by an Object on the Bus"""

  regex = re.compile('([a-zA-Z0-9_]+\\.)*[a-zA-Z0-9_]+')

  def __init__(self, name, events=DEvents(), methods=DMethods(), description=''):
    """Initializes the Event

    Args:
      name (str): the name of the interface
      events (DEvents): the list of events of the interface
      methods (DMethods): the list of methods of the interface
      description (str): a description of the interface
    """
    NamedAndDescribed.__init__(self, name, description)
    self.__events = DEvents.to(events)
    self.__methods = DMethods.to(methods)

  @property
  def events(self) -> DEvents:
    """DEvent: the list of events this interface can emit"""
    return self.__events

  @property
  def methods(self) -> DMethods:
    """DMethods: the list of methods this interface provides"""
    return self.__methods

  def validateEvent(self, event, args):
    """Validates that the given event is an event of this interface and that
    the given arguments are arguments of the event

    Args:
      event (str): the event
      args (dict): the arguments
    Raises:
      ValueError
    """
    event = str(event)
    if event not in self.__events:
      raise ValueError('event {} is unknown'.format(event))
    self.__events[event].validateArgs(args)

  def validateCall(self, method, inArgs):
    """Asserts that the given method is a method of this interface and that
    the given arguments are input arguments of the method

    Args:
      event (str): the event
      inArgs (dict): the input arguments
    Raises:
      AssertationError
    """
    method = str(method)
    if method not in self.__methods:
      raise ValueError('method {} is unknown'.format(method))
    self.__methods[method].validateInArgs(inArgs)

  def validateReturn(self, method, outArgs):
    """Asserts that the given method is a method of this interface and that
    the given arguments are output arguments of the method

    Args:
      event (str): the event
      outArgs (dict): the output arguments
    Raises:
      AssertationError
    """
    method = str(method)
    if method not in self.__methods:
      raise ValueError('method {} is unknown'.format(method))
    self.__methods[method].validateOutArgs(outArgs)

  def dump(self):
    data = {'name': self.name}
    if self.events:
      data['events'] = self.events.dump()
    if self.methods:
      data['methods'] = self.methods.dump()
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

Ancestors (in MRO)

Class variables

var regex

Class Methods

def load(

cls, data)

@classmethod
def load(cls, data):
  return cls(**data)

def toDescription(

cls, value)

Converts the value into a description. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toDescription(cls, value) -> str:
  """Converts the value into a description. If this is impossible a ValueError
  is raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  return str(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var description

Inheritance: NamedAndDescribed.description

str: a description

var events

DEvent: the list of events this interface can emit

var methods

DMethods: the list of methods this interface provides

var name

str: the name

Methods

def __init__(

self, name, events=supcon.intf.DEvents(), methods=supcon.intf.DMethods(), description='')

Initializes the Event

Args: name (str): the name of the interface events (DEvents): the list of events of the interface methods (DMethods): the list of methods of the interface description (str): a description of the interface

def __init__(self, name, events=DEvents(), methods=DMethods(), description=''):
  """Initializes the Event
  Args:
    name (str): the name of the interface
    events (DEvents): the list of events of the interface
    methods (DMethods): the list of methods of the interface
    description (str): a description of the interface
  """
  NamedAndDescribed.__init__(self, name, description)
  self.__events = DEvents.to(events)
  self.__methods = DMethods.to(methods)

def dump(

self)

Converts the supcon.util.Dumpable into a 'simple' datastructure.

def dump(self):
  data = {'name': self.name}
  if self.events:
    data['events'] = self.events.dump()
  if self.methods:
    data['methods'] = self.methods.dump()
  if self.description != '':
    data['description'] = self.description
  return data

def validateCall(

self, method, inArgs)

Asserts that the given method is a method of this interface and that the given arguments are input arguments of the method

Args: event (str): the event inArgs (dict): the input arguments Raises: AssertationError

def validateCall(self, method, inArgs):
  """Asserts that the given method is a method of this interface and that
  the given arguments are input arguments of the method
  Args:
    event (str): the event
    inArgs (dict): the input arguments
  Raises:
    AssertationError
  """
  method = str(method)
  if method not in self.__methods:
    raise ValueError('method {} is unknown'.format(method))
  self.__methods[method].validateInArgs(inArgs)

def validateEvent(

self, event, args)

Validates that the given event is an event of this interface and that the given arguments are arguments of the event

Args: event (str): the event args (dict): the arguments Raises: ValueError

def validateEvent(self, event, args):
  """Validates that the given event is an event of this interface and that
  the given arguments are arguments of the event
  Args:
    event (str): the event
    args (dict): the arguments
  Raises:
    ValueError
  """
  event = str(event)
  if event not in self.__events:
    raise ValueError('event {} is unknown'.format(event))
  self.__events[event].validateArgs(args)

def validateReturn(

self, method, outArgs)

Asserts that the given method is a method of this interface and that the given arguments are output arguments of the method

Args: event (str): the event outArgs (dict): the output arguments Raises: AssertationError

def validateReturn(self, method, outArgs):
  """Asserts that the given method is a method of this interface and that
  the given arguments are output arguments of the method
  Args:
    event (str): the event
    outArgs (dict): the output arguments
  Raises:
    AssertationError
  """
  method = str(method)
  if method not in self.__methods:
    raise ValueError('method {} is unknown'.format(method))
  self.__methods[method].validateOutArgs(outArgs)

class DInterfaces

A readonly map of DInterface instances

class DInterfaces(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DInterface` instances"""
  vtype = DInterface

Ancestors (in MRO)

  • DInterfaces
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var vtype

Class Methods

def load(

cls, data)

Converts the given list of 'simple' datastructures data into an instance of cls, a subclass of supcon.util.NamedList.

@classmethod
def load(cls, data):
  """
  Converts the given list of 'simple' datastructures **data** into an instance
  of **cls**, a subclass of `supcon.util.NamedList`.
  """
  return cls(data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

Methods

def __init__(

self, values=None)

Initializes the supcon.util.NamedList with the given list of values.

An element of values must be of type supcon.util.NamedList.vtype or a 'simple' datastructure that can be converted to an instance of supcon.util.NamedList.vtype by supcon.util.NamedList.vtype.load().

def __init__(self, values=None):
  """
  Initializes the `supcon.util.NamedList` with the given list of **values**.
  An element of **values** must be of type `supcon.util.NamedList.vtype` or a
  'simple' datastructure that can be converted to an instance of
  `supcon.util.NamedList.vtype` by `supcon.util.NamedList.vtype`.load().
  """
  if values is None:
    values = []
  if not issubclass(self.vtype, Named):
    raise ValueError('the value type must be a subclass of Named')
  if not issubclass(self.vtype, Dumpable):
    raise ValueError('the value type must be a subclass of Dumpable')
  self.__values = collections.OrderedDict()
  for value in values:
    if not isinstance(value, self.vtype):
      value = self.vtype.load(value)
    if value.name in self.__values:
      raise ValueError('value.name must be unique in the given list of values')
    self.__values[value.name] = value

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  """
  Converts the `supcon.util.NamedList` into a list of 'simple' datastructures.
  """
  return [value.dump() for value in self.values()]

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class DMethod

A DMethod that can be called on an Object on the Bus

class DMethod(supcon.util.Dumpable, NamedAndDescribed):
  """A DMethod that can be called on an Object on the Bus"""

  regex = re.compile('[a-zA-Z0-9]+')

  def __init__(self, name, inArgs=DArguments(), outArgs=DArguments(), description=''):
    """Initializes the Event

    Args:
      name (str): the name of the method
      inArgs (DArguments): the list of input arguments of the method
      outArgs (DArguments): the list of output arguments of the method
      description (str): a description of the method
    """
    NamedAndDescribed.__init__(self, name, description)
    self.__inArgs = DArguments.to(inArgs)#
    self.__outArgs = DArguments.to(outArgs)

  @property
  def inArgs(self) -> DArguments:
    """DArguments: The input arguments of the method"""
    return self.__inArgs

  @property
  def outArgs(self) -> DArguments:
    """DArguments: The output arguments of the method"""
    return self.__outArgs

  def validateInArgs(self, inArgs):
    """Validates the given argument Mapping. Raises an ValueError if validation fails
    """
    for arg in inArgs:
      if arg not in self.__inArgs:
        raise ValueError('method {} has no input argument {}'.format(self.name, arg))
      self.__inArgs[arg].validate(inArgs[arg])
    for arg in self.__inArgs:
      if arg not in inArgs:
        raise ValueError('method {} needs input argument {}'.format(self.name, arg))

  def validateOutArgs(self, outArgs):
    """Validates the given argument Mapping. Raises an ValueError if validation fails
    """
    for arg in outArgs:
      if arg not in self.__outArgs:
        raise ValueError('method {} has no output argument {}'.format(self.name, arg))
      self.__outArgs[arg].validate(outArgs[arg])
    for arg in self.__outArgs:
      if arg not in outArgs:
        raise ValueError('method {} needs output argument {}'.format(self.name, arg))

  def dump(self):
    data = {'name': self.name}
    if self.inArgs:
      data['inArgs'] = self.inArgs.dump()
    if self.outArgs:
      data['outArgs'] = self.outArgs.dump()
    if self.description != '':
      data['description'] = self.description
    return data

  @classmethod
  def load(cls, data):
    return cls(**data)

Ancestors (in MRO)

Class variables

var regex

Class Methods

def load(

cls, data)

@classmethod
def load(cls, data):
  return cls(**data)

def toDescription(

cls, value)

Converts the value into a description. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toDescription(cls, value) -> str:
  """Converts the value into a description. If this is impossible a ValueError
  is raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  return str(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var description

Inheritance: NamedAndDescribed.description

str: a description

var inArgs

DArguments: The input arguments of the method

var name

str: the name

var outArgs

DArguments: The output arguments of the method

Methods

def __init__(

self, name, inArgs=supcon.intf.DArguments(), outArgs=supcon.intf.DArguments(), description='')

Initializes the Event

Args: name (str): the name of the method inArgs (DArguments): the list of input arguments of the method outArgs (DArguments): the list of output arguments of the method description (str): a description of the method

def __init__(self, name, inArgs=DArguments(), outArgs=DArguments(), description=''):
  """Initializes the Event
  Args:
    name (str): the name of the method
    inArgs (DArguments): the list of input arguments of the method
    outArgs (DArguments): the list of output arguments of the method
    description (str): a description of the method
  """
  NamedAndDescribed.__init__(self, name, description)
  self.__inArgs = DArguments.to(inArgs)#
  self.__outArgs = DArguments.to(outArgs)

def dump(

self)

Converts the supcon.util.Dumpable into a 'simple' datastructure.

def dump(self):
  data = {'name': self.name}
  if self.inArgs:
    data['inArgs'] = self.inArgs.dump()
  if self.outArgs:
    data['outArgs'] = self.outArgs.dump()
  if self.description != '':
    data['description'] = self.description
  return data

def validateInArgs(

self, inArgs)

Validates the given argument Mapping. Raises an ValueError if validation fails

def validateInArgs(self, inArgs):
  """Validates the given argument Mapping. Raises an ValueError if validation fails
  """
  for arg in inArgs:
    if arg not in self.__inArgs:
      raise ValueError('method {} has no input argument {}'.format(self.name, arg))
    self.__inArgs[arg].validate(inArgs[arg])
  for arg in self.__inArgs:
    if arg not in inArgs:
      raise ValueError('method {} needs input argument {}'.format(self.name, arg))

def validateOutArgs(

self, outArgs)

Validates the given argument Mapping. Raises an ValueError if validation fails

def validateOutArgs(self, outArgs):
  """Validates the given argument Mapping. Raises an ValueError if validation fails
  """
  for arg in outArgs:
    if arg not in self.__outArgs:
      raise ValueError('method {} has no output argument {}'.format(self.name, arg))
    self.__outArgs[arg].validate(outArgs[arg])
  for arg in self.__outArgs:
    if arg not in outArgs:
      raise ValueError('method {} needs output argument {}'.format(self.name, arg))

class DMethods

A readonly map of DMethod instances

class DMethods(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DMethod` instances"""
  vtype = DMethod

Ancestors (in MRO)

  • DMethods
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var vtype

Class Methods

def load(

cls, data)

Converts the given list of 'simple' datastructures data into an instance of cls, a subclass of supcon.util.NamedList.

@classmethod
def load(cls, data):
  """
  Converts the given list of 'simple' datastructures **data** into an instance
  of **cls**, a subclass of `supcon.util.NamedList`.
  """
  return cls(data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

Methods

def __init__(

self, values=None)

Initializes the supcon.util.NamedList with the given list of values.

An element of values must be of type supcon.util.NamedList.vtype or a 'simple' datastructure that can be converted to an instance of supcon.util.NamedList.vtype by supcon.util.NamedList.vtype.load().

def __init__(self, values=None):
  """
  Initializes the `supcon.util.NamedList` with the given list of **values**.
  An element of **values** must be of type `supcon.util.NamedList.vtype` or a
  'simple' datastructure that can be converted to an instance of
  `supcon.util.NamedList.vtype` by `supcon.util.NamedList.vtype`.load().
  """
  if values is None:
    values = []
  if not issubclass(self.vtype, Named):
    raise ValueError('the value type must be a subclass of Named')
  if not issubclass(self.vtype, Dumpable):
    raise ValueError('the value type must be a subclass of Dumpable')
  self.__values = collections.OrderedDict()
  for value in values:
    if not isinstance(value, self.vtype):
      value = self.vtype.load(value)
    if value.name in self.__values:
      raise ValueError('value.name must be unique in the given list of values')
    self.__values[value.name] = value

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  """
  Converts the `supcon.util.NamedList` into a list of 'simple' datastructures.
  """
  return [value.dump() for value in self.values()]

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class DNode

A named readonly map of DPath instances

class DNode(Named, supcon.util.NamedList):
  """A named readonly map of `supcon.intf.DPath` instances"""

  vtype = DPath
  regex = re.compile('.+')

  def __init__(self, name, paths=None):
    """Initializes the Path instance

    Args:
      name (str): the name of the argument
      paths (): ...
    """
    if paths is None:
      paths = []

    Named.__init__(self, name)
    supcon.util.NamedList.__init__(self, paths)

  def dump(self):
    return {
      'name': self.name,
      'paths': [value.dump() for value in self.values()]
    }

  @classmethod
  def load(cls, data) -> 'DPath':
    return cls(**data)

  def hasPath(self, path: str) -> bool:
    return path in self

  def hasIntf(self, path: str, intf: str) -> bool:
    return path in self and intf in self[path]

  def addPath(self, path: str) -> 'DNode':
    if path in self:
      raise ValueError('path {} on node {} already exists'.format(path, self.name))
    paths = itertools.chain(self.values(), [DPath(path)])
    return DNode(self.name, paths)

  def delPath(self, path: str) -> 'DNode':
    if path not in self:
      raise ValueError('path {} on node {} does not exist'.format(path, self.name))
    if self[path]:
      raise ValueError('path {} on node {} is not empty'.format(path, self.name))
    paths = (v for v in self.values() if v.name != path)
    return DNode(self.name, paths)

  def addInterface(self, path: str, interface: DInterface) -> 'DNode':
    if path not in self:
      raise ValueError('path {} on node {} does not exist'.format(path, self.name))
    if interface.name in self[path]:
      raise ValueError('interface {} at path {} on node {} already exists'.format(interface.name, path, self.name))
    paths = (v for v in self.values() if v.name != path)
    paths = itertools.chain(paths, [self[path].addInterface(interface)])
    return DNode(self.name, paths)

  def delInterface(self, path: str, interface: DInterface) -> 'DNode':
    if path not in self:
      raise ValueError('path {} on node {} does not exist'.format(path, self.name))
    if interface.name not in self[path]:
      raise ValueError('interface {} at path {} on node {} does not exist'.format(interface.name, path, self.name))
    paths = (v for v in self.values() if v.name != path)
    paths = itertools.chain(paths, [self[path].delInterface(interface)])
    return DNode(self.name, paths)

Ancestors (in MRO)

  • DNode
  • Named
  • supcon.util.Named
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var regex

var vtype

Class Methods

def load(

cls, data)

@classmethod
def load(cls, data) -> 'DPath':
  return cls(**data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var name

Inheritance: Named.name

str: the name

Methods

def __init__(

self, name, paths=None)

Initializes the Path instance

Args: name (str): the name of the argument paths (): ...

def __init__(self, name, paths=None):
  """Initializes the Path instance
  Args:
    name (str): the name of the argument
    paths (): ...
  """
  if paths is None:
    paths = []
  Named.__init__(self, name)
  supcon.util.NamedList.__init__(self, paths)

def addInterface(

self, path, interface)

def addInterface(self, path: str, interface: DInterface) -> 'DNode':
  if path not in self:
    raise ValueError('path {} on node {} does not exist'.format(path, self.name))
  if interface.name in self[path]:
    raise ValueError('interface {} at path {} on node {} already exists'.format(interface.name, path, self.name))
  paths = (v for v in self.values() if v.name != path)
  paths = itertools.chain(paths, [self[path].addInterface(interface)])
  return DNode(self.name, paths)

def addPath(

self, path)

def addPath(self, path: str) -> 'DNode':
  if path in self:
    raise ValueError('path {} on node {} already exists'.format(path, self.name))
  paths = itertools.chain(self.values(), [DPath(path)])
  return DNode(self.name, paths)

def delInterface(

self, path, interface)

def delInterface(self, path: str, interface: DInterface) -> 'DNode':
  if path not in self:
    raise ValueError('path {} on node {} does not exist'.format(path, self.name))
  if interface.name not in self[path]:
    raise ValueError('interface {} at path {} on node {} does not exist'.format(interface.name, path, self.name))
  paths = (v for v in self.values() if v.name != path)
  paths = itertools.chain(paths, [self[path].delInterface(interface)])
  return DNode(self.name, paths)

def delPath(

self, path)

def delPath(self, path: str) -> 'DNode':
  if path not in self:
    raise ValueError('path {} on node {} does not exist'.format(path, self.name))
  if self[path]:
    raise ValueError('path {} on node {} is not empty'.format(path, self.name))
  paths = (v for v in self.values() if v.name != path)
  return DNode(self.name, paths)

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  return {
    'name': self.name,
    'paths': [value.dump() for value in self.values()]
  }

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def hasIntf(

self, path, intf)

def hasIntf(self, path: str, intf: str) -> bool:
  return path in self and intf in self[path]

def hasPath(

self, path)

def hasPath(self, path: str) -> bool:
  return path in self

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class DNodes

A readonly map of DNode instances

class DNodes(supcon.util.NamedList):
  """A readonly map of `supcon.intf.DNode` instances"""
  vtype = DNode

  def hasNode(self, node: str) -> bool:
    return node in self

  def hasPath(self, node: str, path: str) -> bool:
    return node in self and path in self[node]

  def hasIntf(self, node: str, path: str, intf: str) -> bool:
    return node in self and path in self[node] and intf in self[node][path]

  def addNode(self, node: str) -> 'DNodes':
    if node in self:
      raise ValueError('node {} already exists'.format(node))
    nodes = itertools.chain(self.values(), [DNode(node)])
    return DNodes(nodes)

  def delNode(self, node: str) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    if self[node]:
      raise ValueError('node {} is not empty'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    return DNodes(nodes)

  def addPath(self, node: str, path: str) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].addPath(path)])
    return DNodes(nodes)

  def delPath(self, node: str, path: str) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].delPath(path)])
    return DNodes(nodes)

  def addInterface(self, node: str, path: str, interface: DInterface) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].addInterface(path, interface)])
    return DNodes(nodes)

  def delInterface(self, node: str, path: str, interface: DInterface) -> 'DNodes':
    if node not in self:
      raise ValueError('node {} does not exist'.format(node))
    nodes = (v for v in self.values() if v.name != node)
    nodes = itertools.chain(nodes, [self[node].delInterface(path, interface)])
    return DNodes(nodes)

Ancestors (in MRO)

  • DNodes
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var vtype

Class Methods

def load(

cls, data)

Converts the given list of 'simple' datastructures data into an instance of cls, a subclass of supcon.util.NamedList.

@classmethod
def load(cls, data):
  """
  Converts the given list of 'simple' datastructures **data** into an instance
  of **cls**, a subclass of `supcon.util.NamedList`.
  """
  return cls(data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

Methods

def __init__(

self, values=None)

Initializes the supcon.util.NamedList with the given list of values.

An element of values must be of type supcon.util.NamedList.vtype or a 'simple' datastructure that can be converted to an instance of supcon.util.NamedList.vtype by supcon.util.NamedList.vtype.load().

def __init__(self, values=None):
  """
  Initializes the `supcon.util.NamedList` with the given list of **values**.
  An element of **values** must be of type `supcon.util.NamedList.vtype` or a
  'simple' datastructure that can be converted to an instance of
  `supcon.util.NamedList.vtype` by `supcon.util.NamedList.vtype`.load().
  """
  if values is None:
    values = []
  if not issubclass(self.vtype, Named):
    raise ValueError('the value type must be a subclass of Named')
  if not issubclass(self.vtype, Dumpable):
    raise ValueError('the value type must be a subclass of Dumpable')
  self.__values = collections.OrderedDict()
  for value in values:
    if not isinstance(value, self.vtype):
      value = self.vtype.load(value)
    if value.name in self.__values:
      raise ValueError('value.name must be unique in the given list of values')
    self.__values[value.name] = value

def addInterface(

self, node, path, interface)

def addInterface(self, node: str, path: str, interface: DInterface) -> 'DNodes':
  if node not in self:
    raise ValueError('node {} does not exist'.format(node))
  nodes = (v for v in self.values() if v.name != node)
  nodes = itertools.chain(nodes, [self[node].addInterface(path, interface)])
  return DNodes(nodes)

def addNode(

self, node)

def addNode(self, node: str) -> 'DNodes':
  if node in self:
    raise ValueError('node {} already exists'.format(node))
  nodes = itertools.chain(self.values(), [DNode(node)])
  return DNodes(nodes)

def addPath(

self, node, path)

def addPath(self, node: str, path: str) -> 'DNodes':
  if node not in self:
    raise ValueError('node {} does not exist'.format(node))
  nodes = (v for v in self.values() if v.name != node)
  nodes = itertools.chain(nodes, [self[node].addPath(path)])
  return DNodes(nodes)

def delInterface(

self, node, path, interface)

def delInterface(self, node: str, path: str, interface: DInterface) -> 'DNodes':
  if node not in self:
    raise ValueError('node {} does not exist'.format(node))
  nodes = (v for v in self.values() if v.name != node)
  nodes = itertools.chain(nodes, [self[node].delInterface(path, interface)])
  return DNodes(nodes)

def delNode(

self, node)

def delNode(self, node: str) -> 'DNodes':
  if node not in self:
    raise ValueError('node {} does not exist'.format(node))
  if self[node]:
    raise ValueError('node {} is not empty'.format(node))
  nodes = (v for v in self.values() if v.name != node)
  return DNodes(nodes)

def delPath(

self, node, path)

def delPath(self, node: str, path: str) -> 'DNodes':
  if node not in self:
    raise ValueError('node {} does not exist'.format(node))
  nodes = (v for v in self.values() if v.name != node)
  nodes = itertools.chain(nodes, [self[node].delPath(path)])
  return DNodes(nodes)

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  """
  Converts the `supcon.util.NamedList` into a list of 'simple' datastructures.
  """
  return [value.dump() for value in self.values()]

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def hasIntf(

self, node, path, intf)

def hasIntf(self, node: str, path: str, intf: str) -> bool:
  return node in self and path in self[node] and intf in self[node][path]

def hasNode(

self, node)

def hasNode(self, node: str) -> bool:
  return node in self

def hasPath(

self, node, path)

def hasPath(self, node: str, path: str) -> bool:
  return node in self and path in self[node]

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class DPath

A named readonly map of DInterface instances

class DPath(Named, supcon.util.NamedList):
  """A named readonly map of `supcon.intf.DInterface` instances"""

  vtype = DInterface
  regex = re.compile('/(([a-zA-Z0-9_]+/)*[a-zA-Z0-9_]+)?')

  def __init__(self, name, interfaces=None):
    """Initializes the Path instance

    Args:
      name (str): the name of the argument
      interfaces (): ...
    """
    if interfaces is None:
      interfaces = []
    Named.__init__(self, name)
    supcon.util.NamedList.__init__(self, interfaces)

  def dump(self):
    return {
      'name': self.name,
      'interfaces': [value.dump() for value in self.values()]
    }

  @classmethod
  def load(cls, data) -> 'DPath':
    return cls(**data)

  def addInterface(self, interface: DInterface) -> 'DPath':
    if interface.name in self:
      raise ValueError('interface {} at path {} already exists'.format(interface.name, self.name))
    interfaces = itertools.chain(self.values(), [interface])
    return DPath(self.name, interfaces)

  def delInterface(self, interface: DInterface) -> 'DPath':
    if interface.name not in self:
      raise ValueError('interface {} at path {} does not exist'.format(interface.name, self.name))
    interfaces = (v for v in self.values() if v.name != interface.name)
    return DPath(self.name, interfaces)

Ancestors (in MRO)

  • DPath
  • Named
  • supcon.util.Named
  • supcon.util.NamedList
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • supcon.util.Dumpable
  • abc.ABC
  • builtins.object

Class variables

var regex

var vtype

Class Methods

def load(

cls, data)

@classmethod
def load(cls, data) -> 'DPath':
  return cls(**data)

def to(

cls, value)

If the the value is an instance of cls, a subclass of supcon.util.NamedList, the value is returned. If value is not an instance of cls the method tries to convert the value into an instance of cls.

@classmethod
def to(cls, value):
  """
  If the the **value** is an instance of **cls**, a subclass of
  `supcon.util.NamedList`, the value is returned. If value is not an instance
  of **cls** the method tries to convert the **value** into an instance of
  **cls**.
  """
  return value if isinstance(value, cls) else cls.load(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var name

Inheritance: Named.name

str: the name

Methods

def __init__(

self, name, interfaces=None)

Initializes the Path instance

Args: name (str): the name of the argument interfaces (): ...

def __init__(self, name, interfaces=None):
  """Initializes the Path instance
  Args:
    name (str): the name of the argument
    interfaces (): ...
  """
  if interfaces is None:
    interfaces = []
  Named.__init__(self, name)
  supcon.util.NamedList.__init__(self, interfaces)

def addInterface(

self, interface)

def addInterface(self, interface: DInterface) -> 'DPath':
  if interface.name in self:
    raise ValueError('interface {} at path {} already exists'.format(interface.name, self.name))
  interfaces = itertools.chain(self.values(), [interface])
  return DPath(self.name, interfaces)

def delInterface(

self, interface)

def delInterface(self, interface: DInterface) -> 'DPath':
  if interface.name not in self:
    raise ValueError('interface {} at path {} does not exist'.format(interface.name, self.name))
  interfaces = (v for v in self.values() if v.name != interface.name)
  return DPath(self.name, interfaces)

def dump(

self)

Converts the supcon.util.NamedList into a list of 'simple' datastructures.

def dump(self):
  return {
    'name': self.name,
    'interfaces': [value.dump() for value in self.values()]
  }

def get(

self, key, default=None)

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

def get(self, key, default=None):
    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
    try:
        return self[key]
    except KeyError:
        return default

def items(

self)

D.items() -> a set-like object providing a view on D's items

def items(self):
    "D.items() -> a set-like object providing a view on D's items"
    return ItemsView(self)

def keys(

self)

D.keys() -> a set-like object providing a view on D's keys

def keys(self):
    "D.keys() -> a set-like object providing a view on D's keys"
    return KeysView(self)

def values(

self)

D.values() -> an object providing a view on D's values

def values(self):
    "D.values() -> an object providing a view on D's values"
    return ValuesView(self)

class Implementation

The base class for interface implementations

class Implementation(object):
  """The base class for interface implementations"""

  def __init__(self, interface: DInterface):
    """
    Args:
      interface (DInterface): the interface that is implemented by this Implementation
    """
    if not isinstance(interface, DInterface):
      raise ValueError('interface must be an instance of {}'.format(DInterface))
    self.__interface = interface

    self.__callCbs = {}
    self.__fireCbs = []

  @property
  def intf(self) -> str:
    """str: The name of the implemented interface"""
    return self.__interface.name

  @property
  def interface(self) -> DInterface:
    """Interface: The implemented interface"""
    return self.__interface

  def setCallCb(self, method: str, cb):
    """Sets a callback for the given method. The method must be a method of the
    interface this Implementation implements. The callback must implement the
    given method. The callback gets called by calls to Implementation.call()

    Args:
      method (str): the interface method that the callback implements
      cb (callable): the callback
    """
    method = DMethod.toName(method)
    if method in self.__callCbs:
      raise ValueError('Callback for method {} is already set!'.format(method))
    if method not in self.__interface.methods:
      raise ValueError('Interface has no method {}!'.format(method))
    self.__callCbs[method] = cb

  def call(self, method: str, inArgs) -> defer.Deferred:
    """Calls the given interface method with the given arguments. This method
    calls the callback set by Implementation.setCallCb()

    Args:
      method (str): the called interface method
      inArgs (Mapping): a map of input arguments
    Returns:
      defer.Deferred: Resolves with the result of the called method
    """
    def validateReturn(outArgs):
      self.__interface.validateReturn(method, outArgs)
      return outArgs

    try:
      self.__interface.validateCall(method, inArgs)
      if method not in self.__callCbs:
        raise ValueError('Callback for method {} is not set!'.format(method))

      d = self.__callCbs[method](**inArgs)
      if not isinstance(d, defer.Deferred):
        d = defer.succeed(d)
      d.addCallback(validateReturn)
    except BaseException as e:
      traceback.print_exc()
      d = defer.fail(e)

    return d

  def addFireCb(self, cb):
    """Adds a callback that gets called, when this Implementation fires an
    event.

    Args:
      cb (callable): the callback
    """
    self.__fireCbs.append(cb)

  def delFireCb(self, cb):
    """Removes a callback that gets called, when this Implementation fires an
    event.

    Args:
      cb (callable): the callback
    """
    self.__fireCbs.remove(cb)

  def fire(self, event: str, args):
    """Fires the given event with the given arguments.

    Args:
      event (str): the event name
      args (collecion.Mapping): the event arguments
    """
    self.__interface.validateEvent(event, args)

    for cb in self.__fireCbs:
      cb(event, args)

Ancestors (in MRO)

Instance variables

var interface

Interface: The implemented interface

var intf

str: The name of the implemented interface

Methods

def __init__(

self, interface)

Args: interface (DInterface): the interface that is implemented by this Implementation

def __init__(self, interface: DInterface):
  """
  Args:
    interface (DInterface): the interface that is implemented by this Implementation
  """
  if not isinstance(interface, DInterface):
    raise ValueError('interface must be an instance of {}'.format(DInterface))
  self.__interface = interface
  self.__callCbs = {}
  self.__fireCbs = []

def addFireCb(

self, cb)

Adds a callback that gets called, when this Implementation fires an event.

Args: cb (callable): the callback

def addFireCb(self, cb):
  """Adds a callback that gets called, when this Implementation fires an
  event.
  Args:
    cb (callable): the callback
  """
  self.__fireCbs.append(cb)

def call(

self, method, inArgs)

Calls the given interface method with the given arguments. This method calls the callback set by Implementation.setCallCb()

Args: method (str): the called interface method inArgs (Mapping): a map of input arguments Returns: defer.Deferred: Resolves with the result of the called method

def call(self, method: str, inArgs) -> defer.Deferred:
  """Calls the given interface method with the given arguments. This method
  calls the callback set by Implementation.setCallCb()
  Args:
    method (str): the called interface method
    inArgs (Mapping): a map of input arguments
  Returns:
    defer.Deferred: Resolves with the result of the called method
  """
  def validateReturn(outArgs):
    self.__interface.validateReturn(method, outArgs)
    return outArgs
  try:
    self.__interface.validateCall(method, inArgs)
    if method not in self.__callCbs:
      raise ValueError('Callback for method {} is not set!'.format(method))
    d = self.__callCbs[method](**inArgs)
    if not isinstance(d, defer.Deferred):
      d = defer.succeed(d)
    d.addCallback(validateReturn)
  except BaseException as e:
    traceback.print_exc()
    d = defer.fail(e)
  return d

def delFireCb(

self, cb)

Removes a callback that gets called, when this Implementation fires an event.

Args: cb (callable): the callback

def delFireCb(self, cb):
  """Removes a callback that gets called, when this Implementation fires an
  event.
  Args:
    cb (callable): the callback
  """
  self.__fireCbs.remove(cb)

def fire(

self, event, args)

Fires the given event with the given arguments.

Args: event (str): the event name args (collecion.Mapping): the event arguments

def fire(self, event: str, args):
  """Fires the given event with the given arguments.
  Args:
    event (str): the event name
    args (collecion.Mapping): the event arguments
  """
  self.__interface.validateEvent(event, args)
  for cb in self.__fireCbs:
    cb(event, args)

def setCallCb(

self, method, cb)

Sets a callback for the given method. The method must be a method of the interface this Implementation implements. The callback must implement the given method. The callback gets called by calls to Implementation.call()

Args: method (str): the interface method that the callback implements cb (callable): the callback

def setCallCb(self, method: str, cb):
  """Sets a callback for the given method. The method must be a method of the
  interface this Implementation implements. The callback must implement the
  given method. The callback gets called by calls to Implementation.call()
  Args:
    method (str): the interface method that the callback implements
    cb (callable): the callback
  """
  method = DMethod.toName(method)
  if method in self.__callCbs:
    raise ValueError('Callback for method {} is already set!'.format(method))
  if method not in self.__interface.methods:
    raise ValueError('Interface has no method {}!'.format(method))
  self.__callCbs[method] = cb

class Named

A base class for objects with a name.

class Named(supcon.util.Named):
  """A base class for objects with a name.
  """

  regex = None
  """re.RegexObject: a regular expression, the name must conform to"""

  def __init__(self, name):
    """Initializes the NamedAndDescribed instance

    Args:
      name (str): the name of the argument
    """
    self.__name = self.toName(name)

  @property
  def name(self) -> str:
    """str: the name"""
    return self.__name

  @classmethod
  def toName(cls, value) -> str:
    """Converts the value into a name. If this is impossible a ValueError is
    raised.

    Args:
      value (any): the value
    Raises:
      ValueError
    """
    value = str(value)
    if not cls.regex.fullmatch(value):
      raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
    return value

Ancestors (in MRO)

  • Named
  • supcon.util.Named
  • abc.ABC
  • builtins.object

Class variables

var regex

re.RegexObject: a regular expression, the name must conform to

Class Methods

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var name

str: the name

Methods

def __init__(

self, name)

Initializes the NamedAndDescribed instance

Args: name (str): the name of the argument

def __init__(self, name):
  """Initializes the NamedAndDescribed instance
  Args:
    name (str): the name of the argument
  """
  self.__name = self.toName(name)

class NamedAndDescribed

A base class for the interface describing classes supcon.intf.Argument, supcon.intf.Event, supcon.intf.Method and supcon.intf.Interface that all have the properties name and description.

class NamedAndDescribed(Named):
  """A base class for the interface describing classes `supcon.intf.Argument`,
  `supcon.intf.Event`, `supcon.intf.Method` and `supcon.intf.Interface` that
  all have the properties name and description."""

  def __init__(self, name, description=''):
    """Initializes the NamedAndDescribed instance

    Args:
      name (str): the name of the argument
      description (str): a description of the argument
    """
    Named.__init__(self, name)
    self.__description = self.toDescription(description)

  @property
  def description(self) -> str:
    """str: a description"""
    return self.__description

  @classmethod
  def toDescription(cls, value) -> str:
    """Converts the value into a description. If this is impossible a ValueError
    is raised.

    Args:
      value (any): the value
    Raises:
      ValueError
    """
    return str(value)

Ancestors (in MRO)

Class variables

var regex

Class Methods

def toDescription(

cls, value)

Converts the value into a description. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toDescription(cls, value) -> str:
  """Converts the value into a description. If this is impossible a ValueError
  is raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  return str(value)

def toName(

cls, value)

Converts the value into a name. If this is impossible a ValueError is raised.

Args: value (any): the value Raises: ValueError

@classmethod
def toName(cls, value) -> str:
  """Converts the value into a name. If this is impossible a ValueError is
  raised.
  Args:
    value (any): the value
  Raises:
    ValueError
  """
  value = str(value)
  if not cls.regex.fullmatch(value):
    raise ValueError("value {} must match {} fully".format(value, cls.regex.pattern))
  return value

Instance variables

var description

str: a description

var name

str: the name

Methods

def __init__(

self, name, description='')

Initializes the NamedAndDescribed instance

Args: name (str): the name of the argument description (str): a description of the argument

def __init__(self, name, description=''):
  """Initializes the NamedAndDescribed instance
  Args:
    name (str): the name of the argument
    description (str): a description of the argument
  """
  Named.__init__(self, name)
  self.__description = self.toDescription(description)

class Node

The Node Interface. This class defines the methods that participants can use to access the supcon bus.

class Node(abc.ABC):
  """The Node Interface. This class defines the methods that participants can
  use to access the supcon bus."""

  def __init__(self, name):
    super().__init__()
    self.__name = self.toName(name)

  @property
  def name(self) -> str:
    """str: The name of the node on the bus"""
    return self.__name

  @classmethod
  def toName(cls, value) -> str:
    return DNode.toName(value)

  @abc.abstractmethod
  def nodes(self) -> DNodes:
    """list[str]: The currently connected nodes"""
    raise NotImplementedError()

  @abc.abstractmethod
  def connect(self, endpoint):
    """Connects the node to the given endpoint.

    If the connection failes or closes the connection gets reestablished with an
    exponential timeout up to two minutes.

    Args:
      endpoint (twisted.internet.interfaces.IStreamClientEndpoint):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def listen(self, endpoint):
    """Listens at the given endpoint for incoming connections

    Args:
      endpoint (twisted.internet.interfaces.IStreamServerEndpoint):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def register(self, path: str, impl: Implementation):
    """Registers an implementation with the node

    Args:
      impl (Implementation):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def unregister(self, path: str, impl: Implementation):
    """Removes an implementation from the node

    Args:
      impl (supcon.intf.Implementation):
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def call(self, node: str, path: str, intf: str, method: str, args: dict) -> defer.Deferred:
    """Calls a method on the bus

    Args:
      node (str): a node on the bus
      path (str): a path on the given node
      intf (str): an interface at the given path
      method (str): a method of the given interface
      args (dict): a dict of method arguments

    Returns:
      defer.Deferred:
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def on(self, node: str, path: str, intf: str, event: str, cb):
    """Registers a callback for an event on the bus

    Args:
      node (str): a node on the bus
      path (str): a path on the given node
      intf (str): an interface at the given path
      event (str): a method of the given interface
      cb (callable): a callable that gets called with a dict of event arguments
    """
    raise NotImplementedError()

  @abc.abstractmethod
  def off(self, node: str, path: str, intf: str, event: str, cb):
    """Unregisters a callback for an event on the bus

    Args:
      node (str): a node on the bus
      path (str): a path on the given node
      intf (str): an interface at the given path
      event (str): a method of the given interface
      cb (callable): a callable that gets called with a dict of event arguments
    """
    raise NotImplementedError()

Ancestors (in MRO)

  • Node
  • abc.ABC
  • builtins.object

Class Methods

def toName(

cls, value)

@classmethod
def toName(cls, value) -> str:
  return DNode.toName(value)

Instance variables

var name

str: The name of the node on the bus

Methods

def __init__(

self, name)

Initialize self. See help(type(self)) for accurate signature.

def __init__(self, name):
  super().__init__()
  self.__name = self.toName(name)

def call(

self, node, path, intf, method, args)

Calls a method on the bus

Args: node (str): a node on the bus path (str): a path on the given node intf (str): an interface at the given path method (str): a method of the given interface args (dict): a dict of method arguments

Returns: defer.Deferred:

@abc.abstractmethod
def call(self, node: str, path: str, intf: str, method: str, args: dict) -> defer.Deferred:
  """Calls a method on the bus
  Args:
    node (str): a node on the bus
    path (str): a path on the given node
    intf (str): an interface at the given path
    method (str): a method of the given interface
    args (dict): a dict of method arguments
  Returns:
    defer.Deferred:
  """
  raise NotImplementedError()

def connect(

self, endpoint)

Connects the node to the given endpoint.

If the connection failes or closes the connection gets reestablished with an exponential timeout up to two minutes.

Args: endpoint (twisted.internet.interfaces.IStreamClientEndpoint):

@abc.abstractmethod
def connect(self, endpoint):
  """Connects the node to the given endpoint.
  If the connection failes or closes the connection gets reestablished with an
  exponential timeout up to two minutes.
  Args:
    endpoint (twisted.internet.interfaces.IStreamClientEndpoint):
  """
  raise NotImplementedError()

def listen(

self, endpoint)

Listens at the given endpoint for incoming connections

Args: endpoint (twisted.internet.interfaces.IStreamServerEndpoint):

@abc.abstractmethod
def listen(self, endpoint):
  """Listens at the given endpoint for incoming connections
  Args:
    endpoint (twisted.internet.interfaces.IStreamServerEndpoint):
  """
  raise NotImplementedError()

def nodes(

self)

list[str]: The currently connected nodes

@abc.abstractmethod
def nodes(self) -> DNodes:
  """list[str]: The currently connected nodes"""
  raise NotImplementedError()

def off(

self, node, path, intf, event, cb)

Unregisters a callback for an event on the bus

Args: node (str): a node on the bus path (str): a path on the given node intf (str): an interface at the given path event (str): a method of the given interface cb (callable): a callable that gets called with a dict of event arguments

@abc.abstractmethod
def off(self, node: str, path: str, intf: str, event: str, cb):
  """Unregisters a callback for an event on the bus
  Args:
    node (str): a node on the bus
    path (str): a path on the given node
    intf (str): an interface at the given path
    event (str): a method of the given interface
    cb (callable): a callable that gets called with a dict of event arguments
  """
  raise NotImplementedError()

def on(

self, node, path, intf, event, cb)

Registers a callback for an event on the bus

Args: node (str): a node on the bus path (str): a path on the given node intf (str): an interface at the given path event (str): a method of the given interface cb (callable): a callable that gets called with a dict of event arguments

@abc.abstractmethod
def on(self, node: str, path: str, intf: str, event: str, cb):
  """Registers a callback for an event on the bus
  Args:
    node (str): a node on the bus
    path (str): a path on the given node
    intf (str): an interface at the given path
    event (str): a method of the given interface
    cb (callable): a callable that gets called with a dict of event arguments
  """
  raise NotImplementedError()

def register(

self, path, impl)

Registers an implementation with the node

Args: impl (Implementation):

@abc.abstractmethod
def register(self, path: str, impl: Implementation):
  """Registers an implementation with the node
  Args:
    impl (Implementation):
  """
  raise NotImplementedError()

def unregister(

self, path, impl)

Removes an implementation from the node

Args: impl (supcon.intf.Implementation):

@abc.abstractmethod
def unregister(self, path: str, impl: Implementation):
  """Removes an implementation from the node
  Args:
    impl (supcon.intf.Implementation):
  """
  raise NotImplementedError()

class Object

class Object(object):

  def __init__(self, interfaces=None):
    """
    Args:
      interfaces (DInterfaces): the interfaces that are implemented by this Object
    """
    if interfaces is None:
      interfaces = []

    self.__intfs = {}
    self.__impls = {}

    def getCallCb(intf):
      return lambda method, inArgs: self.__call(intf, method, inArgs)

    for interface in interfaces:
      if not isinstance(interface, DInterface):
        raise ValueError('interface must be an instance of {}'.format(DInterface))
      self.__intfs[interface.name] = interface

      implementation = Implementation(interface)
      callCb = getCallCb(implementation.intf)
      for method in interface.methods:
        implementation.setCallCb(method, callCb)
      self.__impls[implementation.intf] = implementation

  @property
  def interfaces(self):
    return self.__intfs.values()

  @property
  def implementations(self):
    return self.__impls.values()

  def interface(self, intf):
    return self.__intfs[intf]

  def implementation(self, intf):
    return self.__impls[intf]

  def __call(self, intf: str, method: str, inArgs) -> defer.Deferred:
    pass

Ancestors (in MRO)

Instance variables

var implementations

var interfaces

Methods

def __init__(

self, interfaces=None)

Args: interfaces (DInterfaces): the interfaces that are implemented by this Object

def __init__(self, interfaces=None):
  """
  Args:
    interfaces (DInterfaces): the interfaces that are implemented by this Object
  """
  if interfaces is None:
    interfaces = []
  self.__intfs = {}
  self.__impls = {}
  def getCallCb(intf):
    return lambda method, inArgs: self.__call(intf, method, inArgs)
  for interface in interfaces:
    if not isinstance(interface, DInterface):
      raise ValueError('interface must be an instance of {}'.format(DInterface))
    self.__intfs[interface.name] = interface
    implementation = Implementation(interface)
    callCb = getCallCb(implementation.intf)
    for method in interface.methods:
      implementation.setCallCb(method, callCb)
    self.__impls[implementation.intf] = implementation

def implementation(

self, intf)

def implementation(self, intf):
  return self.__impls[intf]

def interface(

self, intf)

def interface(self, intf):
  return self.__intfs[intf]