additory 0.1.0a4__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 -177
- 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 -352
- 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/deduce.py +0 -259
- 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 -926
- 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.0a4.dist-info/METADATA +0 -311
- additory-0.1.0a4.dist-info/RECORD +0 -72
- additory-0.1.0a4.dist-info/licenses/LICENSE +0 -21
- {additory-0.1.0a4.dist-info → additory-0.1.1a1.dist-info}/WHEEL +0 -0
- {additory-0.1.0a4.dist-info → additory-0.1.1a1.dist-info}/top_level.txt +0 -0
additory/common/resolver.py
DELETED
|
@@ -1,567 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Pattern Resolution with Fallback Logic
|
|
3
|
-
|
|
4
|
-
Implements the fallback resolution hierarchy for pattern lookup:
|
|
5
|
-
1. User namespace patterns (if enabled, based on priority)
|
|
6
|
-
2. Imported .list files (non-global)
|
|
7
|
-
3. global.list (built-in)
|
|
8
|
-
4. Imported .properties files (non-global)
|
|
9
|
-
5. global.properties (built-in)
|
|
10
|
-
6. Error if not found
|
|
11
|
-
|
|
12
|
-
User namespace priority options:
|
|
13
|
-
- "highest": Check user namespace first (before everything)
|
|
14
|
-
- "before_imports": Check user namespace before imports (default)
|
|
15
|
-
- "after_imports": Check user namespace after imports
|
|
16
|
-
- "lowest": Check user namespace last (after everything)
|
|
17
|
-
|
|
18
|
-
Usage:
|
|
19
|
-
from additory.common.resolver import resolve_pattern, PreferMode
|
|
20
|
-
|
|
21
|
-
# Without user namespace
|
|
22
|
-
result = resolve_pattern(
|
|
23
|
-
pattern_name="first_names",
|
|
24
|
-
imports=["global", "finance"],
|
|
25
|
-
prefer_mode=PreferMode.DEFAULT,
|
|
26
|
-
base_path="reference/schema_definitions"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
# With user namespace
|
|
30
|
-
from additory.common.resolver import PatternResolver
|
|
31
|
-
|
|
32
|
-
resolver = PatternResolver(
|
|
33
|
-
base_path="reference/schema_definitions",
|
|
34
|
-
enable_user_namespace=True,
|
|
35
|
-
user_namespace_priority="before_imports"
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
result = resolver.resolve("my_custom_pattern", ["global"])
|
|
39
|
-
|
|
40
|
-
if result.found:
|
|
41
|
-
print(f"Found in: {result.source}")
|
|
42
|
-
print(f"Type: {result.pattern_type}")
|
|
43
|
-
print(f"Value: {result.value}")
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
from typing import Union, List, Optional, Dict
|
|
47
|
-
from pathlib import Path
|
|
48
|
-
from dataclasses import dataclass
|
|
49
|
-
from enum import Enum
|
|
50
|
-
import logging
|
|
51
|
-
|
|
52
|
-
from .lists import load_list_file, get_list_values, ListFileError
|
|
53
|
-
from .patterns import load_properties_file, get_pattern, PatternFileError
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Configure logging
|
|
57
|
-
logger = logging.getLogger(__name__)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class PreferMode(Enum):
|
|
61
|
-
"""Pattern resolution preference modes."""
|
|
62
|
-
DEFAULT = "default" # Lists first, regex fallback
|
|
63
|
-
LIST_ONLY = "list_only" # Lists only, error if not found
|
|
64
|
-
REGEX_ONLY = "regex_only" # Regex only, error if not found
|
|
65
|
-
USER_ONLY = "user_only" # User namespace only (Phase II)
|
|
66
|
-
BUILTIN_ONLY = "builtin_only" # Built-in patterns only (no user namespace)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
@dataclass
|
|
70
|
-
class PatternResolutionResult:
|
|
71
|
-
"""Result of pattern resolution."""
|
|
72
|
-
found: bool
|
|
73
|
-
value: Optional[Union[List[str], str]] = None
|
|
74
|
-
pattern_type: Optional[str] = None # "list" or "regex"
|
|
75
|
-
source: Optional[str] = None # File where pattern was found
|
|
76
|
-
fallback_used: bool = False
|
|
77
|
-
error_message: Optional[str] = None
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class PatternResolver:
|
|
81
|
-
"""
|
|
82
|
-
Resolves patterns with fallback logic.
|
|
83
|
-
|
|
84
|
-
Implements the fallback hierarchy:
|
|
85
|
-
1. User namespace patterns (if enabled)
|
|
86
|
-
2. Imported .list files (non-global)
|
|
87
|
-
3. global.list
|
|
88
|
-
4. Imported .properties files (non-global)
|
|
89
|
-
5. global.properties
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
def __init__(
|
|
93
|
-
self,
|
|
94
|
-
base_path: str = "reference/schema_definitions",
|
|
95
|
-
enable_user_namespace: bool = False,
|
|
96
|
-
user_namespace_priority: str = "before_imports",
|
|
97
|
-
user_namespace_manager=None
|
|
98
|
-
):
|
|
99
|
-
"""
|
|
100
|
-
Initialize resolver.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
base_path: Base directory for .list and .properties files
|
|
104
|
-
enable_user_namespace: Enable user namespace resolution
|
|
105
|
-
user_namespace_priority: User namespace priority
|
|
106
|
-
- "before_imports": Check user namespace before imports
|
|
107
|
-
- "after_imports": Check user namespace after imports
|
|
108
|
-
- "highest": Check user namespace first (before everything)
|
|
109
|
-
- "lowest": Check user namespace last (after everything)
|
|
110
|
-
user_namespace_manager: Optional UserNamespaceManager instance
|
|
111
|
-
"""
|
|
112
|
-
self.base_path = Path(base_path)
|
|
113
|
-
self.enable_user_namespace = enable_user_namespace
|
|
114
|
-
self.user_namespace_priority = user_namespace_priority
|
|
115
|
-
self._list_cache: Dict[str, Dict[str, List[str]]] = {}
|
|
116
|
-
self._pattern_cache: Dict[str, Dict[str, str]] = {}
|
|
117
|
-
self._user_namespace_manager = user_namespace_manager
|
|
118
|
-
|
|
119
|
-
# Initialize user namespace if enabled and not provided
|
|
120
|
-
if self.enable_user_namespace and self._user_namespace_manager is None:
|
|
121
|
-
try:
|
|
122
|
-
from additory.core.user_namespace import get_user_namespace_manager
|
|
123
|
-
self._user_namespace_manager = get_user_namespace_manager()
|
|
124
|
-
if self._user_namespace_manager.is_initialized():
|
|
125
|
-
logger.info("User namespace enabled and initialized")
|
|
126
|
-
else:
|
|
127
|
-
logger.warning("User namespace enabled but not initialized")
|
|
128
|
-
except ImportError:
|
|
129
|
-
logger.warning("User namespace module not available")
|
|
130
|
-
self.enable_user_namespace = False
|
|
131
|
-
|
|
132
|
-
def _load_list_file_cached(self, filename: str) -> Optional[Dict[str, List[str]]]:
|
|
133
|
-
"""Load .list file with caching."""
|
|
134
|
-
if filename in self._list_cache:
|
|
135
|
-
return self._list_cache[filename]
|
|
136
|
-
|
|
137
|
-
filepath = self.base_path / filename
|
|
138
|
-
|
|
139
|
-
try:
|
|
140
|
-
lists = load_list_file(str(filepath))
|
|
141
|
-
self._list_cache[filename] = lists
|
|
142
|
-
return lists
|
|
143
|
-
except ListFileError as e:
|
|
144
|
-
logger.debug(f"Failed to load {filename}: {e}")
|
|
145
|
-
return None
|
|
146
|
-
|
|
147
|
-
def _load_properties_file_cached(self, filename: str) -> Optional[Dict[str, str]]:
|
|
148
|
-
"""Load .properties file with caching."""
|
|
149
|
-
if filename in self._pattern_cache:
|
|
150
|
-
return self._pattern_cache[filename]
|
|
151
|
-
|
|
152
|
-
filepath = self.base_path / filename
|
|
153
|
-
|
|
154
|
-
try:
|
|
155
|
-
patterns = load_properties_file(str(filepath))
|
|
156
|
-
self._pattern_cache[filename] = patterns
|
|
157
|
-
return patterns
|
|
158
|
-
except PatternFileError as e:
|
|
159
|
-
logger.debug(f"Failed to load {filename}: {e}")
|
|
160
|
-
return None
|
|
161
|
-
|
|
162
|
-
def resolve_from_lists(
|
|
163
|
-
self,
|
|
164
|
-
pattern_name: str,
|
|
165
|
-
imports: List[str]
|
|
166
|
-
) -> PatternResolutionResult:
|
|
167
|
-
"""
|
|
168
|
-
Resolve pattern from .list files.
|
|
169
|
-
|
|
170
|
-
Priority:
|
|
171
|
-
1. Imported .list files (non-global)
|
|
172
|
-
2. global.list
|
|
173
|
-
"""
|
|
174
|
-
# Check imported .list files (non-global)
|
|
175
|
-
for import_name in imports:
|
|
176
|
-
if import_name == "global":
|
|
177
|
-
continue # Skip global, check it last
|
|
178
|
-
|
|
179
|
-
filename = f"{import_name}.list"
|
|
180
|
-
lists = self._load_list_file_cached(filename)
|
|
181
|
-
|
|
182
|
-
if lists:
|
|
183
|
-
values = get_list_values(pattern_name, lists)
|
|
184
|
-
if values:
|
|
185
|
-
logger.info(f"✓ Found '{pattern_name}' in {filename}")
|
|
186
|
-
return PatternResolutionResult(
|
|
187
|
-
found=True,
|
|
188
|
-
value=values,
|
|
189
|
-
pattern_type="list",
|
|
190
|
-
source=filename,
|
|
191
|
-
fallback_used=False
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
# Check global.list (fallback)
|
|
195
|
-
lists = self._load_list_file_cached("global.list")
|
|
196
|
-
if lists:
|
|
197
|
-
values = get_list_values(pattern_name, lists)
|
|
198
|
-
if values:
|
|
199
|
-
logger.info(f"✓ Found '{pattern_name}' in global.list (fallback)")
|
|
200
|
-
return PatternResolutionResult(
|
|
201
|
-
found=True,
|
|
202
|
-
value=values,
|
|
203
|
-
pattern_type="list",
|
|
204
|
-
source="global.list",
|
|
205
|
-
fallback_used=True
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
return PatternResolutionResult(found=False)
|
|
209
|
-
|
|
210
|
-
def resolve_from_patterns(
|
|
211
|
-
self,
|
|
212
|
-
pattern_name: str,
|
|
213
|
-
imports: List[str]
|
|
214
|
-
) -> PatternResolutionResult:
|
|
215
|
-
"""
|
|
216
|
-
Resolve pattern from .properties files.
|
|
217
|
-
|
|
218
|
-
Priority:
|
|
219
|
-
1. Imported .properties files (non-global)
|
|
220
|
-
2. global.properties
|
|
221
|
-
"""
|
|
222
|
-
# Check imported .properties files (non-global)
|
|
223
|
-
for import_name in imports:
|
|
224
|
-
if import_name == "global":
|
|
225
|
-
continue # Skip global, check it last
|
|
226
|
-
|
|
227
|
-
filename = f"{import_name}.properties"
|
|
228
|
-
patterns = self._load_properties_file_cached(filename)
|
|
229
|
-
|
|
230
|
-
if patterns:
|
|
231
|
-
pattern = get_pattern(pattern_name, patterns)
|
|
232
|
-
if pattern:
|
|
233
|
-
logger.info(f"✓ Found '{pattern_name}' in {filename}")
|
|
234
|
-
return PatternResolutionResult(
|
|
235
|
-
found=True,
|
|
236
|
-
value=pattern,
|
|
237
|
-
pattern_type="regex",
|
|
238
|
-
source=filename,
|
|
239
|
-
fallback_used=False
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
# Check global.properties (fallback)
|
|
243
|
-
patterns = self._load_properties_file_cached("global.properties")
|
|
244
|
-
if patterns:
|
|
245
|
-
pattern = get_pattern(pattern_name, patterns)
|
|
246
|
-
if pattern:
|
|
247
|
-
logger.info(f"✓ Found '{pattern_name}' in global.properties (fallback)")
|
|
248
|
-
return PatternResolutionResult(
|
|
249
|
-
found=True,
|
|
250
|
-
value=pattern,
|
|
251
|
-
pattern_type="regex",
|
|
252
|
-
source="global.properties",
|
|
253
|
-
fallback_used=True
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
return PatternResolutionResult(found=False)
|
|
257
|
-
|
|
258
|
-
def resolve(
|
|
259
|
-
self,
|
|
260
|
-
pattern_name: str,
|
|
261
|
-
imports: List[str],
|
|
262
|
-
prefer_mode: PreferMode = PreferMode.DEFAULT
|
|
263
|
-
) -> PatternResolutionResult:
|
|
264
|
-
"""
|
|
265
|
-
Resolve pattern with fallback logic including user namespace.
|
|
266
|
-
|
|
267
|
-
Resolution hierarchy (with user namespace enabled):
|
|
268
|
-
1. User namespace (if priority = "highest" or "before_imports")
|
|
269
|
-
2. Imported .list files (non-global)
|
|
270
|
-
3. global.list
|
|
271
|
-
4. User namespace (if priority = "after_imports")
|
|
272
|
-
5. Imported .properties files (non-global)
|
|
273
|
-
6. global.properties
|
|
274
|
-
7. User namespace (if priority = "lowest")
|
|
275
|
-
|
|
276
|
-
Args:
|
|
277
|
-
pattern_name: Name of pattern to resolve
|
|
278
|
-
imports: List of imports from TOML (e.g., ["global", "finance"])
|
|
279
|
-
prefer_mode: Resolution preference mode
|
|
280
|
-
|
|
281
|
-
Returns:
|
|
282
|
-
PatternResolutionResult with resolution details
|
|
283
|
-
"""
|
|
284
|
-
logger.info(f"Resolving pattern '{pattern_name}' with mode {prefer_mode.value}")
|
|
285
|
-
|
|
286
|
-
# Mode: user_only
|
|
287
|
-
if prefer_mode == PreferMode.USER_ONLY:
|
|
288
|
-
result = self.resolve_from_user_namespace(pattern_name)
|
|
289
|
-
if not result.found:
|
|
290
|
-
result.error_message = f"Pattern '{pattern_name}' not found in user namespace"
|
|
291
|
-
return result
|
|
292
|
-
|
|
293
|
-
# Mode: builtin_only (disable user namespace for this resolution)
|
|
294
|
-
elif prefer_mode == PreferMode.BUILTIN_ONLY:
|
|
295
|
-
# Temporarily disable user namespace
|
|
296
|
-
original_enable = self.enable_user_namespace
|
|
297
|
-
self.enable_user_namespace = False
|
|
298
|
-
|
|
299
|
-
try:
|
|
300
|
-
# Use default resolution without user namespace
|
|
301
|
-
result = self._resolve_builtin(pattern_name, imports)
|
|
302
|
-
return result
|
|
303
|
-
finally:
|
|
304
|
-
self.enable_user_namespace = original_enable
|
|
305
|
-
|
|
306
|
-
# Mode: list_only
|
|
307
|
-
elif prefer_mode == PreferMode.LIST_ONLY:
|
|
308
|
-
result = self._resolve_with_user_namespace(
|
|
309
|
-
pattern_name, imports, lists_only=True
|
|
310
|
-
)
|
|
311
|
-
if not result.found:
|
|
312
|
-
result.error_message = f"Pattern '{pattern_name}' not found in any .list file"
|
|
313
|
-
return result
|
|
314
|
-
|
|
315
|
-
# Mode: regex_only
|
|
316
|
-
elif prefer_mode == PreferMode.REGEX_ONLY:
|
|
317
|
-
result = self._resolve_with_user_namespace(
|
|
318
|
-
pattern_name, imports, regex_only=True
|
|
319
|
-
)
|
|
320
|
-
if not result.found:
|
|
321
|
-
result.error_message = f"Pattern '{pattern_name}' not found in any .properties file"
|
|
322
|
-
return result
|
|
323
|
-
|
|
324
|
-
# Mode: default (lists first, regex fallback, with user namespace)
|
|
325
|
-
else:
|
|
326
|
-
result = self._resolve_with_user_namespace(pattern_name, imports)
|
|
327
|
-
|
|
328
|
-
if not result.found:
|
|
329
|
-
result.error_message = (
|
|
330
|
-
f"Pattern '{pattern_name}' not found in any .list or .properties file"
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
return result
|
|
334
|
-
|
|
335
|
-
def _resolve_builtin(
|
|
336
|
-
self,
|
|
337
|
-
pattern_name: str,
|
|
338
|
-
imports: List[str]
|
|
339
|
-
) -> PatternResolutionResult:
|
|
340
|
-
"""
|
|
341
|
-
Resolve pattern from built-in patterns only (no user namespace).
|
|
342
|
-
|
|
343
|
-
Used for BUILTIN_ONLY mode.
|
|
344
|
-
"""
|
|
345
|
-
# Try lists first
|
|
346
|
-
result = self.resolve_from_lists(pattern_name, imports)
|
|
347
|
-
if result.found:
|
|
348
|
-
return result
|
|
349
|
-
|
|
350
|
-
# Fallback to regex
|
|
351
|
-
logger.warning(f"'{pattern_name}' not found in any .list file, trying .properties")
|
|
352
|
-
result = self.resolve_from_patterns(pattern_name, imports)
|
|
353
|
-
|
|
354
|
-
if result.found:
|
|
355
|
-
result.fallback_used = True
|
|
356
|
-
|
|
357
|
-
return result
|
|
358
|
-
|
|
359
|
-
def _resolve_with_user_namespace(
|
|
360
|
-
self,
|
|
361
|
-
pattern_name: str,
|
|
362
|
-
imports: List[str],
|
|
363
|
-
lists_only: bool = False,
|
|
364
|
-
regex_only: bool = False
|
|
365
|
-
) -> PatternResolutionResult:
|
|
366
|
-
"""
|
|
367
|
-
Resolve pattern with user namespace support.
|
|
368
|
-
|
|
369
|
-
Implements the full resolution hierarchy based on user_namespace_priority.
|
|
370
|
-
"""
|
|
371
|
-
# Priority: highest (check user namespace first)
|
|
372
|
-
if self.enable_user_namespace and self.user_namespace_priority == "highest":
|
|
373
|
-
result = self.resolve_from_user_namespace(pattern_name)
|
|
374
|
-
if result.found:
|
|
375
|
-
return result
|
|
376
|
-
|
|
377
|
-
# Priority: before_imports (check user namespace before imports)
|
|
378
|
-
if self.enable_user_namespace and self.user_namespace_priority == "before_imports":
|
|
379
|
-
result = self.resolve_from_user_namespace(pattern_name)
|
|
380
|
-
if result.found:
|
|
381
|
-
return result
|
|
382
|
-
|
|
383
|
-
# Check lists (unless regex_only)
|
|
384
|
-
if not regex_only:
|
|
385
|
-
result = self.resolve_from_lists(pattern_name, imports)
|
|
386
|
-
if result.found:
|
|
387
|
-
return result
|
|
388
|
-
|
|
389
|
-
# Priority: after_imports (check user namespace after imports, before global)
|
|
390
|
-
if self.enable_user_namespace and self.user_namespace_priority == "after_imports":
|
|
391
|
-
result = self.resolve_from_user_namespace(pattern_name)
|
|
392
|
-
if result.found:
|
|
393
|
-
result.fallback_used = True
|
|
394
|
-
return result
|
|
395
|
-
|
|
396
|
-
# Check regex patterns (unless lists_only)
|
|
397
|
-
if not lists_only:
|
|
398
|
-
logger.warning(f"'{pattern_name}' not found in any .list file, trying .properties")
|
|
399
|
-
result = self.resolve_from_patterns(pattern_name, imports)
|
|
400
|
-
if result.found:
|
|
401
|
-
result.fallback_used = True
|
|
402
|
-
return result
|
|
403
|
-
|
|
404
|
-
# Priority: lowest (check user namespace last)
|
|
405
|
-
if self.enable_user_namespace and self.user_namespace_priority == "lowest":
|
|
406
|
-
result = self.resolve_from_user_namespace(pattern_name)
|
|
407
|
-
if result.found:
|
|
408
|
-
result.fallback_used = True
|
|
409
|
-
return result
|
|
410
|
-
|
|
411
|
-
# Not found anywhere
|
|
412
|
-
return PatternResolutionResult(found=False)
|
|
413
|
-
|
|
414
|
-
def clear_cache(self):
|
|
415
|
-
"""Clear cached files (useful for testing)."""
|
|
416
|
-
self._list_cache.clear()
|
|
417
|
-
self._pattern_cache.clear()
|
|
418
|
-
if self._user_namespace_manager:
|
|
419
|
-
self._user_namespace_manager.clear_cache()
|
|
420
|
-
|
|
421
|
-
def resolve_from_user_namespace(
|
|
422
|
-
self,
|
|
423
|
-
pattern_name: str
|
|
424
|
-
) -> PatternResolutionResult:
|
|
425
|
-
"""
|
|
426
|
-
Resolve pattern from user namespace.
|
|
427
|
-
|
|
428
|
-
Checks user .list and .properties files.
|
|
429
|
-
"""
|
|
430
|
-
if not self.enable_user_namespace or not self._user_namespace_manager:
|
|
431
|
-
return PatternResolutionResult(found=False)
|
|
432
|
-
|
|
433
|
-
try:
|
|
434
|
-
# Get all user patterns
|
|
435
|
-
user_lists, user_properties = self._user_namespace_manager.get_all_user_patterns()
|
|
436
|
-
|
|
437
|
-
# Check user lists first
|
|
438
|
-
if pattern_name in user_lists:
|
|
439
|
-
logger.info(f"✓ Found '{pattern_name}' in user namespace (list)")
|
|
440
|
-
return PatternResolutionResult(
|
|
441
|
-
found=True,
|
|
442
|
-
value=user_lists[pattern_name],
|
|
443
|
-
pattern_type="list",
|
|
444
|
-
source="user:namespace",
|
|
445
|
-
fallback_used=False
|
|
446
|
-
)
|
|
447
|
-
|
|
448
|
-
# Check user properties
|
|
449
|
-
if pattern_name in user_properties:
|
|
450
|
-
logger.info(f"✓ Found '{pattern_name}' in user namespace (regex)")
|
|
451
|
-
return PatternResolutionResult(
|
|
452
|
-
found=True,
|
|
453
|
-
value=user_properties[pattern_name],
|
|
454
|
-
pattern_type="regex",
|
|
455
|
-
source="user:namespace",
|
|
456
|
-
fallback_used=False
|
|
457
|
-
)
|
|
458
|
-
|
|
459
|
-
except Exception as e:
|
|
460
|
-
logger.warning(f"Error resolving from user namespace: {e}")
|
|
461
|
-
|
|
462
|
-
return PatternResolutionResult(found=False)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
# Global resolver instance
|
|
466
|
-
_resolver = None
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
def get_resolver(
|
|
470
|
-
base_path: str = "reference/schema_definitions",
|
|
471
|
-
enable_user_namespace: bool = False,
|
|
472
|
-
user_namespace_priority: str = "before_imports"
|
|
473
|
-
) -> PatternResolver:
|
|
474
|
-
"""
|
|
475
|
-
Get or create global resolver instance.
|
|
476
|
-
|
|
477
|
-
Args:
|
|
478
|
-
base_path: Base directory for pattern files
|
|
479
|
-
enable_user_namespace: Enable user namespace resolution
|
|
480
|
-
user_namespace_priority: User namespace priority
|
|
481
|
-
|
|
482
|
-
Returns:
|
|
483
|
-
PatternResolver instance
|
|
484
|
-
"""
|
|
485
|
-
global _resolver
|
|
486
|
-
if _resolver is None:
|
|
487
|
-
_resolver = PatternResolver(
|
|
488
|
-
base_path,
|
|
489
|
-
enable_user_namespace,
|
|
490
|
-
user_namespace_priority
|
|
491
|
-
)
|
|
492
|
-
return _resolver
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
def resolve_pattern(
|
|
496
|
-
pattern_name: str,
|
|
497
|
-
imports: List[str],
|
|
498
|
-
prefer_mode: PreferMode = PreferMode.DEFAULT,
|
|
499
|
-
base_path: str = "reference/schema_definitions",
|
|
500
|
-
enable_user_namespace: bool = False,
|
|
501
|
-
user_namespace_priority: str = "before_imports"
|
|
502
|
-
) -> PatternResolutionResult:
|
|
503
|
-
"""
|
|
504
|
-
Resolve pattern with fallback logic (convenience function).
|
|
505
|
-
|
|
506
|
-
Args:
|
|
507
|
-
pattern_name: Name of pattern to resolve
|
|
508
|
-
imports: List of imports from TOML
|
|
509
|
-
prefer_mode: Resolution preference mode
|
|
510
|
-
base_path: Base directory for pattern files
|
|
511
|
-
enable_user_namespace: Enable user namespace resolution
|
|
512
|
-
user_namespace_priority: User namespace priority
|
|
513
|
-
|
|
514
|
-
Returns:
|
|
515
|
-
PatternResolutionResult
|
|
516
|
-
|
|
517
|
-
Example:
|
|
518
|
-
>>> result = resolve_pattern("first_names", ["global"], PreferMode.DEFAULT)
|
|
519
|
-
>>> if result.found:
|
|
520
|
-
... print(f"Found in {result.source}: {result.value[:3]}")
|
|
521
|
-
Found in global.list: ['Arjun', 'Vikram', 'Samuel']
|
|
522
|
-
|
|
523
|
-
>>> # With user namespace
|
|
524
|
-
>>> result = resolve_pattern(
|
|
525
|
-
... "my_custom_pattern",
|
|
526
|
-
... ["global"],
|
|
527
|
-
... enable_user_namespace=True
|
|
528
|
-
... )
|
|
529
|
-
>>> if result.found:
|
|
530
|
-
... print(f"Found in {result.source}")
|
|
531
|
-
Found in user:namespace
|
|
532
|
-
"""
|
|
533
|
-
resolver = get_resolver(base_path, enable_user_namespace, user_namespace_priority)
|
|
534
|
-
return resolver.resolve(pattern_name, imports, prefer_mode)
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
def resolve_with_logging(
|
|
538
|
-
pattern_name: str,
|
|
539
|
-
imports: List[str],
|
|
540
|
-
prefer_mode: PreferMode = PreferMode.DEFAULT,
|
|
541
|
-
base_path: str = "reference/schema_definitions"
|
|
542
|
-
) -> PatternResolutionResult:
|
|
543
|
-
"""
|
|
544
|
-
Resolve pattern with detailed logging (convenience function).
|
|
545
|
-
|
|
546
|
-
Same as resolve_pattern but with INFO-level logging enabled.
|
|
547
|
-
"""
|
|
548
|
-
# Temporarily set logging level to INFO
|
|
549
|
-
original_level = logger.level
|
|
550
|
-
logger.setLevel(logging.INFO)
|
|
551
|
-
|
|
552
|
-
try:
|
|
553
|
-
result = resolve_pattern(pattern_name, imports, prefer_mode, base_path)
|
|
554
|
-
|
|
555
|
-
# Log result
|
|
556
|
-
if result.found:
|
|
557
|
-
logger.info(f"Resolution successful:")
|
|
558
|
-
logger.info(f" Pattern: {pattern_name}")
|
|
559
|
-
logger.info(f" Source: {result.source}")
|
|
560
|
-
logger.info(f" Type: {result.pattern_type}")
|
|
561
|
-
logger.info(f" Fallback used: {result.fallback_used}")
|
|
562
|
-
else:
|
|
563
|
-
logger.error(f"Resolution failed: {result.error_message}")
|
|
564
|
-
|
|
565
|
-
return result
|
|
566
|
-
finally:
|
|
567
|
-
logger.setLevel(original_level)
|