# Copyright (C) 2023 - 2024 Jakub Więckowski
import numpy as np
[docs]
class Validator:
[docs]
@staticmethod
def is_type_valid(var, type, var_name, custom_message = None):
if not isinstance(var, type):
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{var_name}' should be given as {type}")
return True
[docs]
@staticmethod
def is_callable(var, var_name, custom_message = None):
if isinstance(var, (list, np.ndarray)):
if any([not callable(v) for v in var]):
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{var_name}' should be given as a list of callable")
else:
if not callable(var):
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{var_name}' should be given as callable")
return True
[docs]
@staticmethod
def is_dimension_valid(var, size, var_name, custom_message = None):
if var.ndim != size:
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should be given as {size}D vector")
return True
[docs]
@staticmethod
def is_sum_valid(var, sum, var_name = 'weights', precision=3, custom_message = None):
if np.round(np.sum(var), precision) != sum:
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should sum up to {sum}")
return True
[docs]
@staticmethod
def is_shape_equal(size1, size2, var_name_1 ='', var_name_2='', custom_message = None):
if size1 != size2:
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name_1}' and '{var_name_2}' have different shape")
return True
[docs]
@staticmethod
def are_indexes_valid(indexes, size, var_name = 'indexes', custom_message = None):
if indexes is not None:
if isinstance(indexes, int):
if indexes >= size or indexes < 0:
if custom_message:
raise IndexError(custom_message)
else:
raise IndexError(f"'{var_name}' out of range. Check element ({indexes})")
else:
for c_idx in indexes:
if isinstance(c_idx, (int, np.integer)):
if c_idx < 0 or c_idx >= size:
if custom_message:
raise IndexError(custom_message)
else:
raise IndexError(f"'{var_name}' out of range. Check element ({c_idx})")
elif isinstance(c_idx, (list, np.ndarray)):
if any([idx < 0 or idx >= size for idx in c_idx]):
if custom_message:
raise IndexError(custom_message)
else:
raise IndexError(f"'{var_name}' out of range. Check element ({c_idx})")
return True
[docs]
@staticmethod
def is_positive_value(var, var_name, bound=0, custom_message = None):
if var <= bound:
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should be a positive value")
return True
[docs]
@staticmethod
def is_in_range(var, min_val, max_val, var_name, custom_message = None):
if isinstance(var, (list, np.ndarray)):
if any([v < min_val or v > max_val for v in var]):
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"All values from '{var_name}' should be in range [{min_val}, {max_val}]")
else:
if min_val > var or var > max_val:
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should be in range [{min_val}, {max_val}]")
return True
[docs]
@staticmethod
def is_in_list(var, var_list, var_name, custom_message = None):
if isinstance(var, (list, np.ndarray)):
if any([v not in var_list for v in var]):
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should contain only values from {var_list}")
else:
if var not in var_list:
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should be one of the values from {var_list}")
return True
[docs]
@staticmethod
def is_key_in_dict(keys, dict, var_name, custom_message = None):
for key in keys:
if key not in list(dict.keys()):
if custom_message:
raise ValueError(custom_message)
else:
raise ValueError(f"'{var_name}' should include `{key}` as one of the keys")
return True
[docs]
@staticmethod
def is_array_2D_3D(var, ref_var, var_name, ref_var_name, custom_message = None):
dim = 0
try: # 2D
if isinstance(var[0][0], (int, np.integer, float)):
shapes = tuple(len(dv) for dv in var)
if ref_var.shape[1] != len(shapes):
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{ref_var_name}' and '{var_name}' have different shapes")
dim = 2
else: # 3D
dv_shape = [len(tuple(len(vals) for vals in dv)) for dv in var]
if len(np.unique(dv_shape)) != 1 or ref_var.shape[0] != dv_shape[0] and ref_var.shape[1] != dv_shape[1]:
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{ref_var_name}' and '{var_name}' have different shapes")
dim = 3
except TypeError:
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{var_name}' should be given as 2D or 3D array")
return True, dim
[docs]
@staticmethod
def is_type_in_dict_valid(key, dict, type, var_name, custom_message = None):
if not isinstance(dict[key], type):
if custom_message:
raise TypeError(custom_message)
else:
raise TypeError(f"'{key}' in '{var_name}' should be given as {type}")
return True