Source code for schrodinger.application.jaguar.workflow_keywords
"""
This module documents all machinery for workflow input keywords.
"""
# Contributors: Mark A. Watson
from voluptuous import Any
from voluptuous import MultipleInvalid
from voluptuous import Required
from voluptuous import Schema
from schrodinger.application.jaguar import workflow_validation as wv
#------------------------------------------------------------------------------
[docs]class Choices(object):
[docs]    def __init__(self, *choices):
        self.choices = choices  
[docs]class WorkflowKeyword(object):
[docs]    def __init__(self, name, valid_type, default, description):
        """
        :type  name: string
        :param name: unique name for keyword
        :type  valid_type: python type
        :param valid_type: keyword type e.g. bool, int
        :type  default: <valid_type>
        :param default: default keyword value
        :type  description: string
        :param description: short description of what the keyword does
        """
        # Define all keywords in lower case
        namel = name.lower()
        self._value = None
        # Define all keywords in lower case
        self._name = namel
        self._default = default
        self._description = description
        # Use Schema to establish the valid type(s) of this keyword
        req = Required(namel, default=default)
        if isinstance(valid_type, Choices):
            sch = {req: Any(*valid_type.choices)}
            self._type = valid_type.choices
        else:
            sch = {req: valid_type}
            self._type = valid_type
        self._schema = Schema(sch)
        self.validate() 
    def __repr__(self):
        return f"<{type(self).__name__} {self.name}: {repr(self.value)}>"
    @property
    def name(self):
        return self._name
    @property
    def valid_type(self):
        return self._type
    @property
    def default(self):
        return self._default
    @property
    def description(self):
        return self._description
    @property
    def value(self):
        """
        Return user-set value.
        If None, return default value.
        """
        if self._value is not None:
            return self._value
        else:
            return self._default
    @value.setter
    def value(self, value):
        self.setValue(value)
[docs]    def setValue(self, value):
        """
        Set to user-defined value.
        :type value: anything
        :type value: user-defined value (e.g. from input file)
        """
        self._value = value
        self.validate() 
[docs]    def reset(self):
        """
        Reset user-value to NoneType.
        """
        self._value = None
        self.validate() 
[docs]    def isNonDefault(self):
        """
        Return True if keyword user-value differs from default value.
        False otherwise.
        :rtype: bool
        """
        return (self.value != self._default) 
[docs]    def validate(self):
        """
        Raise MultipleInvalid or WorkflowKeywordException if keyword
        name/value don't conform to the schema. (i.e. type check)
        """
        # Add an explicit check for integers since volutuous.Schema
        # apparently doesn't raise an Exception when a bool is offered
        # in place of an int. (JAGUAR-7460)
        if isinstance(self.value, bool) and self.valid_type != bool:
            raise wv.WorkflowKeywordValueTypeError(self.name, self.value,
                                                   self.valid_type)
        # Check all other types using Schema
        try:
            self._schema({self.name: self.value})
        except MultipleInvalid as e:
            wv.raise_voluptuous_exception(e, self)