Example #1
0
    for key, value in params.iteritems():
    # Check valid string
        if key in valid_str_keys:
            comp_vtor.check("string(min=0, max=255)", value)

        # Check valid integers
        if key in valid_int_keys:
            comp_vtor.check("integer(min=0)", value)

comp_vtor.functions['check_component'] = component_check
comp_vtor.functions['check_user'] = user_check
comp_vtor.functions['check_sequence'] = sequence_check
comp_vtor.functions['check_reagent'] = reagent_check

### For Testing as a Script ###
if __name__ == "__main__":
    component_data = { 'component_id':'1',
            'sequence_id':'1',
            'previous_component_id':'1',
            'next_component_id':'3',
            'type':'CASSETTE',
            'note':'',
            'details': '{"note": "",\
                    "sequenceid": 1, "reactor": 1, "validationerror": false,\
                    "componenttype": "CASSETTE",\
                    "reagentids": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\
                    "type": "component", "id": 1}'}

    v = comp_vtor.check('check_component', component_data)
Example #2
0
    def test_any_checker(self):
        validator = Validator()
        validator.functions['any'] = any_checker

        # Boolean: True
        self.assertIsInstance(validator.check('any', 'True'), bool)
        self.assertEqual(validator.check('any', 'True'), True)
        self.assertEqual(validator.check('any', 'yes'), True)

        # Boolean: False
        self.assertIsInstance(validator.check('any', 'False'), bool)
        self.assertEqual(validator.check('any', 'False'), False)
        self.assertEqual(validator.check('any', 'no'), False)

        # integers
        self.assertIsInstance(validator.check('any', '2'), int)
        self.assertEqual(validator.check('any', '2'), 2)

        # float
        self.assertIsInstance(validator.check('any', '2.1'), float)
        self.assertEqual(validator.check('any', '2.1'), 2.1)

        # lists
        self.assertEqual(validator.check('any', ','), [])
        self.assertEqual(validator.check('any', '1,'), [1])
        self.assertEqual(validator.check('any', '1,2'), [1, 2])
        self.assertEqual(validator.check('any', '1,false'), [1, False])
        self.assertEqual(validator.check('any', '1,false, string'),
                         [1, False, 'string'])
        self.assertEqual(validator.check('any', '1,false, string, 2.1'),
                         [1, False, 'string', 2.1])
        assert_value_equal(
            validator.check('any', '1,false, string, 2.1, nan'),
            [1, False, 'string', 2.1, float('nan')])

        # string
        self.assertIsInstance(validator.check('any', 'string'), str)
        self.assertEqual(validator.check('any', 'string'), 'string')
class ConfigObjModel(QtCore.QAbstractItemModel):
    """Model for ConfigObj

    A ConfigObj is a tree structured ordered dictionary.
    It represents ini-Files. There can also be a config specification.
    You can validate your ConfigObj against that specification.
    The model holds the configobj and can extract data like
    keys, values, specification.
    It should be used with a tree view because you can nest sections
    inside your ini.

    The data is validated life. So invalid or valid values get different forground roles.

    The internal pointers of the indices are the sections of the ConfigObj.
    The three columns are key, value, spec.
    """

    def __init__(self, conf, parent=None):
        """Constructs a new config obj model

        :param conf: the ConfigObj with its spec already set!.
        :type conf: :class:`configobj.ConfigObj`
        :param parent: the parent object
        :type parent: :class:`PySide.QtCore.QObject`
        :returns: None
        :rtype: None
        :raises: None
        """
        super(ConfigObjModel, self).__init__(parent)
        self._conf = conf
        self._vld = Validator()
        if self._conf.configspec is not None:
            self._conf.validate(self._vld)

        # validation colors
        self._valid_col = QtGui.QColor(105, 205, 105)
        self._invalid_col = QtGui.QColor(250, 135, 135)

    def rowCount(self, parent):
        """Reimplemented from QtCore.QAbstractItemModel"""
        if not parent.isValid():
            v = self._conf
        else:
            v = self.get_value(parent)
        if isinstance(v, Section):
            return len(v.keys())
        else:
            return 0

    def columnCount(self, parent):
        """Reimplemented from QtCore.QAbstractItemModel

        3 Columns: Key, Value, Spec
        """
        return 3

    def data(self, index, role = QtCore.Qt.DisplayRole):
        """Reimplemented from QtCore.QAbstractItemModel

        The value gets validated and is red if validation fails
        and green if it passes.
        """
        if not index.isValid():
            return None
        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            if index.column() == 0:
                p = index.internalPointer()
                k = self.get_key(p, index.row())
                return k
            if index.column() == 1:
                v = self.get_value(index)
                if not isinstance(v, Section):
                    return self._val_to_str(v)
            if index.column() == 2:
                return self.get_configspec_str(index)
        if role == QtCore.Qt.ForegroundRole:
            if index.column() == 1:
                v = self.get_value(index)
                if not isinstance(v, Section):
                    spec = self.get_configspec_str(index)
                    if spec is None or isinstance(spec, Section):
                        return
                    try:
                        self._vld.check(spec, v)
                    except ValidateError:
                        return QtGui.QBrush(self._invalid_col)
                    else:
                        return QtGui.QBrush(self._valid_col)

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        """Reimplemented from QtCore.QAbstractItemModel

        You can only set the value.

        :param index: the index to edit, column should be 1.
        :type index: :class:`PySide.QtCore.QModelIndex`
        :param value: the new value for the configobj
        :type value: object
        :param role: Optional - the ItemDataRole. Default is QtCore.Qt.EditRole
        :type role: QtCore.Qt.ItemDataRole
        :returns: True if index was edited, False if index could not be edited.
        :rtype: bool
        :raises: None

        """
        if index.isValid():
            if role == QtCore.Qt.EditRole:
                if index.column() == 1:
                    p = index.internalPointer()
                    k = self.get_key(p, index.row())
                    # we could just set the value
                    # BUT for listvalues etc it will not work
                    strval = self._val_to_str(value)
                    # _handle_value will parse it correctly
                    # comments gets lost
                    (parsedval, comment) = self._conf._handle_value(strval)
                    p[k] = parsedval
                    self.dataChanged.emit(index, index)
                    return True
        return False

    def restore_default(self, index):
        """Set the value of the given index row to its default

        :param index:
        :type index:
        :returns:
        :rtype:
        :raises:
        """
        spec = self.get_configspec_str(index)
        if spec is None or isinstance(spec, Section):
            return
        try:
            default = self._vld.get_default_value(spec)
            defaultstr = self._val_to_str(default)
            self.setData(index, defaultstr)
        except KeyError:
            raise ConfigError("Missing Default Value in spec: \"%s\"" % spec)

    def headerData(self, section, orientation, role):
        """Reimplemented from QtCore.QAbstractItemModel

        Just the header text for the 3 columns.
        Rows do not have headers.
        """
        dispheaders = ('Key', 'Value', 'Spec')
        if orientation == QtCore.Qt.Horizontal:
            if role == QtCore.Qt.DisplayRole:
                try:
                    return dispheaders[section]
                except IndexError:
                    return None

    def flags(self, index):
        """Reimplemented from QtCore.QAbstractItemModel

        Only the value is editable
        """
        if index.column() == 1:
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
        else:
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def parent(self, index):
        """Reimplemented from QtCore.QAbstractItemModel"""
        if not index.isValid():
            return QtCore.QModelIndex()
        p = index.internalPointer()
        if p is self._conf:
            return QtCore.QModelIndex()
        pp = p.parent
        pk = p.name
        row = (pp.scalars + pp.sections).index(pk)
        return self.createIndex(row, 0, pp)

    def index(self, row, column, parent):
        """Reimplemented from QtCore.QAbstractItemModel

        The internal pointer is the section.
        The row determines the key in the scalars then sections of the configobj.
        So for a given index, use row to retrieve the key::

          key = self.get_key(index.internalPointer(), index.row())

        To use the key on the section to get the value OR
        use get_value(index) / get_configspec_str

        """
        if not parent.isValid():
            s = self._conf
        else:
            p = parent.internalPointer()
            k = self.get_key(p, parent.row())
            s = p[k]
        return self.createIndex(row, column, s)

    def get_value(self, index):
        """ Return the value of the given index

        The index stores the section as internal pointer.
        The row of the index determines the key.
        The key is used on the section to return the value

        :param index: The QModelIndex
        :type index: QModelIndex
        :returns: The value for the given index
        """
        p = index.internalPointer()
        k = self.get_key(p, index.row())
        return p[k]

    def get_configspec_str(self, index):
        """ Return the config spec string of the given index

        The index stores the section as internal pointer.
        The row of the index determines the key.
        The section stores the spec in its configspec attribute
        The key is used on the configspec attribute to return the spec

        :param index: The QModelIndex
        :type index: QModelIndex
        :returns: The spec for the given index or None
        """
        p = index.internalPointer()
        if p is None:
            return
        spec = p.configspec
        if spec is None:
            return None
        k = self.get_key(p, index.row())
        try:
            return spec[k]
        except KeyError:
            return None

    def get_key(self, section, row):
        """ Return the key for the given section and row

        A sections stores scalars and sections.
        The row is the index for the combination of scalars and sections.

        :param section: A ConfigObj section
        :type section: Section
        :param row: the index for (section.scalars + section.sections)
        :type row: int
        :returns: the key
        :rtype: str
        :raises: IndexError
        """
        return (section.scalars + section.sections)[row]

    def set_valid_col(self, color):
        """Set the forgroundrole color for values if they are valid

        :param color: this color will be returned from data() when the value is valid and role is QtCore.Qt.ForegroundRole
        :type color: QtGui.QColor
        :returns: None
        :rtype: None
        :raises: None

        default is: QtGui.QColor(105, 205, 105)
        """
        self._valid_col = color

    def set_invalid_col(self, color):
        """Set the forgroundrole color for values if they are valid

        :param color: this color will be returned from data() when the value is valid and role is QtCore.Qt.ForegroundRole
        :type color: QtGui.QColor
        :returns: None
        :rtype: None
        :raises: None

        default is: QtGui.QColor(250, 135, 135)
        """
        self._invalid_col = color

    def _val_to_str(self, value):
        """Converts the value to a string that will be handled correctly by the confobj

        :param value: the value to parse
        :type value: something configobj supports
        :returns: str
        :rtype: str
        :raises: None

        When the value is a list, it will be converted to a string that can be parsed to
        the same list again.
        """
        # might be a list value
        # then represent it 'nicer' so that when we edit it, the same value will return
        if isinstance(value, list):
            # so we have a list value. the default str(v) would produce something like: ['a', 'b']
            # handling such a value is not possible. it should be: 'a', 'b'
            # so we have to convert it to a string but we have to make sure, we do not loose quotes
            # even when values are integers, they get quoted. thats alright. the config obj will parse them correctly
            return ', '.join("'%s'" % str(i) for i in value)
        return str(value)  # so we always have a line editor. validate can convert from string
Example #4
0
class ConfigHelper(ConfigObj):
    """
    Extended regular config obj that can perform special tasks and extended
    handling.

    Generally the new options should be used over the direct usage of inherited
    functions.
    """
    def __init__(self, *args, **kwargs):
        """
        Raises
        ------
        ValueError
            if the infile :py:class:`configobj.ConfigObj` parameter is not
            specified

        """
        if 'infile' not in kwargs:
            raise ValueError('Must be initialized with infile')
        kwargs['raise_errors'] = True
        kwargs['configspec'] = ConfigObj()
        ConfigObj.__init__(self, *args, **kwargs)

        # Fix missing main sections
        for item in ['Config', 'Setup']:
            if item not in self:
                self.update({item: {}})
            if item not in self.configspec:
                self.configspec.update({item: {}})

        self.validator = Validator()
        self.validator.functions.update(functions)
        self._listeners = {}

    @property
    def option(self):
        """
        Returns config option section from the config handler.

        Returns
        -------
        configobj.Section
        """
        return self['Config']

    @property
    def optionspec(self):
        """
        Returns config option specification section from the config handler.

        Returns
        -------
        configobj.Section
        """
        return self.configspec['Config']

    @property
    def setup(self):
        """
        Returns config setup section from the config handler.

        Returns
        -------
        configobj.Section
        """
        return self['Setup']

    @property
    def setupspec(self):
        """
        Returns config setup specification section from the config handler.

        Returns
        -------
        configobj.Section
        """
        return self.configspec['Setup']

    def add_option(self, key, specification):
        """
        Adds (registers) a new config option with the specified key and
        specification.
        The key must be unique.

        Parameters
        ----------
        key : str
            key to use for storage
        specification : str
            config specification string for validating values for this key
        Raises
        ------
        KeyError
            if the key is a duplicate
        """
        if key in self.optionspec:
            raise KeyError('Duplicate key: %s' % key)
        self.optionspec[key] = specification

    def get_option(self, key, safe=True):
        """
        Returns the handled value for the specified key from the config.

        If the safe option is specified the function will check if any setups
        for the specified key need to be formed and raises an Error if the
        setup is pending. If False this behaviour is disabled

        .. warning::
            if the specified key is missing this method will shutdown the CLI
            with an error message to configure the key


        Parameters
        ----------
        key : str
            key to retrieve the value for
        safe : bool
            whether to check setup is needed

        Returns
        -------
        object
            handled value

        Raises
        ------
        SetupError
            if the setup for the key was not performed
        """
        if safe and key in self.setup:
            if not self.setup[key]['performed']:
                raise SetupError('Setup not performed.')
        try:
            value = self.option[key]
        except KeyError:
            console(
                'Config variable "%s" is not configured. Consider running:' %
                key,
                msg=Msg.error)
            console('config set "%s" "<value>"' % key, msg=Msg.error)
            console('Exiting...', msg=Msg.error)
            sys.exit(-1)

        return self.validator.check(self.optionspec[key], value)

    def set_option(self, key, value):
        """
        Sets the key to the specified value.

        The function will also take care of the following:
        - invalidate setups registered for this key, if any
        - validate the value
        - execute listeners

        Parameters
        ----------
        key : str
            the option key to set
        value : object
            the value to set the key to
        Raises
        ------
        validate.ValidationError
            if the validation of the value failed
        """
        if key in self.setup:
            self.setup[key]['performed'] = False

        # Raise ValidationError
        value = self.validator.check(self.optionspec[key], value)

        if key in self._listeners:
            for f in self._listeners[key]:
                f(key, value, self.option[key])

        self.option[key] = value

    def register_setup(self, key, funcs):
        """
        Registers one or multiple functions that will be called to perform
        the setup for the specified config key.

        This will also create the according setup keys if non existent

        .. note::
            Setup variables should be registered using this function before
            using any other 'setup' related functions.

        Parameters
        ----------
        key : str
            config key to register the setup for
        funcs : callable or Iterable[callable]
            a function or iterable of functions to be called when the setup
            for the specified key is performed

        Raises
        ------
        TypeError
            if funcs is not callable

        """
        if key not in self.setup:
            self.setup.update({
                key: {
                    'performed': False,
                },
            })

        self.setupspec.update({
            key: {
                'performed': 'boolean()',
            },
        })

        if isinstance(funcs, Iterable):
            for f in funcs:
                if not callable(f):
                    raise TypeError('Callable expected.')
        elif not callable(funcs):
            raise TypeError('Callabe expected.')
        else:
            funcs = (funcs, )

        self.setup[key].functions = funcs

    def add_setup_listener(self, config_key, function):
        """
        Adds a listener for the specified config key that triggers when the
        config value was changed.

        Function should take 3 arguments:
        * key: The key that was changed
        * value: the new value
        * old_value: the old value
        
        Parameters
        ----------
        config_key : str
            config key to register the listener for
        function : callable
            callable to add as listener

        Raises
        ------
        TypeError
            if function is not callable
        """
        if not callable(function):
            raise TypeError('Callabe expected.')

        if config_key in self._listeners:
            self._listeners[config_key].append(function)
        else:
            self._listeners[config_key] = [
                function,
            ]

    def add_setup_variable(self, setup_key, variable_key, specification):
        """
        Adds a setup variable, i.e. a variable related to a specific setup

        For example this is useful to store additional information required to
        check whether a new run of setup is needed.

        Parameters
        ----------
        setup_key : str
            the setup key to register the variable for
        variable_key : str
            the key of the variable itself (must be unique)
        specification : str
            the config specification to use for the variable

        Raises
        ------
        KeyError
            if the setup key does not exist
        KeyError
            if the variable key is a duplicate

        """
        if setup_key not in self.setupspec:
            raise KeyError('Setup key "%s" is invalid' % setup_key)
        if variable_key in self.setupspec[setup_key]:
            raise KeyError('Duplicate key: %s' % variable_key)
        self.setupspec[setup_key][variable_key] = specification

    def get_setup_variable(self, setup_key, variable_key):
        """
        Returns the stored variable for the specified setup key

        Parameters
        ----------
        setup_key : str
            the setup key to retrieve the variable for
        variable_key : str
            the config key of the variable to retrieve

        Returns
        -------
        object
            the value of the variable
        """
        return self.setup[setup_key][variable_key]

    def set_setup_variable(self, setup_key, variable_key, value):
        """
        Sets the value for the specified setup key and variable

        Parameters
        ----------
        setup_key : str
            the setup key to set the variable for
        variable_key : str
            the config key of the variable to set
        value : object
            the value to set the variable to

        Raises
        ------
        validate.ValidationError
            if the validation of the value failed

        """
        # Raise ValidationError
        value = self.validator.check(self.setupspec[setup_key][variable_key],
                                     value)
        self.setup[setup_key][variable_key] = value

    def needs_setup(self, key):
        """
        Returns whether the specified config key requires setup or not.

        .. warning ::
            This does not return whether the setup is performed, only whether
            this is a config key that requires setup.

            If you want to know whether setup was performed use is_setup.

        Parameters
        ----------
        key : str
            the setup key to check

        Returns
        -------
        bool
            True if setup needs to be performed
        """
        return key in self.setup

    def is_setup(self, variable):
        """
        Returns whether the specified config key has it's setup performed

        Parameters
        ----------
        key : str
            the setup key to check

        Returns
        -------
        bool
            True if setup is performed
        """
        return self.setup[variable]['performed']

    def setup_or_raise(self, variable):
        """
        Returns True if setup is performed for the specified config variable
        and raises an error if it isn't.

        Parameters
        ----------
        variable : str
            config variable to check against

        Returns
        -------
        True
            if setup is performed

        Raises
        ------
        SetupError
            if setup is not performed
        """
        if not self.is_setup(variable):
            raise SetupError('Setup for %s not performed' % variable)
        return True