schemez 0.2.1__py3-none-any.whl → 0.2.3__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.
- schemez/__init__.py +5 -1
- schemez/pydantic_types.py +52 -0
- schemez/schema.py +12 -2
- schemez/schemadef/schemadef.py +142 -7
- {schemez-0.2.1.dist-info → schemez-0.2.3.dist-info}/METADATA +1 -1
- schemez-0.2.3.dist-info/RECORD +14 -0
- schemez-0.2.1.dist-info/RECORD +0 -13
- {schemez-0.2.1.dist-info → schemez-0.2.3.dist-info}/WHEEL +0 -0
- {schemez-0.2.1.dist-info → schemez-0.2.3.dist-info}/licenses/LICENSE +0 -0
schemez/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
__version__ = "0.2.
|
1
|
+
__version__ = "0.2.3"
|
2
2
|
|
3
3
|
|
4
4
|
from schemez.schema import Schema
|
@@ -9,11 +9,15 @@ from schemez.schemadef.schemadef import (
|
|
9
9
|
ImportedSchemaDef,
|
10
10
|
InlineSchemaDef,
|
11
11
|
)
|
12
|
+
from schemez.pydantic_types import ModelIdentifier, ModelTemperature, MimeType
|
12
13
|
|
13
14
|
__all__ = [
|
14
15
|
"ImportedSchemaDef",
|
15
16
|
"InlineSchemaDef",
|
16
17
|
"JSONCode",
|
18
|
+
"MimeType",
|
19
|
+
"ModelIdentifier",
|
20
|
+
"ModelTemperature",
|
17
21
|
"PythonCode",
|
18
22
|
"Schema",
|
19
23
|
"SchemaDef",
|
@@ -0,0 +1,52 @@
|
|
1
|
+
"""Custom field types with 'field_type' metadata for UI rendering hints."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import Annotated, Any
|
6
|
+
|
7
|
+
from pydantic import BaseModel, Field
|
8
|
+
|
9
|
+
|
10
|
+
ModelIdentifier = Annotated[
|
11
|
+
str,
|
12
|
+
Field(
|
13
|
+
json_schema_extra={"field_type": "model_identifier"},
|
14
|
+
pattern=r"^[a-zA-Z0-9\-]+(/[a-zA-Z0-9\-]+)*(:[\w\-\.]+)?$",
|
15
|
+
examples=["openai:gpt-o1-mini", "anthropic/claude-3-opus"],
|
16
|
+
description="Identifier for an AI model, optionally including provider.",
|
17
|
+
),
|
18
|
+
]
|
19
|
+
|
20
|
+
ModelTemperature = Annotated[
|
21
|
+
float,
|
22
|
+
Field(
|
23
|
+
json_schema_extra={"field_type": "temperature", "step": 0.1},
|
24
|
+
ge=0.0,
|
25
|
+
le=2.0,
|
26
|
+
description=(
|
27
|
+
"Controls randomness in model responses.\n"
|
28
|
+
"Lower values are more deterministic, higher values more creative"
|
29
|
+
),
|
30
|
+
examples=[0.0, 0.7, 1.0],
|
31
|
+
),
|
32
|
+
]
|
33
|
+
|
34
|
+
MimeType = Annotated[
|
35
|
+
str,
|
36
|
+
Field(
|
37
|
+
json_schema_extra={"field_type": "mime_type"},
|
38
|
+
pattern=r"^[a-z]+/[a-z0-9\-+.]+$",
|
39
|
+
examples=["text/plain", "application/pdf", "image/jpeg", "application/json"],
|
40
|
+
description="Standard MIME type identifying file formats and content types",
|
41
|
+
),
|
42
|
+
]
|
43
|
+
|
44
|
+
|
45
|
+
def get_field_type(model: type[BaseModel], field_name: str) -> dict[str, Any]:
|
46
|
+
"""Extract field_type metadata from a model field."""
|
47
|
+
field_info = model.model_fields[field_name]
|
48
|
+
metadata = {}
|
49
|
+
if field_info.json_schema_extra and isinstance(field_info.json_schema_extra, dict):
|
50
|
+
metadata.update(field_info.json_schema_extra)
|
51
|
+
|
52
|
+
return metadata
|
schemez/schema.py
CHANGED
@@ -216,11 +216,21 @@ class Schema(BaseModel):
|
|
216
216
|
|
217
217
|
return get_ctor_basemodel(target_cls)
|
218
218
|
|
219
|
-
def model_dump_yaml(
|
219
|
+
def model_dump_yaml(
|
220
|
+
self,
|
221
|
+
exclude_none: bool = True,
|
222
|
+
exclude_defaults: bool = False,
|
223
|
+
exclude_unset: bool = False,
|
224
|
+
) -> str:
|
220
225
|
"""Dump configuration to YAML string."""
|
221
226
|
import yamling
|
222
227
|
|
223
|
-
|
228
|
+
text = self.model_dump(
|
229
|
+
exclude_none=exclude_none,
|
230
|
+
exclude_defaults=exclude_defaults,
|
231
|
+
exclude_unset=exclude_unset,
|
232
|
+
)
|
233
|
+
return yamling.dump_yaml(text)
|
224
234
|
|
225
235
|
def save(self, path: StrPath, overwrite: bool = False) -> None:
|
226
236
|
"""Save configuration to a YAML file.
|
schemez/schemadef/schemadef.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
+
from enum import Enum
|
5
6
|
from typing import Annotated, Any, Literal
|
6
7
|
|
7
8
|
from pydantic import BaseModel, Field, create_model
|
@@ -16,6 +17,7 @@ class SchemaField(Schema):
|
|
16
17
|
- Data type specification
|
17
18
|
- Optional description
|
18
19
|
- Validation constraints
|
20
|
+
- Enum values (when type is 'enum')
|
19
21
|
|
20
22
|
Used by InlineSchemaDef to structure response fields.
|
21
23
|
"""
|
@@ -26,8 +28,58 @@ class SchemaField(Schema):
|
|
26
28
|
description: str | None = None
|
27
29
|
"""Optional description of what this field represents"""
|
28
30
|
|
31
|
+
values: list[Any] | None = None
|
32
|
+
"""Values for enum type fields"""
|
33
|
+
|
34
|
+
# Common validation constraints
|
35
|
+
default: Any | None = None
|
36
|
+
"""Default value for the field"""
|
37
|
+
|
38
|
+
title: str | None = None
|
39
|
+
"""Title for the field in generated JSON Schema"""
|
40
|
+
|
41
|
+
pattern: str | None = None
|
42
|
+
"""Regex pattern for string validation"""
|
43
|
+
|
44
|
+
min_length: int | None = None
|
45
|
+
"""Minimum length for collections"""
|
46
|
+
|
47
|
+
max_length: int | None = None
|
48
|
+
"""Maximum length for collections"""
|
49
|
+
|
50
|
+
gt: float | None = None
|
51
|
+
"""Greater than (exclusive) validation for numbers"""
|
52
|
+
|
53
|
+
ge: float | None = None
|
54
|
+
"""Greater than or equal (inclusive) validation for numbers"""
|
55
|
+
|
56
|
+
lt: float | None = None
|
57
|
+
"""Less than (exclusive) validation for numbers"""
|
58
|
+
|
59
|
+
le: float | None = None
|
60
|
+
"""Less than or equal (inclusive) validation for numbers"""
|
61
|
+
|
62
|
+
multiple_of: float | None = None
|
63
|
+
"""Number must be a multiple of this value"""
|
64
|
+
|
65
|
+
literal_value: Any | None = None
|
66
|
+
"""Value for Literal type constraint, makes field accept only this specific value"""
|
67
|
+
|
68
|
+
examples: list[Any] | None = None
|
69
|
+
"""Examples for this field in JSON Schema"""
|
70
|
+
|
71
|
+
optional: bool = False
|
72
|
+
"""Whether this field is optional (None value allowed)"""
|
73
|
+
|
74
|
+
json_schema_extra: dict[str, Any] | None = None
|
75
|
+
"""Additional JSON Schema information"""
|
76
|
+
|
77
|
+
field_config: dict[str, Any] | None = None
|
78
|
+
"""Configuration for Pydantic model fields"""
|
79
|
+
|
80
|
+
# Extensibility for future or custom constraints
|
29
81
|
constraints: dict[str, Any] = Field(default_factory=dict)
|
30
|
-
"""
|
82
|
+
"""Additional constraints not covered by explicit fields"""
|
31
83
|
|
32
84
|
|
33
85
|
class BaseSchemaDef(Schema):
|
@@ -66,12 +118,95 @@ class InlineSchemaDef(BaseSchemaDef):
|
|
66
118
|
"""Create Pydantic model from inline definition."""
|
67
119
|
fields = {}
|
68
120
|
for name, field in self.fields.items():
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
121
|
+
# Initialize constraint dictionary
|
122
|
+
field_constraints = {}
|
123
|
+
|
124
|
+
# Handle enum type
|
125
|
+
if field.type == "enum":
|
126
|
+
if not field.values:
|
127
|
+
msg = f"Field '{name}' has type 'enum' but no values defined"
|
128
|
+
raise ValueError(msg)
|
129
|
+
|
130
|
+
# Create dynamic Enum class
|
131
|
+
enum_name = f"{name.capitalize()}Enum"
|
132
|
+
|
133
|
+
# Create enum members dictionary
|
134
|
+
enum_members = {}
|
135
|
+
for i, value in enumerate(field.values):
|
136
|
+
if isinstance(value, str) and value.isidentifier():
|
137
|
+
# If value is a valid Python identifier, use it as is
|
138
|
+
key = value
|
139
|
+
else:
|
140
|
+
# Otherwise, create a synthetic name
|
141
|
+
key = f"VALUE_{i}"
|
142
|
+
enum_members[key] = value
|
143
|
+
|
144
|
+
# Create the enum class
|
145
|
+
enum_class = Enum(enum_name, enum_members)
|
146
|
+
python_type: Any = enum_class
|
147
|
+
|
148
|
+
# Handle enum default value specially
|
149
|
+
if field.default is not None:
|
150
|
+
# Store default value as the enum value string
|
151
|
+
# Pydantic v2 will convert it to the enum instance
|
152
|
+
if field.default in list(field.values):
|
153
|
+
field_constraints["default"] = field.default
|
154
|
+
else:
|
155
|
+
msg = (
|
156
|
+
f"Default value {field.default!r} not found "
|
157
|
+
f"in enum values for field {name!r}"
|
158
|
+
)
|
159
|
+
raise ValueError(msg)
|
160
|
+
else:
|
161
|
+
python_type = helpers.resolve_type_string(field.type)
|
162
|
+
if not python_type:
|
163
|
+
msg = f"Unsupported field type: {field.type}"
|
164
|
+
raise ValueError(msg)
|
165
|
+
|
166
|
+
# Handle literal constraint if provided
|
167
|
+
if field.literal_value is not None:
|
168
|
+
from typing import Literal as LiteralType
|
169
|
+
|
170
|
+
python_type = LiteralType[field.literal_value]
|
171
|
+
|
172
|
+
# Handle optional fields (allowing None)
|
173
|
+
if field.optional:
|
174
|
+
python_type = python_type | None # type: ignore
|
175
|
+
|
176
|
+
# Add standard Pydantic constraints
|
177
|
+
# Collect all constraint values
|
178
|
+
for constraint in [
|
179
|
+
"default",
|
180
|
+
"title",
|
181
|
+
"min_length",
|
182
|
+
"max_length",
|
183
|
+
"pattern",
|
184
|
+
"min_length",
|
185
|
+
"max_length",
|
186
|
+
"gt",
|
187
|
+
"ge",
|
188
|
+
"lt",
|
189
|
+
"le",
|
190
|
+
"multiple_of",
|
191
|
+
]:
|
192
|
+
value = getattr(field, constraint, None)
|
193
|
+
if value is not None:
|
194
|
+
field_constraints[constraint] = value
|
195
|
+
|
196
|
+
# Handle examples separately (Pydantic v2 way)
|
197
|
+
if field.examples:
|
198
|
+
if field.json_schema_extra is None:
|
199
|
+
field.json_schema_extra = {}
|
200
|
+
field.json_schema_extra["examples"] = field.examples
|
201
|
+
|
202
|
+
# Add json_schema_extra if provided
|
203
|
+
if field.json_schema_extra:
|
204
|
+
field_constraints["json_schema_extra"] = field.json_schema_extra
|
205
|
+
|
206
|
+
# Add any additional constraints
|
207
|
+
field_constraints.update(field.constraints)
|
208
|
+
|
209
|
+
field_info = Field(description=field.description, **field_constraints)
|
75
210
|
fields[name] = (python_type, field_info)
|
76
211
|
|
77
212
|
cls_name = self.description or "ResponseType"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
schemez/__init__.py,sha256=QrVN-zXLiAwYYdMbCxin08TTcks9QkRXZt4FyS5XwLw,565
|
2
|
+
schemez/code.py,sha256=usZLov9i5KpK1W2VJxngUzeetgrINtodiooG_AxN-y4,2072
|
3
|
+
schemez/convert.py,sha256=b6Sz11lq0HvpXfMREOqnnw8rcVg2XzTKhjjPNc4YIoE,4403
|
4
|
+
schemez/docstrings.py,sha256=kmd660wcomXzKac0SSNYxPRNbVCUovrpmE9jwnVRS6c,4115
|
5
|
+
schemez/helpers.py,sha256=Ee3wvFbt65ljhWDFdb6ACVUJK4KLjJFVzl4Le75pOBQ,5159
|
6
|
+
schemez/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
schemez/pydantic_types.py,sha256=iiaHqVkWVd1TZry933aDYJnyzMD0HJIABfROR9txxhA,1581
|
8
|
+
schemez/schema.py,sha256=VeNSFec6aCR9GgqXLBE3t4TZeUoS9BDmIoofe9nbqVI,8804
|
9
|
+
schemez/schemadef/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
schemez/schemadef/schemadef.py,sha256=43GQ8puUBByiSMaDbR6sJ0B-AjRSYQhEvX2Rx4gmjHI,8609
|
11
|
+
schemez-0.2.3.dist-info/METADATA,sha256=hI62AloXcRv4SKKeiSmdycBJOuIZWdWfLGeIueu8ss0,5891
|
12
|
+
schemez-0.2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
13
|
+
schemez-0.2.3.dist-info/licenses/LICENSE,sha256=AteGCH9r177TxxrOFEiOARrastASsf7yW6MQxlAHdwA,1078
|
14
|
+
schemez-0.2.3.dist-info/RECORD,,
|
schemez-0.2.1.dist-info/RECORD
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
schemez/__init__.py,sha256=gniCM7yfehxd93fGd154YFF-4suRuZtRbQwJVg-63cU,423
|
2
|
-
schemez/code.py,sha256=usZLov9i5KpK1W2VJxngUzeetgrINtodiooG_AxN-y4,2072
|
3
|
-
schemez/convert.py,sha256=b6Sz11lq0HvpXfMREOqnnw8rcVg2XzTKhjjPNc4YIoE,4403
|
4
|
-
schemez/docstrings.py,sha256=kmd660wcomXzKac0SSNYxPRNbVCUovrpmE9jwnVRS6c,4115
|
5
|
-
schemez/helpers.py,sha256=Ee3wvFbt65ljhWDFdb6ACVUJK4KLjJFVzl4Le75pOBQ,5159
|
6
|
-
schemez/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
schemez/schema.py,sha256=8nwLYW6J-RIMbKjt0BZK3zlktZZzBYXabGFlaQsecCQ,8538
|
8
|
-
schemez/schemadef/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
schemez/schemadef/schemadef.py,sha256=TLfcmCxPLZEvScxuIMlss0QDRWtQNhxLQ8z2i0Linoc,3794
|
10
|
-
schemez-0.2.1.dist-info/METADATA,sha256=sd3YrOY6JfwDjhkO9sidYWd8BhqhQDLxW0pmxrwG3_4,5891
|
11
|
-
schemez-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
-
schemez-0.2.1.dist-info/licenses/LICENSE,sha256=AteGCH9r177TxxrOFEiOARrastASsf7yW6MQxlAHdwA,1078
|
13
|
-
schemez-0.2.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|