You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
5.2 KiB

import re
from functools import wraps
from gooey.gui.components.filtering.prefix_filter import OperatorType
class SuperBool(object):
"""
A boolean which keeps with it the rationale
for when it is false.
"""
def __init__(self, value, rationale):
self.value = value
self.rationale = rationale
def __bool__(self):
return self.value
__nonzero__ = __bool__
def __str__(self):
return str(self.value)
def lift(f):
"""
Lifts a basic predicate to the SuperBool type
stealing the docstring as the rationale message.
This is largely just goofing around and experimenting
since it's a private internal API.
"""
@wraps(f)
def inner(value):
result = f(value)
return SuperBool(result, f.__doc__) if not isinstance(result, SuperBool) else result
return inner
@lift
def is_tuple_or_list(value):
"""Must be either a list or tuple"""
return isinstance(value, list) or isinstance(value, tuple)
@lift
def is_str(value):
"""Must be of type `str`"""
return isinstance(value, str)
@lift
def is_str_or_coll(value):
"""
Colors must be either a hex string or collection of RGB values.
e.g.
Hex string: #fff0ce
RGB Collection: [0, 255, 128] or (0, 255, 128)
"""
return bool(is_str(value)) or bool(is_tuple_or_list(value))
@lift
def has_valid_channel_values(rgb_coll):
"""Colors in an RGB collection must all be in the range 0-255"""
return all([is_0to255(c) and is_int(c) for c in rgb_coll])
@lift
def is_three_channeled(value):
"""Missing channels! Colors in an RGB collection should be of the form [R,G,B] or (R,G,B)"""
return len(value) == 3
@lift
def is_hex_string(value: str):
"""Invalid hexadecimal format. Expected: "#FFFFFF" """
return isinstance(value, str) and bool(re.match('^#[\dABCDEF]{6}$', value, flags=2))
@lift
def is_bool(value):
"""Must be of type Boolean"""
return isinstance(value, bool)
@lift
def non_empty_string(value):
"""Must be a non-empty non-blank string"""
return bool(value) and bool(value.strip())
@lift
def is_tokenization_operator(value):
"""Operator must be a valid OperatorType i.e. one of: (AND, OR)"""
return bool(value) in (OperatorType.AND, OperatorType.OR)
@lift
def is_tokenizer(value):
"""Tokenizers must be valid Regular expressions. see: options.PrefixTokenizers"""
return bool(non_empty_string(value))
@lift
def is_int(value):
"""Invalid type. Expected `int`"""
return isinstance(value, int)
@lift
def is_0to255(value):
"""RGB values must be in the range 0 - 255 (inclusive)"""
return 0 <= value <= 255
def is_0to20(value):
"""Precision values must be in the range 0 - 20 (inclusive)"""
return 0 <= value <= 20
@lift
def is_valid_color(value):
"""Must be either a valid hex string or RGB list"""
if is_str(value):
return is_hex_string(value)
elif is_tuple_or_list(value):
return (is_tuple_or_list(value)
and is_three_channeled(value)
and has_valid_channel_values(value))
else:
return is_str_or_coll(value)
validators = {
'label_color': is_valid_color,
'label_bg_color': is_valid_color,
'help_color': is_valid_color,
'help_bg_color': is_valid_color,
'error_color': is_valid_color,
'error_bg_color': is_valid_color,
'show_label': is_bool,
'show_help': is_bool,
'visible': is_bool,
'full_width': is_bool,
'height': is_int,
'readonly': is_bool,
'initial_selection': is_int,
'title': non_empty_string,
'checkbox_label': non_empty_string,
'placeholder': non_empty_string,
'empty_message': non_empty_string,
'max_size': is_int,
'choice_tokenizer': is_tokenizer,
'input_tokenizer': is_tokenizer,
'ignore_case': is_bool,
'operator': is_tokenization_operator,
'index_suffix': is_bool,
'wildcard': non_empty_string,
'default_dir': non_empty_string,
'default_file': non_empty_string,
'default_path': non_empty_string,
'message': non_empty_string,
'precision': is_0to20
}
def collect_errors(predicates, m):
return {
k:predicates[k](v).rationale
for k,v in m.items()
if k in predicates and not predicates[k](v)}
def validate(pred, value):
result = pred(value)
if not result:
raise ValueError(result.rationale)
if __name__ == '__main__':
# TODO: there should be tests
pass
# print(validateColor((1, 'ergerg', 1234)))
# print(validateColor(1234))
# print(validateColor(123.234))
# print(validateColor('123.234'))
# print(validateColor('FFFAAA'))
# print(validateColor('#FFFAAA'))
# print(validateColor([]))
# print(validateColor(()))
# print(validateColor((1, 2)))
# print(validateColor((1, 2, 1234)))
# print(is_lifted(lift(is_int)))
# print(is_lifted(is_int))
# print(OR(is_poop, is_int)('poop'))
# print(AND(is_poop, is_lower, is_lower)('pooP'))
# print(OR(is_poop, is_int))
# print(is_lifted(OR(is_poop, is_int)))
# print(validate(is_valid_color, [255, 255, 256]))
# print(is_valid_color('#fff000'))
# print(is_valid_color([255, 244, 256]))
# print(non_empty_string('asdf') and non_empty_string('asdf'))
# validate(is_valid_color, 1234)