From 03bd1b95bd4a7d6ca9eb99ad25c5610c2bcadd80 Mon Sep 17 00:00:00 2001 From: Yesudeep Mangalapilly Date: Thu, 13 Feb 2025 14:31:43 -0800 Subject: [PATCH] fix: formatting, linting, and schema code generation #1935 ISSUE: https://github.com/firebase/genkit/issues/1935 CHANGELOG: - [ ] Addresses error handling and parallelized formatting for toml files. - [ ] Configures the ruff formatter to use requested format. - [ ] Fixes snake_case for several Python variables. - [ ] Configures the schemas.py code generator to generate snake_case field names to avoid lint reports and wraps the actual name in Field() metadata. - [ ] Clean up some lint. - [ ] Removes go-vulncheck from the pre-commit hook while retaining it during pre-push (easy to skip this using `-f --no-verify`). --- py/bin/fmt | 2 +- py/bin/format_toml_files | 82 +++++----- py/bin/generate_schema_types | 20 +-- py/bin/sanitize_schemas.py | 5 +- py/bin/setup | 9 +- py/captainhook.json | 11 ++ py/packages/genkit/src/genkit/core/action.py | 5 +- py/packages/genkit/src/genkit/core/schemas.py | 152 ++++++++++-------- py/packages/genkit/src/genkit/core/tracing.py | 4 +- py/pyproject.toml | 14 +- py/samples/hello/hello.py | 1 + py/uv.lock | 53 ++---- 12 files changed, 176 insertions(+), 182 deletions(-) diff --git a/py/bin/fmt b/py/bin/fmt index fda0432d2..04acb30bb 100755 --- a/py/bin/fmt +++ b/py/bin/fmt @@ -33,7 +33,7 @@ if [[ $? -ne 0 ]]; then fi # Format all Python code. -uvx ruff format "${TOP_DIR}/py" +uv run --directory "${TOP_DIR}/py" ruff format . if [[ $? -ne 0 ]]; then exit 1 fi diff --git a/py/bin/format_toml_files b/py/bin/format_toml_files index eef13cf5f..6ad0b811c 100755 --- a/py/bin/format_toml_files +++ b/py/bin/format_toml_files @@ -7,54 +7,48 @@ set -euo pipefail -GIT_ROOT=$(git rev-parse --show-toplevel) +TOP_DIR=$(git rev-parse --show-toplevel) -if command -v rust-parallel >/dev/null 2>&1; then +if command -v taplo >/dev/null 2>&1; then + if [ ! -f "${TOP_DIR}/py/taplo.toml" ]; then + echo "error: config file not found at ${TOP_DIR}/py/taplo.toml" + exit 1 + fi + + FORMATTER_COMMAND="taplo format --config ${TOP_DIR}/py/taplo.toml" + if command -v rust-parallel >/dev/null 2>&1; then + FORMATTER_COMMAND="rust-parallel -j4 ${FORMATTER_COMMAND}" + else + echo "warning: it is recommended to install https://crates.io/crates/rust-parallel for faster formatting" + fi + + pushd "${TOP_DIR}" if command -v fd >/dev/null 2>&1; then + echo "Using fd" fd -e toml \ - --exclude 'py/**/*.egg-info/**' \ - --exclude 'py/**/.dist/**' \ - --exclude 'py/**/.next/**' \ - --exclude 'py/**/.output/**' \ - --exclude 'py/**/.pytest_cache/**' \ - --exclude 'py/**/.venv/**' \ - --exclude 'py/**/__pycache__/**' \ - --exclude 'py/**/build/**' \ - --exclude 'py/**/develop-eggs/**' \ - --exclude 'py/**/dist/**' \ - --exclude 'py/**/eggs/**' \ - --exclude 'py/**/node_modules/**' \ - --exclude 'py/**/sdist/**' \ - --exclude 'py/**/site/**' \ - --exclude 'py/**/target/**' \ - --exclude 'py/**/venv/**' \ - --exclude 'py/**/wheels/**' | - rust-parallel -j4 \ - taplo format --config "${GIT_ROOT}/py/taplo.toml" + --exclude '**/*.egg-info/**' \ + --exclude '**/.dist/**' \ + --exclude '**/.next/**' \ + --exclude '**/.output/**' \ + --exclude '**/.pytest_cache/**' \ + --exclude '**/.venv/**' \ + --exclude '**/__pycache__/**' \ + --exclude '**/bazel-*/**' \ + --exclude '**/build/**' \ + --exclude '**/develop-eggs/**' \ + --exclude '**/dist/**' \ + --exclude '**/eggs/**' \ + --exclude '**/node_modules/**' \ + --exclude '**/sdist/**' \ + --exclude '**/site/**' \ + --exclude '**/target/**' \ + --exclude '**/venv/**' \ + --exclude '**/wheels/**' | + ${FORMATTER_COMMAND} else - echo "Using find" - find "${GIT_ROOT}" -name "*.toml" \ - ! -path 'py/**/*.egg-info/**' \ - ! -path 'py/**/.dist/**' \ - ! -path 'py/**/.next/**' \ - ! -path 'py/**/.output/**' \ - ! -path 'py/**/.pytest_cache/**' \ - ! -path 'py/**/.venv/**' \ - ! -path 'py/**/__pycache__/**' \ - ! -path 'py/**/build/**' \ - ! -path 'py/**/develop-eggs/**' \ - ! -path 'py/**/dist/**' \ - ! -path 'py/**/eggs/**' \ - ! -path 'py/**/node_modules/**' \ - ! -path 'py/**/sdist/**' \ - ! -path 'py/**/site/**' \ - ! -path 'py/**/target/**' \ - ! -path 'py/**/venv/**' \ - ! -path 'py/**/wheels/**' \ - -print0 | - rust-parallel -j4 \ - taplo format --config "${GIT_ROOT}/py/taplo.toml" + echo "Please install https://github.com/sharkdp/fd to find files to format." fi + popd else - echo "Please install GNU parallel to use this script" + echo "Please install https://github.com/tamasfe/taplo to format TOML files." fi diff --git a/py/bin/generate_schema_types b/py/bin/generate_schema_types index 03ff2be78..1e770e8d3 100755 --- a/py/bin/generate_schema_types +++ b/py/bin/generate_schema_types @@ -6,30 +6,30 @@ set -euo pipefail TOP_DIR=$(git rev-parse --show-toplevel) -SCHEMA_FILE="$TOP_DIR/py/packages/genkit/src/genkit/core/schemas.py" +SCHEMA_FILE="${TOP_DIR}/py/packages/genkit/src/genkit/core/schemas.py" # Generate types using configuration from pyproject.toml -uv run --directory "$TOP_DIR/py" datamodel-codegen +uv run --directory "${TOP_DIR}/py" datamodel-codegen # This isn't causing runtime errors at the moment so letting it be. -#sed -i '' '/^class Model(RootModel\[Any\]):$/,/^ root: Any$/d' "$SCHEMA_FILE" +#sed -i '' '/^class Model(RootModel\[Any\]):$/,/^ root: Any$/d' "${SCHEMA_FILE}" # Sanitize the generated schema. -python3 "${TOP_DIR}/py/bin/sanitize_schemas.py" "$SCHEMA_FILE" +python3 "${TOP_DIR}/py/bin/sanitize_schemas.py" "${SCHEMA_FILE}" # Add a generated by `generate_schema_types` comment. sed -i '' '1i\ # DO NOT EDIT: Generated by `generate_schema_types` from `genkit-schemas.json`. -' "$SCHEMA_FILE" +' "${SCHEMA_FILE}" # Add license header. addlicense \ -c "Google LLC" \ -s=only \ - "$SCHEMA_FILE" + "${SCHEMA_FILE}" # Checks and formatting. -uv run --directory "$TOP_DIR/py" \ - ruff check --fix "$SCHEMA_FILE" -uv run --directory "$TOP_DIR/py" \ - ruff format "$SCHEMA_FILE" +uv run --directory "${TOP_DIR}/py" \ + ruff format "${TOP_DIR}" +uv run --directory "${TOP_DIR}/py" \ + ruff check --fix "${SCHEMA_FILE}" diff --git a/py/bin/sanitize_schemas.py b/py/bin/sanitize_schemas.py index 25e7d39b9..94c7aaa00 100644 --- a/py/bin/sanitize_schemas.py +++ b/py/bin/sanitize_schemas.py @@ -24,8 +24,9 @@ def is_rootmodel_class(self, node: ast.ClassDef) -> bool: return True return False - def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: - """Visit class definitions and remove model_config if class inherits from RootModel.""" + def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: # noqa: N802 + """Visit class definitions and remove model_config if class + inherits from RootModel.""" if self.is_rootmodel_class(node): # Filter out model_config assignments new_body = [] diff --git a/py/bin/setup b/py/bin/setup index 77180dc10..a468dfa19 100755 --- a/py/bin/setup +++ b/py/bin/setup @@ -171,12 +171,11 @@ function genkit::install_google_cloud_sdk() { # This depends on Python 3.11 and installs it for the user on some systems. if command -v gcloud &>/dev/null; then gcloud config set disable_usage_reporting true - gcloud components update - return 0 + yes | gcloud components update + else + curl https://sdk.cloud.google.com | bash -s -- --disable-prompts + gcloud config set disable_usage_reporting true fi - - curl https://sdk.cloud.google.com | bash -s -- --disable-prompts - gcloud config set disable_usage_reporting true } # Install all the required tools that have been written in Go. diff --git a/py/captainhook.json b/py/captainhook.json index 964b2ae04..236c8ba84 100644 --- a/py/captainhook.json +++ b/py/captainhook.json @@ -94,6 +94,17 @@ { "run": "go test go/..." }, + { + "run": "govulncheck -C go ./...", + "conditions": [ + { + "run": "CaptainHook::FileChanged.Any", + "options": { + "files": ["go/**/*.go", "go/**/go.mod", "go/**/go.sum"] + } + } + ] + }, { "run": "py/.hooks/commit-message-format-pre-push" } diff --git a/py/packages/genkit/src/genkit/core/action.py b/py/packages/genkit/src/genkit/core/action.py index 11ce5c68f..ef9b10615 100644 --- a/py/packages/genkit/src/genkit/core/action.py +++ b/py/packages/genkit/src/genkit/core/action.py @@ -1,19 +1,20 @@ # Copyright 2025 Google LLC # SPDX-License-Identifier: Apache-2. + import inspect import json from collections.abc import Callable from typing import Any from genkit.core.tracing import tracer -from pydantic import BaseModel, ConfigDict, TypeAdapter +from pydantic import BaseModel, ConfigDict, Field, TypeAdapter class ActionResponse(BaseModel): model_config = ConfigDict(extra='forbid') response: Any - trace_id: str + trace_id: str = Field(alias='traceId') class Action: diff --git a/py/packages/genkit/src/genkit/core/schemas.py b/py/packages/genkit/src/genkit/core/schemas.py index bf7768aa3..7c6f78d89 100644 --- a/py/packages/genkit/src/genkit/core/schemas.py +++ b/py/packages/genkit/src/genkit/core/schemas.py @@ -18,15 +18,15 @@ class InstrumentationLibrary(BaseModel): model_config = ConfigDict(extra='forbid') name: str version: str | None = None - schemaUrl: str | None = None + schema_url: str | None = Field(None, alias='schemaUrl') class SpanContext(BaseModel): model_config = ConfigDict(extra='forbid') - traceId: str - spanId: str - isRemote: bool | None = None - traceFlags: float + trace_id: str = Field(..., alias='traceId') + span_id: str = Field(..., alias='spanId') + is_remote: bool | None = Field(None, alias='isRemote') + trace_flags: float = Field(..., alias='traceFlags') class SameProcessAsParentSpan(BaseModel): @@ -45,7 +45,7 @@ class SpanMetadata(BaseModel): state: State | None = None input: Any | None = None output: Any | None = None - isRoot: bool | None = None + is_root: bool | None = Field(None, alias='isRoot') metadata: dict[str, str] | None = None @@ -84,8 +84,8 @@ class DataPart(BaseModel): model_config = ConfigDict(extra='forbid') text: Any | None = None media: Any | None = None - toolRequest: Any | None = None - toolResponse: Any | None = None + tool_request: Any | None = Field(None, alias='toolRequest') + tool_response: Any | None = Field(None, alias='toolResponse') data: Any | None = None metadata: dict[str, Any] | None = None @@ -107,7 +107,7 @@ class Content(BaseModel): class Media(BaseModel): model_config = ConfigDict(extra='forbid') - contentType: str | None = None + content_type: str | None = Field(None, alias='contentType') url: str @@ -132,9 +132,9 @@ class ToolChoice(Enum): class Output(BaseModel): model_config = ConfigDict(extra='forbid') format: str | None = None - contentType: str | None = None + content_type: str | None = Field(None, alias='contentType') instructions: bool | str | None = None - jsonSchema: Any | None = None + json_schema: Any | None = Field(None, alias='jsonSchema') constrained: bool | None = None @@ -154,25 +154,25 @@ 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 + max_output_tokens: float | None = Field(None, alias='maxOutputTokens') + top_k: float | None = Field(None, alias='topK') + top_p: float | None = Field(None, alias='topP') + stop_sequences: list[str] | None = Field(None, alias='stopSequences') 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 + input_tokens: float | None = Field(None, alias='inputTokens') + output_tokens: float | None = Field(None, alias='outputTokens') + total_tokens: float | None = Field(None, alias='totalTokens') + input_characters: float | None = Field(None, alias='inputCharacters') + output_characters: float | None = Field(None, alias='outputCharacters') + input_images: float | None = Field(None, alias='inputImages') + output_images: float | None = Field(None, alias='outputImages') + input_videos: float | None = Field(None, alias='inputVideos') + output_videos: float | None = Field(None, alias='outputVideos') + input_audio_files: float | None = Field(None, alias='inputAudioFiles') + output_audio_files: float | None = Field(None, alias='outputAudioFiles') custom: dict[str, float] | None = None @@ -187,12 +187,12 @@ class Supports(BaseModel): multiturn: bool | None = None media: bool | None = None tools: bool | None = None - systemRole: bool | None = None + system_role: bool | None = Field(None, alias='systemRole') output: list[str] | None = None - contentType: list[str] | None = None + content_type: list[str] | None = Field(None, alias='contentType') context: bool | None = None constrained: Constrained | None = None - toolChoice: bool | None = None + tool_choice: bool | None = Field(None, alias='toolChoice') class ModelInfo(BaseModel): @@ -213,11 +213,15 @@ class ToolDefinition(BaseModel): model_config = ConfigDict(extra='forbid') name: str description: str - inputSchema: dict[str, Any] = Field( - ..., description='Valid JSON Schema representing the input of the tool.' + input_schema: dict[str, Any] = Field( + ..., + alias='inputSchema', + description='Valid JSON Schema representing the input of the tool.', ) - outputSchema: dict[str, Any] | None = Field( - None, description='Valid JSON Schema describing the output of the tool.' + output_schema: dict[str, Any] | None = Field( + None, + alias='outputSchema', + description='Valid JSON Schema describing the output of the tool.', ) metadata: dict[str, Any] | None = Field( None, description='additional metadata for this tool definition' @@ -266,7 +270,7 @@ class Content2(BaseModel): class Media2(BaseModel): model_config = ConfigDict(extra='forbid') - contentType: str | None = None + content_type: str | None = Field(None, alias='contentType') url: str @@ -328,38 +332,44 @@ class Link(BaseModel): model_config = ConfigDict(extra='forbid') context: SpanContext | None = None attributes: dict[str, Any] | None = None - droppedAttributesCount: float | None = None + dropped_attributes_count: float | None = Field( + None, alias='droppedAttributesCount' + ) class TimeEvents(BaseModel): model_config = ConfigDict(extra='forbid') - timeEvent: list[TimeEvent] | None = None + time_event: list[TimeEvent] | None = Field(None, alias='timeEvent') class SpanData(BaseModel): model_config = ConfigDict(extra='forbid') - spanId: str - traceId: str - parentSpanId: str | None = None - startTime: float - endTime: float + span_id: str = Field(..., alias='spanId') + trace_id: str = Field(..., alias='traceId') + parent_span_id: str | None = Field(None, alias='parentSpanId') + start_time: float = Field(..., alias='startTime') + end_time: float = Field(..., alias='endTime') attributes: dict[str, Any] - displayName: str + display_name: str = Field(..., alias='displayName') links: list[Link] | None = None - instrumentationLibrary: InstrumentationLibrary - spanKind: str - sameProcessAsParentSpan: SameProcessAsParentSpan | None = None + instrumentation_library: InstrumentationLibrary = Field( + ..., alias='instrumentationLibrary' + ) + span_kind: str = Field(..., alias='spanKind') + same_process_as_parent_span: SameProcessAsParentSpan | None = Field( + None, alias='sameProcessAsParentSpan' + ) status: SpanStatus | None = None - timeEvents: TimeEvents | None = None + time_events: TimeEvents | None = Field(None, alias='timeEvents') truncated: bool | None = None class TraceData(BaseModel): model_config = ConfigDict(extra='forbid') - traceId: str - displayName: str | None = None - startTime: float | None = None - endTime: float | None = None + trace_id: str = Field(..., alias='traceId') + display_name: str | None = Field(None, alias='displayName') + start_time: float | None = Field(None, alias='startTime') + end_time: float | None = Field(None, alias='endTime') spans: dict[str, SpanData] @@ -367,8 +377,8 @@ class MediaPart(BaseModel): model_config = ConfigDict(extra='forbid') text: Text | None = None media: Media - toolRequest: ToolRequest | None = None - toolResponse: ToolResponse | None = None + tool_request: ToolRequest | None = Field(None, alias='toolRequest') + tool_response: ToolResponse | None = Field(None, alias='toolResponse') data: Any | None = None metadata: Metadata | None = None @@ -377,8 +387,8 @@ class TextPart(BaseModel): model_config = ConfigDict(extra='forbid') text: str media: MediaModel | None = None - toolRequest: ToolRequest | None = None - toolResponse: ToolResponse | None = None + tool_request: ToolRequest | None = Field(None, alias='toolRequest') + tool_response: ToolResponse | None = Field(None, alias='toolResponse') data: Data | None = None metadata: Metadata | None = None @@ -387,8 +397,8 @@ class ToolRequestPart(BaseModel): model_config = ConfigDict(extra='forbid') text: Text | None = None media: MediaModel | None = None - toolRequest: ToolRequest1 - toolResponse: ToolResponse | None = None + tool_request: ToolRequest1 = Field(..., alias='toolRequest') + tool_response: ToolResponse | None = Field(None, alias='toolResponse') data: Data | None = None metadata: Metadata | None = None @@ -397,8 +407,8 @@ class ToolResponsePart(BaseModel): model_config = ConfigDict(extra='forbid') text: Text | None = None media: MediaModel | None = None - toolRequest: ToolRequest | None = None - toolResponse: ToolResponse1 + tool_request: ToolRequest | None = Field(None, alias='toolRequest') + tool_response: ToolResponse1 = Field(..., alias='toolResponse') data: Data | None = None metadata: Metadata | None = None @@ -455,8 +465,8 @@ class Candidate(BaseModel): index: float message: Message usage: GenerationUsage | None = None - finishReason: FinishReason - finishMessage: str | None = None + finish_reason: FinishReason = Field(..., alias='finishReason') + finish_message: str | None = Field(None, alias='finishMessage') custom: Any | None = None @@ -466,11 +476,11 @@ class GenerateActionOptions(BaseModel): docs: list[Doc] | None = None messages: list[Message] tools: list[str] | None = None - toolChoice: ToolChoice | None = None + tool_choice: ToolChoice | None = Field(None, alias='toolChoice') config: Any | None = None output: Output | None = None - returnToolRequests: bool | None = None - maxTurns: float | None = None + return_tool_requests: bool | None = Field(None, alias='returnToolRequests') + max_turns: float | None = Field(None, alias='maxTurns') class GenerateRequest(BaseModel): @@ -478,7 +488,7 @@ class GenerateRequest(BaseModel): messages: list[Message] config: Any | None = None tools: list[ToolDefinition] | None = None - toolChoice: ToolChoice | None = None + tool_choice: ToolChoice | None = Field(None, alias='toolChoice') output: Output1 | None = None context: list[Items] | None = None candidates: float | None = None @@ -487,9 +497,9 @@ class GenerateRequest(BaseModel): class GenerateResponse(BaseModel): model_config = ConfigDict(extra='forbid') message: Message | None = None - finishReason: FinishReason | None = None - finishMessage: str | None = None - latencyMs: float | None = None + finish_reason: FinishReason | None = Field(None, alias='finishReason') + finish_message: str | None = Field(None, alias='finishMessage') + latency_ms: float | None = Field(None, alias='latencyMs') usage: GenerationUsage | None = None custom: Any | None = None request: GenerateRequest | None = None @@ -501,7 +511,7 @@ class ModelRequest(BaseModel): messages: Messages config: Config | None = None tools: Tools | None = None - toolChoice: ToolChoice | None = None + tool_choice: ToolChoice | None = Field(None, alias='toolChoice') output: OutputModel | None = None context: list[Items] | None = None @@ -513,9 +523,9 @@ class Request(RootModel[GenerateRequest]): class ModelResponse(BaseModel): model_config = ConfigDict(extra='forbid') message: Message | None = None - finishReason: FinishReason - finishMessage: FinishMessage | None = None - latencyMs: LatencyMs | None = None + finish_reason: FinishReason = Field(..., alias='finishReason') + finish_message: FinishMessage | None = Field(None, alias='finishMessage') + latency_ms: LatencyMs | None = Field(None, alias='latencyMs') usage: Usage | None = None custom: Custom | None = None request: Request | None = None diff --git a/py/packages/genkit/src/genkit/core/tracing.py b/py/packages/genkit/src/genkit/core/tracing.py index 08ef95ad5..a539ac7f1 100644 --- a/py/packages/genkit/src/genkit/core/tracing.py +++ b/py/packages/genkit/src/genkit/core/tracing.py @@ -73,8 +73,8 @@ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult: span_data['startTime'] = span.start_time span_data['endTime'] = span.end_time - # TODO: telemetry server URL must be dynamic, - # whatever tools notification says + # TODO: telemetry server URL must be dynamic, whatever tools + # notification says requests.post( 'http://localhost:4033/api/traces', data=json.dumps(span_data), diff --git a/py/pyproject.toml b/py/pyproject.toml index 2e315c54c..d4ff36e23 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -21,12 +21,12 @@ version = "0.1.0" [dependency-groups] dev = [ "bpython>=0.25", - "ipython>=8.31.0", + "ipython>=8.32.0", "jupyter>=1.1.1", - "pytest-asyncio>=0.25.2", + "pytest-asyncio>=0.25.3", "pytest>=8.3.4", "pytest-cov>=6.0.0", - "datamodel-code-generator>=0.26.5", + "datamodel-code-generator>=0.27.3", ] lint = ["mypy~=1.15", "ruff~=0.9"] @@ -97,6 +97,7 @@ exclude = [ ".vscode", "__pypackages__", "_build", + "bazel-*", "buck-out", "build", "dist", @@ -136,7 +137,6 @@ line-ending = "lf" quote-style = "single" skip-magic-trailing-comma = false - # Static type checking. [tool.mypy] disallow_incomplete_defs = true @@ -144,8 +144,10 @@ 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. +#strict-types = ["str", "int", "float", "bool", "bytes"] # Don't use; produces StrictStr, StrictInt, etc. +#use-subclass-enum = true +capitalize-enum-members = true disable-timestamp = true enable-version-header = true field-constraints = true @@ -153,8 +155,10 @@ input = "../genkit-tools/genkit-schema.json" input-file-type = "jsonschema" output = "packages/genkit/src/genkit/core/schemas.py" output-model-type = "pydantic_v2.BaseModel" +snake-case-field = true strict-nullable = true target-python-version = "3.12" use-schema-description = true use-standard-collections = true use-union-operator = true +use-unique-items-as-set = true diff --git a/py/samples/hello/hello.py b/py/samples/hello/hello.py index ff8a39515..4e799bfe1 100644 --- a/py/samples/hello/hello.py +++ b/py/samples/hello/hello.py @@ -8,6 +8,7 @@ from pydantic import BaseModel, Field ai = Genkit(plugins=[vertex_ai()], model=gemini('gemini-1.5-flash')) +ai = Genkit(plugins=[vertex_ai()], model=gemini('gemini-1.5-flash')) class MyInput(BaseModel): diff --git a/py/uv.lock b/py/uv.lock index 08cc94480..bd740cf02 100644 --- a/py/uv.lock +++ b/py/uv.lock @@ -425,7 +425,7 @@ wheels = [ [[package]] name = "datamodel-code-generator" -version = "0.26.5" +version = "0.27.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argcomplete" }, @@ -435,12 +435,12 @@ dependencies = [ { name = "isort" }, { name = "jinja2" }, { name = "packaging" }, - { name = "pydantic", extra = ["email"], marker = "python_full_version < '4.0'" }, + { name = "pydantic" }, { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/53/17/53cec24a4edb2021c3b89a3c50c83a9a8dd0e506495d5f7ce486be4a24fa/datamodel_code_generator-0.27.3.tar.gz", hash = "sha256:01e928c00b800aec8d2ee77b5d4b47e1bc159a3a1c32f0f405df0a442d9ab5e7", size = 440612 } 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 }, + { url = "https://files.pythonhosted.org/packages/08/28/a72154c09d09b4c331fee613bb43451a8c43860b52f349777db7935dde04/datamodel_code_generator-0.27.3-py3-none-any.whl", hash = "sha256:ddef49e66e2b90a4c9b238f6ce42dc5a2a23f6ab1b8370eaca08576777921e43", size = 116023 }, ] [[package]] @@ -490,15 +490,6 @@ 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" @@ -519,19 +510,6 @@ 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" @@ -710,11 +688,11 @@ 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 = "datamodel-code-generator", specifier = ">=0.27.3" }, + { name = "ipython", specifier = ">=8.32.0" }, { name = "jupyter", specifier = ">=1.1.1" }, { name = "pytest", specifier = ">=8.3.4" }, - { name = "pytest-asyncio", specifier = ">=0.25.2" }, + { name = "pytest-asyncio", specifier = ">=0.25.3" }, { name = "pytest-cov", specifier = ">=6.0.0" }, ] lint = [ @@ -1117,7 +1095,7 @@ wheels = [ [[package]] name = "ipython" -version = "8.31.0" +version = "8.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1130,9 +1108,9 @@ dependencies = [ { name = "stack-data" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/35/6f90fdddff7a08b7b715fccbd2427b5212c9525cd043d26fdc45bee0708d/ipython-8.31.0.tar.gz", hash = "sha256:b6a2274606bec6166405ff05e54932ed6e5cfecaca1fc05f2cacde7bb074d70b", size = 5501011 } +sdist = { url = "https://files.pythonhosted.org/packages/36/80/4d2a072e0db7d250f134bc11676517299264ebe16d62a8619d49a78ced73/ipython-8.32.0.tar.gz", hash = "sha256:be2c91895b0b9ea7ba49d33b23e2040c352b33eb6a519cca7ce6e0c743444251", size = 5507441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/60/d0feb6b6d9fe4ab89fe8fe5b47cbf6cd936bfd9f1e7ffa9d0015425aeed6/ipython-8.31.0-py3-none-any.whl", hash = "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6", size = 821583 }, + { url = "https://files.pythonhosted.org/packages/e7/e1/f4474a7ecdb7745a820f6f6039dc43c66add40f1bcc66485607d93571af6/ipython-8.32.0-py3-none-any.whl", hash = "sha256:cae85b0c61eff1fc48b0a8002de5958b6528fa9c8defb1894da63f42613708aa", size = 825524 }, ] [[package]] @@ -1926,11 +1904,6 @@ 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" @@ -1996,14 +1969,14 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "0.25.2" +version = "0.25.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a8/ecbc8ede70921dd2f544ab1cadd3ff3bf842af27f87bbdea774c7baa1d38/pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a", size = 54239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400 }, + { url = "https://files.pythonhosted.org/packages/67/17/3493c5624e48fd97156ebaec380dcaafee9506d7e2c46218ceebbb57d7de/pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3", size = 19467 }, ] [[package]]