Source code for pyrolab.drivers.sample

# Copyright © PyroLab Project Contributors
# Licensed under the terms of the GNU GPLv3+ License
# (see pyrolab/__init__.py for details)

"""
Sample Services
===============

This module implements some simple, sample services for testing whether a server
is working properly.
"""

import logging
import time
from typing import Any, List, Union

from pyrolab.api import behavior, expose
from pyrolab.drivers import Instrument
from pyrolab.service import Service

log = logging.getLogger(__name__)
log.debug("Sample module loaded")


Number = Union[int, float]


[docs] @expose class SampleService(Service): """ A sample service with a few stubbed functions. """ def __init__(self) -> None: log.info("SampleService created") self._attribute = False @property def attribute(self) -> None: """ Some hidden property. Can be set to any value. """ return self._attribute @attribute.setter def attribute(self, value) -> Any: self._attribute = value
[docs] def close(self) -> None: """ Close the sample service. """ log.info("SampleService closed") pass
[docs] def echo(self, message: str) -> str: """ Echoes back as the response the exact message as received with "SERVER RECEIVED: " prepended to the message. Parameters ---------- message : str The message to be echoed by the server. Returns ------- resp : str The message to be echoed, prepended with "SERVER RECEIVED: ". """ return "SERVER RECEIVED: " + message
[docs] def delayed_echo(self, message: str, seconds: int) -> str: """ Echoes back as the response the exact message as received with "SERVER RECEIVED: " prepended to the message after delaying by the specified number of seconds. This function demonstrates that the connection does not die out even for long running requests. Parameters ---------- message : str The message to be echoed by the server. seconds : int The number of seconds the server should wait before responding. Returns ------- resp : str The message to be echoed, prepended with "SERVER RECEIVED: ". """ time.sleep(seconds) return "SERVER RECEIVED: " + message
[docs] def whoami(self): """ Returns the object id of the instance that handled the request. Returns ------- resp : str The object id of the handling instance. """ return "OBJECT ID: " + str(id(self))
[docs] def add(self, *a: Number) -> Number: """ Adds an unconstrained number of arguments together. Parameters ---------- a : Number Any number of arguments to be added together. Returns ------- resp : Number The result of the addition. """ return sum(a)
[docs] def subtract(self, a: Number, b: Number) -> Number: """ Subtracts the second parameter from the first. Parameters ---------- a : Number The number to be subtracted from. b : Number The number to be subtracted. Returns ------- resp : Number The result of the subtraction. """ return a - b
[docs] def multiply(self, *vals: Number) -> Number: """ Multiplies an unconstrained number of arguments together. Parameters ---------- vals : Number Any number of arguments to be multiplied together. Returns ------- resp : Number The result of the multiplication. """ final = 1 for val in vals: final = final * val return final
[docs] def divide(self, num: Number, den: Number) -> Number: """ Divides the first argument by the second. Parameters ---------- num : Number The numerator. den : Number The denominator. Returns ------- resp : Number The result of the division. """ return num / den
[docs] class SelectiveSampleService(Service): """ Not all functions of this service are exposed over Pyro5. Maintains a list of items. Can be accessed via indexing, etc. Parameters ---------- items : List[Any] A catalog of items. """ def __init__(self, items: List[Any] = []) -> None: self._items = items self.some_attribute = True @property @expose def items(self) -> List[Any]: return self._items @items.setter @expose def items(self, items: List[Any]) -> None: self._items = items @property @expose def attribute(self) -> Any: return self.some_attribute @attribute.setter @expose def attribute(self, value: Any) -> None: self.some_attribute = value
[docs] @expose def sort(self, reverse: bool = False): self.items = sorted(self.items, reverse=reverse)
[docs] @expose def item(self, index: int) -> Any: return self.items[index]
[docs] @expose def set_item(self, index: int, value: Any) -> None: self.items[index] = value
[docs] def objectid(self) -> int: return id(self)
[docs] @behavior(instance_mode="single") @expose class SampleAutoconnectInstrument(Instrument): """ A service that mocks a hardware instrument with connection parameters. This service will only be accessible if your configuration file lists the autoconnect parameters correctly. """ def __init__(self) -> None: self.connected = False
[docs] def close(self): """ Close the hosting computer's connection with the hardware instrument. """ self.connected = False
[docs] def connect(self, address="localhost", port=9090) -> bool: """ Connect to the hardware instrument. Default parameters are invalid. Parameters ---------- address : str The address of the hardware instrument. Must be "0.0.0.0" for successful connection. port : int The port of the hardware instrument. Must be any integer besides 9090 for successful connection. Returns ------- connected : bool Whether or not the connection was successful. """ if address != "0.0.0.0": raise Exception("This test method requires address to be '0.0.0.0'.") if port == 9090: raise Exception( "This test method requires the port to not be the default of 9090." ) self.connected = True return True
[docs] def do_something(self): """ A method that does nothing and passes silently. Raises ------ Exception If no successful connection has been made. """ if not self.connected: raise Exception("This object cannot do work until connection is made.") return True
[docs] def whoami(self): """ Returns the object id of the instance that handled the request. Returns ------- resp : str The object id of the handling instance. """ return "OBJECT ID: " + str(id(self))