From 2735ceba5792a21123dff2a15e2f5be8e66b9585 Mon Sep 17 00:00:00 2001 From: Yesudeep Mangalapilly Date: Mon, 3 Feb 2025 23:35:55 -0800 Subject: [PATCH] feat(py): generate `types.py` from `genkit-schema.json` using datamodel-codegen #1807 ISSUE: https://github.com/firebase/genkit/issues/1807 CHANGELOG: - [ ] Add a bin/generate_schema_types script that generates the Pydantic types.py module. - [ ] Update the pre-commit hooks to ensure this file gets regenerated routinely. - [ ] Remove timestamp to ensure we do not treat a file with identical content differently preventing the hassles of updating this file per commit. --- py/bin/generate_schema_types | 26 + py/captainhook.json | 6 + py/packages/genkit/src/genkit/core/types.py | 652 ++++++++++++-------- py/pyproject.toml | 17 + py/uv.lock | 133 +++- 5 files changed, 585 insertions(+), 249 deletions(-) create mode 100755 py/bin/generate_schema_types diff --git a/py/bin/generate_schema_types b/py/bin/generate_schema_types new file mode 100755 index 000000000..a103d1cd0 --- /dev/null +++ b/py/bin/generate_schema_types @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# +# Copyright 2025 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +TOP_DIR=$(git rev-parse --show-toplevel) +TYPES_FILE="$TOP_DIR/py/packages/genkit/src/genkit/core/types.py" + +# Generate types using configuration from pyproject.toml +uv run --directory "$TOP_DIR/py" datamodel-codegen + +# Remove the Model class that uses RootModel +sed -i '' '/^class Model(RootModel\[Any\]):$/,/^ root: Any$/d' "$TYPES_FILE" + +addlicense \ + -c "Google LLC" \ + -s=only \ + "$TYPES_FILE" + +uv run --directory "$TOP_DIR/py" \ + ruff check --fix "$TYPES_FILE" + +uv run --directory "$TOP_DIR/py" \ + ruff format "$TYPES_FILE" diff --git a/py/captainhook.json b/py/captainhook.json index 78234a94a..56bbad814 100644 --- a/py/captainhook.json +++ b/py/captainhook.json @@ -33,6 +33,9 @@ { "run": "pnpm i --frozen-lockfile" }, + { + "run": "py/bin/generate_schema_types" + }, { "run": "py/bin/fmt" }, @@ -81,6 +84,9 @@ { "run": "pnpm i --frozen-lockfile" }, + { + "run": "py/bin/generate_schema_types" + }, { "run": "py/bin/fmt" }, diff --git a/py/packages/genkit/src/genkit/core/types.py b/py/packages/genkit/src/genkit/core/types.py index 52f1e3493..1e2700a83 100644 --- a/py/packages/genkit/src/genkit/core/types.py +++ b/py/packages/genkit/src/genkit/core/types.py @@ -1,38 +1,41 @@ # Copyright 2025 Google LLC # SPDX-License-Identifier: Apache-2.0 - # generated by datamodel-codegen: # filename: genkit-schema.json -# timestamp: 2025-01-17T17:30:26+00:00 +# version: 0.26.5 from __future__ import annotations from enum import Enum -from pydantic import ConfigDict, BaseModel, Field -from typing import Any, Dict, List, Optional, Union +from typing import Any +from pydantic import BaseModel, ConfigDict, Field, RootModel -class InstrumentationLibrary(BaseModel): - model_config = ConfigDict(extra='forbid') +class InstrumentationLibrary(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) name: str - version: Optional[str] = None - schemaUrl: Optional[str] = None + version: str | None = None + schemaUrl: str | None = None class SpanContext(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) traceId: str spanId: str - isRemote: Optional[bool] = None + isRemote: bool | None = None traceFlags: float class SameProcessAsParentSpan(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) value: bool @@ -42,33 +45,37 @@ class State(Enum): class SpanMetadata(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) name: str - state: Optional[State] = None - input: Optional[Any] = None - output: Optional[Any] = None - isRoot: Optional[bool] = None - metadata: Optional[Dict[str, str]] = None + state: State | None = None + input: Any | None = None + output: Any | None = None + isRoot: bool | None = None + metadata: dict[str, str] | None = None class SpanStatus(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) code: float - message: Optional[str] = None + message: str | None = None class Annotation(BaseModel): - model_config = ConfigDict(extra='forbid') - - attributes: Dict[str, Any] + model_config = ConfigDict( + extra='forbid', + ) + attributes: dict[str, Any] description: str class TimeEvent(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) time: float annotation: Annotation @@ -80,99 +87,148 @@ class Code(Enum): class CandidateError(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) index: float code: Code - message: Optional[str] = None + message: str | None = None + + +class DataPart(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + text: Any | None = None + media: Any | None = None + toolRequest: Any | None = None + toolResponse: Any | None = None + data: Any | None = None + metadata: dict[str, Any] | None = None class FinishReason(Enum): stop = 'stop' length = 'length' blocked = 'blocked' + interrupted = 'interrupted' other = 'other' unknown = 'unknown' -class DataPart(BaseModel): - model_config = ConfigDict(extra='forbid') - - text: Optional[Any] = None - media: Optional[Any] = None - toolRequest: Optional[Any] = None - toolResponse: Optional[Any] = None - data: Optional[Any] = None - metadata: Optional[Dict[str, Any]] = None +class Content(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + text: str + media: Any | None = None -class Format(Enum): - json = 'json' - text = 'text' - media = 'media' +class Media(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + contentType: str | None = None + url: str -class Output(BaseModel): - model_config = ConfigDict(extra='forbid') +class Content1(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + text: Any | None = None + media: Media - format: Optional[Format] = None - schema_: Optional[Dict[str, Any]] = Field(None, alias='schema') +class Doc(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + content: list[Content | Content1] + metadata: dict[str, Any] | None = None -class Content(BaseModel): - model_config = ConfigDict(extra='forbid') - text: str - media: Optional[Any] = None +class ToolChoice(Enum): + auto = 'auto' + required = 'required' + none = 'none' -class Media(BaseModel): - model_config = ConfigDict(extra='forbid') +class Output(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + format: str | None = None + contentType: str | None = None + instructions: bool | str | None = None + jsonSchema: Any | None = None - contentType: Optional[str] = None - url: str +class Format(Enum): + json = 'json' + text = 'text' + media = 'media' -class Content1(BaseModel): - model_config = ConfigDict(extra='forbid') - text: Optional[Any] = None - media: Media +class Output1(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + format: Format | None = None + schema_: dict[str, Any] | None = Field(None, alias='schema') -class ContextItem(BaseModel): - model_config = ConfigDict(extra='forbid') +class GenerationCommonConfig(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + version: str | None = None + temperature: float | None = None + maxOutputTokens: float | None = None + topK: float | None = None + topP: float | None = None + stopSequences: list[str] | None = None - content: List[Union[Content, Content1]] - metadata: Optional[Dict[str, Any]] = None +class GenerationUsage(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + inputTokens: float | None = None + outputTokens: float | None = None + totalTokens: float | None = None + inputCharacters: float | None = None + outputCharacters: float | None = None + inputImages: float | None = None + outputImages: float | None = None + inputVideos: float | None = None + outputVideos: float | None = None + inputAudioFiles: float | None = None + outputAudioFiles: float | None = None + custom: dict[str, float] | None = None -class GenerationCommonConfig(BaseModel): - model_config = ConfigDict(extra='forbid') - version: Optional[str] = None - temperature: Optional[float] = None - maxOutputTokens: Optional[float] = None - topK: Optional[float] = None - topP: Optional[float] = None - stopSequences: Optional[List[str]] = None +class Supports(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + multiturn: bool | None = None + media: bool | None = None + tools: bool | None = None + systemRole: bool | None = None + output: list[str] | None = None + contentType: list[str] | None = None + context: bool | None = None + constrained: bool | None = None -class GenerationUsage(BaseModel): - model_config = ConfigDict(extra='forbid') - - inputTokens: Optional[float] = None - outputTokens: Optional[float] = None - totalTokens: Optional[float] = None - inputCharacters: Optional[float] = None - outputCharacters: Optional[float] = None - inputImages: Optional[float] = None - outputImages: Optional[float] = None - inputVideos: Optional[float] = None - outputVideos: Optional[float] = None - inputAudioFiles: Optional[float] = None - outputAudioFiles: Optional[float] = None - custom: Optional[Dict[str, float]] = None +class ModelInfo(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + versions: list[str] | None = None + label: str | None = None + supports: Supports | None = None class Role(Enum): @@ -183,270 +239,370 @@ class Role(Enum): class ToolDefinition(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) name: str description: str - inputSchema: Dict[str, Any] = Field( + inputSchema: dict[str, Any] = Field( ..., description='Valid JSON Schema representing the input of the tool.' ) - outputSchema: Optional[Dict[str, Any]] = Field( + outputSchema: dict[str, Any] | None = Field( None, description='Valid JSON Schema describing the output of the tool.' ) - metadata: Optional[Dict[str, Any]] = Field( + metadata: dict[str, Any] | None = Field( None, description='additional metadata for this tool definition' ) class ToolRequest1(BaseModel): - model_config = ConfigDict(extra='forbid') - - ref: Optional[str] = None + model_config = ConfigDict( + extra='forbid', + ) + ref: str | None = None name: str - input: Optional[Any] = None + input: Any | None = None class ToolResponse1(BaseModel): - model_config = ConfigDict(extra='forbid') - - ref: Optional[str] = None + model_config = ConfigDict( + extra='forbid', + ) + ref: str | None = None name: str - output: Optional[Any] = None + output: Any | None = None -class Content2(BaseModel): - model_config = ConfigDict(extra='forbid') +class MediaModel(RootModel[Any]): + model_config = ConfigDict( + extra='forbid', + ) + root: Any + +class Metadata(RootModel[dict[str, Any] | None]): + root: dict[str, Any] | None = None + + +class Text(RootModel[Any]): + root: Any + + +class ToolRequest(RootModel[Any]): + root: Any + + +class ToolResponse(RootModel[Any]): + root: Any + + +class Content2(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) text: str - media: Optional[Any] = None + media: Any | None = None class Media2(BaseModel): - model_config = ConfigDict(extra='forbid') - - contentType: Optional[str] = None + model_config = ConfigDict( + extra='forbid', + ) + contentType: str | None = None url: str class Content3(BaseModel): - model_config = ConfigDict(extra='forbid') - - text: Optional[Any] = None + model_config = ConfigDict( + extra='forbid', + ) + text: Any | None = None media: Media2 class Items(BaseModel): - model_config = ConfigDict(extra='forbid') + model_config = ConfigDict( + extra='forbid', + ) + content: list[Content2 | Content3] + metadata: dict[str, Any] | None = None + - content: List[Union[Content2, Content3]] - metadata: Optional[Dict[str, Any]] = None +class Config(RootModel[Any]): + root: Any class OutputModel(BaseModel): - model_config = ConfigDict(extra='forbid') + model_config = ConfigDict( + extra='forbid', + ) + format: Format | None = None + schema_: dict[str, Any] | None = Field(None, alias='schema') - format: Optional[Format] = None - schema_: Optional[Dict[str, Any]] = Field(None, alias='schema') +class Tools(RootModel[list[ToolDefinition]]): + root: list[ToolDefinition] -class Link(BaseModel): - model_config = ConfigDict(extra='forbid') - context: Optional[SpanContext] = None - attributes: Optional[Dict[str, Any]] = None - droppedAttributesCount: Optional[float] = None +class Custom(RootModel[Any]): + root: Any -class TimeEvents(BaseModel): - model_config = ConfigDict(extra='forbid') +class FinishMessage(RootModel[str]): + root: str - timeEvent: Optional[List[TimeEvent]] = None +class LatencyMs(RootModel[float]): + root: float + + +class Usage(RootModel[GenerationUsage]): + root: GenerationUsage + + +class Aggregated(RootModel[bool]): + root: bool + + +class Index(RootModel[float]): + root: float + + +class Data(RootModel[Any]): + root: Any + + +class Link(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + context: SpanContext | None = None + attributes: dict[str, Any] | None = None + droppedAttributesCount: float | None = None + + +class TimeEvents(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + timeEvent: list[TimeEvent] | None = None -class SpanData(BaseModel): - model_config = ConfigDict(extra='forbid') +class SpanData(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) spanId: str traceId: str - parentSpanId: Optional[str] = None + parentSpanId: str | None = None startTime: float endTime: float - attributes: Dict[str, Any] + attributes: dict[str, Any] displayName: str - links: Optional[List[Link]] = None + links: list[Link] | None = None instrumentationLibrary: InstrumentationLibrary spanKind: str - sameProcessAsParentSpan: Optional[SameProcessAsParentSpan] = None - status: Optional[SpanStatus] = None - timeEvents: Optional[TimeEvents] = None - truncated: Optional[bool] = None + sameProcessAsParentSpan: SameProcessAsParentSpan | None = None + status: SpanStatus | None = None + timeEvents: TimeEvents | None = None + truncated: bool | None = None class TraceData(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) traceId: str - displayName: Optional[str] = None - startTime: Optional[float] = None - endTime: Optional[float] = None - spans: Dict[str, SpanData] + displayName: str | None = None + startTime: float | None = None + endTime: float | None = None + spans: dict[str, SpanData] class MediaPart(BaseModel): - model_config = ConfigDict(extra='forbid') - - text: Optional[Any] = None + model_config = ConfigDict( + extra='forbid', + ) + text: Text | None = None media: Media - toolRequest: Optional[Any] = None - toolResponse: Optional[Any] = None - data: Optional[Any] = None - metadata: Optional[Dict[str, Any]] = None - - -class Supports(BaseModel): - model_config = ConfigDict(extra='forbid') - - multiturn: Optional[bool] = None - media: Optional[bool] = None - tools: Optional[bool] = None - systemRole: Optional[bool] = None - output: Optional[List[Format]] = None - context: Optional[bool] = None - - -class ModelInfo(BaseModel): - model_config = ConfigDict(extra='forbid') - - versions: Optional[List[str]] = None - label: Optional[str] = None - supports: Optional[Supports] = None + toolRequest: ToolRequest | None = None + toolResponse: ToolResponse | None = None + data: Any | None = None + metadata: Metadata | None = None class TextPart(BaseModel): - model_config = ConfigDict(extra='forbid') - + model_config = ConfigDict( + extra='forbid', + ) text: str - media: Optional[Any] = None - toolRequest: Optional[Any] = None - toolResponse: Optional[Any] = None - data: Optional[Any] = None - metadata: Optional[Dict[str, Any]] = None + media: MediaModel | None = None + toolRequest: ToolRequest | None = None + toolResponse: ToolResponse | None = None + data: Data | None = None + metadata: Metadata | None = None class ToolRequestPart(BaseModel): - model_config = ConfigDict(extra='forbid') - - text: Optional[Any] = None - media: Optional[Any] = None + model_config = ConfigDict( + extra='forbid', + ) + text: Text | None = None + media: MediaModel | None = None toolRequest: ToolRequest1 - toolResponse: Optional[Any] = None - data: Optional[Any] = None - metadata: Optional[Dict[str, Any]] = None + toolResponse: ToolResponse | None = None + data: Data | None = None + metadata: Metadata | None = None class ToolResponsePart(BaseModel): - model_config = ConfigDict(extra='forbid') - - text: Optional[Any] = None - media: Optional[Any] = None - toolRequest: Optional[Any] = None + model_config = ConfigDict( + extra='forbid', + ) + text: Text | None = None + media: MediaModel | None = None + toolRequest: ToolRequest | None = None toolResponse: ToolResponse1 - data: Optional[Any] = None - metadata: Optional[Dict[str, Any]] = None + data: Data | None = None + metadata: Metadata | None = None -class DocumentData(BaseModel): - model_config = ConfigDict(extra='forbid') - - content: List[ - Union[TextPart, MediaPart, ToolRequestPart, ToolResponsePart, DataPart] +class Part( + RootModel[ + TextPart | MediaPart | ToolRequestPart | ToolResponsePart | DataPart ] - metadata: Optional[Dict[str, Any]] = None +): + root: TextPart | MediaPart | ToolRequestPart | ToolResponsePart | DataPart -class GenerateResponseChunk(BaseModel): - model_config = ConfigDict(extra='forbid') +class ContentModel(RootModel[list[Part]]): + model_config = ConfigDict( + extra='forbid', + ) + root: list[Part] - content: List[ - Union[TextPart, MediaPart, ToolRequestPart, ToolResponsePart, DataPart] - ] - custom: Optional[Any] = None - aggregated: Optional[bool] = None - index: float + +class DocumentData(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + content: list[Part] + metadata: dict[str, Any] | None = None -class Message(BaseModel): - model_config = ConfigDict(extra='forbid') +class GenerateResponseChunk(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + role: Role | None = None + index: float | None = None + content: list[Part] + custom: Any | None = None + aggregated: bool | None = None + +class Message(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) role: Role - content: List[ - Union[TextPart, MediaPart, ToolRequestPart, ToolResponsePart, DataPart] - ] - metadata: Optional[Dict[str, Any]] = None + content: list[Part] + metadata: dict[str, Any] | None = None class ModelResponseChunk(BaseModel): - model_config = ConfigDict(extra='forbid') + model_config = ConfigDict( + extra='forbid', + ) + role: Role | None = None + index: Index | None = None + content: ContentModel + custom: Custom | None = None + aggregated: Aggregated | None = None - content: List[ - Union[TextPart, MediaPart, ToolRequestPart, ToolResponsePart, DataPart] - ] - custom: Optional[Any] = None - aggregated: Optional[bool] = None +class Messages(RootModel[list[Message]]): + root: list[Message] -class Candidate(BaseModel): - model_config = ConfigDict(extra='forbid') +class Candidate(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) index: float message: Message - usage: Optional[GenerationUsage] = None + usage: GenerationUsage | None = None finishReason: FinishReason - finishMessage: Optional[str] = None - custom: Optional[Any] = None + finishMessage: str | None = None + custom: Any | None = None -class GenerateRequest(BaseModel): - model_config = ConfigDict(extra='forbid') +class GenerateActionOptions(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + model: str + docs: list[Doc] | None = None + messages: list[Message] + tools: list[str | ToolDefinition] | None = None + toolChoice: ToolChoice | None = None + config: Any | None = None + output: Output | None = None + returnToolRequests: bool | None = None + maxTurns: float | None = None - messages: List[Message] - config: Optional[Any] = None - tools: Optional[List[ToolDefinition]] = None - output: Optional[Output] = None - context: Optional[List[ContextItem]] = None - candidates: Optional[float] = None +class GenerateRequest(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + messages: list[Message] + config: Any | None = None + tools: list[ToolDefinition] | None = None + toolChoice: ToolChoice | None = None + output: Output1 | None = None + context: list[Items] | None = None + candidates: float | None = None -class GenerateResponse(BaseModel): - model_config = ConfigDict(extra='forbid') - message: Optional[Message] = None - finishReason: Optional[FinishReason] = None - finishMessage: Optional[str] = None - latencyMs: Optional[float] = None - usage: Optional[GenerationUsage] = None - custom: Optional[Any] = None - request: Optional[GenerateRequest] = None - candidates: Optional[List[Candidate]] = None +class GenerateResponse(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + message: Message | None = None + finishReason: FinishReason | None = None + finishMessage: str | None = None + latencyMs: float | None = None + usage: GenerationUsage | None = None + custom: Any | None = None + request: GenerateRequest | None = None + candidates: list[Candidate] | None = None class ModelRequest(BaseModel): - model_config = ConfigDict(extra='forbid') + model_config = ConfigDict( + extra='forbid', + ) + messages: Messages + config: Config | None = None + tools: Tools | None = None + toolChoice: ToolChoice | None = None + output: OutputModel | None = None + context: list[Items] | None = None - messages: List[Message] - config: Optional[Any] = None - tools: Optional[List[ToolDefinition]] = None - output: Optional[OutputModel] = None - context: Optional[List[Items]] = None +class Request(RootModel[GenerateRequest]): + root: GenerateRequest -class ModelResponse(BaseModel): - model_config = ConfigDict(extra='forbid') - message: Optional[Message] = None +class ModelResponse(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + message: Message | None = None finishReason: FinishReason - finishMessage: Optional[str] = None - latencyMs: Optional[float] = None - usage: Optional[GenerationUsage] = None - custom: Optional[Any] = None - request: Optional[GenerateRequest] = None + finishMessage: FinishMessage | None = None + latencyMs: LatencyMs | None = None + usage: Usage | None = None + custom: Custom | None = None + request: Request | None = None diff --git a/py/pyproject.toml b/py/pyproject.toml index b9cb5b853..2839a3582 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -26,6 +26,7 @@ dev = [ "pytest-asyncio>=0.25.2", "pytest>=8.3.4", "pytest-cov>=6.0.0", + "datamodel-code-generator>=0.26.5", ] lint = ["mypy>=1.14.1", "ruff>=0.9.2"] @@ -86,3 +87,19 @@ quote-style = "single" disallow_incomplete_defs = true disallow_untyped_defs = true warn_unused_configs = true + +[tool.datamodel-codegen] +#strict-types = ["str", "int", "float", "bool", "bytes"] # Don't use; produces StrictStr, StrictInt, etc. +#collapse-root-models = true # Don't use; produces Any as types. +disable-timestamp = true +enable-version-header = true +field-constraints = true +input = "../genkit-tools/genkit-schema.json" +input-file-type = "jsonschema" +output = "packages/genkit/src/genkit/core/types.py" +output-model-type = "pydantic_v2.BaseModel" +strict-nullable = true +target-python-version = "3.12" +use-schema-description = true +use-standard-collections = true +use-union-operator = true diff --git a/py/uv.lock b/py/uv.lock index f7481742b..1c9b30889 100644 --- a/py/uv.lock +++ b/py/uv.lock @@ -1,7 +1,8 @@ version = 1 requires-python = ">=3.12" resolution-markers = [ - "python_full_version >= '3.13'", + "python_full_version >= '4.0'", + "python_full_version >= '3.13' and python_full_version < '4.0'", "python_full_version < '3.13'", ] @@ -62,6 +63,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, ] +[[package]] +name = "argcomplete" +version = "3.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/be/6c23d80cb966fb8f83fb1ebfb988351ae6b0554d0c3a613ee4531c026597/argcomplete-3.5.3.tar.gz", hash = "sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392", size = 72999 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/08/2a4db06ec3d203124c967fc89295e85a202e5cbbcdc08fd6a64b65217d1e/argcomplete-3.5.3-py3-none-any.whl", hash = "sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61", size = 43569 }, +] + [[package]] name = "argon2-cffi" version = "23.1.0" @@ -156,6 +166,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 }, ] +[[package]] +name = "black" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988 }, + { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985 }, + { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816 }, + { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860 }, + { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673 }, + { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190 }, + { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926 }, + { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613 }, + { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, +] + [[package]] name = "bleach" version = "6.2.0" @@ -290,6 +324,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, ] +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -377,6 +423,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/a2/462eebec8f0aa88751de678cbcdecd8b36ddf1ad05c25662541ef3e4455b/cwcwidth-0.1.9-cp312-cp312-win_amd64.whl", hash = "sha256:40466f16e85c338e8fc3eee87a8c9ca23416cc68b3049f68cb4cead5fb8b71b3", size = 24896 }, ] +[[package]] +name = "datamodel-code-generator" +version = "0.26.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "black" }, + { name = "genson" }, + { name = "inflect" }, + { name = "isort" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pydantic", extra = ["email"], marker = "python_full_version < '4.0'" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/e4/53153452235a387112df40f67aaf24072d4b5e33aa7bb385004f4c4baf38/datamodel_code_generator-0.26.5.tar.gz", hash = "sha256:c4a94a7dbf7972129882732d9bcee44c9ae090f57c82edd58d237b9d48c40dd0", size = 92586 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/d8/ead3e857d4048947fe92a731d6b1f257dcb267cc8b8918d3b72598c9b728/datamodel_code_generator-0.26.5-py3-none-any.whl", hash = "sha256:e32f986b9914a2b45093947043aa0192d704650be93151f78acf5c95676601ce", size = 114982 }, +] + [[package]] name = "debugpy" version = "1.8.12" @@ -424,6 +490,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1d/8f/c7f227eb42cfeaddce3eb0c96c60cbca37797fa7b34f8e1aeadf6c5c0983/Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", size = 9941 }, ] +[[package]] +name = "dnspython" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, +] + [[package]] name = "docstring-parser" version = "0.16" @@ -444,6 +519,19 @@ dependencies = [ [package.metadata] requires-dist = [{ name = "handlebarz", editable = "packages/handlebarz" }] +[[package]] +name = "email-validator" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython", marker = "python_full_version < '4.0'" }, + { name = "idna", marker = "python_full_version < '4.0'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, +] + [[package]] name = "executing" version = "2.1.0" @@ -593,6 +681,7 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "bpython" }, + { name = "datamodel-code-generator" }, { name = "ipython" }, { name = "jupyter" }, { name = "pytest" }, @@ -621,6 +710,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "bpython", specifier = ">=0.25" }, + { name = "datamodel-code-generator", specifier = ">=0.26.5" }, { name = "ipython", specifier = ">=8.31.0" }, { name = "jupyter", specifier = ">=1.1.1" }, { name = "pytest", specifier = ">=8.3.4" }, @@ -632,6 +722,15 @@ lint = [ { name = "ruff", specifier = ">=0.9.2" }, ] +[[package]] +name = "genson" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/cf/2303c8ad276dcf5ee2ad6cf69c4338fd86ef0f471a5207b069adf7a393cf/genson-1.3.0.tar.gz", hash = "sha256:e02db9ac2e3fd29e65b5286f7135762e2cd8a986537c075b06fc5f1517308e37", size = 34919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/5c/e226de133afd8bb267ec27eead9ae3d784b95b39a287ed404caab39a5f50/genson-1.3.0-py3-none-any.whl", hash = "sha256:468feccd00274cc7e4c09e84b08704270ba8d95232aa280f65b986139cec67f7", size = 21470 }, +] + [[package]] name = "google-api-core" version = "2.24.0" @@ -974,6 +1073,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, ] +[[package]] +name = "inflect" +version = "5.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/db/cae5d8524c4b5e574c281895b212062f3b06d0e14186904ed71c538b4e90/inflect-5.6.2.tar.gz", hash = "sha256:aadc7ed73928f5e014129794bbac03058cca35d0a973a5fc4eb45c7fa26005f9", size = 69378 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/d8/3e1a32d305215166f5c32652c473aa766bd7809cd10b34c544dbc31facb5/inflect-5.6.2-py3-none-any.whl", hash = "sha256:b45d91a4a28a4e617ff1821117439b06eaa86e2a4573154af0149e9be6687238", size = 33704 }, +] + [[package]] name = "iniconfig" version = "2.0.0" @@ -1055,6 +1163,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, ] +[[package]] +name = "isort" +version = "5.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, +] + [[package]] name = "jedi" version = "0.19.2" @@ -1646,6 +1763,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, ] +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + [[package]] name = "pexpect" version = "4.9.0" @@ -1800,6 +1926,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/58/26/82663c79010b28eddf29dcdd0ea723439535fa917fce5905885c0e9ba562/pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53", size = 431426 }, ] +[package.optional-dependencies] +email = [ + { name = "email-validator", marker = "python_full_version < '4.0'" }, +] + [[package]] name = "pydantic-core" version = "2.27.2"