Source code for msl.equipment.config

"""
Load an XML :ref:`configuration-file`.
"""
import os
from xml.etree import cElementTree

from .utils import (
    logger,
    convert_to_primitive,
)


[docs]class Config(object): PyVISA_LIBRARY = '@ivi' """:class:`str`: The PyVISA backend :ref:`library <intro-configuring>` to use.""" DEMO_MODE = False """:class:`bool`: Whether to open connections in demo mode. If enabled then the equipment does not need to be physically connected to a computer and the connection is simulated. """ PATH = [] """:class:`list` of :class:`str`: Paths are also appended to :data:`os.environ['PATH'] <os.environ>`.""" def __init__(self, path): """Load an XML :ref:`configuration-file`. This function is used to set the configuration constants to use for the Python runtime and it allows you to access :class:`.EquipmentRecord`'s from an :ref:`equipment-database` and :class:`.ConnectionRecord`'s from a :ref:`connections-database`. The following table summarizes the XML elements that are used by **MSL-Equipment** and can be defined in a :ref:`configuration-file`: +----------------+----------------------------------------+-----------------------------------------------+ | XML Tag | Example Values | Description | +================+========================================+===============================================+ | pyvisa_library | @ivi, @py, @sim, /path/to/libvisa.so.7 | The PyVISA :ref:`library <intro-configuring>` | | | | to use. | +----------------+----------------------------------------+-----------------------------------------------+ | demo_mode | true, false, True, False | Whether to open connections in demo | | | | mode. | +----------------+----------------------------------------+-----------------------------------------------+ | path | /path/to/SDKs, D:/images | A path that contains external resources. | | | | Accepts a *recursive="true"* attribute. | | | | The path(s) are appended to | | | | :data:`os.environ['PATH'] <os.environ>` | | | | and to :attr:`.PATH` | +----------------+----------------------------------------+-----------------------------------------------+ The user is also encouraged to define their own application-specific elements within the :ref:`configuration-file`. Parameters ---------- path : :class:`str` The path to an XML :ref:`configuration-file`. Raises ------ OSError If `path` does not exist or if the :ref:`configuration-file` is invalid. """ logger.debug('Loading %s', path) try: self._root = cElementTree.parse(path).getroot() parse_err = '' except cElementTree.ParseError as err: parse_err = str(err) if parse_err: raise OSError(parse_err) self._path = path self._database = None element = self._root.find('pyvisa_library') if element is not None: Config.PyVISA_LIBRARY = element.text logger.debug('update Config.PyVISA_LIBRARY = %s', Config.PyVISA_LIBRARY) element = self._root.find('demo_mode') if element is not None: Config.DEMO_MODE = element.text.lower() == 'true' logger.debug('update Config.DEMO_MODE = %s', Config.DEMO_MODE) for element in self._root.findall('path'): if not os.path.isdir(element.text): logger.warning('Not a valid PATH %s', element.text) continue if element.attrib.get('recursive', 'false').lower() == 'true': for root, dirs, files in os.walk(element.text): Config.PATH.append(root) else: Config.PATH.append(element.text) for p in Config.PATH: os.environ['PATH'] += os.pathsep + p logger.debug('append Config.PATH %s', p) @property def path(self): """:class:`str`: The path to the configuration file.""" return self._path @property def root(self): """Returns the root element (the first node) of the XML tree. Returns ------- :class:`~xml.etree.ElementTree.Element` The root element. """ return self._root
[docs] def database(self): """ Returns ------- :class:`~.database.Database` A reference to the equipment and connection records in the database(s) that are specified in the configuration file. """ if self._database is None: from .database import Database # import here to avoid circular import errors self._database = Database(self._path) return self._database
[docs] def value(self, tag, default=None): """Gets the value associated with the specified `tag` in the configuration file. The first element with name `tag` (relative to the :obj:`root`) is used. The value is converted to the appropriate data type if possible. Otherwise, the value will be returned as a :class:`str`. Parameters ---------- tag : :class:`str` The name of an XML tag in the configuration file. default The default value if `tag` cannot be found. Returns ------- The value associated with `tag` or `default` if the tag cannot be found. """ element = self._root.find(tag) if element is not None: return convert_to_primitive(element.text) return default
[docs] def find(self, tag): """Find the first sub-element (from the :obj:`root`) matching `tag` in the configuration file. Parameters ---------- tag : :class:`str` The name of an XML tag in the configuration file. Returns ------- :class:`~xml.etree.ElementTree.Element` or :data:`None` The first sub-element or :data:`None` if the tag cannot be found. """ return self._root.find(tag)
[docs] def findall(self, tag): """Find all matching sub-elements (from the :obj:`root`) matching `tag` in the configuration file. Parameters ---------- tag : :class:`str` The name of an XML tag in the configuration file. Returns ------- :class:`list` of :class:`~xml.etree.ElementTree.Element` All matching elements in document order. """ return self._root.findall(tag)
[docs] def attrib(self, tag): """Get the attributes of an :class:`~xml.etree.ElementTree.Element` in the configuration file. The first element with name `tag` (relative to the :obj:`root`) is used. The values are converted to the appropriate data type if possible. Otherwise, the value will be kept as a :class:`str`. Parameters ---------- tag : :class:`str` The name of an XML element in the configuration file. Returns ------- :class:`dict` The attributes of the :class:`~xml.etree.ElementTree.Element`. If an element with the name `tag` does not exist, then an empty :class:`dict` is returned. """ element = self._root.find(tag) if element is None: return {} return dict((k, convert_to_primitive(v)) for k, v in element.attrib.items())