string-schema 0.1.1__tar.gz → 0.1.3__tar.gz

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. {string_schema-0.1.1/string_schema.egg-info → string_schema-0.1.3}/PKG-INFO +2 -3
  2. {string_schema-0.1.1 → string_schema-0.1.3}/pyproject.toml +5 -5
  3. {string_schema-0.1.1 → string_schema-0.1.3}/setup.py +1 -2
  4. string_schema-0.1.3/string_schema/core/__init__.py +23 -0
  5. string_schema-0.1.3/string_schema/core/builders.py +244 -0
  6. string_schema-0.1.3/string_schema/core/fields.py +138 -0
  7. string_schema-0.1.3/string_schema/core/validators.py +242 -0
  8. string_schema-0.1.3/string_schema/examples/__init__.py +36 -0
  9. string_schema-0.1.3/string_schema/examples/presets.py +345 -0
  10. string_schema-0.1.3/string_schema/examples/recipes.py +380 -0
  11. string_schema-0.1.3/string_schema/integrations/__init__.py +15 -0
  12. string_schema-0.1.3/string_schema/integrations/json_schema.py +385 -0
  13. string_schema-0.1.3/string_schema/integrations/openapi.py +484 -0
  14. string_schema-0.1.3/string_schema/integrations/pydantic.py +662 -0
  15. string_schema-0.1.3/string_schema/integrations/reverse.py +275 -0
  16. string_schema-0.1.3/string_schema/parsing/__init__.py +16 -0
  17. string_schema-0.1.3/string_schema/parsing/optimizer.py +246 -0
  18. string_schema-0.1.3/string_schema/parsing/string_parser.py +703 -0
  19. string_schema-0.1.3/string_schema/parsing/syntax.py +250 -0
  20. {string_schema-0.1.1 → string_schema-0.1.3/string_schema.egg-info}/PKG-INFO +2 -3
  21. string_schema-0.1.3/string_schema.egg-info/SOURCES.txt +40 -0
  22. string_schema-0.1.1/string_schema.egg-info/SOURCES.txt +0 -24
  23. {string_schema-0.1.1 → string_schema-0.1.3}/LICENSE +0 -0
  24. {string_schema-0.1.1 → string_schema-0.1.3}/MANIFEST.in +0 -0
  25. {string_schema-0.1.1 → string_schema-0.1.3}/README.md +0 -0
  26. {string_schema-0.1.1 → string_schema-0.1.3}/docs/README.md +0 -0
  27. {string_schema-0.1.1 → string_schema-0.1.3}/docs/advanced-usage.md +0 -0
  28. {string_schema-0.1.1 → string_schema-0.1.3}/docs/api-reference.md +0 -0
  29. {string_schema-0.1.1 → string_schema-0.1.3}/docs/examples.md +0 -0
  30. {string_schema-0.1.1 → string_schema-0.1.3}/docs/faq.md +0 -0
  31. {string_schema-0.1.1 → string_schema-0.1.3}/docs/getting-started.md +0 -0
  32. {string_schema-0.1.1 → string_schema-0.1.3}/docs/pydantic-utilities.md +0 -0
  33. {string_schema-0.1.1 → string_schema-0.1.3}/docs/string-syntax.md +0 -0
  34. {string_schema-0.1.1 → string_schema-0.1.3}/docs/troubleshooting.md +0 -0
  35. {string_schema-0.1.1 → string_schema-0.1.3}/examples/demo.py +0 -0
  36. {string_schema-0.1.1 → string_schema-0.1.3}/examples/pydantic_utility_demo.py +0 -0
  37. {string_schema-0.1.1 → string_schema-0.1.3}/setup.cfg +0 -0
  38. {string_schema-0.1.1 → string_schema-0.1.3}/string_schema/__init__.py +0 -0
  39. {string_schema-0.1.1 → string_schema-0.1.3}/string_schema/py.typed +0 -0
  40. {string_schema-0.1.1 → string_schema-0.1.3}/string_schema/utilities.py +0 -0
  41. {string_schema-0.1.1 → string_schema-0.1.3}/string_schema.egg-info/dependency_links.txt +0 -0
  42. {string_schema-0.1.1 → string_schema-0.1.3}/string_schema.egg-info/requires.txt +0 -0
  43. {string_schema-0.1.1 → string_schema-0.1.3}/string_schema.egg-info/top_level.txt +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: string-schema
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: A simple, LLM-friendly schema definition library for converting string syntax to structured schemas
5
5
  Home-page: https://github.com/xychenmsn/string-schema
6
6
  Author: Michael Chen
7
7
  Author-email: Michael Chen <xychen@msn.com>
8
8
  Maintainer-email: Michael Chen <xychen@msn.com>
9
- License: MIT
9
+ License-Expression: MIT
10
10
  Project-URL: Homepage, https://github.com/xychenmsn/string-schema
11
11
  Project-URL: Documentation, https://github.com/xychenmsn/string-schema#readme
12
12
  Project-URL: Repository, https://github.com/xychenmsn/string-schema
@@ -15,7 +15,6 @@ Project-URL: Changelog, https://github.com/xychenmsn/string-schema/releases
15
15
  Keywords: schema,validation,json,llm,ai,data-extraction,pydantic
16
16
  Classifier: Development Status :: 3 - Alpha
17
17
  Classifier: Intended Audience :: Developers
18
- Classifier: License :: OSI Approved :: MIT License
19
18
  Classifier: Operating System :: OS Independent
20
19
  Classifier: Programming Language :: Python :: 3
21
20
  Classifier: Programming Language :: Python :: 3.11
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "string-schema"
7
- version = "0.1.1"
7
+ version = "0.1.3"
8
8
  description = "A simple, LLM-friendly schema definition library for converting string syntax to structured schemas"
9
9
  readme = "README.md"
10
- license = {text = "MIT"}
10
+ license = "MIT"
11
11
  authors = [
12
12
  {name = "Michael Chen", email = "xychen@msn.com"}
13
13
  ]
@@ -18,7 +18,6 @@ keywords = ["schema", "validation", "json", "llm", "ai", "data-extraction", "pyd
18
18
  classifiers = [
19
19
  "Development Status :: 3 - Alpha",
20
20
  "Intended Audience :: Developers",
21
- "License :: OSI Approved :: MIT License",
22
21
  "Operating System :: OS Independent",
23
22
  "Programming Language :: Python :: 3",
24
23
  "Programming Language :: Python :: 3.11",
@@ -58,8 +57,9 @@ Repository = "https://github.com/xychenmsn/string-schema"
58
57
  "Bug Reports" = "https://github.com/xychenmsn/string-schema/issues"
59
58
  Changelog = "https://github.com/xychenmsn/string-schema/releases"
60
59
 
61
- [tool.setuptools]
62
- packages = ["string_schema"]
60
+ [tool.setuptools.packages.find]
61
+ where = ["."]
62
+ include = ["string_schema*"]
63
63
 
64
64
  [tool.setuptools.package-data]
65
65
  string_schema = ["py.typed"]
@@ -9,7 +9,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
9
9
 
10
10
  setup(
11
11
  name="string-schema",
12
- version="0.1.1",
12
+ version="0.1.3",
13
13
  author="Michael Chen",
14
14
  author_email="xychen@msn.com",
15
15
  description="A simple, LLM-friendly schema definition library for converting string syntax to structured schemas",
@@ -20,7 +20,6 @@ setup(
20
20
  classifiers=[
21
21
  "Development Status :: 3 - Alpha",
22
22
  "Intended Audience :: Developers",
23
- "License :: OSI Approved :: MIT License",
24
23
  "Operating System :: OS Independent",
25
24
  "Programming Language :: Python :: 3",
26
25
  "Programming Language :: Python :: 3.11",
@@ -0,0 +1,23 @@
1
+ """
2
+ Core module for String Schema
3
+
4
+ Contains the fundamental classes and functions for schema definition and building.
5
+ """
6
+
7
+ from .fields import SimpleField
8
+ from .builders import (
9
+ simple_schema,
10
+ list_of_objects_schema,
11
+ simple_array_schema,
12
+ quick_pydantic_model
13
+ )
14
+ from .validators import validate_schema
15
+
16
+ __all__ = [
17
+ "SimpleField",
18
+ "simple_schema",
19
+ "list_of_objects_schema",
20
+ "simple_array_schema",
21
+ "quick_pydantic_model",
22
+ "validate_schema"
23
+ ]
@@ -0,0 +1,244 @@
1
+ """
2
+ Schema builders for Simple Schema
3
+
4
+ Contains functions for building schemas from SimpleField definitions.
5
+ """
6
+
7
+ from typing import Any, Dict, List, Optional, Union, Type
8
+ import logging
9
+
10
+ from .fields import SimpleField
11
+
12
+ # Optional pydantic import
13
+ try:
14
+ from pydantic import BaseModel, Field, create_model
15
+ HAS_PYDANTIC = True
16
+ except ImportError:
17
+ HAS_PYDANTIC = False
18
+ BaseModel = None
19
+ Field = None
20
+ create_model = None
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def simple_schema(fields: Dict[str, Union[str, SimpleField]]) -> Dict[str, Any]:
26
+ """Generate JSON Schema from simple field definitions with enhanced support"""
27
+ properties = {}
28
+ required = []
29
+
30
+ for field_name, field_def in fields.items():
31
+ if isinstance(field_def, str):
32
+ field_def = SimpleField(field_def)
33
+
34
+ prop_schema = _simple_field_to_json_schema(field_def)
35
+ properties[field_name] = prop_schema
36
+
37
+ if field_def.required:
38
+ required.append(field_name)
39
+
40
+ schema = {
41
+ "type": "object",
42
+ "properties": properties
43
+ }
44
+ if required:
45
+ schema["required"] = required
46
+
47
+ return schema
48
+
49
+
50
+ def _simple_field_to_json_schema(field: SimpleField) -> Dict[str, Any]:
51
+ """Convert SimpleField to JSON Schema property with enhanced features"""
52
+ # Handle union types first
53
+ if field.union_types and len(field.union_types) > 1:
54
+ union_schemas = []
55
+ for union_type in field.union_types:
56
+ if union_type == "null":
57
+ union_schemas.append({"type": "null"})
58
+ else:
59
+ union_schemas.append({"type": union_type})
60
+ prop = {"anyOf": union_schemas}
61
+
62
+ # Add description to the union
63
+ if field.description:
64
+ prop["description"] = field.description
65
+
66
+ return prop
67
+
68
+ # Regular single type
69
+ prop = {"type": field.field_type}
70
+
71
+ if field.description:
72
+ prop["description"] = field.description
73
+ if field.default is not None:
74
+ prop["default"] = field.default
75
+
76
+ # Handle enum/choices
77
+ if field.choices:
78
+ prop["enum"] = field.choices
79
+
80
+ # Add format hints for special types
81
+ if field.format_hint:
82
+ if field.format_hint == "email":
83
+ prop["format"] = "email"
84
+ elif field.format_hint in ["url", "uri"]:
85
+ prop["format"] = "uri"
86
+ elif field.format_hint == "datetime":
87
+ prop["format"] = "date-time"
88
+ elif field.format_hint == "date":
89
+ prop["format"] = "date"
90
+ elif field.format_hint == "uuid":
91
+ prop["format"] = "uuid"
92
+ # Note: phone doesn't have a standard JSON Schema format
93
+
94
+ # Numeric constraints
95
+ if field.field_type in ["integer", "number"]:
96
+ if field.min_val is not None:
97
+ prop["minimum"] = field.min_val
98
+ if field.max_val is not None:
99
+ prop["maximum"] = field.max_val
100
+
101
+ # String constraints
102
+ if field.field_type == "string":
103
+ if field.min_length is not None:
104
+ prop["minLength"] = field.min_length
105
+ if field.max_length is not None:
106
+ prop["maxLength"] = field.max_length
107
+
108
+ # Array constraints (for when this field itself is an array)
109
+ if field.min_items is not None:
110
+ prop["minItems"] = field.min_items
111
+ if field.max_items is not None:
112
+ prop["maxItems"] = field.max_items
113
+
114
+ return prop
115
+
116
+
117
+ def list_of_objects_schema(item_fields: Dict[str, Union[str, SimpleField]],
118
+ description: str = "List of objects",
119
+ min_items: Optional[int] = None,
120
+ max_items: Optional[int] = None) -> Dict[str, Any]:
121
+ """Generate schema for array of objects with enhanced constraints"""
122
+ item_schema = simple_schema(item_fields)
123
+
124
+ array_schema = {
125
+ "type": "array",
126
+ "description": description,
127
+ "items": item_schema
128
+ }
129
+
130
+ # Add array size constraints
131
+ if min_items is not None:
132
+ array_schema["minItems"] = min_items
133
+ if max_items is not None:
134
+ array_schema["maxItems"] = max_items
135
+
136
+ return array_schema
137
+
138
+
139
+ def simple_array_schema(item_type: str = 'string', description: str = 'Array of items',
140
+ min_items: Optional[int] = None, max_items: Optional[int] = None,
141
+ format_hint: Optional[str] = None) -> Dict[str, Any]:
142
+ """Generate schema for simple arrays like [string], [int], [email]"""
143
+ items_schema = {"type": item_type}
144
+
145
+ # Add format for special types
146
+ if format_hint:
147
+ if format_hint == "email":
148
+ items_schema["format"] = "email"
149
+ elif format_hint in ["url", "uri"]:
150
+ items_schema["format"] = "uri"
151
+ elif format_hint == "datetime":
152
+ items_schema["format"] = "date-time"
153
+ elif format_hint == "date":
154
+ items_schema["format"] = "date"
155
+ elif format_hint == "uuid":
156
+ items_schema["format"] = "uuid"
157
+
158
+ array_schema = {
159
+ "type": "array",
160
+ "description": description,
161
+ "items": items_schema
162
+ }
163
+
164
+ # Add array size constraints
165
+ if min_items is not None:
166
+ array_schema["minItems"] = min_items
167
+ if max_items is not None:
168
+ array_schema["maxItems"] = max_items
169
+
170
+ return array_schema
171
+
172
+
173
+ def quick_pydantic_model(name: str, fields: Dict[str, Union[str, SimpleField]]) -> Type:
174
+ """Create Pydantic model from simple field definitions"""
175
+ if not HAS_PYDANTIC:
176
+ raise ImportError("Pydantic is required for quick_pydantic_model. Install with: pip install pydantic")
177
+
178
+ pydantic_fields = {}
179
+
180
+ for field_name, field_def in fields.items():
181
+ if isinstance(field_def, str):
182
+ field_def = SimpleField(field_def)
183
+
184
+ from ..integrations.pydantic import _simple_field_to_pydantic
185
+ python_type, field_info = _simple_field_to_pydantic(field_def)
186
+ pydantic_fields[field_name] = (python_type, field_info)
187
+
188
+ return create_model(name, **pydantic_fields)
189
+
190
+
191
+ def _simple_field_to_pydantic(field: SimpleField) -> tuple:
192
+ """Convert SimpleField to Pydantic field specification"""
193
+ if not HAS_PYDANTIC:
194
+ raise ImportError("Pydantic is required for this function")
195
+
196
+ # Type mapping
197
+ type_mapping = {
198
+ 'string': str,
199
+ 'integer': int,
200
+ 'number': float,
201
+ 'boolean': bool
202
+ }
203
+
204
+ python_type = type_mapping.get(field.field_type, str)
205
+
206
+ # Handle union types
207
+ if field.union_types and len(field.union_types) > 1:
208
+ from typing import Union as TypingUnion
209
+ union_python_types = []
210
+ for union_type in field.union_types:
211
+ if union_type == "null":
212
+ union_python_types.append(type(None))
213
+ else:
214
+ union_python_types.append(type_mapping.get(union_type, str))
215
+ python_type = TypingUnion[tuple(union_python_types)]
216
+
217
+ # Handle optional fields
218
+ if not field.required:
219
+ python_type = Optional[python_type]
220
+
221
+ # Build Field arguments
222
+ field_kwargs = {}
223
+
224
+ if field.description:
225
+ field_kwargs['description'] = field.description
226
+
227
+ if field.default is not None:
228
+ field_kwargs['default'] = field.default
229
+ elif not field.required:
230
+ field_kwargs['default'] = None
231
+
232
+ # Numeric constraints
233
+ if field.min_val is not None:
234
+ field_kwargs['ge'] = field.min_val
235
+ if field.max_val is not None:
236
+ field_kwargs['le'] = field.max_val
237
+
238
+ # String constraints
239
+ if field.min_length is not None:
240
+ field_kwargs['min_length'] = field.min_length
241
+ if field.max_length is not None:
242
+ field_kwargs['max_length'] = field.max_length
243
+
244
+ return python_type, Field(**field_kwargs) if field_kwargs else Field()
@@ -0,0 +1,138 @@
1
+ """
2
+ Core field definitions for Simple Schema
3
+
4
+ Contains the SimpleField class and related field utilities.
5
+ """
6
+
7
+ from typing import Any, List, Optional, Union
8
+ import logging
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class SimpleField:
14
+ """Enhanced SimpleField with support for all new features"""
15
+
16
+ def __init__(self, field_type: str, description: str = "", required: bool = True,
17
+ default: Any = None, min_val: Optional[Union[int, float]] = None,
18
+ max_val: Optional[Union[int, float]] = None, min_length: Optional[int] = None,
19
+ max_length: Optional[int] = None, choices: Optional[List[Any]] = None,
20
+ min_items: Optional[int] = None, max_items: Optional[int] = None,
21
+ format_hint: Optional[str] = None, union_types: Optional[List[str]] = None):
22
+ """
23
+ Initialize a SimpleField with comprehensive validation options.
24
+
25
+ Args:
26
+ field_type: The base type (string, integer, number, boolean)
27
+ description: Human-readable description of the field
28
+ required: Whether the field is required (default: True)
29
+ default: Default value if field is not provided
30
+ min_val: Minimum value for numeric types
31
+ max_val: Maximum value for numeric types
32
+ min_length: Minimum length for string types
33
+ max_length: Maximum length for string types
34
+ choices: List of allowed values (enum)
35
+ min_items: Minimum items for array types
36
+ max_items: Maximum items for array types
37
+ format_hint: Special format hint (email, url, datetime, etc.)
38
+ union_types: List of types for union fields
39
+ """
40
+ self.field_type = field_type
41
+ self.description = description
42
+ self.required = required
43
+ self.default = default
44
+ self.min_val = min_val
45
+ self.max_val = max_val
46
+ self.min_length = min_length
47
+ self.max_length = max_length
48
+ self.choices = choices
49
+ self.min_items = min_items
50
+ self.max_items = max_items
51
+ self.format_hint = format_hint
52
+ self.union_types = union_types or []
53
+
54
+ def __repr__(self):
55
+ """String representation of the field"""
56
+ parts = [f"type={self.field_type}"]
57
+ if self.description:
58
+ parts.append(f"desc='{self.description}'")
59
+ if not self.required:
60
+ parts.append("optional")
61
+ if self.choices:
62
+ parts.append(f"choices={self.choices}")
63
+ if self.union_types:
64
+ parts.append(f"union={self.union_types}")
65
+ return f"SimpleField({', '.join(parts)})"
66
+
67
+ def to_dict(self) -> dict:
68
+ """Convert field to dictionary representation"""
69
+ result = {
70
+ 'type': self.field_type,
71
+ 'required': self.required
72
+ }
73
+
74
+ if self.description:
75
+ result['description'] = self.description
76
+ if self.default is not None:
77
+ result['default'] = self.default
78
+ if self.min_val is not None:
79
+ result['min_val'] = self.min_val
80
+ if self.max_val is not None:
81
+ result['max_val'] = self.max_val
82
+ if self.min_length is not None:
83
+ result['min_length'] = self.min_length
84
+ if self.max_length is not None:
85
+ result['max_length'] = self.max_length
86
+ if self.choices:
87
+ result['choices'] = self.choices
88
+ if self.min_items is not None:
89
+ result['min_items'] = self.min_items
90
+ if self.max_items is not None:
91
+ result['max_items'] = self.max_items
92
+ if self.format_hint:
93
+ result['format_hint'] = self.format_hint
94
+ if self.union_types:
95
+ result['union_types'] = self.union_types
96
+
97
+ return result
98
+
99
+ @classmethod
100
+ def from_dict(cls, data: dict) -> 'SimpleField':
101
+ """Create SimpleField from dictionary representation"""
102
+ return cls(
103
+ field_type=data['type'],
104
+ description=data.get('description', ''),
105
+ required=data.get('required', True),
106
+ default=data.get('default'),
107
+ min_val=data.get('min_val'),
108
+ max_val=data.get('max_val'),
109
+ min_length=data.get('min_length'),
110
+ max_length=data.get('max_length'),
111
+ choices=data.get('choices'),
112
+ min_items=data.get('min_items'),
113
+ max_items=data.get('max_items'),
114
+ format_hint=data.get('format_hint'),
115
+ union_types=data.get('union_types')
116
+ )
117
+
118
+
119
+ # Utility functions for creating common field types
120
+ def create_enhanced_field(field_type: str, **kwargs) -> SimpleField:
121
+ """Create enhanced SimpleField with all features"""
122
+ return SimpleField(field_type, **kwargs)
123
+
124
+
125
+ def create_special_type_field(special_type: str, required: bool = True, **kwargs) -> SimpleField:
126
+ """Create field with special type hints"""
127
+ return SimpleField('string', format_hint=special_type, required=required, **kwargs)
128
+
129
+
130
+ def create_enum_field(values: List[str], required: bool = True, **kwargs) -> SimpleField:
131
+ """Create enum field with specific values"""
132
+ return SimpleField('string', choices=values, required=required, **kwargs)
133
+
134
+
135
+ def create_union_field(types: List[str], required: bool = True, **kwargs) -> SimpleField:
136
+ """Create union field with multiple types"""
137
+ primary_type = types[0] if types else 'string'
138
+ return SimpleField(primary_type, union_types=types, required=required, **kwargs)