schemez 1.1.0__tar.gz → 1.1.1__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.1.0 → schemez-1.1.1}/PKG-INFO +1 -1
- {schemez-1.1.0 → schemez-1.1.1}/pyproject.toml +1 -1
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/helpers.py +72 -51
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/schema.py +2 -1
- {schemez-1.1.0 → schemez-1.1.1}/LICENSE +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/README.md +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/__init__.py +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/code.py +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/convert.py +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/docstrings.py +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/py.typed +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/pydantic_types.py +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/schemadef/__init__.py +0 -0
- {schemez-1.1.0 → schemez-1.1.1}/src/schemez/schemadef/schemadef.py +0 -0
@@ -4,19 +4,19 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
import asyncio
|
6
6
|
import importlib
|
7
|
-
import json
|
8
7
|
import os
|
9
8
|
from pathlib import Path
|
10
9
|
import subprocess
|
11
10
|
import sys
|
12
11
|
import tempfile
|
13
|
-
from typing import TYPE_CHECKING, Any
|
12
|
+
from typing import TYPE_CHECKING, Any, Literal
|
14
13
|
|
15
14
|
from pydantic import BaseModel
|
15
|
+
from pydantic_core import to_json
|
16
16
|
|
17
17
|
|
18
18
|
StrPath = str | os.PathLike[str]
|
19
|
-
|
19
|
+
PythonVersion = Literal["3.13", "3.14", "3.15"]
|
20
20
|
|
21
21
|
if TYPE_CHECKING:
|
22
22
|
from collections.abc import Callable
|
@@ -177,11 +177,48 @@ def resolve_type_string(type_string: str, safe: bool = True) -> type:
|
|
177
177
|
raise ValueError(msg) from e
|
178
178
|
|
179
179
|
|
180
|
+
async def _detect_command(command: str, *, test_flag: str = "--version") -> list[str]:
|
181
|
+
"""Detect the correct command prefix for running a command.
|
182
|
+
|
183
|
+
Tries 'uv run' first, then falls back to direct execution.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
command: The command to detect
|
187
|
+
test_flag: Flag to test command availability with
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
Command prefix list (empty for direct execution)
|
191
|
+
|
192
|
+
Raises:
|
193
|
+
RuntimeError: If command is not available
|
194
|
+
"""
|
195
|
+
cmd_prefixes = [["uv", "run"], []]
|
196
|
+
|
197
|
+
for prefix in cmd_prefixes:
|
198
|
+
try:
|
199
|
+
proc = await asyncio.create_subprocess_exec(
|
200
|
+
*prefix,
|
201
|
+
command,
|
202
|
+
test_flag,
|
203
|
+
stdout=asyncio.subprocess.PIPE,
|
204
|
+
stderr=asyncio.subprocess.PIPE,
|
205
|
+
)
|
206
|
+
await proc.communicate()
|
207
|
+
if proc.returncode == 0:
|
208
|
+
return prefix
|
209
|
+
except FileNotFoundError:
|
210
|
+
continue
|
211
|
+
|
212
|
+
msg = f"{command} not available (tried both 'uv run' and direct execution)"
|
213
|
+
raise RuntimeError(msg)
|
214
|
+
|
215
|
+
|
180
216
|
async def model_to_python_code(
|
181
217
|
model: type[BaseModel],
|
182
218
|
*,
|
183
219
|
class_name: str | None = None,
|
184
|
-
target_python_version:
|
220
|
+
target_python_version: PythonVersion | None = None,
|
221
|
+
model_type: str = "pydantic.BaseModel",
|
185
222
|
) -> str:
|
186
223
|
"""Convert a BaseModel to Python code asynchronously.
|
187
224
|
|
@@ -190,6 +227,7 @@ async def model_to_python_code(
|
|
190
227
|
class_name: Optional custom class name for the generated code
|
191
228
|
target_python_version: Target Python version for code generation.
|
192
229
|
Defaults to current system Python version.
|
230
|
+
model_type: Type of the generated model. Defaults to "pydantic.BaseModel".
|
193
231
|
|
194
232
|
Returns:
|
195
233
|
Generated Python code as string
|
@@ -198,67 +236,50 @@ async def model_to_python_code(
|
|
198
236
|
RuntimeError: If datamodel-codegen is not available
|
199
237
|
subprocess.CalledProcessError: If code generation fails
|
200
238
|
"""
|
201
|
-
|
202
|
-
# Check if datamodel-codegen is available
|
203
|
-
proc = await asyncio.create_subprocess_exec(
|
204
|
-
"datamodel-codegen",
|
205
|
-
"--version",
|
206
|
-
stdout=asyncio.subprocess.PIPE,
|
207
|
-
stderr=asyncio.subprocess.PIPE,
|
208
|
-
)
|
209
|
-
await proc.communicate()
|
210
|
-
if proc.returncode != 0:
|
211
|
-
raise subprocess.CalledProcessError(
|
212
|
-
proc.returncode or -1, "datamodel-codegen"
|
213
|
-
)
|
214
|
-
except FileNotFoundError as e:
|
215
|
-
msg = "datamodel-codegen not available"
|
216
|
-
raise RuntimeError(msg) from e
|
239
|
+
working_prefix = await _detect_command("datamodel-codegen")
|
217
240
|
|
218
|
-
# Get model schema
|
219
241
|
schema = model.model_json_schema()
|
220
242
|
name = class_name or model.__name__
|
221
|
-
|
222
|
-
target_python_version or f"{sys.version_info.major}.{sys.version_info.minor}"
|
223
|
-
)
|
224
|
-
|
225
|
-
# Create temporary file with schema
|
243
|
+
py = target_python_version or f"{sys.version_info.major}.{sys.version_info.minor}"
|
226
244
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
|
227
|
-
|
245
|
+
# Use pydantic_core.to_json for proper schema serialization
|
246
|
+
schema_json = to_json(schema, indent=2).decode()
|
247
|
+
f.write(schema_json)
|
228
248
|
schema_file = Path(f.name)
|
229
249
|
|
230
|
-
|
231
|
-
|
250
|
+
args = [
|
251
|
+
"--input",
|
252
|
+
str(schema_file),
|
253
|
+
"--input-file-type",
|
254
|
+
"jsonschema",
|
255
|
+
"--output-model-type",
|
256
|
+
model_type,
|
257
|
+
"--class-name",
|
258
|
+
name,
|
259
|
+
"--disable-timestamp",
|
260
|
+
"--use-union-operator",
|
261
|
+
"--use-schema-description",
|
262
|
+
"--enum-field-as-literal",
|
263
|
+
"all",
|
264
|
+
"--target-python-version",
|
265
|
+
py,
|
266
|
+
]
|
267
|
+
|
268
|
+
try: # Generate model using datamodel-codegen
|
232
269
|
proc = await asyncio.create_subprocess_exec(
|
270
|
+
*working_prefix,
|
233
271
|
"datamodel-codegen",
|
234
|
-
|
235
|
-
str(schema_file),
|
236
|
-
"--input-file-type",
|
237
|
-
"jsonschema",
|
238
|
-
"--output-model-type",
|
239
|
-
"pydantic.BaseModel",
|
240
|
-
"--class-name",
|
241
|
-
name,
|
242
|
-
"--disable-timestamp",
|
243
|
-
"--use-union-operator",
|
244
|
-
"--use-schema-description",
|
245
|
-
"--enum-field-as-literal",
|
246
|
-
"all",
|
247
|
-
"--target-python-version",
|
248
|
-
python_version,
|
272
|
+
*args,
|
249
273
|
stdout=asyncio.subprocess.PIPE,
|
250
274
|
stderr=asyncio.subprocess.PIPE,
|
251
275
|
)
|
252
|
-
stdout,
|
276
|
+
stdout, _stderr = await proc.communicate()
|
253
277
|
|
254
278
|
if proc.returncode != 0:
|
255
|
-
|
256
|
-
raise subprocess.CalledProcessError(
|
257
|
-
proc.returncode or -1, "datamodel-codegen"
|
258
|
-
)
|
279
|
+
code = proc.returncode or -1
|
280
|
+
raise subprocess.CalledProcessError(code, "datamodel-codegen")
|
259
281
|
|
260
282
|
return stdout.decode().strip()
|
261
283
|
|
262
|
-
finally:
|
263
|
-
# Cleanup temp file
|
284
|
+
finally: # Cleanup temp file
|
264
285
|
schema_file.unlink(missing_ok=True)
|
@@ -19,6 +19,7 @@ if TYPE_CHECKING:
|
|
19
19
|
|
20
20
|
StrPath = str | os.PathLike[str]
|
21
21
|
SourceType = Literal["pdf", "image"]
|
22
|
+
PythonVersion = Literal["3.13", "3.14", "3.15"]
|
22
23
|
|
23
24
|
DEFAULT_SYSTEM_PROMPT = "You are a schema extractor for {name} BaseModels."
|
24
25
|
DEFAULT_USER_PROMPT = "Extract information from this document:"
|
@@ -260,7 +261,7 @@ class Schema(BaseModel):
|
|
260
261
|
cls,
|
261
262
|
*,
|
262
263
|
class_name: str | None = None,
|
263
|
-
target_python_version:
|
264
|
+
target_python_version: PythonVersion | None = None,
|
264
265
|
) -> str:
|
265
266
|
"""Convert this model to Python code asynchronously.
|
266
267
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|