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.
@@ -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"