Source code for pynio.service

from copy import deepcopy
from .block import Block


[docs]class Service(object): """n.io Service Args: name (str): Name of new service. type (str, optional): ServiceType of new service. config (dict, optional): Optional configuration of service. instance (Instance, optional): Optional instance to add the service to. Attributes: name (str): Name of service. type (str): ServiceType of service. config (dict): Configuration of service. status (str): Status of service. """ def __init__(self, name, type='Service', config=None, instance=None): if not name: raise ValueError("name cannot be blank") self._name = name self._type = type self.config = deepcopy(config) or {} self._instance = instance
[docs] def save(self): """PUTs the service config to nio. Will create a new service if one does not exist by this name. Otherwise it will update the existing service config. Raises: Exception: If service is not associated with an instance. """ if not self._instance: raise Exception('Service is not associated with an instance') config = self.config config['name'] = self._name config['type'] = self._type self._put('services/{}'.format(self._name), config) self._instance.services[self._name] = self
def _put(self, endpoint, config): self._instance._put(endpoint, config)
[docs] def connect(self, blk1, blk2=None): """Connect two blocks. Args: blk1 (Block): Sends signals to `blk2`. If `blk2` is not specified then `blk1` is added to the service with no receivers. blk2 (Block, optional): Receives signal form `blk1`. """ # initialize execution to an empty list if it doesn't already exist execution = self.config.get('execution', []) self.config['execution'] = execution # check if source block is already in config connection = None for blk in execution: if blk['name'] == blk1.name: connection = blk break if blk2 is not None: for blk in execution: if blk['name'] == blk2.name: break else: # block2 doesn't exist, so add it execution.append({'name': blk2.name, 'receivers': []}) # if block exists, add the receiever, otherwise init connection receivers = [] if blk2 is None else [blk2.name] if connection: cr = connection['receivers'] cr.extend(receivers) # remove duplicates but preserve order seen = set() seen_add = seen.add cr[:] = [x for x in cr if not(x in seen or seen_add(x))] else: connection = {'name': blk1.name, 'receivers': receivers} execution.append(connection)
[docs] def remove_block(self, block): """Remove a block from service. Does NOT delete the block. Args: block (Block): Block to remove from service. """ execution = self.config.get('execution', None) if execution is None: # no blocks return block = block._name def clean(connection): '''removes block from connection if it is in the list. returns False if whole connection should be removed''' if connection['name'] == block: return False try: connection['receivers'].remove(block) except ValueError: pass return True execution[:] = [c for c in execution if clean(c)]
[docs] def start(self): """Starts the nio Service.""" self.command('start')
[docs] def stop(self): """Stops the nio Service.""" self.command('stop')
[docs] def command(self, command, block=None, **request_kwargs): """Send a command to the service or to a block in the service. Args: command (str): The name of the command. block (str, optional): The name of the block if commanding a block. request_kwargs: Keyword arguments are passed to http request. Examples: data, timeout (set the request timeout). """ get = self._instance._get if block is None: return get('services/{}/{}'.format(self._name, command), **request_kwargs) else: return get('services/{}/{}/{}'.format(self._name, block._name, command), **request_kwargs)
[docs] def create_block(self, name, type, config=None): """Create a new block and add it to the service. Args: name (str): Name of new block. type (str, optional): BlockType of new block. config (dict, optional): Optional configuration of block. """ blk = Block(name, type, config=config, instance=self._instance) self.connect(blk) if self._instance: self.save() blk.save() return blk
@property
[docs] def blocks(self): """Return a list of blocks used by this service.""" if not self._instance: raise TypeError("Can only get block objects when attached to an " "instance") blocks = self._instance.blocks return [blocks[i['name']] for i in self.config.get('execution', [])]
def _status(self): """Returns the status of the Service.""" return self._instance._get( 'services/{}/status'.format(self._name)) @property def name(self): return self._name @name.setter
[docs] def name(self, value): print('You cannot change this attribute.') pass
@property
[docs] def type(self): return self._type
@property
[docs] def status(self): return self._status()['status']
[docs] def delete(self): """Delete the service from the instance""" self._instance._delete( 'services/{}'.format(self._name)) self._instance.services.pop(self._name) self._instance = None # make sure it isn't used anymore
@property def pid(self): return self._status()['pid'] def __str__(self): # get connections, ones with most connections first execution = sorted(self.config.get('execution', []), key=lambda i: len(i['receivers']), reverse=True) name_fmat = '{} --> {}'.format outstr = [] outstr = [name_fmat(i['name'], ', '.join(i['receivers'])) for i in execution] return ('Service({}).connections:{{\n '.format(self.name) + '\n '.join(outstr) + '\n}\n')