additory 0.1.0a2__py3-none-any.whl → 0.1.0a3__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.
Files changed (43) hide show
  1. additory/__init__.py +4 -0
  2. additory/common/__init__.py +2 -2
  3. additory/common/backend.py +20 -4
  4. additory/common/distributions.py +1 -1
  5. additory/common/sample_data.py +19 -19
  6. additory/core/backends/arrow_bridge.py +7 -0
  7. additory/core/polars_expression_engine.py +66 -16
  8. additory/dynamic_api.py +42 -46
  9. additory/expressions/proxy.py +4 -1
  10. additory/synthetic/__init__.py +7 -95
  11. additory/synthetic/column_name_resolver.py +149 -0
  12. additory/{augment → synthetic}/distributions.py +2 -2
  13. additory/{augment → synthetic}/forecast.py +1 -1
  14. additory/synthetic/linked_list_parser.py +415 -0
  15. additory/synthetic/namespace_lookup.py +129 -0
  16. additory/{augment → synthetic}/smote.py +1 -1
  17. additory/{augment → synthetic}/strategies.py +11 -44
  18. additory/{augment/augmentor.py → synthetic/synthesizer.py} +75 -15
  19. additory/utilities/units.py +4 -1
  20. {additory-0.1.0a2.dist-info → additory-0.1.0a3.dist-info}/METADATA +10 -17
  21. {additory-0.1.0a2.dist-info → additory-0.1.0a3.dist-info}/RECORD +24 -40
  22. {additory-0.1.0a2.dist-info → additory-0.1.0a3.dist-info}/WHEEL +1 -1
  23. additory/augment/__init__.py +0 -24
  24. additory/augment/builtin_lists.py +0 -430
  25. additory/augment/list_registry.py +0 -177
  26. additory/synthetic/api.py +0 -220
  27. additory/synthetic/common_integration.py +0 -314
  28. additory/synthetic/config.py +0 -262
  29. additory/synthetic/engines.py +0 -529
  30. additory/synthetic/exceptions.py +0 -180
  31. additory/synthetic/file_managers.py +0 -518
  32. additory/synthetic/generator.py +0 -702
  33. additory/synthetic/generator_parser.py +0 -68
  34. additory/synthetic/integration.py +0 -319
  35. additory/synthetic/models.py +0 -241
  36. additory/synthetic/pattern_resolver.py +0 -573
  37. additory/synthetic/performance.py +0 -469
  38. additory/synthetic/polars_integration.py +0 -464
  39. additory/synthetic/proxy.py +0 -60
  40. additory/synthetic/schema_parser.py +0 -685
  41. additory/synthetic/validator.py +0 -553
  42. {additory-0.1.0a2.dist-info → additory-0.1.0a3.dist-info}/licenses/LICENSE +0 -0
  43. {additory-0.1.0a2.dist-info → additory-0.1.0a3.dist-info}/top_level.txt +0 -0
@@ -1,180 +0,0 @@
1
- """
2
- Exception classes for synthetic data generation system.
3
-
4
- Provides a hierarchy of exceptions for different error conditions with
5
- clear error messages and actionable suggestions.
6
- """
7
-
8
- from typing import Optional, List, Dict, Any
9
-
10
-
11
- class SyntheticDataError(Exception):
12
- """Base exception for all synthetic data generation errors."""
13
-
14
- def __init__(self, message: str, suggestions: Optional[List[str]] = None):
15
- super().__init__(message)
16
- self.suggestions = suggestions or []
17
-
18
- def __str__(self) -> str:
19
- msg = super().__str__()
20
- if self.suggestions:
21
- suggestions_text = "\n".join(f" - {s}" for s in self.suggestions)
22
- msg += f"\n\nSuggestions:\n{suggestions_text}"
23
- return msg
24
-
25
-
26
- class PatternResolutionError(SyntheticDataError):
27
- """Raised when pattern resolution fails in the hierarchy."""
28
-
29
- def __init__(self, message: str, pattern_name: str, searched_sources: List[str],
30
- details: Optional[str] = None):
31
- self.pattern_name = pattern_name
32
- self.searched_sources = searched_sources
33
- self.details = details
34
-
35
- suggestions = [
36
- f"Define pattern '{pattern_name}' in one of the hierarchy sources",
37
- "Check if pattern name is spelled correctly",
38
- "Verify import declarations in schema files",
39
- "Ensure pattern files are accessible and properly formatted"
40
- ]
41
-
42
- if details:
43
- suggestions.append(f"Additional details: {details}")
44
-
45
- super().__init__(message, suggestions)
46
-
47
-
48
- class ValidationError(SyntheticDataError):
49
- """Raised when validation fails for patterns, schemas, or configurations."""
50
-
51
- def __init__(self, message: str, file_path: Optional[str] = None,
52
- line_number: Optional[int] = None, suggestions: Optional[List[str]] = None):
53
- self.file_path = file_path
54
- self.line_number = line_number
55
-
56
- if file_path:
57
- location = f" in {file_path}"
58
- if line_number:
59
- location += f" at line {line_number}"
60
- message += location
61
-
62
- super().__init__(message, suggestions)
63
-
64
-
65
- class DistributionError(SyntheticDataError):
66
- """Raised when distribution strategy application fails."""
67
-
68
- def __init__(self, strategy_type: str, column_name: str, reason: str):
69
- self.strategy_type = strategy_type
70
- self.column_name = column_name
71
- self.reason = reason
72
-
73
- message = f"Distribution strategy '{strategy_type}' failed for column '{column_name}': {reason}"
74
-
75
- suggestions = [
76
- f"Check if '{strategy_type}' is compatible with the data type of '{column_name}'",
77
- "Verify distribution parameters are within valid ranges",
78
- "Ensure the pattern generates appropriate data for the distribution"
79
- ]
80
-
81
- super().__init__(message, suggestions)
82
-
83
-
84
- class FileFormatError(SyntheticDataError):
85
- """Raised when file format validation fails."""
86
-
87
- def __init__(self, file_path: str, expected_format: str, actual_format: Optional[str] = None):
88
- self.file_path = file_path
89
- self.expected_format = expected_format
90
- self.actual_format = actual_format
91
-
92
- message = f"Invalid file format for '{file_path}'. Expected: {expected_format}"
93
- if actual_format:
94
- message += f", Got: {actual_format}"
95
-
96
- suggestions = [
97
- f"Ensure the file has the correct extension (.{expected_format})",
98
- f"Verify the file content follows {expected_format} syntax",
99
- "Check file permissions and accessibility"
100
- ]
101
-
102
- super().__init__(message, suggestions)
103
-
104
-
105
-
106
-
107
-
108
- class RegexValidationError(ValidationError):
109
- """Raised when regex pattern validation fails."""
110
-
111
- def __init__(self, pattern: str, regex_error: str, pattern_name: Optional[str] = None):
112
- self.pattern = pattern
113
- self.regex_error = regex_error
114
- self.pattern_name = pattern_name
115
-
116
- name_part = f" for pattern '{pattern_name}'" if pattern_name else ""
117
- message = f"Invalid regex pattern{name_part}: {regex_error}"
118
-
119
- suggestions = [
120
- "Check regex syntax for polars compatibility",
121
- "Escape special characters properly",
122
- "Test the regex pattern with online validators",
123
- "Refer to polars regex documentation for supported features"
124
- ]
125
-
126
- super().__init__(message, suggestions=suggestions)
127
-
128
-
129
- class SchemaParsingError(ValidationError):
130
- """Raised when schema file parsing fails."""
131
-
132
- def __init__(self, file_path: str, parsing_error: str, line_number: Optional[int] = None):
133
- self.parsing_error = parsing_error
134
-
135
- suggestions = [
136
- "Check TOML syntax for proper formatting",
137
- "Ensure all strings are properly quoted",
138
- "Verify section headers are correctly formatted",
139
- "Check for missing commas or brackets"
140
- ]
141
-
142
- super().__init__(f"Schema parsing failed: {parsing_error}",
143
- file_path, line_number, suggestions)
144
-
145
-
146
- class PatternImportError(SyntheticDataError):
147
- """Raised when pattern file import fails."""
148
-
149
- def __init__(self, import_name: str, file_path: Optional[str] = None, reason: str = "File not found"):
150
- self.import_name = import_name
151
- self.file_path = file_path
152
- self.reason = reason
153
-
154
- message = f"Failed to import pattern file '{import_name}': {reason}"
155
- if file_path:
156
- message += f" (looked for: {file_path})"
157
-
158
- suggestions = [
159
- f"Ensure '{import_name}.properties' exists in reference/schema_definitions/",
160
- "Check file permissions and accessibility",
161
- "Verify the import name matches the filename exactly",
162
- "Check for typos in the import declaration"
163
- ]
164
-
165
- super().__init__(message, suggestions)
166
-
167
-
168
- class DistributionValidationError(SyntheticDataError):
169
- """Raised when distribution strategy validation fails."""
170
-
171
- def __init__(self, message: str, distribution_type: str, details: str = ""):
172
- super().__init__(message, ["Check distribution strategy parameters and syntax"])
173
- self.distribution_type = distribution_type
174
- self.details = details
175
-
176
- def __str__(self) -> str:
177
- base_msg = super().__str__()
178
- if self.details:
179
- return f"{base_msg}\nDistribution Type: {self.distribution_type}\nDetails: {self.details}"
180
- return f"{base_msg}\nDistribution Type: {self.distribution_type}"
@@ -1,518 +0,0 @@
1
- """
2
- File management for synthetic data generation system.
3
-
4
- Handles loading and validation of .properties and .toml files
5
- with proper error handling and syntax validation.
6
- """
7
-
8
- import re
9
- import toml
10
- from pathlib import Path
11
- from typing import Dict, List, Optional, Tuple
12
- from dataclasses import dataclass
13
-
14
- from .models import ValidationResult, PatternDefinition, PatternSource, ValidationStatus
15
- from .exceptions import FileFormatError, ValidationError, PatternImportError, SchemaParsingError
16
-
17
-
18
- @dataclass
19
- class ParsedPropertiesFile:
20
- """Result of parsing a .properties file."""
21
- patterns: Dict[str, str]
22
- file_path: str
23
- line_count: int
24
- comments: List[str]
25
-
26
-
27
- @dataclass
28
- class ParsedSchemaFile:
29
- """Result of parsing a .toml schema file."""
30
- imports: List[str]
31
- inline_patterns: Dict[str, str]
32
- schema_definitions: Dict[str, str]
33
- metadata: Dict[str, str]
34
- file_path: str
35
-
36
-
37
- class PatternFileManager:
38
- """
39
- Manages loading and validation of .properties pattern files.
40
-
41
- Handles the parsing of .properties files with proper syntax validation,
42
- comment handling, and error reporting with line numbers.
43
- """
44
-
45
- def __init__(self):
46
- self._pattern_cache: Dict[str, ParsedPropertiesFile] = {}
47
- self._validation_cache: Dict[str, ValidationResult] = {}
48
-
49
- def load_properties_file(self, file_path: str) -> ParsedPropertiesFile:
50
- """
51
- Load and parse a .properties file.
52
-
53
- Args:
54
- file_path: Path to the .properties file
55
-
56
- Returns:
57
- ParsedPropertiesFile with patterns and metadata
58
-
59
- Raises:
60
- FileFormatError: If file format is invalid
61
- ValidationError: If file syntax is invalid
62
- FileNotFoundError: If file doesn't exist
63
- """
64
- path = Path(file_path)
65
-
66
- # Check file extension
67
- if not path.suffix == '.properties':
68
- raise FileFormatError(file_path, "properties", path.suffix[1:] if path.suffix else "unknown")
69
-
70
- # Check if file exists
71
- if not path.exists():
72
- raise FileNotFoundError(f"Properties file not found: {file_path}")
73
-
74
- # Check cache
75
- cache_key = str(path.absolute())
76
- if cache_key in self._pattern_cache:
77
- return self._pattern_cache[cache_key]
78
-
79
- try:
80
- content = path.read_text(encoding='utf-8')
81
- except UnicodeDecodeError as e:
82
- raise ValidationError(f"File encoding error: {e}", file_path)
83
-
84
- # Parse the content
85
- parsed = self._parse_properties_content(content, file_path)
86
-
87
- # Cache the result
88
- self._pattern_cache[cache_key] = parsed
89
-
90
- return parsed
91
-
92
- def _parse_properties_content(self, content: str, file_path: str) -> ParsedPropertiesFile:
93
- """
94
- Parse the content of a .properties file.
95
-
96
- Args:
97
- content: File content as string
98
- file_path: Path for error reporting
99
-
100
- Returns:
101
- ParsedPropertiesFile with parsed data
102
-
103
- Raises:
104
- ValidationError: If syntax is invalid
105
- """
106
- patterns = {}
107
- comments = []
108
- line_number = 0
109
-
110
- for line in content.splitlines():
111
- line_number += 1
112
- line = line.strip()
113
-
114
- # Skip empty lines
115
- if not line:
116
- continue
117
-
118
- # Handle comments
119
- if line.startswith('#'):
120
- comments.append(line[1:].strip())
121
- continue
122
-
123
- # Parse key=value pairs
124
- if '=' not in line:
125
- raise ValidationError(
126
- f"Invalid syntax: missing '=' separator",
127
- file_path,
128
- line_number,
129
- ["Each line should be in format: pattern_name=regex_pattern"]
130
- )
131
-
132
- # Split on first '=' only
133
- key, value = line.split('=', 1)
134
- key = key.strip()
135
- value = value.strip()
136
-
137
- # Validate key
138
- if not key:
139
- raise ValidationError(
140
- "Empty pattern name",
141
- file_path,
142
- line_number,
143
- ["Pattern names must not be empty"]
144
- )
145
-
146
- if not self._is_valid_pattern_name(key):
147
- raise ValidationError(
148
- f"Invalid pattern name '{key}'",
149
- file_path,
150
- line_number,
151
- ["Pattern names must start with a letter and contain only letters, numbers, and underscores"]
152
- )
153
-
154
- # Validate value
155
- if not value:
156
- raise ValidationError(
157
- f"Empty regex pattern for '{key}'",
158
- file_path,
159
- line_number,
160
- ["Regex patterns must not be empty"]
161
- )
162
-
163
- # Check for duplicates
164
- if key in patterns:
165
- raise ValidationError(
166
- f"Duplicate pattern name '{key}'",
167
- file_path,
168
- line_number,
169
- [f"Pattern '{key}' is already defined in this file"]
170
- )
171
-
172
- patterns[key] = value
173
-
174
- return ParsedPropertiesFile(
175
- patterns=patterns,
176
- file_path=file_path,
177
- line_count=line_number,
178
- comments=comments
179
- )
180
-
181
- def _is_valid_pattern_name(self, name: str) -> bool:
182
- """
183
- Validate pattern name format.
184
-
185
- Args:
186
- name: Pattern name to validate
187
-
188
- Returns:
189
- True if valid, False otherwise
190
- """
191
- # Pattern names must start with letter, contain only letters, numbers, underscores
192
- pattern = r'^[a-zA-Z][a-zA-Z0-9_]*$'
193
- return bool(re.match(pattern, name))
194
-
195
- def validate_properties_syntax(self, content: str) -> ValidationResult:
196
- """
197
- Validate .properties file syntax without full parsing.
198
-
199
- Args:
200
- content: File content to validate
201
-
202
- Returns:
203
- ValidationResult with validation status
204
- """
205
- result = ValidationResult(is_valid=True)
206
- line_number = 0
207
- seen_keys = set()
208
-
209
- for line in content.splitlines():
210
- line_number += 1
211
- line = line.strip()
212
-
213
- # Skip empty lines and comments
214
- if not line or line.startswith('#'):
215
- continue
216
-
217
- # Check for '=' separator
218
- if '=' not in line:
219
- result.add_error(
220
- f"Line {line_number}: Missing '=' separator",
221
- "Each line should be in format: pattern_name=regex_pattern"
222
- )
223
- continue
224
-
225
- # Split and validate
226
- key, value = line.split('=', 1)
227
- key = key.strip()
228
- value = value.strip()
229
-
230
- # Validate key
231
- if not key:
232
- result.add_error(f"Line {line_number}: Empty pattern name")
233
- elif not self._is_valid_pattern_name(key):
234
- result.add_error(
235
- f"Line {line_number}: Invalid pattern name '{key}'",
236
- "Pattern names must start with a letter and contain only letters, numbers, and underscores"
237
- )
238
- elif key in seen_keys:
239
- result.add_error(f"Line {line_number}: Duplicate pattern name '{key}'")
240
- else:
241
- seen_keys.add(key)
242
-
243
- # Validate value
244
- if not value:
245
- result.add_error(f"Line {line_number}: Empty regex pattern for '{key}'")
246
-
247
- return result
248
-
249
- def create_pattern_definitions(self, parsed_file: ParsedPropertiesFile,
250
- source: PatternSource) -> List[PatternDefinition]:
251
- """
252
- Create PatternDefinition objects from parsed file.
253
-
254
- Args:
255
- parsed_file: Parsed .properties file
256
- source: Source type for the patterns
257
-
258
- Returns:
259
- List of PatternDefinition objects
260
- """
261
- definitions = []
262
-
263
- for name, regex in parsed_file.patterns.items():
264
- definition = PatternDefinition(
265
- name=name,
266
- regex=regex,
267
- source=source,
268
- validation_status=ValidationStatus.NOT_VALIDATED,
269
- polars_compatible=False, # Will be validated later
270
- source_file=parsed_file.file_path
271
- )
272
- definitions.append(definition)
273
-
274
- return definitions
275
-
276
- def clear_cache(self):
277
- """Clear the file cache."""
278
- self._pattern_cache.clear()
279
- self._validation_cache.clear()
280
-
281
-
282
- class SchemaFileManager:
283
- """
284
- Manages loading and validation of .toml schema files.
285
-
286
- Handles the parsing of TOML schema files with proper structure validation,
287
- import resolution, and error reporting.
288
- """
289
-
290
- def __init__(self):
291
- self._schema_cache: Dict[str, ParsedSchemaFile] = {}
292
-
293
- def load_toml_schema(self, file_path: str) -> ParsedSchemaFile:
294
- """
295
- Load and parse a .toml schema file.
296
-
297
- Args:
298
- file_path: Path to the .toml file
299
-
300
- Returns:
301
- ParsedSchemaFile with schema data
302
-
303
- Raises:
304
- FileFormatError: If file format is invalid
305
- SchemaParsingError: If TOML parsing fails
306
- FileNotFoundError: If file doesn't exist
307
- """
308
- path = Path(file_path)
309
-
310
- # Check file extension
311
- if not path.suffix == '.toml':
312
- raise FileFormatError(file_path, "toml", path.suffix[1:] if path.suffix else "unknown")
313
-
314
- # Check if file exists
315
- if not path.exists():
316
- raise FileNotFoundError(f"Schema file not found: {file_path}")
317
-
318
- # Check cache
319
- cache_key = str(path.absolute())
320
- if cache_key in self._schema_cache:
321
- return self._schema_cache[cache_key]
322
-
323
- try:
324
- content = path.read_text(encoding='utf-8')
325
- except UnicodeDecodeError as e:
326
- raise SchemaParsingError(file_path, f"File encoding error: {e}")
327
-
328
- # Parse TOML content
329
- try:
330
- toml_data = toml.loads(content)
331
- except toml.TomlDecodeError as e:
332
- raise SchemaParsingError(file_path, f"TOML parsing error: {e}")
333
-
334
- # Parse the schema structure
335
- parsed = self._parse_schema_structure(toml_data, file_path)
336
-
337
- # Cache the result
338
- self._schema_cache[cache_key] = parsed
339
-
340
- return parsed
341
-
342
- def _parse_schema_structure(self, toml_data: Dict, file_path: str) -> ParsedSchemaFile:
343
- """
344
- Parse the structure of a TOML schema file.
345
-
346
- Supports two formats:
347
- 1. Legacy format: [generator] section with import and inline patterns
348
- 2. New format: [generation] section with imports, prefer_mode, and patterns
349
-
350
- Args:
351
- toml_data: Parsed TOML data
352
- file_path: Path for error reporting
353
-
354
- Returns:
355
- ParsedSchemaFile with structured data
356
-
357
- Raises:
358
- SchemaParsingError: If structure is invalid
359
- """
360
- imports = []
361
- inline_patterns = {}
362
- prefer_mode = "default" # Default prefer mode
363
-
364
- # Try new format first: [generation] section
365
- generation_section = toml_data.get('generation', {})
366
- if generation_section:
367
- # Handle imports (array format)
368
- import_value = generation_section.get('imports', [])
369
- if isinstance(import_value, str):
370
- imports = [import_value]
371
- elif isinstance(import_value, list):
372
- imports = import_value
373
- elif import_value: # Not None or empty
374
- raise SchemaParsingError(
375
- file_path,
376
- "imports declaration must be a string or list of strings"
377
- )
378
-
379
- # Handle prefer_mode
380
- prefer_mode_value = generation_section.get('prefer_mode', 'default')
381
- if not isinstance(prefer_mode_value, str):
382
- raise SchemaParsingError(
383
- file_path,
384
- "prefer_mode must be a string (default, list_only, or regex_only)"
385
- )
386
- if prefer_mode_value not in ['default', 'list_only', 'regex_only']:
387
- raise SchemaParsingError(
388
- file_path,
389
- f"Invalid prefer_mode '{prefer_mode_value}'. Valid values: default, list_only, regex_only"
390
- )
391
- prefer_mode = prefer_mode_value
392
-
393
- # Handle inline patterns (everything except 'imports' and 'prefer_mode')
394
- for key, value in generation_section.items():
395
- if key not in ['imports', 'prefer_mode']:
396
- # Support both string (regex) and array (list) patterns
397
- if isinstance(value, str):
398
- inline_patterns[key] = value
399
- elif isinstance(value, list):
400
- inline_patterns[key] = value
401
- else:
402
- raise SchemaParsingError(
403
- file_path,
404
- f"Inline pattern '{key}' must be a string (regex) or array (list)"
405
- )
406
-
407
- # Fallback to legacy format: [generator] section
408
- generator_section = toml_data.get('generator', {})
409
- if generator_section and not generation_section:
410
- # Handle imports (legacy: 'import' instead of 'imports')
411
- import_value = generator_section.get('import', [])
412
- if isinstance(import_value, str):
413
- imports = [import_value]
414
- elif isinstance(import_value, list):
415
- imports = import_value
416
- elif import_value: # Not None or empty
417
- raise SchemaParsingError(
418
- file_path,
419
- "Import declaration must be a string or list of strings"
420
- )
421
-
422
- # Handle inline patterns (everything except 'import')
423
- for key, value in generator_section.items():
424
- if key != 'import':
425
- if not isinstance(value, str):
426
- raise SchemaParsingError(
427
- file_path,
428
- f"Inline pattern '{key}' must be a string"
429
- )
430
- inline_patterns[key] = value
431
-
432
- # Extract schema section
433
- schema_section = toml_data.get('schema', {})
434
- schema_definitions = {}
435
-
436
- for key, value in schema_section.items():
437
- # Support both string (reference/regex) and array (list) patterns
438
- if isinstance(value, str):
439
- schema_definitions[key] = value
440
- elif isinstance(value, list):
441
- schema_definitions[key] = value
442
- else:
443
- raise SchemaParsingError(
444
- file_path,
445
- f"Schema definition '{key}' must be a string or array"
446
- )
447
-
448
- # Extract metadata (any other sections)
449
- metadata = {}
450
- for key, value in toml_data.items():
451
- if key not in ['generator', 'generation', 'schema']:
452
- metadata[key] = value
453
-
454
- # Store prefer_mode in metadata
455
- metadata['prefer_mode'] = prefer_mode
456
-
457
- return ParsedSchemaFile(
458
- imports=imports,
459
- inline_patterns=inline_patterns,
460
- schema_definitions=schema_definitions,
461
- metadata=metadata,
462
- file_path=file_path
463
- )
464
-
465
- def validate_toml_syntax(self, content: str) -> ValidationResult:
466
- """
467
- Validate TOML syntax without full parsing.
468
-
469
- Args:
470
- content: TOML content to validate
471
-
472
- Returns:
473
- ValidationResult with validation status
474
- """
475
- result = ValidationResult(is_valid=True)
476
-
477
- try:
478
- toml_data = toml.loads(content)
479
-
480
- # Validate expected sections
481
- valid_sections = {'generator', 'schema'}
482
- for section in toml_data:
483
- if section not in valid_sections and not isinstance(toml_data[section], dict):
484
- result.add_warning(f"Unexpected section '{section}' - will be treated as metadata")
485
-
486
- # Validate generator section structure
487
- if 'generator' in toml_data:
488
- generator = toml_data['generator']
489
- if not isinstance(generator, dict):
490
- result.add_error("Generator section must be a table/dictionary")
491
- else:
492
- # Validate import format
493
- if 'import' in generator:
494
- import_val = generator['import']
495
- if not isinstance(import_val, (str, list)):
496
- result.add_error("Import declaration must be a string or list of strings")
497
-
498
- # Validate schema section structure
499
- if 'schema' in toml_data:
500
- schema = toml_data['schema']
501
- if not isinstance(schema, dict):
502
- result.add_error("Schema section must be a table/dictionary")
503
- else:
504
- for key, value in schema.items():
505
- if not isinstance(value, str):
506
- result.add_error(f"Schema definition '{key}' must be a string")
507
-
508
- except toml.TomlDecodeError as e:
509
- result.add_error(
510
- f"TOML syntax error: {e}",
511
- "Check TOML syntax for proper formatting, quotes, and brackets"
512
- )
513
-
514
- return result
515
-
516
- def clear_cache(self):
517
- """Clear the schema cache."""
518
- self._schema_cache.clear()