Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ini_client.py 5.22 KiB
from src.comms_client import CommClient
import configparser
import numpy


numpy_to_ini_dict = {
    numpy.int64: int,
    numpy.double: float,
    numpy.bool_: bool,
    str: str
}
ini_to_numpy_dict = {
    int: numpy.int64,
    float: numpy.double,
    bool: numpy.bool_,
    str: str
}

import os


class ini_client(CommClient):
    """
    this class provides an example implementation of a comms_client.
    Durirng initialisation it creates a correctly shaped zero filled value. on read that value is returned and on write its modified.
    """

    def start(self):
        super().start()

    def __init__(self, filename, fault_func, streams, try_interval=2):
        """
        initialises the class and tries to connect to the client.
        """
        self.config = configparser.ConfigParser()
        self.filename = filename

        if not filename.endswith(".ini"):
            filename = filename + ".ini"


        super().__init__(fault_func, streams, try_interval)

        # Explicitly connect
        if not self.connect():
            # hardware or infra is down -- needs fixing first
            fault_func()
            return

    def connect(self):
        files_path = [os.path.abspath(x) for x in os.listdir()]
        self.streams.debug_stream(" %s", files_path)
        self.config_file = open(self.filename, "rw")

        self.connected = True  # set connected to true
        return True  # if succesfull, return true. otherwise return false

    def disconnect(self):
        self.connected = False  # always force a reconnect, regardless of a successful disconnect
        self.streams.debug_stream("disconnected from the 'client' ")

    def _setup_annotation(self, annotation):
        """
        this function gives the client access to the comm client annotation data given to the attribute wrapper.
        The annotation data can be used to provide whatever extra data is necessary in order to find/access the monitor/control point.

        the annotation can be in whatever format may be required. it is up to the user to handle its content
        example annotation may include:
        - a file path and file line/location
        - COM object path
        """

        # as this is an example, just print the annotation
        self.streams.debug_stream("annotation: {}".format(annotation))
        name = annotation.get('name')
        if name is None:
            AssertionError("ini client requires a variable name to set/get")
        section = annotation.get('section')
        if section is None:
            AssertionError("requires a section to open")

        return section, name


    def _setup_value_conversion(self, attribute):
        """
        gives the client access to the attribute_wrapper object in order to access all
        necessary data such as dimensionality and data type
        """

        if attribute.dim_y > 1:
            dims = (attribute.dim_y, attribute.dim_x)
        else:
            dims = (attribute.dim_x,)

        dtype = attribute.numpy_type

        return dims, dtype

    def _setup_mapping(self, name, section, dtype):
        """
        takes all gathered data to configure and return the correct read and write functions
        """

        def read_function():
            value = self.config.get(section, name)
            value = ini_to_numpy_dict[dtype](value)
            return value

        def write_function(write_value):
            self.config.set(section, name, write_value)
            fp = open(self.filename, 'w')
            self.config.write(fp)

        return read_function, write_function

    def setup_attribute(self, annotation=None, attribute=None):
        """
        MANDATORY function: is used by the attribute wrapper to get read/write functions.
        must return the read and write functions
        """

        # process the comms_annotation
        section, name = self._setup_annotation(annotation)

        # get all the necessary data to set up the read/write functions from the attribute_wrapper
        dims, dtype = self._setup_value_conversion(attribute)

        # configure and return the read/write functions
        read_function, write_function = self._setup_mapping(name, section, dtype)

        # return the read/write functions
        return read_function, write_function


def write_config():
    config = configparser.ConfigParser()
    config['scalar'] = {}
    config['scalar']['double_scalar'] = '1.2'
    config['scalar']['double_scalar'] = '3.4'
    config['scalar']['bool_scalar'] = 'True'
    config['scalar']['bool_scalar'] = 'False'
    config['scalar']['int_scalar'] = '5'
    config['scalar']['int_scalar'] = '6'
    config['scalar']['str_scalar'] = 'this is'
    config['scalar']['str_scalar'] = 'a test'

    config['spectrum'] = {}
    config['spectrum']['double_scalar'] = '[1.2, 2.3, 3.4]'
    config['spectrum']['double_scalar'] = '[5.6, 6.7, 7.8]'
    config['spectrum']['bool_scalar'] = '[True, True, False]'
    config['spectrum']['bool_scalar'] = '[False, False, True]'
    config['spectrum']['int_scalar'] = '[5'
    config['spectrum']['int_scalar'] = '[6,7,8,9]'
    config['spectrum']['str_scalar'] = '["a", "b", "c"]'
    config['spectrum']['str_scalar'] = '["D", "E", "F"]'



    with open('example.ini', 'w') as configfile:
        config.write(configfile)