string-schema 0.1.0__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.
- simple_schema/__init__.py +108 -0
- simple_schema/core/__init__.py +23 -0
- simple_schema/core/builders.py +244 -0
- simple_schema/core/fields.py +138 -0
- simple_schema/core/validators.py +242 -0
- simple_schema/examples/__init__.py +36 -0
- simple_schema/examples/presets.py +345 -0
- simple_schema/examples/recipes.py +380 -0
- simple_schema/integrations/__init__.py +15 -0
- simple_schema/integrations/json_schema.py +385 -0
- simple_schema/integrations/openapi.py +484 -0
- simple_schema/integrations/pydantic.py +662 -0
- simple_schema/integrations/reverse.py +275 -0
- simple_schema/parsing/__init__.py +16 -0
- simple_schema/parsing/optimizer.py +246 -0
- simple_schema/parsing/string_parser.py +703 -0
- simple_schema/parsing/syntax.py +250 -0
- simple_schema/utilities.py +501 -0
- string_schema-0.1.0.dist-info/METADATA +545 -0
- string_schema-0.1.0.dist-info/RECORD +23 -0
- string_schema-0.1.0.dist-info/WHEEL +5 -0
- string_schema-0.1.0.dist-info/licenses/LICENSE +21 -0
- string_schema-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Validation utilities for Simple Schema
|
|
3
|
+
|
|
4
|
+
Contains functions for validating schemas and field definitions.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List, Union
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from .fields import SimpleField
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def validate_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
16
|
+
"""
|
|
17
|
+
Validate a JSON schema generated by Simple Schema.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
schema: The JSON schema to validate
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Dictionary with validation results including:
|
|
24
|
+
- valid: Boolean indicating if schema is valid
|
|
25
|
+
- errors: List of error messages
|
|
26
|
+
- warnings: List of warning messages
|
|
27
|
+
- field_count: Number of fields in the schema
|
|
28
|
+
"""
|
|
29
|
+
result = {
|
|
30
|
+
'valid': True,
|
|
31
|
+
'errors': [],
|
|
32
|
+
'warnings': [],
|
|
33
|
+
'field_count': 0,
|
|
34
|
+
'features_used': []
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
# Basic schema structure validation
|
|
39
|
+
if not isinstance(schema, dict):
|
|
40
|
+
result['errors'].append("Schema must be a dictionary")
|
|
41
|
+
result['valid'] = False
|
|
42
|
+
return result
|
|
43
|
+
|
|
44
|
+
if 'type' not in schema:
|
|
45
|
+
result['errors'].append("Schema must have a 'type' field")
|
|
46
|
+
result['valid'] = False
|
|
47
|
+
return result
|
|
48
|
+
|
|
49
|
+
schema_type = schema['type']
|
|
50
|
+
|
|
51
|
+
if schema_type == 'object':
|
|
52
|
+
result.update(_validate_object_schema(schema))
|
|
53
|
+
elif schema_type == 'array':
|
|
54
|
+
result.update(_validate_array_schema(schema))
|
|
55
|
+
else:
|
|
56
|
+
result['warnings'].append(f"Unusual schema type: {schema_type}")
|
|
57
|
+
|
|
58
|
+
# Check for potential issues
|
|
59
|
+
if result['field_count'] > 20:
|
|
60
|
+
result['warnings'].append("Schema has many fields (>20), consider simplifying")
|
|
61
|
+
|
|
62
|
+
if result['field_count'] == 0:
|
|
63
|
+
result['warnings'].append("Schema has no fields defined")
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
result['errors'].append(f"Validation error: {str(e)}")
|
|
67
|
+
result['valid'] = False
|
|
68
|
+
|
|
69
|
+
# Set overall validity
|
|
70
|
+
result['valid'] = len(result['errors']) == 0
|
|
71
|
+
|
|
72
|
+
return result
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _validate_object_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
76
|
+
"""Validate object-type schema"""
|
|
77
|
+
result = {
|
|
78
|
+
'field_count': 0,
|
|
79
|
+
'features_used': [],
|
|
80
|
+
'errors': [],
|
|
81
|
+
'warnings': []
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
properties = schema.get('properties', {})
|
|
85
|
+
required = schema.get('required', [])
|
|
86
|
+
|
|
87
|
+
result['field_count'] = len(properties)
|
|
88
|
+
|
|
89
|
+
# Validate each property
|
|
90
|
+
for field_name, field_schema in properties.items():
|
|
91
|
+
field_result = _validate_field_schema(field_name, field_schema)
|
|
92
|
+
result['errors'].extend(field_result['errors'])
|
|
93
|
+
result['warnings'].extend(field_result['warnings'])
|
|
94
|
+
result['features_used'].extend(field_result['features_used'])
|
|
95
|
+
|
|
96
|
+
# Validate required fields
|
|
97
|
+
for req_field in required:
|
|
98
|
+
if req_field not in properties:
|
|
99
|
+
result['errors'].append(f"Required field '{req_field}' not found in properties")
|
|
100
|
+
|
|
101
|
+
# Remove duplicate features
|
|
102
|
+
result['features_used'] = list(set(result['features_used']))
|
|
103
|
+
|
|
104
|
+
return result
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _validate_array_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
108
|
+
"""Validate array-type schema"""
|
|
109
|
+
result = {
|
|
110
|
+
'field_count': 0,
|
|
111
|
+
'features_used': ['arrays'],
|
|
112
|
+
'errors': [],
|
|
113
|
+
'warnings': []
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
items = schema.get('items', {})
|
|
117
|
+
|
|
118
|
+
if not items:
|
|
119
|
+
result['errors'].append("Array schema must have 'items' definition")
|
|
120
|
+
return result
|
|
121
|
+
|
|
122
|
+
# Validate array constraints
|
|
123
|
+
if 'minItems' in schema:
|
|
124
|
+
result['features_used'].append('array_constraints')
|
|
125
|
+
if 'maxItems' in schema:
|
|
126
|
+
result['features_used'].append('array_constraints')
|
|
127
|
+
|
|
128
|
+
# Validate items schema
|
|
129
|
+
if items.get('type') == 'object':
|
|
130
|
+
items_result = _validate_object_schema(items)
|
|
131
|
+
result['field_count'] = items_result['field_count']
|
|
132
|
+
result['errors'].extend(items_result['errors'])
|
|
133
|
+
result['warnings'].extend(items_result['warnings'])
|
|
134
|
+
result['features_used'].extend(items_result['features_used'])
|
|
135
|
+
else:
|
|
136
|
+
# Simple array items
|
|
137
|
+
field_result = _validate_field_schema('array_item', items)
|
|
138
|
+
result['errors'].extend(field_result['errors'])
|
|
139
|
+
result['warnings'].extend(field_result['warnings'])
|
|
140
|
+
result['features_used'].extend(field_result['features_used'])
|
|
141
|
+
|
|
142
|
+
return result
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _validate_field_schema(field_name: str, field_schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
146
|
+
"""Validate individual field schema"""
|
|
147
|
+
result = {
|
|
148
|
+
'features_used': [],
|
|
149
|
+
'errors': [],
|
|
150
|
+
'warnings': []
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Check for union types
|
|
154
|
+
if 'anyOf' in field_schema:
|
|
155
|
+
result['features_used'].append('union_types')
|
|
156
|
+
# Validate each union option
|
|
157
|
+
for i, union_option in enumerate(field_schema['anyOf']):
|
|
158
|
+
if 'type' not in union_option:
|
|
159
|
+
result['errors'].append(f"Union option {i} in field '{field_name}' missing type")
|
|
160
|
+
|
|
161
|
+
# Check for enum
|
|
162
|
+
if 'enum' in field_schema:
|
|
163
|
+
result['features_used'].append('enums')
|
|
164
|
+
enum_values = field_schema['enum']
|
|
165
|
+
if not isinstance(enum_values, list) or len(enum_values) == 0:
|
|
166
|
+
result['errors'].append(f"Field '{field_name}' enum must be non-empty list")
|
|
167
|
+
|
|
168
|
+
# Check for format hints
|
|
169
|
+
if 'format' in field_schema:
|
|
170
|
+
result['features_used'].append('special_types')
|
|
171
|
+
format_value = field_schema['format']
|
|
172
|
+
valid_formats = ['email', 'uri', 'date-time', 'date', 'uuid']
|
|
173
|
+
if format_value not in valid_formats:
|
|
174
|
+
result['warnings'].append(f"Field '{field_name}' uses non-standard format: {format_value}")
|
|
175
|
+
|
|
176
|
+
# Check for constraints
|
|
177
|
+
constraint_fields = ['minimum', 'maximum', 'minLength', 'maxLength', 'minItems', 'maxItems']
|
|
178
|
+
if any(field in field_schema for field in constraint_fields):
|
|
179
|
+
result['features_used'].append('constraints')
|
|
180
|
+
|
|
181
|
+
# Validate constraint values
|
|
182
|
+
if 'minimum' in field_schema and 'maximum' in field_schema:
|
|
183
|
+
if field_schema['minimum'] > field_schema['maximum']:
|
|
184
|
+
result['errors'].append(f"Field '{field_name}' minimum > maximum")
|
|
185
|
+
|
|
186
|
+
if 'minLength' in field_schema and 'maxLength' in field_schema:
|
|
187
|
+
if field_schema['minLength'] > field_schema['maxLength']:
|
|
188
|
+
result['errors'].append(f"Field '{field_name}' minLength > maxLength")
|
|
189
|
+
|
|
190
|
+
if 'minItems' in field_schema and 'maxItems' in field_schema:
|
|
191
|
+
if field_schema['minItems'] > field_schema['maxItems']:
|
|
192
|
+
result['errors'].append(f"Field '{field_name}' minItems > maxItems")
|
|
193
|
+
|
|
194
|
+
return result
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def validate_simple_field(field: SimpleField) -> Dict[str, Any]:
|
|
198
|
+
"""
|
|
199
|
+
Validate a SimpleField instance.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
field: The SimpleField to validate
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
Dictionary with validation results
|
|
206
|
+
"""
|
|
207
|
+
result = {
|
|
208
|
+
'valid': True,
|
|
209
|
+
'errors': [],
|
|
210
|
+
'warnings': []
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Validate field type
|
|
214
|
+
valid_types = ['string', 'integer', 'number', 'boolean']
|
|
215
|
+
if field.field_type not in valid_types:
|
|
216
|
+
result['warnings'].append(f"Unusual field type: {field.field_type}")
|
|
217
|
+
|
|
218
|
+
# Validate constraints
|
|
219
|
+
if field.min_val is not None and field.max_val is not None:
|
|
220
|
+
if field.min_val > field.max_val:
|
|
221
|
+
result['errors'].append("min_val cannot be greater than max_val")
|
|
222
|
+
|
|
223
|
+
if field.min_length is not None and field.max_length is not None:
|
|
224
|
+
if field.min_length > field.max_length:
|
|
225
|
+
result['errors'].append("min_length cannot be greater than max_length")
|
|
226
|
+
|
|
227
|
+
if field.min_items is not None and field.max_items is not None:
|
|
228
|
+
if field.min_items > field.max_items:
|
|
229
|
+
result['errors'].append("min_items cannot be greater than max_items")
|
|
230
|
+
|
|
231
|
+
# Validate choices
|
|
232
|
+
if field.choices and len(field.choices) == 0:
|
|
233
|
+
result['errors'].append("choices list cannot be empty")
|
|
234
|
+
|
|
235
|
+
# Validate union types
|
|
236
|
+
if field.union_types and len(field.union_types) < 2:
|
|
237
|
+
result['warnings'].append("union_types should have at least 2 types")
|
|
238
|
+
|
|
239
|
+
# Set overall validity
|
|
240
|
+
result['valid'] = len(result['errors']) == 0
|
|
241
|
+
|
|
242
|
+
return result
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Examples module for Simple Schema
|
|
3
|
+
|
|
4
|
+
Contains built-in schema presets and common patterns.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .presets import (
|
|
8
|
+
user_schema,
|
|
9
|
+
product_schema,
|
|
10
|
+
contact_schema,
|
|
11
|
+
article_schema,
|
|
12
|
+
event_schema,
|
|
13
|
+
get_examples
|
|
14
|
+
)
|
|
15
|
+
from .recipes import (
|
|
16
|
+
create_list_schema,
|
|
17
|
+
create_nested_schema,
|
|
18
|
+
create_enum_schema,
|
|
19
|
+
create_union_schema
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# Presets
|
|
24
|
+
"user_schema",
|
|
25
|
+
"product_schema",
|
|
26
|
+
"contact_schema",
|
|
27
|
+
"article_schema",
|
|
28
|
+
"event_schema",
|
|
29
|
+
"get_examples",
|
|
30
|
+
|
|
31
|
+
# Recipes
|
|
32
|
+
"create_list_schema",
|
|
33
|
+
"create_nested_schema",
|
|
34
|
+
"create_enum_schema",
|
|
35
|
+
"create_union_schema"
|
|
36
|
+
]
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Built-in schema presets for Simple Schema
|
|
3
|
+
|
|
4
|
+
Contains commonly used schema definitions for typical data structures.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List, Optional, Union
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from ..core.fields import SimpleField
|
|
11
|
+
from ..core.builders import simple_schema, list_of_objects_schema
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def user_schema(include_email: bool = True, include_phone: bool = False,
|
|
17
|
+
include_profile: bool = False, include_preferences: bool = False) -> Dict[str, Any]:
|
|
18
|
+
"""Generate enhanced user schema with special types"""
|
|
19
|
+
fields = {
|
|
20
|
+
'name': SimpleField('string', 'Full name', min_length=1, max_length=100),
|
|
21
|
+
'age': SimpleField('integer', 'Age in years', min_val=13, max_val=120, required=False)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if include_email:
|
|
25
|
+
fields['email'] = SimpleField('string', 'Email address', format_hint='email')
|
|
26
|
+
|
|
27
|
+
if include_phone:
|
|
28
|
+
fields['phone'] = SimpleField('string', 'Phone number', format_hint='phone', required=False)
|
|
29
|
+
|
|
30
|
+
if include_profile:
|
|
31
|
+
fields['bio'] = SimpleField('string', 'Biography', max_length=500, required=False)
|
|
32
|
+
fields['avatar'] = SimpleField('string', 'Avatar URL', format_hint='url', required=False)
|
|
33
|
+
|
|
34
|
+
if include_preferences:
|
|
35
|
+
fields['theme'] = SimpleField('string', 'UI theme', choices=['light', 'dark'], required=False)
|
|
36
|
+
fields['notifications'] = SimpleField('boolean', 'Email notifications enabled', required=False)
|
|
37
|
+
|
|
38
|
+
return simple_schema(fields)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def product_schema(include_price: bool = True, include_description: bool = True,
|
|
42
|
+
include_images: bool = False, include_reviews: bool = False) -> Dict[str, Any]:
|
|
43
|
+
"""Generate enhanced product schema"""
|
|
44
|
+
fields = {
|
|
45
|
+
'name': SimpleField('string', 'Product name', min_length=1, max_length=200),
|
|
46
|
+
'category': SimpleField('string', 'Product category',
|
|
47
|
+
choices=['electronics', 'clothing', 'books', 'home', 'sports'])
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if include_price:
|
|
51
|
+
fields['price'] = SimpleField('number', 'Price', min_val=0)
|
|
52
|
+
|
|
53
|
+
if include_description:
|
|
54
|
+
fields['description'] = SimpleField('string', 'Product description',
|
|
55
|
+
max_length=1000, required=False)
|
|
56
|
+
|
|
57
|
+
if include_images:
|
|
58
|
+
# This would need to be handled as a nested array, which is complex
|
|
59
|
+
# For now, we'll represent it as a simple field
|
|
60
|
+
fields['image_urls'] = SimpleField('string', 'Comma-separated image URLs', required=False)
|
|
61
|
+
|
|
62
|
+
if include_reviews:
|
|
63
|
+
# Similarly, this would be a complex nested structure
|
|
64
|
+
fields['avg_rating'] = SimpleField('number', 'Average rating', min_val=1.0, max_val=5.0, required=False)
|
|
65
|
+
fields['review_count'] = SimpleField('integer', 'Number of reviews', min_val=0, required=False)
|
|
66
|
+
|
|
67
|
+
return simple_schema(fields)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def contact_schema(include_company: bool = False, include_address: bool = False,
|
|
71
|
+
include_social: bool = False) -> Dict[str, Any]:
|
|
72
|
+
"""Generate enhanced contact schema"""
|
|
73
|
+
fields = {
|
|
74
|
+
'name': SimpleField('string', 'Contact name', min_length=1, max_length=100),
|
|
75
|
+
'email': SimpleField('string', 'Email address', format_hint='email'),
|
|
76
|
+
'phone': SimpleField('string', 'Phone number', format_hint='phone', required=False)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if include_company:
|
|
80
|
+
fields['company'] = SimpleField('string', 'Company name', max_length=200, required=False)
|
|
81
|
+
fields['job_title'] = SimpleField('string', 'Job title', max_length=100, required=False)
|
|
82
|
+
|
|
83
|
+
if include_address:
|
|
84
|
+
fields['address'] = SimpleField('string', 'Full address', max_length=500, required=False)
|
|
85
|
+
fields['city'] = SimpleField('string', 'City', max_length=100, required=False)
|
|
86
|
+
fields['country'] = SimpleField('string', 'Country', max_length=100, required=False)
|
|
87
|
+
|
|
88
|
+
if include_social:
|
|
89
|
+
fields['linkedin'] = SimpleField('string', 'LinkedIn URL', format_hint='url', required=False)
|
|
90
|
+
fields['twitter'] = SimpleField('string', 'Twitter URL', format_hint='url', required=False)
|
|
91
|
+
fields['website'] = SimpleField('string', 'Personal website', format_hint='url', required=False)
|
|
92
|
+
|
|
93
|
+
return simple_schema(fields)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def article_schema(include_summary: bool = True, include_tags: bool = False,
|
|
97
|
+
include_metadata: bool = False) -> Dict[str, Any]:
|
|
98
|
+
"""Generate enhanced article schema"""
|
|
99
|
+
fields = {
|
|
100
|
+
'title': SimpleField('string', 'Article title', min_length=1, max_length=200),
|
|
101
|
+
'content': SimpleField('string', 'Article content', min_length=10)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if include_summary:
|
|
105
|
+
fields['summary'] = SimpleField('string', 'Brief summary', max_length=500, required=False)
|
|
106
|
+
|
|
107
|
+
if include_tags:
|
|
108
|
+
# Represented as comma-separated for simplicity
|
|
109
|
+
fields['tags'] = SimpleField('string', 'Comma-separated tags', max_length=200, required=False)
|
|
110
|
+
|
|
111
|
+
if include_metadata:
|
|
112
|
+
fields['author'] = SimpleField('string', 'Author name', max_length=100, required=False)
|
|
113
|
+
fields['published_date'] = SimpleField('string', 'Publication date', format_hint='date', required=False)
|
|
114
|
+
fields['word_count'] = SimpleField('integer', 'Word count', min_val=0, required=False)
|
|
115
|
+
|
|
116
|
+
return simple_schema(fields)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def event_schema(include_location: bool = True, include_attendees: bool = False) -> Dict[str, Any]:
|
|
120
|
+
"""Generate enhanced event schema"""
|
|
121
|
+
fields = {
|
|
122
|
+
'title': SimpleField('string', 'Event title', min_length=1, max_length=200),
|
|
123
|
+
'date': SimpleField('string', 'Event date', format_hint='datetime'),
|
|
124
|
+
'status': SimpleField('string', 'Event status',
|
|
125
|
+
choices=['planned', 'active', 'completed', 'cancelled'])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if include_location:
|
|
129
|
+
fields['venue'] = SimpleField('string', 'Venue name', max_length=200, required=False)
|
|
130
|
+
fields['address'] = SimpleField('string', 'Event address', max_length=500, required=False)
|
|
131
|
+
fields['is_online'] = SimpleField('boolean', 'Is online event', required=False)
|
|
132
|
+
fields['meeting_url'] = SimpleField('string', 'Meeting URL', format_hint='url', required=False)
|
|
133
|
+
|
|
134
|
+
if include_attendees:
|
|
135
|
+
fields['max_attendees'] = SimpleField('integer', 'Maximum attendees', min_val=1, required=False)
|
|
136
|
+
fields['current_attendees'] = SimpleField('integer', 'Current attendee count', min_val=0, required=False)
|
|
137
|
+
|
|
138
|
+
return simple_schema(fields)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# List versions of schemas
|
|
142
|
+
def user_list_schema(**kwargs) -> Dict[str, Any]:
|
|
143
|
+
"""Generate schema for array of users"""
|
|
144
|
+
user_fields = {}
|
|
145
|
+
user_base = user_schema(**kwargs)
|
|
146
|
+
|
|
147
|
+
# Convert properties to SimpleField definitions
|
|
148
|
+
for field_name, field_schema in user_base['properties'].items():
|
|
149
|
+
field_type = field_schema['type']
|
|
150
|
+
required = field_name in user_base.get('required', [])
|
|
151
|
+
|
|
152
|
+
simple_field = SimpleField(field_type, required=required)
|
|
153
|
+
|
|
154
|
+
# Copy constraints
|
|
155
|
+
if 'minimum' in field_schema:
|
|
156
|
+
simple_field.min_val = field_schema['minimum']
|
|
157
|
+
if 'maximum' in field_schema:
|
|
158
|
+
simple_field.max_val = field_schema['maximum']
|
|
159
|
+
if 'minLength' in field_schema:
|
|
160
|
+
simple_field.min_length = field_schema['minLength']
|
|
161
|
+
if 'maxLength' in field_schema:
|
|
162
|
+
simple_field.max_length = field_schema['maxLength']
|
|
163
|
+
if 'enum' in field_schema:
|
|
164
|
+
simple_field.choices = field_schema['enum']
|
|
165
|
+
if 'format' in field_schema:
|
|
166
|
+
simple_field.format_hint = field_schema['format']
|
|
167
|
+
|
|
168
|
+
user_fields[field_name] = simple_field
|
|
169
|
+
|
|
170
|
+
return list_of_objects_schema(user_fields, "List of users")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def product_list_schema(**kwargs) -> Dict[str, Any]:
|
|
174
|
+
"""Generate schema for array of products"""
|
|
175
|
+
return _convert_object_to_list_schema(product_schema(**kwargs), "List of products")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def contact_list_schema(**kwargs) -> Dict[str, Any]:
|
|
179
|
+
"""Generate schema for array of contacts"""
|
|
180
|
+
return _convert_object_to_list_schema(contact_schema(**kwargs), "List of contacts")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def article_list_schema(**kwargs) -> Dict[str, Any]:
|
|
184
|
+
"""Generate schema for array of articles"""
|
|
185
|
+
return _convert_object_to_list_schema(article_schema(**kwargs), "List of articles")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def event_list_schema(**kwargs) -> Dict[str, Any]:
|
|
189
|
+
"""Generate schema for array of events"""
|
|
190
|
+
return _convert_object_to_list_schema(event_schema(**kwargs), "List of events")
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _convert_object_to_list_schema(object_schema: Dict[str, Any], description: str) -> Dict[str, Any]:
|
|
194
|
+
"""Helper function to convert object schema to list schema"""
|
|
195
|
+
fields = {}
|
|
196
|
+
|
|
197
|
+
# Convert properties to SimpleField definitions
|
|
198
|
+
for field_name, field_schema in object_schema['properties'].items():
|
|
199
|
+
field_type = field_schema['type']
|
|
200
|
+
required = field_name in object_schema.get('required', [])
|
|
201
|
+
|
|
202
|
+
simple_field = SimpleField(field_type, required=required)
|
|
203
|
+
|
|
204
|
+
# Copy constraints
|
|
205
|
+
if 'minimum' in field_schema:
|
|
206
|
+
simple_field.min_val = field_schema['minimum']
|
|
207
|
+
if 'maximum' in field_schema:
|
|
208
|
+
simple_field.max_val = field_schema['maximum']
|
|
209
|
+
if 'minLength' in field_schema:
|
|
210
|
+
simple_field.min_length = field_schema['minLength']
|
|
211
|
+
if 'maxLength' in field_schema:
|
|
212
|
+
simple_field.max_length = field_schema['maxLength']
|
|
213
|
+
if 'enum' in field_schema:
|
|
214
|
+
simple_field.choices = field_schema['enum']
|
|
215
|
+
if 'format' in field_schema:
|
|
216
|
+
simple_field.format_hint = field_schema['format']
|
|
217
|
+
if 'description' in field_schema:
|
|
218
|
+
simple_field.description = field_schema['description']
|
|
219
|
+
|
|
220
|
+
fields[field_name] = simple_field
|
|
221
|
+
|
|
222
|
+
return list_of_objects_schema(fields, description)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Enhanced utility schemas
|
|
226
|
+
def simple_list_schema(item_type: str = 'string', description: str = 'List of items',
|
|
227
|
+
min_items: Optional[int] = None, max_items: Optional[int] = None) -> Dict[str, Any]:
|
|
228
|
+
"""Generate schema for simple arrays with enhanced constraints"""
|
|
229
|
+
from ..core.builders import simple_array_schema
|
|
230
|
+
return simple_array_schema(item_type, description, min_items, max_items)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def key_value_schema(description: str = 'Key-value pairs') -> Dict[str, Any]:
|
|
234
|
+
"""Generate schema for flexible key-value objects"""
|
|
235
|
+
return {
|
|
236
|
+
"type": "object",
|
|
237
|
+
"description": description,
|
|
238
|
+
"additionalProperties": {"type": "string"}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def enum_schema(field_name: str, values: List[str], description: str = "") -> Dict[str, Any]:
|
|
243
|
+
"""Generate schema for a single enum field"""
|
|
244
|
+
fields = {
|
|
245
|
+
field_name: SimpleField('string', description, choices=values)
|
|
246
|
+
}
|
|
247
|
+
return simple_schema(fields)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def union_schema(field_name: str, types: List[str], description: str = "") -> Dict[str, Any]:
|
|
251
|
+
"""Generate schema for a single union field"""
|
|
252
|
+
fields = {
|
|
253
|
+
field_name: SimpleField('string', description, union_types=types)
|
|
254
|
+
}
|
|
255
|
+
return simple_schema(fields)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# Enhanced examples with all new features
|
|
259
|
+
ENHANCED_EXAMPLES = {
|
|
260
|
+
"simple_user": {
|
|
261
|
+
"description": "Basic user information with special types",
|
|
262
|
+
"schema": user_schema(include_email=True, include_phone=True),
|
|
263
|
+
"prompt_example": "Extract user: John Doe, 25 years old, john@example.com, phone +1-555-0123"
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
"product_with_enum": {
|
|
267
|
+
"description": "Product with category enum",
|
|
268
|
+
"schema": product_schema(include_price=True, include_description=True),
|
|
269
|
+
"prompt_example": "Product: iPhone 14, $999, Electronics category, Latest smartphone with advanced features"
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
"contact_with_social": {
|
|
273
|
+
"description": "Contact with social media links",
|
|
274
|
+
"schema": contact_schema(include_company=True, include_social=True),
|
|
275
|
+
"prompt_example": "Contact: Jane Smith, jane@company.org, works at TechCorp as Developer, LinkedIn: linkedin.com/in/janesmith"
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
"simple_string_array": {
|
|
279
|
+
"description": "Simple array of strings (FIXED!)",
|
|
280
|
+
"schema": simple_list_schema('string', 'List of tags', max_items=5),
|
|
281
|
+
"prompt_example": "Tags: python, javascript, react, machine-learning, AI"
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
"email_array": {
|
|
285
|
+
"description": "Array of email addresses",
|
|
286
|
+
"schema": simple_list_schema('string', 'List of emails', min_items=1, max_items=3),
|
|
287
|
+
"prompt_example": "Emails: john@example.com, jane@company.org, admin@website.com"
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
"user_list": {
|
|
291
|
+
"description": "List of user objects",
|
|
292
|
+
"schema": user_list_schema(include_email=True),
|
|
293
|
+
"prompt_example": "Users: John Doe (25, john@example.com), Jane Smith (30, jane@company.org)"
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
"enum_status": {
|
|
297
|
+
"description": "Simple enum field",
|
|
298
|
+
"schema": enum_schema('status', ['active', 'inactive', 'pending'], 'User status'),
|
|
299
|
+
"prompt_example": "Status: active"
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
"union_id": {
|
|
303
|
+
"description": "Union type field",
|
|
304
|
+
"schema": union_schema('id', ['string', 'integer'], 'Flexible ID field'),
|
|
305
|
+
"prompt_example": "ID: abc123 or ID: 12345"
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def get_examples() -> Dict[str, Dict[str, Any]]:
|
|
311
|
+
"""Get all enhanced simple schema examples"""
|
|
312
|
+
return ENHANCED_EXAMPLES.copy()
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def print_examples():
|
|
316
|
+
"""Print all enhanced simple schema examples"""
|
|
317
|
+
print("š§ Enhanced Simple Schema Examples:")
|
|
318
|
+
print("=" * 60)
|
|
319
|
+
|
|
320
|
+
for name, example in ENHANCED_EXAMPLES.items():
|
|
321
|
+
print(f"\nš {name.upper().replace('_', ' ')}")
|
|
322
|
+
print(f"Description: {example['description']}")
|
|
323
|
+
print(f"Prompt: {example['prompt_example']}")
|
|
324
|
+
print(f"Schema Preview: {_schema_preview(example['schema'])}")
|
|
325
|
+
print("-" * 40)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _schema_preview(schema: Dict[str, Any]) -> str:
|
|
329
|
+
"""Generate a preview of the schema structure"""
|
|
330
|
+
if schema.get('type') == 'object':
|
|
331
|
+
properties = schema.get('properties', {})
|
|
332
|
+
field_names = list(properties.keys())
|
|
333
|
+
if len(field_names) <= 3:
|
|
334
|
+
return f"Object with fields: {', '.join(field_names)}"
|
|
335
|
+
else:
|
|
336
|
+
return f"Object with {len(field_names)} fields: {', '.join(field_names[:3])}..."
|
|
337
|
+
elif schema.get('type') == 'array':
|
|
338
|
+
items = schema.get('items', {})
|
|
339
|
+
if items.get('type') == 'object':
|
|
340
|
+
item_fields = list(items.get('properties', {}).keys())
|
|
341
|
+
return f"Array of objects with fields: {', '.join(item_fields[:3])}"
|
|
342
|
+
else:
|
|
343
|
+
return f"Array of {items.get('type', 'items')}"
|
|
344
|
+
else:
|
|
345
|
+
return f"{schema.get('type', 'unknown')} type"
|