schemez 1.2.0__tar.gz → 1.2.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.
- schemez-1.2.3/PKG-INFO +340 -0
- schemez-1.2.3/README.md +296 -0
- {schemez-1.2.0 → schemez-1.2.3}/pyproject.toml +7 -3
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/convert.py +1 -1
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/functionschema.py +18 -20
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/helpers.py +15 -44
- schemez-1.2.3/src/schemez/log.py +17 -0
- schemez-1.2.3/src/schemez/tool_executor/__init__.py +8 -0
- schemez-1.2.3/src/schemez/tool_executor/executor.py +322 -0
- schemez-1.2.3/src/schemez/tool_executor/helpers.py +46 -0
- schemez-1.2.3/src/schemez/tool_executor/types.py +28 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/typedefs.py +2 -2
- schemez-1.2.0/PKG-INFO +0 -86
- schemez-1.2.0/README.md +0 -26
- {schemez-1.2.0 → schemez-1.2.3}/LICENSE +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/__init__.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/bind_kwargs.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/code.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/create_type.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/docstrings.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/executable.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/py.typed +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/pydantic_types.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/schema.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/schema_generators.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/schemadef/__init__.py +0 -0
- {schemez-1.2.0 → schemez-1.2.3}/src/schemez/schemadef/schemadef.py +0 -0
schemez-1.2.3/PKG-INFO
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: schemez
|
3
|
+
Version: 1.2.3
|
4
|
+
Summary: Pydantic shim for config stuff
|
5
|
+
Keywords:
|
6
|
+
Author: Philipp Temminghoff
|
7
|
+
Author-email: Philipp Temminghoff <philipptemminghoff@googlemail.com>
|
8
|
+
License-Expression: MIT
|
9
|
+
License-File: LICENSE
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
11
|
+
Classifier: Framework :: Pydantic
|
12
|
+
Classifier: Framework :: Pydantic :: 2
|
13
|
+
Classifier: Intended Audience :: Developers
|
14
|
+
Classifier: Operating System :: OS Independent
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
20
|
+
Classifier: Topic :: Documentation
|
21
|
+
Classifier: Topic :: Software Development
|
22
|
+
Classifier: Topic :: Utilities
|
23
|
+
Classifier: Typing :: Typed
|
24
|
+
Requires-Dist: docstring-parser>=0.17.0
|
25
|
+
Requires-Dist: griffe>=1.7.3
|
26
|
+
Requires-Dist: pydantic
|
27
|
+
Requires-Dist: universal-pathlib>=0.2.6
|
28
|
+
Requires-Dist: llmling-agent ; extra == 'ai'
|
29
|
+
Requires-Dist: anyenv>=0.4.14 ; extra == 'ai'
|
30
|
+
Requires-Dist: datamodel-code-generator ; extra == 'codegen'
|
31
|
+
Requires-Dist: fastapi>=0.118.2 ; extra == 'tool-execution'
|
32
|
+
Requires-Dist: yamling ; extra == 'yaml'
|
33
|
+
Requires-Python: >=3.13
|
34
|
+
Project-URL: Code coverage, https://app.codecov.io/gh/phil65/schemez
|
35
|
+
Project-URL: Discussions, https://github.com/phil65/schemez/discussions
|
36
|
+
Project-URL: Documentation, https://phil65.github.io/schemez/
|
37
|
+
Project-URL: Issues, https://github.com/phil65/schemez/issues
|
38
|
+
Project-URL: Source, https://github.com/phil65/schemez
|
39
|
+
Provides-Extra: ai
|
40
|
+
Provides-Extra: codegen
|
41
|
+
Provides-Extra: tool-execution
|
42
|
+
Provides-Extra: yaml
|
43
|
+
Description-Content-Type: text/markdown
|
44
|
+
|
45
|
+
# Schemez
|
46
|
+
|
47
|
+
[](https://pypi.org/project/schemez/)
|
48
|
+
[](https://pypi.org/project/schemez/)
|
49
|
+
[](https://pypi.org/project/schemez/)
|
50
|
+
[](https://pypi.org/project/schemez/)
|
51
|
+
[](https://pypi.org/project/schemez/)
|
52
|
+
[](https://pypi.org/project/schemez/)
|
53
|
+
[](https://pypi.org/project/schemez/)
|
54
|
+
[](https://github.com/phil65/schemez/releases)
|
55
|
+
[](https://github.com/phil65/schemez/graphs/contributors)
|
56
|
+
[](https://github.com/phil65/schemez/discussions)
|
57
|
+
[](https://github.com/phil65/schemez/forks)
|
58
|
+
[](https://github.com/phil65/schemez/issues)
|
59
|
+
[](https://github.com/phil65/schemez/pulls)
|
60
|
+
[](https://github.com/phil65/schemez/watchers)
|
61
|
+
[](https://github.com/phil65/schemez/stars)
|
62
|
+
[](https://github.com/phil65/schemez)
|
63
|
+
[](https://github.com/phil65/schemez/commits)
|
64
|
+
[](https://github.com/phil65/schemez/releases)
|
65
|
+
[](https://github.com/phil65/schemez)
|
66
|
+
[](https://github.com/phil65/schemez)
|
67
|
+
[](https://codecov.io/gh/phil65/schemez/)
|
68
|
+
[](https://pyup.io/repos/github/phil65/schemez/)
|
69
|
+
|
70
|
+
[Read the documentation!](https://phil65.github.io/schemez/)
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
# OpenAI Function Schema Generator
|
75
|
+
|
76
|
+
Convert Python functions to OpenAI-compatible function schemas automatically.
|
77
|
+
|
78
|
+
## Installation
|
79
|
+
|
80
|
+
```bash
|
81
|
+
pip install schemez
|
82
|
+
```
|
83
|
+
|
84
|
+
## Basic Usage
|
85
|
+
|
86
|
+
```python
|
87
|
+
from schemez import create_schema
|
88
|
+
from typing import Literal
|
89
|
+
|
90
|
+
def get_weather(
|
91
|
+
location: str,
|
92
|
+
unit: Literal["C", "F"] = "C",
|
93
|
+
detailed: bool = False,
|
94
|
+
) -> dict[str, str | float]:
|
95
|
+
"""Get the weather for a location.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
location: City or address to get weather for
|
99
|
+
unit: Temperature unit (Celsius or Fahrenheit)
|
100
|
+
detailed: Include extended forecast
|
101
|
+
"""
|
102
|
+
return {"temp": 22.5, "conditions": "sunny"}
|
103
|
+
|
104
|
+
# Create schema
|
105
|
+
schema = create_schema(get_weather)
|
106
|
+
|
107
|
+
# The schema.model_dump_openai() returns a TypedDict with the complete OpenAI tool definition:
|
108
|
+
# OpenAIFunctionTool = TypedDict({
|
109
|
+
# "type": Literal["function"],
|
110
|
+
# "function": OpenAIFunctionDefinition
|
111
|
+
# })
|
112
|
+
|
113
|
+
# Use with OpenAI
|
114
|
+
from openai import OpenAI
|
115
|
+
|
116
|
+
client = OpenAI()
|
117
|
+
response = client.chat.completions.create(
|
118
|
+
model="gpt-4",
|
119
|
+
messages=[{"role": "user", "content": "What's the weather in London?"}],
|
120
|
+
tools=[schema.model_dump_openai()], # Schema includes the type: "function" wrapper
|
121
|
+
tool_choice="auto"
|
122
|
+
)
|
123
|
+
```
|
124
|
+
|
125
|
+
> **Note**: This library supports the OpenAI API v1 format (openai>=1.0.0). For older
|
126
|
+
> versions of the OpenAI package that use the legacy functions API, you'll need to
|
127
|
+
> unwrap the function definition using `schema.model_dump_openai()["function"]`.
|
128
|
+
```
|
129
|
+
|
130
|
+
## Supported Types
|
131
|
+
|
132
|
+
### Basic Types
|
133
|
+
```python
|
134
|
+
def func(
|
135
|
+
text: str, # -> "type": "string"
|
136
|
+
number: int, # -> "type": "integer"
|
137
|
+
amount: float, # -> "type": "number"
|
138
|
+
enabled: bool, # -> "type": "boolean"
|
139
|
+
anything: Any, # -> "type": "string"
|
140
|
+
) -> None: ...
|
141
|
+
```
|
142
|
+
|
143
|
+
### Container Types
|
144
|
+
```python
|
145
|
+
def func(
|
146
|
+
items: list[str], # -> "type": "array", "items": {"type": "string"}
|
147
|
+
numbers: set[int], # -> same as list
|
148
|
+
mapping: dict[str, Any], # -> "type": "object", "additionalProperties": true
|
149
|
+
nested: list[dict[str, int]], # -> nested array/object types
|
150
|
+
sequence: Sequence[str], # -> "type": "array"
|
151
|
+
collection: Collection[int], # -> "type": "array"
|
152
|
+
) -> None: ...
|
153
|
+
```
|
154
|
+
|
155
|
+
### Enums and Literals
|
156
|
+
```python
|
157
|
+
class Color(Enum):
|
158
|
+
RED = "red"
|
159
|
+
BLUE = "blue"
|
160
|
+
|
161
|
+
def func(
|
162
|
+
color: Color, # -> "type": "string", "enum": ["red", "blue"]
|
163
|
+
mode: Literal["fast", "slow"], # -> "type": "string", "enum": ["fast", "slow"]
|
164
|
+
) -> None: ...
|
165
|
+
```
|
166
|
+
|
167
|
+
### Optional and Union Types
|
168
|
+
```python
|
169
|
+
def func(
|
170
|
+
opt1: str | None, # -> "type": "string"
|
171
|
+
opt2: int | None, # -> "type": "integer"
|
172
|
+
union: str | int, # -> "type": "string" (first type)
|
173
|
+
) -> None: ...
|
174
|
+
```
|
175
|
+
|
176
|
+
### Custom Types
|
177
|
+
```python
|
178
|
+
@dataclass
|
179
|
+
class User:
|
180
|
+
name: str
|
181
|
+
age: int
|
182
|
+
|
183
|
+
def func(
|
184
|
+
user: User, # -> "type": "object"
|
185
|
+
data: JsonDict, # -> "type": "object"
|
186
|
+
) -> None: ...
|
187
|
+
```
|
188
|
+
|
189
|
+
### Type Aliases
|
190
|
+
```python
|
191
|
+
JsonValue = dict[str, Any] | list[Any] | str | int | float | bool | None
|
192
|
+
JsonDict = dict[str, JsonValue]
|
193
|
+
|
194
|
+
def func(
|
195
|
+
data: JsonDict, # -> "type": "object"
|
196
|
+
values: list[JsonValue], # -> "type": "array"
|
197
|
+
) -> None: ...
|
198
|
+
```
|
199
|
+
|
200
|
+
### Recursive Types
|
201
|
+
```python
|
202
|
+
def func(
|
203
|
+
tree: dict[str, "dict[str, Any] | str"], # -> "type": "object"
|
204
|
+
nested: dict[str, list["dict[str, Any]"]], # -> "type": "object"
|
205
|
+
) -> None: ...
|
206
|
+
```
|
207
|
+
|
208
|
+
## Generated Schema Example
|
209
|
+
|
210
|
+
```python
|
211
|
+
{
|
212
|
+
"type": "function",
|
213
|
+
"function": {
|
214
|
+
"name": "get_weather",
|
215
|
+
"description": "Get the weather for a location.",
|
216
|
+
"parameters": {
|
217
|
+
"type": "object",
|
218
|
+
"properties": {
|
219
|
+
"location": {
|
220
|
+
"type": "string",
|
221
|
+
"description": "City or address to get weather for"
|
222
|
+
},
|
223
|
+
"unit": {
|
224
|
+
"type": "string",
|
225
|
+
"enum": ["C", "F"],
|
226
|
+
"description": "Temperature unit (Celsius or Fahrenheit)",
|
227
|
+
"default": "C"
|
228
|
+
},
|
229
|
+
"detailed": {
|
230
|
+
"type": "boolean",
|
231
|
+
"description": "Include extended forecast",
|
232
|
+
"default": false
|
233
|
+
}
|
234
|
+
},
|
235
|
+
"required": ["location"]
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
```
|
240
|
+
|
241
|
+
## Schema Generators
|
242
|
+
|
243
|
+
### Module Schemas
|
244
|
+
|
245
|
+
You can generate schemas for all public functions in a module using `create_schemas_from_module`:
|
246
|
+
|
247
|
+
```python
|
248
|
+
from schemez import create_schemas_from_module
|
249
|
+
import math
|
250
|
+
|
251
|
+
# Generate schemas for all public functions
|
252
|
+
schemas = create_schemas_from_module(math)
|
253
|
+
|
254
|
+
# Generate schemas for specific functions only
|
255
|
+
schemas = create_schemas_from_module(math, include_functions=['sin', 'cos'])
|
256
|
+
|
257
|
+
# Import module by string name
|
258
|
+
schemas = create_schemas_from_module('math')
|
259
|
+
```
|
260
|
+
|
261
|
+
### Class Schemas
|
262
|
+
|
263
|
+
Generate schemas for all public methods in a class using `create_schemas_from_class`:
|
264
|
+
|
265
|
+
```python
|
266
|
+
from schemez import create_schemas_from_class
|
267
|
+
|
268
|
+
class Calculator:
|
269
|
+
def add(self, x: int, y: int) -> int:
|
270
|
+
"""Add two numbers.
|
271
|
+
|
272
|
+
Args:
|
273
|
+
x: First number
|
274
|
+
y: Second number
|
275
|
+
|
276
|
+
Returns:
|
277
|
+
Sum of x and y
|
278
|
+
"""
|
279
|
+
return x + y
|
280
|
+
|
281
|
+
@classmethod
|
282
|
+
def multiply(cls, x: int, y: int) -> int:
|
283
|
+
"""Multiply two numbers.
|
284
|
+
|
285
|
+
Args:
|
286
|
+
x: First number
|
287
|
+
y: Second number
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
Product of x and y
|
291
|
+
"""
|
292
|
+
return x * y
|
293
|
+
|
294
|
+
@staticmethod
|
295
|
+
def divide(x: float, y: float) -> float:
|
296
|
+
"""Divide two numbers.
|
297
|
+
|
298
|
+
Args:
|
299
|
+
x: Numerator
|
300
|
+
y: Denominator
|
301
|
+
|
302
|
+
Returns:
|
303
|
+
Result of x divided by y
|
304
|
+
"""
|
305
|
+
return x / y
|
306
|
+
|
307
|
+
# Generate schemas for all public methods
|
308
|
+
schemas = create_schemas_from_class(Calculator)
|
309
|
+
|
310
|
+
# Access individual method schemas
|
311
|
+
add_schema = schemas['Calculator.add']
|
312
|
+
multiply_schema = schemas['Calculator.multiply']
|
313
|
+
divide_schema = schemas['Calculator.divide']
|
314
|
+
```
|
315
|
+
|
316
|
+
The schema generators support:
|
317
|
+
|
318
|
+
- Regular functions
|
319
|
+
- Regular instance methods (bound and unbound)
|
320
|
+
- Class methods
|
321
|
+
- Static methods
|
322
|
+
- Decorated functions / methods
|
323
|
+
- Async functions / methods
|
324
|
+
- Property methods
|
325
|
+
- Basically all stdlib typing features as well as many stdlib types
|
326
|
+
- Method docstrings for descriptions
|
327
|
+
- Default values
|
328
|
+
- Return type hints
|
329
|
+
|
330
|
+
|
331
|
+
## Diferences to pydantic schema generation
|
332
|
+
|
333
|
+
While Pydantics schema generation preserves detailed type information, `schema.model_dump_openai()`
|
334
|
+
simplifies types to match OpenAI's function calling format. Most special types
|
335
|
+
(datetime, UUID, Path, etc.) are handled similarly by both (we only strip unused information), but we handle enums
|
336
|
+
differently: Instead of preserving enum class information, we extract just the values
|
337
|
+
as a string enum. Union types and Optionals are also handled differently - we typically
|
338
|
+
pick the first type to keep the schema simple and practical for AI interaction.
|
339
|
+
This ensures compatibility with OpenAI's function calling API while maintaining enough
|
340
|
+
type information for the AI to understand the function signature.
|
schemez-1.2.3/README.md
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
# Schemez
|
2
|
+
|
3
|
+
[](https://pypi.org/project/schemez/)
|
4
|
+
[](https://pypi.org/project/schemez/)
|
5
|
+
[](https://pypi.org/project/schemez/)
|
6
|
+
[](https://pypi.org/project/schemez/)
|
7
|
+
[](https://pypi.org/project/schemez/)
|
8
|
+
[](https://pypi.org/project/schemez/)
|
9
|
+
[](https://pypi.org/project/schemez/)
|
10
|
+
[](https://github.com/phil65/schemez/releases)
|
11
|
+
[](https://github.com/phil65/schemez/graphs/contributors)
|
12
|
+
[](https://github.com/phil65/schemez/discussions)
|
13
|
+
[](https://github.com/phil65/schemez/forks)
|
14
|
+
[](https://github.com/phil65/schemez/issues)
|
15
|
+
[](https://github.com/phil65/schemez/pulls)
|
16
|
+
[](https://github.com/phil65/schemez/watchers)
|
17
|
+
[](https://github.com/phil65/schemez/stars)
|
18
|
+
[](https://github.com/phil65/schemez)
|
19
|
+
[](https://github.com/phil65/schemez/commits)
|
20
|
+
[](https://github.com/phil65/schemez/releases)
|
21
|
+
[](https://github.com/phil65/schemez)
|
22
|
+
[](https://github.com/phil65/schemez)
|
23
|
+
[](https://codecov.io/gh/phil65/schemez/)
|
24
|
+
[](https://pyup.io/repos/github/phil65/schemez/)
|
25
|
+
|
26
|
+
[Read the documentation!](https://phil65.github.io/schemez/)
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
# OpenAI Function Schema Generator
|
31
|
+
|
32
|
+
Convert Python functions to OpenAI-compatible function schemas automatically.
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
|
36
|
+
```bash
|
37
|
+
pip install schemez
|
38
|
+
```
|
39
|
+
|
40
|
+
## Basic Usage
|
41
|
+
|
42
|
+
```python
|
43
|
+
from schemez import create_schema
|
44
|
+
from typing import Literal
|
45
|
+
|
46
|
+
def get_weather(
|
47
|
+
location: str,
|
48
|
+
unit: Literal["C", "F"] = "C",
|
49
|
+
detailed: bool = False,
|
50
|
+
) -> dict[str, str | float]:
|
51
|
+
"""Get the weather for a location.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
location: City or address to get weather for
|
55
|
+
unit: Temperature unit (Celsius or Fahrenheit)
|
56
|
+
detailed: Include extended forecast
|
57
|
+
"""
|
58
|
+
return {"temp": 22.5, "conditions": "sunny"}
|
59
|
+
|
60
|
+
# Create schema
|
61
|
+
schema = create_schema(get_weather)
|
62
|
+
|
63
|
+
# The schema.model_dump_openai() returns a TypedDict with the complete OpenAI tool definition:
|
64
|
+
# OpenAIFunctionTool = TypedDict({
|
65
|
+
# "type": Literal["function"],
|
66
|
+
# "function": OpenAIFunctionDefinition
|
67
|
+
# })
|
68
|
+
|
69
|
+
# Use with OpenAI
|
70
|
+
from openai import OpenAI
|
71
|
+
|
72
|
+
client = OpenAI()
|
73
|
+
response = client.chat.completions.create(
|
74
|
+
model="gpt-4",
|
75
|
+
messages=[{"role": "user", "content": "What's the weather in London?"}],
|
76
|
+
tools=[schema.model_dump_openai()], # Schema includes the type: "function" wrapper
|
77
|
+
tool_choice="auto"
|
78
|
+
)
|
79
|
+
```
|
80
|
+
|
81
|
+
> **Note**: This library supports the OpenAI API v1 format (openai>=1.0.0). For older
|
82
|
+
> versions of the OpenAI package that use the legacy functions API, you'll need to
|
83
|
+
> unwrap the function definition using `schema.model_dump_openai()["function"]`.
|
84
|
+
```
|
85
|
+
|
86
|
+
## Supported Types
|
87
|
+
|
88
|
+
### Basic Types
|
89
|
+
```python
|
90
|
+
def func(
|
91
|
+
text: str, # -> "type": "string"
|
92
|
+
number: int, # -> "type": "integer"
|
93
|
+
amount: float, # -> "type": "number"
|
94
|
+
enabled: bool, # -> "type": "boolean"
|
95
|
+
anything: Any, # -> "type": "string"
|
96
|
+
) -> None: ...
|
97
|
+
```
|
98
|
+
|
99
|
+
### Container Types
|
100
|
+
```python
|
101
|
+
def func(
|
102
|
+
items: list[str], # -> "type": "array", "items": {"type": "string"}
|
103
|
+
numbers: set[int], # -> same as list
|
104
|
+
mapping: dict[str, Any], # -> "type": "object", "additionalProperties": true
|
105
|
+
nested: list[dict[str, int]], # -> nested array/object types
|
106
|
+
sequence: Sequence[str], # -> "type": "array"
|
107
|
+
collection: Collection[int], # -> "type": "array"
|
108
|
+
) -> None: ...
|
109
|
+
```
|
110
|
+
|
111
|
+
### Enums and Literals
|
112
|
+
```python
|
113
|
+
class Color(Enum):
|
114
|
+
RED = "red"
|
115
|
+
BLUE = "blue"
|
116
|
+
|
117
|
+
def func(
|
118
|
+
color: Color, # -> "type": "string", "enum": ["red", "blue"]
|
119
|
+
mode: Literal["fast", "slow"], # -> "type": "string", "enum": ["fast", "slow"]
|
120
|
+
) -> None: ...
|
121
|
+
```
|
122
|
+
|
123
|
+
### Optional and Union Types
|
124
|
+
```python
|
125
|
+
def func(
|
126
|
+
opt1: str | None, # -> "type": "string"
|
127
|
+
opt2: int | None, # -> "type": "integer"
|
128
|
+
union: str | int, # -> "type": "string" (first type)
|
129
|
+
) -> None: ...
|
130
|
+
```
|
131
|
+
|
132
|
+
### Custom Types
|
133
|
+
```python
|
134
|
+
@dataclass
|
135
|
+
class User:
|
136
|
+
name: str
|
137
|
+
age: int
|
138
|
+
|
139
|
+
def func(
|
140
|
+
user: User, # -> "type": "object"
|
141
|
+
data: JsonDict, # -> "type": "object"
|
142
|
+
) -> None: ...
|
143
|
+
```
|
144
|
+
|
145
|
+
### Type Aliases
|
146
|
+
```python
|
147
|
+
JsonValue = dict[str, Any] | list[Any] | str | int | float | bool | None
|
148
|
+
JsonDict = dict[str, JsonValue]
|
149
|
+
|
150
|
+
def func(
|
151
|
+
data: JsonDict, # -> "type": "object"
|
152
|
+
values: list[JsonValue], # -> "type": "array"
|
153
|
+
) -> None: ...
|
154
|
+
```
|
155
|
+
|
156
|
+
### Recursive Types
|
157
|
+
```python
|
158
|
+
def func(
|
159
|
+
tree: dict[str, "dict[str, Any] | str"], # -> "type": "object"
|
160
|
+
nested: dict[str, list["dict[str, Any]"]], # -> "type": "object"
|
161
|
+
) -> None: ...
|
162
|
+
```
|
163
|
+
|
164
|
+
## Generated Schema Example
|
165
|
+
|
166
|
+
```python
|
167
|
+
{
|
168
|
+
"type": "function",
|
169
|
+
"function": {
|
170
|
+
"name": "get_weather",
|
171
|
+
"description": "Get the weather for a location.",
|
172
|
+
"parameters": {
|
173
|
+
"type": "object",
|
174
|
+
"properties": {
|
175
|
+
"location": {
|
176
|
+
"type": "string",
|
177
|
+
"description": "City or address to get weather for"
|
178
|
+
},
|
179
|
+
"unit": {
|
180
|
+
"type": "string",
|
181
|
+
"enum": ["C", "F"],
|
182
|
+
"description": "Temperature unit (Celsius or Fahrenheit)",
|
183
|
+
"default": "C"
|
184
|
+
},
|
185
|
+
"detailed": {
|
186
|
+
"type": "boolean",
|
187
|
+
"description": "Include extended forecast",
|
188
|
+
"default": false
|
189
|
+
}
|
190
|
+
},
|
191
|
+
"required": ["location"]
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
```
|
196
|
+
|
197
|
+
## Schema Generators
|
198
|
+
|
199
|
+
### Module Schemas
|
200
|
+
|
201
|
+
You can generate schemas for all public functions in a module using `create_schemas_from_module`:
|
202
|
+
|
203
|
+
```python
|
204
|
+
from schemez import create_schemas_from_module
|
205
|
+
import math
|
206
|
+
|
207
|
+
# Generate schemas for all public functions
|
208
|
+
schemas = create_schemas_from_module(math)
|
209
|
+
|
210
|
+
# Generate schemas for specific functions only
|
211
|
+
schemas = create_schemas_from_module(math, include_functions=['sin', 'cos'])
|
212
|
+
|
213
|
+
# Import module by string name
|
214
|
+
schemas = create_schemas_from_module('math')
|
215
|
+
```
|
216
|
+
|
217
|
+
### Class Schemas
|
218
|
+
|
219
|
+
Generate schemas for all public methods in a class using `create_schemas_from_class`:
|
220
|
+
|
221
|
+
```python
|
222
|
+
from schemez import create_schemas_from_class
|
223
|
+
|
224
|
+
class Calculator:
|
225
|
+
def add(self, x: int, y: int) -> int:
|
226
|
+
"""Add two numbers.
|
227
|
+
|
228
|
+
Args:
|
229
|
+
x: First number
|
230
|
+
y: Second number
|
231
|
+
|
232
|
+
Returns:
|
233
|
+
Sum of x and y
|
234
|
+
"""
|
235
|
+
return x + y
|
236
|
+
|
237
|
+
@classmethod
|
238
|
+
def multiply(cls, x: int, y: int) -> int:
|
239
|
+
"""Multiply two numbers.
|
240
|
+
|
241
|
+
Args:
|
242
|
+
x: First number
|
243
|
+
y: Second number
|
244
|
+
|
245
|
+
Returns:
|
246
|
+
Product of x and y
|
247
|
+
"""
|
248
|
+
return x * y
|
249
|
+
|
250
|
+
@staticmethod
|
251
|
+
def divide(x: float, y: float) -> float:
|
252
|
+
"""Divide two numbers.
|
253
|
+
|
254
|
+
Args:
|
255
|
+
x: Numerator
|
256
|
+
y: Denominator
|
257
|
+
|
258
|
+
Returns:
|
259
|
+
Result of x divided by y
|
260
|
+
"""
|
261
|
+
return x / y
|
262
|
+
|
263
|
+
# Generate schemas for all public methods
|
264
|
+
schemas = create_schemas_from_class(Calculator)
|
265
|
+
|
266
|
+
# Access individual method schemas
|
267
|
+
add_schema = schemas['Calculator.add']
|
268
|
+
multiply_schema = schemas['Calculator.multiply']
|
269
|
+
divide_schema = schemas['Calculator.divide']
|
270
|
+
```
|
271
|
+
|
272
|
+
The schema generators support:
|
273
|
+
|
274
|
+
- Regular functions
|
275
|
+
- Regular instance methods (bound and unbound)
|
276
|
+
- Class methods
|
277
|
+
- Static methods
|
278
|
+
- Decorated functions / methods
|
279
|
+
- Async functions / methods
|
280
|
+
- Property methods
|
281
|
+
- Basically all stdlib typing features as well as many stdlib types
|
282
|
+
- Method docstrings for descriptions
|
283
|
+
- Default values
|
284
|
+
- Return type hints
|
285
|
+
|
286
|
+
|
287
|
+
## Diferences to pydantic schema generation
|
288
|
+
|
289
|
+
While Pydantics schema generation preserves detailed type information, `schema.model_dump_openai()`
|
290
|
+
simplifies types to match OpenAI's function calling format. Most special types
|
291
|
+
(datetime, UUID, Path, etc.) are handled similarly by both (we only strip unused information), but we handle enums
|
292
|
+
differently: Instead of preserving enum class information, we extract just the values
|
293
|
+
as a string enum. Union types and Optionals are also handled differently - we typically
|
294
|
+
pick the first type to keep the schema simple and practical for AI interaction.
|
295
|
+
This ensures compatibility with OpenAI's function calling API while maintaining enough
|
296
|
+
type information for the AI to understand the function signature.
|
@@ -1,10 +1,11 @@
|
|
1
1
|
[project]
|
2
2
|
name = "schemez"
|
3
|
-
version = "1.2.
|
3
|
+
version = "1.2.3"
|
4
4
|
description = "Pydantic shim for config stuff"
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">=3.13"
|
7
|
-
license =
|
7
|
+
license = "MIT"
|
8
|
+
license-files = ["LICENSE"]
|
8
9
|
authors = [
|
9
10
|
{ name = "Philipp Temminghoff", email = "philipptemminghoff@googlemail.com" },
|
10
11
|
]
|
@@ -42,6 +43,8 @@ Source = "https://github.com/phil65/schemez"
|
|
42
43
|
|
43
44
|
[project.optional-dependencies]
|
44
45
|
ai = ["llmling-agent", "anyenv>=0.4.14"]
|
46
|
+
codegen = ["datamodel-code-generator"]
|
47
|
+
tool_execution = ["fastapi>=0.118.2"]
|
45
48
|
yaml = ["yamling"]
|
46
49
|
|
47
50
|
[dependency-groups]
|
@@ -258,13 +261,14 @@ combine-as-imports = true
|
|
258
261
|
[tool.ruff.lint.per-file-ignores]
|
259
262
|
"__init__.py" = ["E402", "I001"]
|
260
263
|
"scripts/*" = ["INP001"]
|
264
|
+
"*tests/*" = ["D100"]
|
261
265
|
|
262
266
|
[tool.ruff.format]
|
263
|
-
# Enable preview style formatting.
|
264
267
|
preview = true
|
265
268
|
|
266
269
|
[tool.ty.environment]
|
267
270
|
python-version = "3.13"
|
271
|
+
python-platform = "all"
|
268
272
|
|
269
273
|
[tool.uv]
|
270
274
|
default-groups = ["dev", "lint", "docs"]
|
@@ -64,7 +64,7 @@ def get_function_model(func: AnyCallable, *, name: str | None = None) -> type[Sc
|
|
64
64
|
|
65
65
|
for param_name, param in sig.parameters.items():
|
66
66
|
# Skip self/cls for methods
|
67
|
-
if param_name in
|
67
|
+
if param_name in {"self", "cls"}:
|
68
68
|
continue
|
69
69
|
|
70
70
|
type_hint = hints.get(param_name, Any)
|