Coretex
utils.py
1 # Copyright (C) 2023 Coretex LLC
2 
3 # This file is part of Coretex.ai
4 
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 
18 from typing import Optional, Any, Tuple, Dict, List
19 
20 from .base_parameter import ParameterType
21 
22 
23 def validateEnumStructure(name: str, value: Optional[Any], required: bool) -> Tuple[bool, Optional[str]]:
24  if not isinstance(value, dict):
25  return False, None
26 
27  # Enum parameter must contain 2 key-value pairs: selected and options
28  if len(value) != 2 or "options" not in value or "selected" not in value:
29  keys = ", ".join(value.keys())
30  return False, f"Enum parameter \"{name}\" must contain only \"selected\" and \"options\" properties, but it contains \"{keys}\""
31 
32  options = value.get("options")
33 
34  # options must be an object of type list
35  if not isinstance(options, list):
36  return False, f"Enum parameter \"{name}.options\" has invalid type. Expected \"list[str]\", got \"{type(options).__name__}\""
37 
38  # all elements of options list must be strings
39  if not all(isinstance(element, str) for element in options):
40  elementTypes = ", ".join({type(element).__name__ for element in options})
41  return False, f"Elements of enum parameter \"{name}.options\" have invalid type. Expected \"list[str]\" got \"list[{elementTypes}]\""
42 
43  # options elements must not be empty strings
44  if not all(element != "" for element in options):
45  return False, f"Elements of enum parameter \"{name}.options\" must be non-empty strings."
46 
47  selected = value.get("selected")
48  if selected is None and required:
49  return False, f"Enum parameter \"{name}.selected\" has invalid type. Expected \"int\", got \"{type(selected).__name__}\""
50 
51  return True, None
52 
53 
54 def validateRangeStructure(name: str, value: Dict[str, Any], required: bool) -> Tuple[bool, Optional[str]]:
55  if len(value) != 3 or "from" not in value or "to" not in value or "step" not in value:
56  keys = ", ".join(value.keys())
57  return False, f"Range parameter \"{name}\" must contain only \"from\", \"to\" and \"step\" properties, but it contains \"{keys}\""
58 
59  if any(element is None for element in value.values()) and required:
60  return False, f"Elements of range parameter \"{name}\" must not be null"
61 
62  if not all(type(element) is int for element in value.values()) and required:
63  elementTypes = ", ".join({type(element).__name__ for element in value.values()})
64  return False, f"Elements of range parameter \"{name}\" have invalid type. Expected \"int\" got \"{elementTypes}\""
65 
66  if any(type(element) is float for element in value.values()):
67  return False, "Range parameter does not support float values"
68 
69  return True, None
70 
71 def getValueParamType(value: Any, name: str) -> ParameterType:
72  if isinstance(value, bool):
73  return ParameterType.boolean
74 
75  if isinstance(value, int):
76  return ParameterType.integer
77 
78  if isinstance(value, float):
79  return ParameterType.floatingPoint
80 
81  if isinstance(value, str):
82  return ParameterType.string
83 
84  if isinstance(value, list):
85  return getListParamType(value, name)
86 
87  supportedTypes = [type_.name for type_ in ParameterType]
88 
89  raise ValueError(f">> [Coretex] Parameter \"{name}\" has invalid type. Expected \"{supportedTypes}\", got \"{type(value)}\".")
90 
91 def getListParamType(value: List[Any], name: str) -> ParameterType:
92  if all(isinstance(item, int) for item in value):
93  return ParameterType.intList
94 
95  if all(isinstance(item, float) for item in value):
96  return ParameterType.floatList
97 
98  if all(isinstance(item, str) for item in value):
99  return ParameterType.strList
100 
101  typesFound = ", ".join([type(item).__name__ for item in value])
102  raise ValueError(f">> [Coretex] Parameter \"{name}\" cannot contain multiple value type: \"{typesFound}\".")