additory 0.1.0a3__py3-none-any.whl → 0.1.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- additory/__init__.py +58 -14
- additory/common/__init__.py +31 -147
- additory/common/column_selector.py +255 -0
- additory/common/distributions.py +286 -613
- additory/common/extractors.py +313 -0
- additory/common/knn_imputation.py +332 -0
- additory/common/result.py +380 -0
- additory/common/strategy_parser.py +243 -0
- additory/common/unit_conversions.py +338 -0
- additory/common/validation.py +283 -103
- additory/core/__init__.py +34 -22
- additory/core/backend.py +258 -0
- additory/core/config.py +177 -305
- additory/core/logging.py +230 -24
- additory/core/memory_manager.py +157 -495
- additory/expressions/__init__.py +2 -23
- additory/expressions/compiler.py +457 -0
- additory/expressions/engine.py +264 -487
- additory/expressions/integrity.py +179 -0
- additory/expressions/loader.py +263 -0
- additory/expressions/parser.py +363 -167
- additory/expressions/resolver.py +274 -0
- additory/functions/__init__.py +1 -0
- additory/functions/analyze/__init__.py +144 -0
- additory/functions/analyze/cardinality.py +58 -0
- additory/functions/analyze/correlations.py +66 -0
- additory/functions/analyze/distributions.py +53 -0
- additory/functions/analyze/duplicates.py +49 -0
- additory/functions/analyze/features.py +61 -0
- additory/functions/analyze/imputation.py +66 -0
- additory/functions/analyze/outliers.py +65 -0
- additory/functions/analyze/patterns.py +65 -0
- additory/functions/analyze/presets.py +72 -0
- additory/functions/analyze/quality.py +59 -0
- additory/functions/analyze/timeseries.py +53 -0
- additory/functions/analyze/types.py +45 -0
- additory/functions/expressions/__init__.py +161 -0
- additory/functions/snapshot/__init__.py +82 -0
- additory/functions/snapshot/filter.py +119 -0
- additory/functions/synthetic/__init__.py +113 -0
- additory/functions/synthetic/mode_detector.py +47 -0
- additory/functions/synthetic/strategies/__init__.py +1 -0
- additory/functions/synthetic/strategies/advanced.py +35 -0
- additory/functions/synthetic/strategies/augmentative.py +160 -0
- additory/functions/synthetic/strategies/generative.py +168 -0
- additory/functions/synthetic/strategies/presets.py +116 -0
- additory/functions/to/__init__.py +188 -0
- additory/functions/to/lookup.py +351 -0
- additory/functions/to/merge.py +189 -0
- additory/functions/to/sort.py +91 -0
- additory/functions/to/summarize.py +170 -0
- additory/functions/transform/__init__.py +140 -0
- additory/functions/transform/datetime.py +79 -0
- additory/functions/transform/extract.py +85 -0
- additory/functions/transform/harmonize.py +105 -0
- additory/functions/transform/knn.py +62 -0
- additory/functions/transform/onehotencoding.py +68 -0
- additory/functions/transform/transpose.py +42 -0
- additory-0.1.1a1.dist-info/METADATA +83 -0
- additory-0.1.1a1.dist-info/RECORD +62 -0
- additory/analysis/__init__.py +0 -48
- additory/analysis/cardinality.py +0 -126
- additory/analysis/correlations.py +0 -124
- additory/analysis/distributions.py +0 -376
- additory/analysis/quality.py +0 -158
- additory/analysis/scan.py +0 -400
- additory/common/backend.py +0 -371
- additory/common/column_utils.py +0 -191
- additory/common/exceptions.py +0 -62
- additory/common/lists.py +0 -229
- additory/common/patterns.py +0 -240
- additory/common/resolver.py +0 -567
- additory/common/sample_data.py +0 -182
- additory/core/ast_builder.py +0 -165
- additory/core/backends/__init__.py +0 -23
- additory/core/backends/arrow_bridge.py +0 -483
- additory/core/backends/cudf_bridge.py +0 -355
- additory/core/column_positioning.py +0 -358
- additory/core/compiler_polars.py +0 -166
- additory/core/enhanced_cache_manager.py +0 -1119
- additory/core/enhanced_matchers.py +0 -473
- additory/core/enhanced_version_manager.py +0 -325
- additory/core/executor.py +0 -59
- additory/core/integrity_manager.py +0 -477
- additory/core/loader.py +0 -190
- additory/core/namespace_manager.py +0 -657
- additory/core/parser.py +0 -176
- additory/core/polars_expression_engine.py +0 -601
- additory/core/registry.py +0 -176
- additory/core/sample_data_manager.py +0 -492
- additory/core/user_namespace.py +0 -751
- additory/core/validator.py +0 -27
- additory/dynamic_api.py +0 -304
- additory/expressions/proxy.py +0 -549
- additory/expressions/registry.py +0 -313
- additory/expressions/samples.py +0 -492
- additory/synthetic/__init__.py +0 -13
- additory/synthetic/column_name_resolver.py +0 -149
- additory/synthetic/distributions.py +0 -22
- additory/synthetic/forecast.py +0 -1132
- additory/synthetic/linked_list_parser.py +0 -415
- additory/synthetic/namespace_lookup.py +0 -129
- additory/synthetic/smote.py +0 -320
- additory/synthetic/strategies.py +0 -850
- additory/synthetic/synthesizer.py +0 -713
- additory/utilities/__init__.py +0 -53
- additory/utilities/encoding.py +0 -600
- additory/utilities/games.py +0 -300
- additory/utilities/keys.py +0 -8
- additory/utilities/lookup.py +0 -103
- additory/utilities/matchers.py +0 -216
- additory/utilities/resolvers.py +0 -286
- additory/utilities/settings.py +0 -167
- additory/utilities/units.py +0 -749
- additory/utilities/validators.py +0 -153
- additory-0.1.0a3.dist-info/METADATA +0 -288
- additory-0.1.0a3.dist-info/RECORD +0 -71
- additory-0.1.0a3.dist-info/licenses/LICENSE +0 -21
- {additory-0.1.0a3.dist-info → additory-0.1.1a1.dist-info}/WHEEL +0 -0
- {additory-0.1.0a3.dist-info → additory-0.1.1a1.dist-info}/top_level.txt +0 -0
additory/common/validation.py
CHANGED
|
@@ -1,197 +1,377 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Input validation utilities for Additory.
|
|
3
3
|
|
|
4
|
-
Provides consistent validation across all
|
|
4
|
+
Provides consistent validation across all functions with clear error messages.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
from
|
|
9
|
-
from .exceptions import ValidationError
|
|
7
|
+
import re
|
|
8
|
+
from typing import Any, Callable, List
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
def
|
|
11
|
+
def is_dataframe(df: Any) -> bool:
|
|
13
12
|
"""
|
|
14
|
-
|
|
13
|
+
Check if input is a DataFrame (pandas/polars/cuDF).
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
df: Input to check
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
True if input is a DataFrame, False otherwise
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
>>> is_dataframe(pl.DataFrame({'a': [1, 2, 3]}))
|
|
23
|
+
True
|
|
24
|
+
>>> is_dataframe([1, 2, 3])
|
|
25
|
+
False
|
|
26
|
+
"""
|
|
27
|
+
# Check for polars DataFrame
|
|
28
|
+
try:
|
|
29
|
+
import polars as pl
|
|
30
|
+
if isinstance(df, pl.DataFrame):
|
|
31
|
+
return True
|
|
32
|
+
except ImportError:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
# Check for pandas DataFrame
|
|
36
|
+
try:
|
|
37
|
+
import pandas as pd
|
|
38
|
+
if isinstance(df, pd.DataFrame):
|
|
39
|
+
return True
|
|
40
|
+
except ImportError:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
# Check for cuDF DataFrame
|
|
44
|
+
try:
|
|
45
|
+
import cudf
|
|
46
|
+
if isinstance(df, cudf.DataFrame):
|
|
47
|
+
return True
|
|
48
|
+
except ImportError:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def validate_dataframe(df: Any, param_name: str = 'df') -> Any:
|
|
55
|
+
"""
|
|
56
|
+
Validate that input is a DataFrame (pandas/polars/cuDF).
|
|
15
57
|
|
|
16
58
|
Args:
|
|
17
59
|
df: Input to validate
|
|
18
|
-
|
|
60
|
+
param_name: Parameter name for error messages
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Input df if valid
|
|
19
64
|
|
|
20
65
|
Raises:
|
|
21
|
-
|
|
66
|
+
TypeError: If input is not a DataFrame
|
|
22
67
|
|
|
23
|
-
|
|
24
|
-
|
|
68
|
+
Example:
|
|
69
|
+
df = validate_dataframe(df, 'df')
|
|
25
70
|
"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
71
|
+
# Check for polars DataFrame
|
|
72
|
+
try:
|
|
73
|
+
import polars as pl
|
|
74
|
+
if isinstance(df, pl.DataFrame):
|
|
75
|
+
return df
|
|
76
|
+
except ImportError:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
# Check for pandas DataFrame
|
|
80
|
+
try:
|
|
81
|
+
import pandas as pd
|
|
82
|
+
if isinstance(df, pd.DataFrame):
|
|
83
|
+
return df
|
|
84
|
+
except ImportError:
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
# Check for cuDF DataFrame
|
|
88
|
+
try:
|
|
89
|
+
import cudf
|
|
90
|
+
if isinstance(df, cudf.DataFrame):
|
|
91
|
+
return df
|
|
92
|
+
except ImportError:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
# If we get here, it's not a valid DataFrame
|
|
96
|
+
raise TypeError(
|
|
97
|
+
f"Parameter '{param_name}' must be a DataFrame "
|
|
98
|
+
f"(pandas, polars, or cuDF), got {type(df).__name__}"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def validate_not_empty(df: Any, param_name: str = 'df') -> bool:
|
|
103
|
+
"""
|
|
104
|
+
Validate that DataFrame is not empty.
|
|
31
105
|
|
|
32
|
-
|
|
33
|
-
|
|
106
|
+
Args:
|
|
107
|
+
df: DataFrame to check
|
|
108
|
+
param_name: Parameter name for error messages
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
True if not empty
|
|
112
|
+
|
|
113
|
+
Raises:
|
|
114
|
+
ValueError: If DataFrame is empty
|
|
115
|
+
"""
|
|
116
|
+
# Check row count (works for pandas, polars, cuDF)
|
|
117
|
+
if hasattr(df, 'shape'):
|
|
118
|
+
if df.shape[0] == 0:
|
|
119
|
+
raise ValueError(f"Parameter '{param_name}' cannot be empty (0 rows)")
|
|
120
|
+
elif hasattr(df, '__len__'):
|
|
121
|
+
if len(df) == 0:
|
|
122
|
+
raise ValueError(f"Parameter '{param_name}' cannot be empty (0 rows)")
|
|
123
|
+
|
|
124
|
+
return True
|
|
34
125
|
|
|
35
126
|
|
|
36
|
-
def
|
|
37
|
-
df_name: str = "dataframe") -> None:
|
|
127
|
+
def validate_column_name(name: str) -> bool:
|
|
38
128
|
"""
|
|
39
|
-
Validate that
|
|
129
|
+
Validate that column name is valid.
|
|
40
130
|
|
|
41
131
|
Args:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
132
|
+
name: Column name to validate
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
True if valid
|
|
45
136
|
|
|
46
137
|
Raises:
|
|
47
|
-
|
|
138
|
+
ValueError: If column name is invalid
|
|
48
139
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
140
|
+
Rules:
|
|
141
|
+
- Not empty
|
|
142
|
+
- No leading/trailing whitespace
|
|
143
|
+
- No special characters except underscore
|
|
144
|
+
- Not a reserved keyword
|
|
52
145
|
"""
|
|
53
|
-
if
|
|
54
|
-
|
|
146
|
+
if not name:
|
|
147
|
+
raise ValueError("Column name cannot be empty")
|
|
55
148
|
|
|
56
|
-
|
|
57
|
-
|
|
149
|
+
if name != name.strip():
|
|
150
|
+
raise ValueError(f"Column name '{name}' has leading/trailing whitespace")
|
|
58
151
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
f"
|
|
152
|
+
# Check for valid characters (alphanumeric and underscore only)
|
|
153
|
+
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', name):
|
|
154
|
+
raise ValueError(
|
|
155
|
+
f"Column name '{name}' contains invalid characters. "
|
|
156
|
+
"Only alphanumeric and underscore allowed, must start with letter or underscore"
|
|
63
157
|
)
|
|
158
|
+
|
|
159
|
+
# Check for reserved keywords (Python keywords)
|
|
160
|
+
reserved = [
|
|
161
|
+
'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del',
|
|
162
|
+
'elif', 'else', 'except', 'False', 'finally', 'for', 'from', 'global',
|
|
163
|
+
'if', 'import', 'in', 'is', 'lambda', 'None', 'nonlocal', 'not', 'or',
|
|
164
|
+
'pass', 'raise', 'return', 'True', 'try', 'while', 'with', 'yield'
|
|
165
|
+
]
|
|
166
|
+
if name in reserved:
|
|
167
|
+
raise ValueError(f"Column name '{name}' is a reserved keyword")
|
|
168
|
+
|
|
169
|
+
return True
|
|
64
170
|
|
|
65
171
|
|
|
66
|
-
def
|
|
172
|
+
def validate_positive_integer(value: int, param_name: str) -> bool:
|
|
67
173
|
"""
|
|
68
|
-
Validate that value is a positive
|
|
174
|
+
Validate that value is a positive integer.
|
|
69
175
|
|
|
70
176
|
Args:
|
|
71
177
|
value: Value to validate
|
|
72
178
|
param_name: Parameter name for error messages
|
|
73
179
|
|
|
74
|
-
|
|
75
|
-
|
|
180
|
+
Returns:
|
|
181
|
+
True if valid
|
|
76
182
|
|
|
77
|
-
|
|
78
|
-
|
|
183
|
+
Raises:
|
|
184
|
+
TypeError: If value is not an integer
|
|
185
|
+
ValueError: If value is not positive
|
|
79
186
|
"""
|
|
80
|
-
if not isinstance(value,
|
|
81
|
-
raise
|
|
187
|
+
if not isinstance(value, int):
|
|
188
|
+
raise TypeError(f"Parameter '{param_name}' must be an integer, got {type(value).__name__}")
|
|
82
189
|
|
|
83
190
|
if value <= 0:
|
|
84
|
-
raise
|
|
191
|
+
raise ValueError(f"Parameter '{param_name}' must be positive, got {value}")
|
|
192
|
+
|
|
193
|
+
return True
|
|
85
194
|
|
|
86
195
|
|
|
87
|
-
def
|
|
196
|
+
def validate_percentage(value: str) -> bool:
|
|
88
197
|
"""
|
|
89
|
-
Validate that value is a
|
|
198
|
+
Validate that value is a valid percentage string.
|
|
90
199
|
|
|
91
200
|
Args:
|
|
92
|
-
value:
|
|
93
|
-
|
|
201
|
+
value: Percentage string to validate (e.g., '50%')
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
True if valid
|
|
94
205
|
|
|
95
206
|
Raises:
|
|
96
|
-
|
|
207
|
+
ValueError: If percentage is invalid
|
|
97
208
|
|
|
98
|
-
|
|
99
|
-
|
|
209
|
+
Example:
|
|
210
|
+
validate_percentage('50%') # True
|
|
211
|
+
validate_percentage('150%') # True
|
|
212
|
+
validate_percentage('abc') # Raises ValueError
|
|
100
213
|
"""
|
|
101
|
-
if not isinstance(value,
|
|
102
|
-
raise
|
|
214
|
+
if not isinstance(value, str):
|
|
215
|
+
raise ValueError(f"Percentage must be a string, got {type(value).__name__}")
|
|
216
|
+
|
|
217
|
+
if not value.endswith('%'):
|
|
218
|
+
raise ValueError(f"Percentage must end with '%', got '{value}'")
|
|
219
|
+
|
|
220
|
+
# Extract numeric part
|
|
221
|
+
numeric_part = value[:-1].strip()
|
|
103
222
|
|
|
104
|
-
|
|
105
|
-
|
|
223
|
+
try:
|
|
224
|
+
percent = float(numeric_part)
|
|
225
|
+
except ValueError:
|
|
226
|
+
raise ValueError(f"Invalid percentage value: '{value}'")
|
|
227
|
+
|
|
228
|
+
if percent < 0:
|
|
229
|
+
raise ValueError(f"Percentage cannot be negative, got '{value}'")
|
|
230
|
+
|
|
231
|
+
return True
|
|
106
232
|
|
|
107
233
|
|
|
108
|
-
def
|
|
109
|
-
param_name: str) -> None:
|
|
234
|
+
def validate_mode(mode: str, allowed_modes: List[str], param_name: str = 'mode') -> bool:
|
|
110
235
|
"""
|
|
111
|
-
Validate that
|
|
236
|
+
Validate that mode is in allowed list.
|
|
112
237
|
|
|
113
238
|
Args:
|
|
114
|
-
|
|
115
|
-
|
|
239
|
+
mode: Mode to validate
|
|
240
|
+
allowed_modes: List of allowed modes
|
|
116
241
|
param_name: Parameter name for error messages
|
|
117
242
|
|
|
243
|
+
Returns:
|
|
244
|
+
True if valid
|
|
245
|
+
|
|
118
246
|
Raises:
|
|
119
|
-
|
|
247
|
+
ValueError: If mode is not in allowed list
|
|
120
248
|
|
|
121
|
-
|
|
122
|
-
|
|
249
|
+
Example:
|
|
250
|
+
validate_mode('transpose', ['transpose', 'onehotencoding', 'extract'])
|
|
123
251
|
"""
|
|
124
|
-
if
|
|
125
|
-
raise
|
|
126
|
-
f"Invalid {param_name}
|
|
127
|
-
f"Must be one of: {
|
|
252
|
+
if mode not in allowed_modes:
|
|
253
|
+
raise ValueError(
|
|
254
|
+
f"Invalid {param_name} '{mode}'. "
|
|
255
|
+
f"Must be one of: {', '.join(allowed_modes)}"
|
|
128
256
|
)
|
|
257
|
+
|
|
258
|
+
return True
|
|
129
259
|
|
|
130
260
|
|
|
131
|
-
def
|
|
261
|
+
def validate_dict(value: Any, param_name: str) -> bool:
|
|
132
262
|
"""
|
|
133
|
-
Validate that value is a
|
|
263
|
+
Validate that value is a dictionary.
|
|
134
264
|
|
|
135
265
|
Args:
|
|
136
266
|
value: Value to validate
|
|
137
267
|
param_name: Parameter name for error messages
|
|
138
268
|
|
|
139
|
-
|
|
140
|
-
|
|
269
|
+
Returns:
|
|
270
|
+
True if valid
|
|
141
271
|
|
|
142
|
-
|
|
143
|
-
|
|
272
|
+
Raises:
|
|
273
|
+
TypeError: If value is not a dictionary
|
|
144
274
|
"""
|
|
145
|
-
if not isinstance(value,
|
|
146
|
-
raise
|
|
275
|
+
if not isinstance(value, dict):
|
|
276
|
+
raise TypeError(
|
|
277
|
+
f"Parameter '{param_name}' must be a dictionary, got {type(value).__name__}"
|
|
278
|
+
)
|
|
147
279
|
|
|
148
|
-
|
|
149
|
-
raise ValidationError(f"{param_name} must be between 0.0 and 1.0, got {value}")
|
|
280
|
+
return True
|
|
150
281
|
|
|
151
282
|
|
|
152
|
-
def
|
|
283
|
+
def validate_list(value: Any, param_name: str, allow_empty: bool = False) -> bool:
|
|
153
284
|
"""
|
|
154
|
-
Validate that
|
|
285
|
+
Validate that value is a list.
|
|
155
286
|
|
|
156
287
|
Args:
|
|
157
|
-
value:
|
|
288
|
+
value: Value to validate
|
|
158
289
|
param_name: Parameter name for error messages
|
|
290
|
+
allow_empty: Whether to allow empty lists
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
True if valid
|
|
159
294
|
|
|
160
295
|
Raises:
|
|
161
|
-
|
|
296
|
+
TypeError: If value is not a list
|
|
297
|
+
ValueError: If list is empty and allow_empty is False
|
|
298
|
+
"""
|
|
299
|
+
if not isinstance(value, list):
|
|
300
|
+
raise TypeError(
|
|
301
|
+
f"Parameter '{param_name}' must be a list, got {type(value).__name__}"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
if not allow_empty and len(value) == 0:
|
|
305
|
+
raise ValueError(f"Parameter '{param_name}' cannot be an empty list")
|
|
306
|
+
|
|
307
|
+
return True
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def validate_string(value: Any, param_name: str, allow_empty: bool = False) -> bool:
|
|
311
|
+
"""
|
|
312
|
+
Validate that value is a string.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
value: Value to validate
|
|
316
|
+
param_name: Parameter name for error messages
|
|
317
|
+
allow_empty: Whether to allow empty strings
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
True if valid
|
|
162
321
|
|
|
163
|
-
|
|
164
|
-
|
|
322
|
+
Raises:
|
|
323
|
+
TypeError: If value is not a string
|
|
324
|
+
ValueError: If string is empty and allow_empty is False
|
|
165
325
|
"""
|
|
166
326
|
if not isinstance(value, str):
|
|
167
|
-
raise
|
|
327
|
+
raise TypeError(
|
|
328
|
+
f"Parameter '{param_name}' must be a string, got {type(value).__name__}"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
if not allow_empty and len(value) == 0:
|
|
332
|
+
raise ValueError(f"Parameter '{param_name}' cannot be an empty string")
|
|
168
333
|
|
|
169
|
-
|
|
170
|
-
raise ValidationError(f"{param_name} cannot be empty")
|
|
334
|
+
return True
|
|
171
335
|
|
|
172
336
|
|
|
173
|
-
def
|
|
174
|
-
min_val: int = None, max_val: int = None) -> None:
|
|
337
|
+
def validate_boolean(value: Any, param_name: str) -> bool:
|
|
175
338
|
"""
|
|
176
|
-
Validate that
|
|
339
|
+
Validate that value is a boolean.
|
|
177
340
|
|
|
178
341
|
Args:
|
|
179
|
-
value:
|
|
342
|
+
value: Value to validate
|
|
180
343
|
param_name: Parameter name for error messages
|
|
181
|
-
min_val: Minimum allowed value (inclusive)
|
|
182
|
-
max_val: Maximum allowed value (inclusive)
|
|
183
344
|
|
|
184
|
-
|
|
185
|
-
|
|
345
|
+
Returns:
|
|
346
|
+
True if valid
|
|
186
347
|
|
|
187
|
-
|
|
188
|
-
|
|
348
|
+
Raises:
|
|
349
|
+
TypeError: If value is not a boolean
|
|
189
350
|
"""
|
|
190
|
-
if not isinstance(value,
|
|
191
|
-
raise
|
|
351
|
+
if not isinstance(value, bool):
|
|
352
|
+
raise TypeError(
|
|
353
|
+
f"Parameter '{param_name}' must be a boolean, got {type(value).__name__}"
|
|
354
|
+
)
|
|
192
355
|
|
|
193
|
-
|
|
194
|
-
|
|
356
|
+
return True
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def validate_optional(value: Any, validator: Callable, param_name: str) -> bool:
|
|
360
|
+
"""
|
|
361
|
+
Validate optional parameter (None or valid value).
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
value: Value to validate
|
|
365
|
+
validator: Validation function to use if not None
|
|
366
|
+
param_name: Parameter name for error messages
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
True if valid (None or passes validator)
|
|
370
|
+
|
|
371
|
+
Example:
|
|
372
|
+
validate_optional(strategy, validate_dict, 'strategy')
|
|
373
|
+
"""
|
|
374
|
+
if value is None:
|
|
375
|
+
return True
|
|
195
376
|
|
|
196
|
-
|
|
197
|
-
raise ValidationError(f"{param_name} must be <= {max_val}, got {value}")
|
|
377
|
+
return validator(value, param_name)
|
additory/core/__init__.py
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"""
|
|
2
|
+
Core infrastructure for Additory.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
This module provides essential infrastructure components:
|
|
5
|
+
- logging: Transparent logging system
|
|
6
|
+
- memory_manager: Memory cleanup utilities
|
|
7
|
+
- backend: Backend detection and conversion
|
|
8
|
+
- config: Global configuration settings
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .logging import Logger, get_logger, set_log_level
|
|
12
|
+
from .memory_manager import (
|
|
13
|
+
MemoryManager,
|
|
14
|
+
get_memory_manager,
|
|
15
|
+
cleanup_after_operation,
|
|
16
|
+
estimate_memory_usage
|
|
17
|
+
)
|
|
18
|
+
from .config import (
|
|
19
|
+
Config,
|
|
20
|
+
get_config,
|
|
21
|
+
set_expressions_folder,
|
|
22
|
+
set_default_backend,
|
|
23
|
+
derive_namespace_from_path
|
|
10
24
|
)
|
|
11
|
-
from .loader import load_expression
|
|
12
|
-
from .parser import parse_expression
|
|
13
|
-
from .validator import validate_expression
|
|
14
|
-
from .logging import log_info, log_warning
|
|
15
25
|
|
|
16
26
|
__all__ = [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
'Logger',
|
|
28
|
+
'get_logger',
|
|
29
|
+
'set_log_level',
|
|
30
|
+
'MemoryManager',
|
|
31
|
+
'get_memory_manager',
|
|
32
|
+
'cleanup_after_operation',
|
|
33
|
+
'estimate_memory_usage',
|
|
34
|
+
'Config',
|
|
35
|
+
'get_config',
|
|
36
|
+
'set_expressions_folder',
|
|
37
|
+
'set_default_backend',
|
|
38
|
+
'derive_namespace_from_path'
|
|
27
39
|
]
|