Source code for schrodinger.application.jaguar.validation

"""
Jaguar keywords input validation and custom Exceptions

Copyright Schrodinger, LLC. All rights reserved.
"""

import schrodinger.application.jaguar.jaguar_keyword_utils as kwutils
from schrodinger.application.jaguar.exceptions import JaguarUserFacingException
from schrodinger.application.jaguar.keywordDB import Setting
from schrodinger.application.jaguar.keywordDB import load_keywords

STRING = 'string'
INTEGER = 'integer'
REAL = 'real'

#-----------------------------------------------------------------------------


[docs]class JaguarKeywordException(JaguarUserFacingException): """ Base exception class for all custom Jaguar keyword validation errors """
[docs]class JaguarKeywordError(JaguarKeywordException): """ Exception class raised when nonexistant Jaguar keyword is requested """
[docs] def __init__(self, keyword, allowed_keywords): """ :type keyword: string :param keyword: input keyword :type allowed_keywords: list :param allowed_keywords: list of allowed keywords """ msg = "%s is not a Jaguar keyword." % keyword super(self.__class__, self).__init__(msg) self.keyword = keyword self.allowed_keywords = allowed_keywords
[docs]class JaguarKeywordValueTypeError(JaguarKeywordException): """ Exception class raised when Jaguar keyword value has wrong type """
[docs] def __init__(self, keyword, value, valid_type): """ :type keyword: string :param keyword: input keyword :type value: string :param value: input value :type valid_type: string :param valid_type: types as described in keywordsDB_mod.py """ msg = "%s is not a valid type for keyword %s; expected %s." % ( value, keyword, valid_type) super(self.__class__, self).__init__(msg) self.keyword = keyword self.value = value self.valid_type = valid_type
[docs]class JaguarKeywordValueError(JaguarKeywordException): """ Exception class raised when Jaguar keyword value is invalid """
[docs] def __init__(self, keyword, value, settings): """ :type keyword: string :param keyword: input keyword :type value: string :param value: input value :type settings: list of Settings objects :param settings: settings associated with a keyword """ self.keyword = keyword self.value = value self.allowed_settings = settings self.allowed_values = [x.value for x in settings] msg = "%s is not an allowed value for keyword %s; allowed values are: %s" % ( value, keyword, ", ".join(self.allowed_values)) super(self.__class__, self).__init__(msg)
[docs]class JaguarKeywordFormatError(JaguarKeywordException): """ Exception class raised when a string not in the keyword=value format is found """
[docs] def __init__(self, token): """ :type token: string :param token: The token that violates the keyword=value format """ msg = ("%s does not conform to the required keyword=value format." % token) super(self.__class__, self).__init__(msg) self.keyword = token
#-----------------------------------------------------------------------------
[docs]def value_is_type(valid_type, value): """ Check if value has type equivalent to valid_type after converting string :type valid_type: string :param valid_type: types as described in keywordsDB.py :type value: string :param value: keyword value from input :return: True or False """ # unittested # Test if valid int try: int(value) is_int = True except ValueError: is_int = False # Test if valid float try: float(value) is_float = True except ValueError: is_float = False if valid_type == INTEGER: if is_int: return True else: return False elif valid_type == REAL: if is_float: return True else: return False elif valid_type == STRING: # e.g. accept neither '12' nor '12.0' if is_int or is_float: return False else: return True else: raise AttributeError("Jaguar keyword type not recognized")
_keywords_list = _keywords_dict = None
[docs]def keyword_value_pair_is_valid(keyword, value): """ Validate a specific keyword=value pair. The checks are case insensitive. :type keyword: string :param keyword: e.g. 'igeopt' :type value: string :param value: e.g. '2' or '0.004' or any string :return: True if all pairs valid, otherwise raise specialized exceptions. """ # unittested global _keywords_list, _keywords_dict # Transform to lowercase for comparisons keywordl = keyword.lower() valuel = value.lower() if _keywords_list is None: # We only read the file in once because it is an expensive (~0.2 # seconds) read and will never change during a session JAGUAR-7587. filename = kwutils.jaguar_keywords_xml_filename() _keywords_list, _keywords_dict = load_keywords(filename) # 1) Check for valid Jaguar keyword keywords = list(_keywords_dict) if keywordl not in keywords: raise JaguarKeywordError(keyword, keywords) # 2) Check for valid value type valid_type = _keywords_dict[keywordl].type if not value_is_type(valid_type, valuel): raise JaguarKeywordValueTypeError(keyword, value, valid_type) # 3) Check for valid value if keyword.lower() == 'dftname': # Handle dftname as a special case because choices are not present in .xml file allowed_values = [x.lower() for x in kwutils.all_dftnames()] settings = [Setting('dftname', 'dftname', v) for v in allowed_values] else: kwobj = _keywords_dict[keywordl] settings = kwobj.settings allowed_values = [x.value for x in kwobj.settings] if allowed_values: # If free to choose, settings attribute is empty list if valuel not in allowed_values: raise JaguarKeywordValueError(keyword, value, settings) return True
[docs]def keyword_value_pairs_are_valid(pairs): """ Validate a string of keyword=value pairs :type pairs: string :param pairs: e.g. '-keyword1=val1 -keyword2=value2 -keyword3=value3' :return: True if all pairs valid, otherwise raise specialized exceptions. """ for item in pairs.split(): try: keyword, value = item.split("=") except ValueError: raise JaguarKeywordFormatError(item) keyword_value_pair_is_valid(keyword, value) return True