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]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