From 8afdf7eb14082bc1956c9babb5de78788df74188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9B=90=E7=B2=92=20Yanli?= Date: Wed, 13 May 2026 05:23:45 +0800 Subject: [PATCH] split dify-agent client server deps --- .../agenton_examples/pydantic_ai_bridge.py | 14 +- .../run_pydantic_ai_agent.py | 9 +- .../run_server_consumer.py | 14 +- .../run_server_sync_client.py | 19 +- dify-agent/pyproject.toml | 18 +- .../src/agenton_collections/__init__.py | 13 +- .../layers/plain/__init__.py | 9 +- .../agenton_collections/layers/plain/basic.py | 8 +- .../transformers/__init__.py | 15 +- dify-agent/src/dify_agent/__init__.py | 11 +- .../dify_agent/layers/dify_plugin/__init__.py | 10 +- .../dify_agent/layers/dify_plugin/configs.py | 13 +- .../layers/dify_plugin/llm_layer.py | 4 +- .../layers/dify_plugin/plugin_layer.py | 4 +- .../layers/plain/test_basic.py | 6 + .../local/dify_agent/client/test_client.py | 3 +- .../layers/dify_plugin/test_configs.py | 8 +- .../layers/dify_plugin/test_layers.py | 12 +- .../protocol/test_protocol_schemas.py | 15 +- .../dify_agent/test_import_boundaries.py | 112 ++++++++ .../examples/test_dify_agent_examples.py | 10 +- dify-agent/tests/local/test_packaging.py | 44 +++ dify-agent/uv.lock | 270 ++---------------- 23 files changed, 316 insertions(+), 325 deletions(-) create mode 100644 dify-agent/tests/local/agenton_collections/layers/plain/test_basic.py create mode 100644 dify-agent/tests/local/dify_agent/test_import_boundaries.py create mode 100644 dify-agent/tests/local/test_packaging.py diff --git a/dify-agent/examples/agenton/agenton_examples/pydantic_ai_bridge.py b/dify-agent/examples/agenton/agenton_examples/pydantic_ai_bridge.py index ce6e10fbc7..0b6ff588d1 100644 --- a/dify-agent/examples/agenton/agenton_examples/pydantic_ai_bridge.py +++ b/dify-agent/examples/agenton/agenton_examples/pydantic_ai_bridge.py @@ -1,4 +1,11 @@ -"""Run with: uv run --project dify-agent python -m agenton_examples.pydantic_ai_bridge.""" +"""Pydantic AI bridge example for use from a source checkout. + +`agenton_examples` is not part of the published package, so run this module from +the repository root with: + + PYTHONPATH=dify-agent/src:dify-agent/examples/agenton \ + uv run --project dify-agent python -m agenton_examples.pydantic_ai_bridge +""" from __future__ import annotations @@ -13,10 +20,9 @@ from pydantic_ai.models.openai import OpenAIChatModel # pyright: ignore[reportD from pydantic_ai.models.test import TestModel from agenton.compositor import Compositor, LayerNode, LayerProvider -from agenton_collections.layers.plain import ObjectLayer, PromptLayer, ToolsLayer -from agenton_collections.layers.plain.basic import PromptLayerConfig +from agenton_collections.layers.plain import ObjectLayer, PromptLayer, PromptLayerConfig, ToolsLayer from agenton_collections.layers.pydantic_ai import PydanticAIBridgeLayer -from agenton_collections.transformers import PYDANTIC_AI_TRANSFORMERS +from agenton_collections.transformers.pydantic_ai import PYDANTIC_AI_TRANSFORMERS @dataclass(frozen=True, slots=True) diff --git a/dify-agent/examples/dify_agent/dify_agent_examples/run_pydantic_ai_agent.py b/dify-agent/examples/dify_agent/dify_agent_examples/run_pydantic_ai_agent.py index 2783b7f860..12eb42dc1b 100644 --- a/dify-agent/examples/dify_agent/dify_agent_examples/run_pydantic_ai_agent.py +++ b/dify-agent/examples/dify_agent/dify_agent_examples/run_pydantic_ai_agent.py @@ -1,11 +1,16 @@ """Run a Pydantic AI agent through the Dify plugin-daemon adapter. Prerequisites: +- Sync the server runtime dependencies first: `uv sync --project dify-agent --extra server`. - Start the plugin daemon from `dify-aio/dify/docker/docker-compose.middleware.yaml`. - Run the Dify API with `dify-aio/dify/api/.env` so the daemon can resolve tenants/plugins. - Fill `dify-agent/.env` with a real tenant, plugin, provider, model, and provider credentials. -Example: +This example is meant to be run from a source checkout because +`dify_agent_examples` is not part of the published package. + +Example from the repository root: + PYTHONPATH=dify-agent/src:dify-agent/examples/dify_agent \ uv run --project dify-agent python -m dify_agent_examples.run_pydantic_ai_agent """ @@ -19,7 +24,7 @@ from typing import Any from pydantic_ai import Agent -from dify_agent import DifyLLMAdapterModel, DifyPluginDaemonProvider +from dify_agent.adapters.llm import DifyLLMAdapterModel, DifyPluginDaemonProvider PROJECT_ROOT = Path(__file__).resolve().parents[3] diff --git a/dify-agent/examples/dify_agent/dify_agent_examples/run_server_consumer.py b/dify-agent/examples/dify_agent/dify_agent_examples/run_server_consumer.py index 3d2b7278d3..a3d0474b46 100644 --- a/dify-agent/examples/dify_agent/dify_agent_examples/run_server_consumer.py +++ b/dify-agent/examples/dify_agent/dify_agent_examples/run_server_consumer.py @@ -1,6 +1,8 @@ """Async Python client example for the Dify Agent run server. -Requires Redis and a running API server. The server schedules runs in-process, for +Requires Redis and a running API server. Before starting the server, sync the +server runtime dependencies with `uv sync --project dify-agent --extra server` +or install `dify-agent[server]`. The server schedules runs in-process, for example: uv run --project dify-agent uvicorn dify_agent.server.app:app --reload @@ -13,9 +15,11 @@ recover after client-side uncertainty. import asyncio -from agenton_collections.layers.plain import PromptLayerConfig +from agenton_collections.layers.plain import PLAIN_PROMPT_LAYER_TYPE_ID, PromptLayerConfig from dify_agent.client import Client from dify_agent.layers.dify_plugin import ( + DIFY_PLUGIN_LAYER_TYPE_ID, + DIFY_PLUGIN_LLM_LAYER_TYPE_ID, DifyPluginCredentialValue, DifyPluginLLMLayerConfig, DifyPluginLayerConfig, @@ -39,7 +43,7 @@ async def main() -> None: layers=[ RunLayerSpec( name="prompt", - type="plain.prompt", + type=PLAIN_PROMPT_LAYER_TYPE_ID, config=PromptLayerConfig( prefix="You are a concise assistant.", user="Say hello from the Dify Agent API server example.", @@ -47,12 +51,12 @@ async def main() -> None: ), RunLayerSpec( name="plugin", - type="dify.plugin", + type=DIFY_PLUGIN_LAYER_TYPE_ID, config=DifyPluginLayerConfig(tenant_id=TENANT_ID, plugin_id=PLUGIN_ID), ), RunLayerSpec( name=DIFY_AGENT_MODEL_LAYER_ID, - type="dify.plugin.llm", + type=DIFY_PLUGIN_LLM_LAYER_TYPE_ID, deps={"plugin": "plugin"}, config=DifyPluginLLMLayerConfig( model_provider=PLUGIN_PROVIDER, diff --git a/dify-agent/examples/dify_agent/dify_agent_examples/run_server_sync_client.py b/dify-agent/examples/dify_agent/dify_agent_examples/run_server_sync_client.py index c85184b082..3c789571f1 100644 --- a/dify-agent/examples/dify_agent/dify_agent_examples/run_server_sync_client.py +++ b/dify-agent/examples/dify_agent/dify_agent_examples/run_server_sync_client.py @@ -1,13 +1,18 @@ """Synchronous Python client example for the Dify Agent run server. -Requires the same running FastAPI server as the async examples. ``create_run_sync`` -does not retry ``POST /runs``; if a timeout occurs, inspect server state or create -a new run explicitly rather than assuming the original request was not accepted. +Requires the same running FastAPI server as the async examples. Before starting +that server, sync the server runtime dependencies with +`uv sync --project dify-agent --extra server` or install +`dify-agent[server]`. ``create_run_sync`` does not retry ``POST /runs``; if a +timeout occurs, inspect server state or create a new run explicitly rather than +assuming the original request was not accepted. """ -from agenton_collections.layers.plain import PromptLayerConfig +from agenton_collections.layers.plain import PLAIN_PROMPT_LAYER_TYPE_ID, PromptLayerConfig from dify_agent.client import Client from dify_agent.layers.dify_plugin import ( + DIFY_PLUGIN_LAYER_TYPE_ID, + DIFY_PLUGIN_LLM_LAYER_TYPE_ID, DifyPluginCredentialValue, DifyPluginLLMLayerConfig, DifyPluginLayerConfig, @@ -31,7 +36,7 @@ def main() -> None: layers=[ RunLayerSpec( name="prompt", - type="plain.prompt", + type=PLAIN_PROMPT_LAYER_TYPE_ID, config=PromptLayerConfig( prefix="You are a concise assistant.", user="Say hello from the synchronous Dify Agent client example.", @@ -39,12 +44,12 @@ def main() -> None: ), RunLayerSpec( name="plugin", - type="dify.plugin", + type=DIFY_PLUGIN_LAYER_TYPE_ID, config=DifyPluginLayerConfig(tenant_id=TENANT_ID, plugin_id=PLUGIN_ID), ), RunLayerSpec( name=DIFY_AGENT_MODEL_LAYER_ID, - type="dify.plugin.llm", + type=DIFY_PLUGIN_LLM_LAYER_TYPE_ID, deps={"plugin": "plugin"}, config=DifyPluginLLMLayerConfig( model_provider=PLUGIN_PROVIDER, diff --git a/dify-agent/pyproject.toml b/dify-agent/pyproject.toml index 662fa89ca5..552cabb58b 100644 --- a/dify-agent/pyproject.toml +++ b/dify-agent/pyproject.toml @@ -5,28 +5,28 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.12" dependencies = [ - "anyio>=4.13.0", + "httpx>=0.28.1", + "pydantic>=2.13.3", + "pydantic-ai-slim>=1.85.1", + "typing-extensions>=4.12.2", +] + +[project.optional-dependencies] +server = [ "fastapi>=0.136.0", "graphon~=0.2.2", - "httpx>=0.28.1", - "logfire>=4.32.1", - "pydantic>=2.13.3", "pydantic-ai-slim[anthropic,google,openai]>=1.85.1", "pydantic-settings>=2.12.0", "redis>=5", - "sqlmodel>=0.0.38", "uvicorn[standard]>=0.38.0", - "uvloop>=0.22.1", ] [tool.setuptools.packages.find] -where = ["src", "examples/agenton", "examples/dify_agent"] +where = ["src"] include = [ "agenton*", "agenton_collections*", - "agenton_examples*", "dify_agent*", - "dify_agent_examples*", ] [tool.pyright] diff --git a/dify-agent/src/agenton_collections/__init__.py b/dify-agent/src/agenton_collections/__init__.py index 6e0b3750f0..b4b52de993 100644 --- a/dify-agent/src/agenton_collections/__init__.py +++ b/dify-agent/src/agenton_collections/__init__.py @@ -1,9 +1,10 @@ """Convenience exports for reusable layer implementations. Concrete collection layers live in family subpackages such as -``agenton_collections.plain`` and ``agenton_collections.pydantic_ai``. The -package root keeps the short import path for common layers while avoiding -implementation code in ``__init__``. +``agenton_collections.layers.plain`` and +``agenton_collections.layers.pydantic_ai``. The package root keeps short +client-safe imports for common plain layers while requiring explicit submodule +imports for pydantic-ai bridge implementations. """ from agenton.layers.types import ( @@ -20,10 +21,6 @@ from agenton.layers.types import ( PydanticAITool, PydanticAIToolType, ) -from agenton_collections.layers.pydantic_ai import ( - PydanticAIBridgeLayer, - PydanticAIBridgeLayerDeps, -) from agenton_collections.layers.plain import ( DynamicToolsLayer, DynamicToolsLayerDeps, @@ -45,8 +42,6 @@ __all__ = [ "PlainTool", "PlainToolType", "PromptLayer", - "PydanticAIBridgeLayer", - "PydanticAIBridgeLayerDeps", "PydanticAILayer", "PydanticAIPrompt", "PydanticAIPromptType", diff --git a/dify-agent/src/agenton_collections/layers/plain/__init__.py b/dify-agent/src/agenton_collections/layers/plain/__init__.py index a5b0b75384..a3e20cc204 100644 --- a/dify-agent/src/agenton_collections/layers/plain/__init__.py +++ b/dify-agent/src/agenton_collections/layers/plain/__init__.py @@ -1,6 +1,12 @@ """Reusable collection layers for the plain layer family.""" -from agenton_collections.layers.plain.basic import ObjectLayer, PromptLayer, PromptLayerConfig, ToolsLayer +from agenton_collections.layers.plain.basic import ( + PLAIN_PROMPT_LAYER_TYPE_ID, + ObjectLayer, + PromptLayer, + PromptLayerConfig, + ToolsLayer, +) from agenton_collections.layers.plain.dynamic_tools import ( DynamicToolsLayer, DynamicToolsLayerDeps, @@ -11,6 +17,7 @@ __all__ = [ "DynamicToolsLayer", "DynamicToolsLayerDeps", "ObjectLayer", + "PLAIN_PROMPT_LAYER_TYPE_ID", "PromptLayer", "PromptLayerConfig", "ToolsLayer", diff --git a/dify-agent/src/agenton_collections/layers/plain/basic.py b/dify-agent/src/agenton_collections/layers/plain/basic.py index faeecc096e..aeefd1abf8 100644 --- a/dify-agent/src/agenton_collections/layers/plain/basic.py +++ b/dify-agent/src/agenton_collections/layers/plain/basic.py @@ -8,7 +8,7 @@ dynamic layers. from collections.abc import Callable, Sequence from dataclasses import dataclass, field -from typing import Any +from typing import Any, Final from pydantic import ConfigDict, Field from typing_extensions import Self, override @@ -17,6 +17,9 @@ from agenton.layers.base import LayerConfig, NoLayerDeps from agenton.layers.types import PlainLayer +PLAIN_PROMPT_LAYER_TYPE_ID: Final[str] = "plain.prompt" + + class PromptLayerConfig(LayerConfig): """Serializable config schema for ``PromptLayer``.""" @@ -43,7 +46,7 @@ class ObjectLayer[ObjectT](PlainLayer[NoLayerDeps]): class PromptLayer(PlainLayer[NoLayerDeps, PromptLayerConfig]): """Layer that contributes configured system and user prompt fragments.""" - type_id = "plain.prompt" + type_id = PLAIN_PROMPT_LAYER_TYPE_ID prefix: list[str] | str = field(default_factory=list) user: list[str] | str = field(default_factory=list) @@ -93,6 +96,7 @@ class ToolsLayer(PlainLayer[NoLayerDeps]): __all__ = [ "ObjectLayer", + "PLAIN_PROMPT_LAYER_TYPE_ID", "PromptLayerConfig", "PromptLayer", "ToolsLayer", diff --git a/dify-agent/src/agenton_collections/transformers/__init__.py b/dify-agent/src/agenton_collections/transformers/__init__.py index dd46275944..9767d57fc3 100644 --- a/dify-agent/src/agenton_collections/transformers/__init__.py +++ b/dify-agent/src/agenton_collections/transformers/__init__.py @@ -1,11 +1,8 @@ -"""Reusable compositor transformers for collection integrations.""" +"""Transformer package marker for collection integrations. -from agenton_collections.transformers.pydantic_ai import ( - PYDANTIC_AI_TRANSFORMERS, - PydanticAICompositorTransformerKwargs, -) +Import pydantic-ai transformer presets from +``agenton_collections.transformers.pydantic_ai`` explicitly so default imports do +not pull runtime bridge implementations into client-safe environments. +""" -__all__ = [ - "PYDANTIC_AI_TRANSFORMERS", - "PydanticAICompositorTransformerKwargs", -] +__all__: list[str] = [] diff --git a/dify-agent/src/dify_agent/__init__.py b/dify-agent/src/dify_agent/__init__.py index bb11ce70c8..b83189b195 100644 --- a/dify-agent/src/dify_agent/__init__.py +++ b/dify-agent/src/dify_agent/__init__.py @@ -1,5 +1,10 @@ -"""Adapters for using Dify components inside the local agent package.""" +"""Client-safe top-level exports for the Dify Agent package. -from .adapters.llm import DifyLLMAdapterModel, DifyPluginDaemonProvider +Default installs must be able to import ``dify_agent`` without pulling in server +runtime adapters or their optional dependencies. Server-only adapter entry points +remain under ``dify_agent.adapters.llm``. +""" -__all__ = ["DifyLLMAdapterModel", "DifyPluginDaemonProvider"] +from dify_agent.client import Client + +__all__ = ["Client"] diff --git a/dify-agent/src/dify_agent/layers/dify_plugin/__init__.py b/dify-agent/src/dify_agent/layers/dify_plugin/__init__.py index 54396fa1bb..5b2f1dccce 100644 --- a/dify-agent/src/dify_agent/layers/dify_plugin/__init__.py +++ b/dify-agent/src/dify_agent/layers/dify_plugin/__init__.py @@ -1,12 +1,20 @@ -"""Client-safe exports for Dify plugin layer config DTOs.""" +"""Client-safe exports for Dify plugin DTOs and public layer type ids. + +Implementation layers live in sibling modules and require server-side runtime +dependencies. Keep this package root import-safe for client-only installs. +""" from dify_agent.layers.dify_plugin.configs import ( + DIFY_PLUGIN_LAYER_TYPE_ID, + DIFY_PLUGIN_LLM_LAYER_TYPE_ID, DifyPluginCredentialValue, DifyPluginLLMLayerConfig, DifyPluginLayerConfig, ) __all__ = [ + "DIFY_PLUGIN_LAYER_TYPE_ID", + "DIFY_PLUGIN_LLM_LAYER_TYPE_ID", "DifyPluginCredentialValue", "DifyPluginLLMLayerConfig", "DifyPluginLayerConfig", diff --git a/dify-agent/src/dify_agent/layers/dify_plugin/configs.py b/dify-agent/src/dify_agent/layers/dify_plugin/configs.py index 42790f9605..5fff7dde51 100644 --- a/dify-agent/src/dify_agent/layers/dify_plugin/configs.py +++ b/dify-agent/src/dify_agent/layers/dify_plugin/configs.py @@ -1,12 +1,13 @@ """Client-safe DTOs for Dify plugin-backed Agenton layers. This module intentionally contains only public config schemas and scalar type -aliases. Runtime objects such as HTTP clients, server settings, and adapter -implementations live in sibling implementation modules so clients can build run -requests without importing server-only dependencies. +aliases plus stable layer type identifiers. Runtime objects such as HTTP +clients, server settings, and adapter implementations live in sibling +implementation modules so clients can build run requests without importing +server-only dependencies. """ -from typing import ClassVar, TypeAlias +from typing import ClassVar, Final, TypeAlias from pydantic import ConfigDict, Field from pydantic_ai.settings import ModelSettings @@ -15,6 +16,8 @@ from agenton.layers import LayerConfig DifyPluginCredentialValue: TypeAlias = str | int | float | bool | None +DIFY_PLUGIN_LAYER_TYPE_ID: Final[str] = "dify.plugin" +DIFY_PLUGIN_LLM_LAYER_TYPE_ID: Final[str] = "dify.plugin.llm" class DifyPluginLayerConfig(LayerConfig): @@ -39,6 +42,8 @@ class DifyPluginLLMLayerConfig(LayerConfig): __all__ = [ + "DIFY_PLUGIN_LAYER_TYPE_ID", + "DIFY_PLUGIN_LLM_LAYER_TYPE_ID", "DifyPluginCredentialValue", "DifyPluginLLMLayerConfig", "DifyPluginLayerConfig", diff --git a/dify-agent/src/dify_agent/layers/dify_plugin/llm_layer.py b/dify-agent/src/dify_agent/layers/dify_plugin/llm_layer.py index 75fe0c2908..4ac053df3f 100644 --- a/dify-agent/src/dify_agent/layers/dify_plugin/llm_layer.py +++ b/dify-agent/src/dify_agent/layers/dify_plugin/llm_layer.py @@ -16,7 +16,7 @@ from typing_extensions import Self, override from agenton.layers import LayerDeps, PlainLayer from dify_agent.adapters.llm import DifyLLMAdapterModel -from dify_agent.layers.dify_plugin.configs import DifyPluginLLMLayerConfig +from dify_agent.layers.dify_plugin.configs import DIFY_PLUGIN_LLM_LAYER_TYPE_ID, DifyPluginLLMLayerConfig from dify_agent.layers.dify_plugin.plugin_layer import DifyPluginLayer @@ -30,7 +30,7 @@ class DifyPluginLLMDeps(LayerDeps): class DifyPluginLLMLayer(PlainLayer[DifyPluginLLMDeps, DifyPluginLLMLayerConfig]): """Layer that creates the Dify plugin-daemon Pydantic AI model.""" - type_id = "dify.plugin.llm" + type_id = DIFY_PLUGIN_LLM_LAYER_TYPE_ID config: DifyPluginLLMLayerConfig diff --git a/dify-agent/src/dify_agent/layers/dify_plugin/plugin_layer.py b/dify-agent/src/dify_agent/layers/dify_plugin/plugin_layer.py index 0f2c5b56e1..71c649b6de 100644 --- a/dify-agent/src/dify_agent/layers/dify_plugin/plugin_layer.py +++ b/dify-agent/src/dify_agent/layers/dify_plugin/plugin_layer.py @@ -17,14 +17,14 @@ from typing_extensions import Self, override from agenton.layers import EmptyRuntimeState, NoLayerDeps, PlainLayer from dify_agent.adapters.llm import DifyPluginDaemonProvider -from dify_agent.layers.dify_plugin.configs import DifyPluginLayerConfig +from dify_agent.layers.dify_plugin.configs import DIFY_PLUGIN_LAYER_TYPE_ID, DifyPluginLayerConfig @dataclass(slots=True) class DifyPluginLayer(PlainLayer[NoLayerDeps, DifyPluginLayerConfig, EmptyRuntimeState]): """Layer that carries plugin daemon identity without owning live resources.""" - type_id = "dify.plugin" + type_id = DIFY_PLUGIN_LAYER_TYPE_ID config: DifyPluginLayerConfig daemon_url: str diff --git a/dify-agent/tests/local/agenton_collections/layers/plain/test_basic.py b/dify-agent/tests/local/agenton_collections/layers/plain/test_basic.py new file mode 100644 index 0000000000..45928d079b --- /dev/null +++ b/dify-agent/tests/local/agenton_collections/layers/plain/test_basic.py @@ -0,0 +1,6 @@ +from agenton_collections.layers.plain import PLAIN_PROMPT_LAYER_TYPE_ID, PromptLayer + + +def test_prompt_layer_type_id_constant_matches_implementation_class() -> None: + assert PLAIN_PROMPT_LAYER_TYPE_ID == "plain.prompt" + assert PromptLayer.type_id == PLAIN_PROMPT_LAYER_TYPE_ID diff --git a/dify-agent/tests/local/dify_agent/client/test_client.py b/dify-agent/tests/local/dify_agent/client/test_client.py index 81ae96a700..990475909d 100644 --- a/dify-agent/tests/local/dify_agent/client/test_client.py +++ b/dify-agent/tests/local/dify_agent/client/test_client.py @@ -10,6 +10,7 @@ import httpx import pytest from agenton.compositor import CompositorSessionSnapshot +from agenton_collections.layers.plain import PLAIN_PROMPT_LAYER_TYPE_ID from dify_agent.client import ( Client, DifyAgentHTTPError, @@ -33,7 +34,7 @@ def _create_run_payload() -> dict[str, object]: return { "composition": { "schema_version": 1, - "layers": [{"name": "prompt", "type": "plain.prompt", "config": {"user": "hello"}}], + "layers": [{"name": "prompt", "type": PLAIN_PROMPT_LAYER_TYPE_ID, "config": {"user": "hello"}}], } } diff --git a/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_configs.py b/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_configs.py index 8545e622c9..47d0fd4e19 100644 --- a/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_configs.py +++ b/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_configs.py @@ -3,6 +3,8 @@ from pydantic import ValidationError import dify_agent.layers.dify_plugin as dify_plugin_exports from dify_agent.layers.dify_plugin import ( + DIFY_PLUGIN_LAYER_TYPE_ID, + DIFY_PLUGIN_LLM_LAYER_TYPE_ID, DifyPluginCredentialValue, DifyPluginLLMLayerConfig, DifyPluginLayerConfig, @@ -11,14 +13,16 @@ from dify_agent.layers.dify_plugin import ( def test_dify_plugin_package_exports_client_safe_config_symbols_only() -> None: assert dify_plugin_exports.__all__ == [ + "DIFY_PLUGIN_LAYER_TYPE_ID", + "DIFY_PLUGIN_LLM_LAYER_TYPE_ID", "DifyPluginCredentialValue", "DifyPluginLLMLayerConfig", "DifyPluginLayerConfig", ] + assert dify_plugin_exports.DIFY_PLUGIN_LAYER_TYPE_ID == "dify.plugin" + assert dify_plugin_exports.DIFY_PLUGIN_LLM_LAYER_TYPE_ID == "dify.plugin.llm" assert not hasattr(dify_plugin_exports, "DifyPluginLayer") assert not hasattr(dify_plugin_exports, "DifyPluginLLMLayer") - - def test_dify_plugin_layer_config_forbids_runtime_settings() -> None: config = DifyPluginLayerConfig(tenant_id="tenant-1", plugin_id="plugin-1", user_id="user-1") diff --git a/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_layers.py b/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_layers.py index 0484ebe65a..78c833d946 100644 --- a/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_layers.py +++ b/dify-agent/tests/local/dify_agent/layers/dify_plugin/test_layers.py @@ -5,7 +5,12 @@ import pytest from agenton.compositor import Compositor, LayerNode, LayerProvider from dify_agent.adapters.llm import DifyLLMAdapterModel -from dify_agent.layers.dify_plugin.configs import DifyPluginLLMLayerConfig, DifyPluginLayerConfig +from dify_agent.layers.dify_plugin.configs import ( + DIFY_PLUGIN_LAYER_TYPE_ID, + DIFY_PLUGIN_LLM_LAYER_TYPE_ID, + DifyPluginLLMLayerConfig, + DifyPluginLayerConfig, +) from dify_agent.layers.dify_plugin.llm_layer import DifyPluginLLMLayer from dify_agent.layers.dify_plugin.plugin_layer import DifyPluginLayer @@ -42,6 +47,11 @@ def _plugin_provider() -> LayerProvider[DifyPluginLayer]: ) +def test_dify_plugin_type_id_constants_match_implementation_classes() -> None: + assert DIFY_PLUGIN_LAYER_TYPE_ID == DifyPluginLayer.type_id + assert DIFY_PLUGIN_LLM_LAYER_TYPE_ID == DifyPluginLLMLayer.type_id + + def test_dify_plugin_layer_creates_daemon_provider_from_shared_http_client() -> None: async def scenario() -> None: plugin = _plugin_layer() diff --git a/dify-agent/tests/local/dify_agent/protocol/test_protocol_schemas.py b/dify-agent/tests/local/dify_agent/protocol/test_protocol_schemas.py index cd96f233da..a07352a3c2 100644 --- a/dify-agent/tests/local/dify_agent/protocol/test_protocol_schemas.py +++ b/dify-agent/tests/local/dify_agent/protocol/test_protocol_schemas.py @@ -4,8 +4,9 @@ from pydantic_ai.messages import FinalResultEvent from agenton.compositor import CompositorSessionSnapshot from agenton.layers import ExitIntent -from agenton_collections.layers.plain import PromptLayerConfig +from agenton_collections.layers.plain import PLAIN_PROMPT_LAYER_TYPE_ID, PromptLayerConfig import dify_agent.protocol as protocol_exports +from dify_agent.layers.dify_plugin import DIFY_PLUGIN_LAYER_TYPE_ID, DIFY_PLUGIN_LLM_LAYER_TYPE_ID from dify_agent.protocol import DIFY_AGENT_MODEL_LAYER_ID from dify_agent.protocol.schemas import ( RUN_EVENT_ADAPTER, @@ -80,11 +81,11 @@ def test_create_run_request_accepts_dto_first_public_composition_and_normalizes_ request = CreateRunRequest( composition=RunComposition( layers=[ - RunLayerSpec(name="prompt", type="plain.prompt", config=prompt_config), - RunLayerSpec(name="plugin", type="dify.plugin", config=plugin_config), + RunLayerSpec(name="prompt", type=PLAIN_PROMPT_LAYER_TYPE_ID, config=prompt_config), + RunLayerSpec(name="plugin", type=DIFY_PLUGIN_LAYER_TYPE_ID, config=plugin_config), RunLayerSpec( name=DIFY_AGENT_MODEL_LAYER_ID, - type="dify.plugin.llm", + type=DIFY_PLUGIN_LLM_LAYER_TYPE_ID, deps={"plugin": "plugin"}, config=llm_config, ), @@ -97,11 +98,11 @@ def test_create_run_request_accepts_dto_first_public_composition_and_normalizes_ assert payload["composition"]["layers"][0]["config"] == {"prefix": "system", "user": "hello", "suffix": []} assert [layer.model_dump(mode="json") for layer in graph_config.layers] == [ - {"name": "prompt", "type": "plain.prompt", "deps": {}, "metadata": {}}, - {"name": "plugin", "type": "dify.plugin", "deps": {}, "metadata": {}}, + {"name": "prompt", "type": PLAIN_PROMPT_LAYER_TYPE_ID, "deps": {}, "metadata": {}}, + {"name": "plugin", "type": DIFY_PLUGIN_LAYER_TYPE_ID, "deps": {}, "metadata": {}}, { "name": DIFY_AGENT_MODEL_LAYER_ID, - "type": "dify.plugin.llm", + "type": DIFY_PLUGIN_LLM_LAYER_TYPE_ID, "deps": {"plugin": "plugin"}, "metadata": {}, }, diff --git a/dify-agent/tests/local/dify_agent/test_import_boundaries.py b/dify-agent/tests/local/dify_agent/test_import_boundaries.py new file mode 100644 index 0000000000..d7a86a524e --- /dev/null +++ b/dify-agent/tests/local/dify_agent/test_import_boundaries.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +import os +import subprocess +import sys +from pathlib import Path + + +PROJECT_ROOT = Path(__file__).resolve().parents[3] + + +def _run_import_check(*, blocked_imports: list[str], imports: list[str], assertions: list[str]) -> None: + python_path = os.pathsep.join([str(PROJECT_ROOT / "src"), os.environ.get("PYTHONPATH", "")]) + module_aliases = {module_name: module_name.replace(".", "_") for module_name in imports} + script = "\n".join( + [ + "import builtins", + "import importlib", + f"blocked_imports = {blocked_imports!r}", + f"imports = {imports!r}", + f"module_aliases = {module_aliases!r}", + f"assertions = {assertions!r}", + "original_import = builtins.__import__", + "def guarded_import(name, globals=None, locals=None, fromlist=(), level=0):", + " for blocked in blocked_imports:", + " if name == blocked or name.startswith(f'{blocked}.'):", + " raise ModuleNotFoundError(f'blocked import: {name}')", + " return original_import(name, globals, locals, fromlist, level)", + "builtins.__import__ = guarded_import", + "namespace = {}", + "for module_name in imports:", + " namespace[module_aliases[module_name]] = importlib.import_module(module_name)", + "for statement in assertions:", + " exec(statement, namespace)", + ] + ) + env = os.environ.copy() + env["PYTHONPATH"] = python_path + + result = subprocess.run( + [sys.executable, "-c", script], + cwd=PROJECT_ROOT, + env=env, + text=True, + capture_output=True, + check=False, + ) + + assert result.returncode == 0, result.stderr + + +def test_dify_agent_root_import_is_client_safe() -> None: + _run_import_check( + blocked_imports=[ + "anthropic", + "dify_agent.adapters.llm", + "dify_agent.runtime", + "dify_agent.server", + "fastapi", + "google", + "graphon", + "openai", + "pydantic_settings", + "redis", + ], + imports=["dify_agent"], + assertions=[ + "from dify_agent import Client", + "assert dify_agent.__all__ == ['Client']", + "assert dify_agent.Client is Client", + "assert not hasattr(dify_agent, 'DifyLLMAdapterModel')", + "assert not hasattr(dify_agent, 'DifyPluginDaemonProvider')", + ], + ) + + +def test_protocol_and_dify_plugin_exports_do_not_import_server_only_modules() -> None: + _run_import_check( + blocked_imports=[ + "anthropic", + "dify_agent.adapters.llm", + "dify_agent.layers.dify_plugin.llm_layer", + "dify_agent.layers.dify_plugin.plugin_layer", + "dify_agent.runtime", + "dify_agent.server", + "fastapi", + "google", + "graphon", + "openai", + "pydantic_settings", + "redis", + ], + imports=["dify_agent.protocol", "dify_agent.layers.dify_plugin"], + assertions=[ + "assert hasattr(dify_agent_protocol, 'PydanticAIStreamRunEvent')", + "assert dify_agent_layers_dify_plugin.__all__ == ['DIFY_PLUGIN_LAYER_TYPE_ID', 'DIFY_PLUGIN_LLM_LAYER_TYPE_ID', 'DifyPluginCredentialValue', 'DifyPluginLLMLayerConfig', 'DifyPluginLayerConfig']", + ], + ) + + +def test_agenton_collection_roots_do_not_eagerly_import_pydantic_ai_implementations() -> None: + _run_import_check( + blocked_imports=[ + "agenton_collections.layers.pydantic_ai", + "agenton_collections.transformers.pydantic_ai", + ], + imports=["agenton_collections", "agenton_collections.transformers"], + assertions=[ + "assert 'PydanticAIBridgeLayer' not in agenton_collections.__all__", + "assert agenton_collections_transformers.__all__ == []", + ], + ) diff --git a/dify-agent/tests/local/examples/test_dify_agent_examples.py b/dify-agent/tests/local/examples/test_dify_agent_examples.py index 5b4cd3d9b9..d0530181c7 100644 --- a/dify-agent/tests/local/examples/test_dify_agent_examples.py +++ b/dify-agent/tests/local/examples/test_dify_agent_examples.py @@ -1,9 +1,17 @@ from __future__ import annotations import importlib +from pathlib import Path + +import pytest -def test_dify_agent_examples_are_importable() -> None: +PROJECT_ROOT = Path(__file__).resolve().parents[3] + + +def test_dify_agent_examples_are_importable_from_repo_checkout(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.syspath_prepend(str(PROJECT_ROOT / "examples" / "dify_agent")) + for module_name in [ "dify_agent_examples.run_pydantic_ai_agent", "dify_agent_examples.run_server_consumer", diff --git a/dify-agent/tests/local/test_packaging.py b/dify-agent/tests/local/test_packaging.py new file mode 100644 index 0000000000..babf9e7ef5 --- /dev/null +++ b/dify-agent/tests/local/test_packaging.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +import tomllib +from pathlib import Path + + +PROJECT_ROOT = Path(__file__).resolve().parents[2] + +CLIENT_SHARED_DTO_DEPENDENCIES = { + "httpx>=0.28.1", + "pydantic>=2.13.3", + "pydantic-ai-slim>=1.85.1", + "typing-extensions>=4.12.2", +} + +SERVER_RUNTIME_DEPENDENCIES = { + "fastapi>=0.136.0", + "graphon~=0.2.2", + "pydantic-ai-slim[anthropic,google,openai]>=1.85.1", + "pydantic-settings>=2.12.0", + "redis>=5", + "uvicorn[standard]>=0.38.0", +} + + +def _read_pyproject() -> dict[str, object]: + return tomllib.loads((PROJECT_ROOT / "pyproject.toml").read_text(encoding="utf-8")) + + +def test_project_dependencies_split_client_and_server_requirements() -> None: + pyproject = _read_pyproject() + project = pyproject["project"] + + assert set(project["dependencies"]) == CLIENT_SHARED_DTO_DEPENDENCIES + assert set(project["optional-dependencies"]["server"]) == SERVER_RUNTIME_DEPENDENCIES + + +def test_default_package_discovery_excludes_example_packages() -> None: + pyproject = _read_pyproject() + find_config = pyproject["tool"]["setuptools"]["packages"]["find"] + + assert find_config["where"] == ["src"] + assert "agenton_examples*" not in find_config["include"] + assert "dify_agent_examples*" not in find_config["include"] diff --git a/dify-agent/uv.lock b/dify-agent/uv.lock index 983ca72035..b1da1a3547 100644 --- a/dify-agent/uv.lock +++ b/dify-agent/uv.lock @@ -575,18 +575,20 @@ name = "dify-agent" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "anyio" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "pydantic-ai-slim" }, + { name = "typing-extensions" }, +] + +[package.optional-dependencies] +server = [ { name = "fastapi" }, { name = "graphon" }, - { name = "httpx" }, - { name = "logfire" }, - { name = "pydantic" }, { name = "pydantic-ai-slim", extra = ["anthropic", "google", "openai"] }, { name = "pydantic-settings" }, { name = "redis" }, - { name = "sqlmodel" }, { name = "uvicorn", extra = ["standard"] }, - { name = "uvloop" }, ] [package.dev-dependencies] @@ -607,19 +609,18 @@ docs = [ [package.metadata] requires-dist = [ - { name = "anyio", specifier = ">=4.13.0" }, - { name = "fastapi", specifier = ">=0.136.0" }, - { name = "graphon", specifier = "~=0.2.2" }, + { name = "fastapi", marker = "extra == 'server'", specifier = ">=0.136.0" }, + { name = "graphon", marker = "extra == 'server'", specifier = "~=0.2.2" }, { name = "httpx", specifier = ">=0.28.1" }, - { name = "logfire", specifier = ">=4.32.1" }, { name = "pydantic", specifier = ">=2.13.3" }, - { name = "pydantic-ai-slim", extras = ["anthropic", "google", "openai"], specifier = ">=1.85.1" }, - { name = "pydantic-settings", specifier = ">=2.12.0" }, - { name = "redis", specifier = ">=5" }, - { name = "sqlmodel", specifier = ">=0.0.38" }, - { name = "uvicorn", extras = ["standard"], specifier = ">=0.38.0" }, - { name = "uvloop", specifier = ">=0.22.1" }, + { name = "pydantic-ai-slim", specifier = ">=1.85.1" }, + { name = "pydantic-ai-slim", extras = ["anthropic", "google", "openai"], marker = "extra == 'server'", specifier = ">=1.85.1" }, + { name = "pydantic-settings", marker = "extra == 'server'", specifier = ">=2.12.0" }, + { name = "redis", marker = "extra == 'server'", specifier = ">=5" }, + { name = "typing-extensions", specifier = ">=4.12.2" }, + { name = "uvicorn", extras = ["standard"], marker = "extra == 'server'", specifier = ">=0.38.0" }, ] +provides-extras = ["server"] [package.metadata.requires-dev] dev = [ @@ -673,15 +674,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, ] -[[package]] -name = "executing" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, -] - [[package]] name = "fastapi" version = "0.136.0" @@ -789,18 +781,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/65/af/508e0528015240d710c6763f7c89ff44fab9a94a80b4377e265d692cbfd6/google_genai-1.73.1-py3-none-any.whl", hash = "sha256:af2d2287d25e42a187de19811ef33beb2e347c7e2bdb4dc8c467d78254e43a2c", size = 783595, upload-time = "2026-04-14T21:06:17.464Z" }, ] -[[package]] -name = "googleapis-common-protos" -version = "1.74.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/b0/be5d3329badb9230b765de6eea66b73abd5944bdeb5afb3562ddcd80ae84/googleapis_common_protos-1.74.0-py3-none-any.whl", hash = "sha256:702216f78610bb510e3f12ac3cafd281b7ac45cc5d86e90ad87e4d301a3426b5", size = 300743, upload-time = "2026-04-02T21:22:49.108Z" }, -] - [[package]] name = "graphon" version = "0.2.2" @@ -829,45 +809,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/89/a6340afdaf5169d17a318e00fc685fb67ed99baa602c2cbbbf6af6a76096/graphon-0.2.2-py3-none-any.whl", hash = "sha256:754e544d08779138f99eac6547ab08559463680e2c76488b05e1c978210392b4", size = 340808, upload-time = "2026-04-17T08:52:26.5Z" }, ] -[[package]] -name = "greenlet" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/94/a5935717b307d7c71fe877b52b884c6af707d2d2090db118a03fbd799369/greenlet-3.4.0.tar.gz", hash = "sha256:f50a96b64dafd6169e595a5c56c9146ef80333e67d4476a65a9c55f400fc22ff", size = 195913, upload-time = "2026-04-08T17:08:00.863Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/8b/3669ad3b3f247a791b2b4aceb3aa5a31f5f6817bf547e4e1ff712338145a/greenlet-3.4.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:1a54a921561dd9518d31d2d3db4d7f80e589083063ab4d3e2e950756ef809e1a", size = 286902, upload-time = "2026-04-08T15:52:12.138Z" }, - { url = "https://files.pythonhosted.org/packages/38/3e/3c0e19b82900873e2d8469b590a6c4b3dfd2b316d0591f1c26b38a4879a5/greenlet-3.4.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16dec271460a9a2b154e3b1c2fa1050ce6280878430320e85e08c166772e3f97", size = 606099, upload-time = "2026-04-08T16:24:38.408Z" }, - { url = "https://files.pythonhosted.org/packages/b5/33/99fef65e7754fc76a4ed14794074c38c9ed3394a5bd129d7f61b705f3168/greenlet-3.4.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90036ce224ed6fe75508c1907a77e4540176dcf0744473627785dd519c6f9996", size = 618837, upload-time = "2026-04-08T16:30:58.298Z" }, - { url = "https://files.pythonhosted.org/packages/36/f7/229f3aed6948faa20e0616a0b8568da22e365ede6a54d7d369058b128afd/greenlet-3.4.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1c4f6b453006efb8310affb2d132832e9bbb4fc01ce6df6b70d810d38f1f6dc", size = 615062, upload-time = "2026-04-08T15:56:33.766Z" }, - { url = "https://files.pythonhosted.org/packages/08/97/d988180011aa40135c46cd0d0cf01dd97f7162bae14139b4a3ef54889ba5/greenlet-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b2d9a138ffa0e306d0e2b72976d2fb10b97e690d40ab36a472acaab0838e2de", size = 1573511, upload-time = "2026-04-08T16:26:20.058Z" }, - { url = "https://files.pythonhosted.org/packages/d4/0f/a5a26fe152fb3d12e6a474181f6e9848283504d0afd095f353d85726374b/greenlet-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8424683caf46eb0eb6f626cb95e008e8cc30d0cb675bdfa48200925c79b38a08", size = 1640396, upload-time = "2026-04-08T15:57:30.88Z" }, - { url = "https://files.pythonhosted.org/packages/42/cf/bb2c32d9a100e36ee9f6e38fad6b1e082b8184010cb06259b49e1266ca01/greenlet-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0a53fb071531d003b075c444014ff8f8b1a9898d36bb88abd9ac7b3524648a2", size = 238892, upload-time = "2026-04-08T17:03:10.094Z" }, - { url = "https://files.pythonhosted.org/packages/b7/47/6c41314bac56e71436ce551c7fbe3cc830ed857e6aa9708dbb9c65142eb6/greenlet-3.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:f38b81880ba28f232f1f675893a39cf7b6db25b31cc0a09bb50787ecf957e85e", size = 235599, upload-time = "2026-04-08T15:52:54.3Z" }, - { url = "https://files.pythonhosted.org/packages/7a/75/7e9cd1126a1e1f0cd67b0eda02e5221b28488d352684704a78ed505bd719/greenlet-3.4.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:43748988b097f9c6f09364f260741aa73c80747f63389824435c7a50bfdfd5c1", size = 285856, upload-time = "2026-04-08T15:52:45.82Z" }, - { url = "https://files.pythonhosted.org/packages/9d/c4/3e2df392e5cb199527c4d9dbcaa75c14edcc394b45040f0189f649631e3c/greenlet-3.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5566e4e2cd7a880e8c27618e3eab20f3494452d12fd5129edef7b2f7aa9a36d1", size = 610208, upload-time = "2026-04-08T16:24:39.674Z" }, - { url = "https://files.pythonhosted.org/packages/da/af/750cdfda1d1bd30a6c28080245be8d0346e669a98fdbae7f4102aa95fff3/greenlet-3.4.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1054c5a3c78e2ab599d452f23f7adafef55062a783a8e241d24f3b633ba6ff82", size = 621269, upload-time = "2026-04-08T16:30:59.767Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/0cbc693622cd54ebe25207efbb3a0eb07c2639cb8594f6e3aaaa0bb077a8/greenlet-3.4.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f82cb6cddc27dd81c96b1506f4aa7def15070c3b2a67d4e46fd19016aacce6cf", size = 617549, upload-time = "2026-04-08T15:56:34.893Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c0/8966767de01343c1ff47e8b855dc78e7d1a8ed2b7b9c83576a57e289f81d/greenlet-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:227a46251ecba4ff46ae742bc5ce95c91d5aceb4b02f885487aff269c127a729", size = 1575310, upload-time = "2026-04-08T16:26:21.671Z" }, - { url = "https://files.pythonhosted.org/packages/b8/38/bcdc71ba05e9a5fda87f63ffc2abcd1f15693b659346df994a48c968003d/greenlet-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b99e87be7eba788dd5b75ba1cde5639edffdec5f91fe0d734a249535ec3408c", size = 1640435, upload-time = "2026-04-08T15:57:32.572Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c2/19b664b7173b9e4ef5f77e8cef9f14c20ec7fce7920dc1ccd7afd955d093/greenlet-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:849f8bc17acd6295fcb5de8e46d55cc0e52381c56eaf50a2afd258e97bc65940", size = 238760, upload-time = "2026-04-08T17:04:03.878Z" }, - { url = "https://files.pythonhosted.org/packages/9b/96/795619651d39c7fbd809a522f881aa6f0ead504cc8201c3a5b789dfaef99/greenlet-3.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9390ad88b652b1903814eaabd629ca184db15e0eeb6fe8a390bbf8b9106ae15a", size = 235498, upload-time = "2026-04-08T17:05:00.584Z" }, - { url = "https://files.pythonhosted.org/packages/78/02/bde66806e8f169cf90b14d02c500c44cdbe02c8e224c9c67bafd1b8cadd1/greenlet-3.4.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:10a07aca6babdd18c16a3f4f8880acfffc2b88dfe431ad6aa5f5740759d7d75e", size = 286291, upload-time = "2026-04-08T17:09:34.307Z" }, - { url = "https://files.pythonhosted.org/packages/05/1f/39da1c336a87d47c58352fb8a78541ce63d63ae57c5b9dae1fe02801bbc2/greenlet-3.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:076e21040b3a917d3ce4ad68fb5c3c6b32f1405616c4a57aa83120979649bd3d", size = 656749, upload-time = "2026-04-08T16:24:41.721Z" }, - { url = "https://files.pythonhosted.org/packages/d3/6c/90ee29a4ee27af7aa2e2ec408799eeb69ee3fcc5abcecac6ddd07a5cd0f2/greenlet-3.4.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e82689eea4a237e530bb5cb41b180ef81fa2160e1f89422a67be7d90da67f615", size = 669084, upload-time = "2026-04-08T16:31:01.372Z" }, - { url = "https://files.pythonhosted.org/packages/07/49/d4cad6e5381a50947bb973d2f6cf6592621451b09368b8c20d9b8af49c5b/greenlet-3.4.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4df3b0b2289ec686d3c821a5fee44259c05cfe824dd5e6e12c8e5f5df23085cf", size = 665621, upload-time = "2026-04-08T15:56:35.995Z" }, - { url = "https://files.pythonhosted.org/packages/37/31/d1edd54f424761b5d47718822f506b435b6aab2f3f93b465441143ea5119/greenlet-3.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8bff29d586ea415688f4cec96a591fcc3bf762d046a796cdadc1fdb6e7f2d5bf", size = 1622259, upload-time = "2026-04-08T16:26:23.201Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c6/6d3f9cdcb21c4e12a79cb332579f1c6aa1af78eb68059c5a957c7812d95e/greenlet-3.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a569c2fb840c53c13a2b8967c63621fafbd1a0e015b9c82f408c33d626a2fda", size = 1686916, upload-time = "2026-04-08T15:57:34.282Z" }, - { url = "https://files.pythonhosted.org/packages/63/45/c1ca4a1ad975de4727e52d3ffe641ae23e1d7a8ffaa8ff7a0477e1827b92/greenlet-3.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:207ba5b97ea8b0b60eb43ffcacf26969dd83726095161d676aac03ff913ee50d", size = 239821, upload-time = "2026-04-08T17:03:48.423Z" }, - { url = "https://files.pythonhosted.org/packages/71/c4/6f621023364d7e85a4769c014c8982f98053246d142420e0328980933ceb/greenlet-3.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:f8296d4e2b92af34ebde81085a01690f26a51eb9ac09a0fcadb331eb36dbc802", size = 236932, upload-time = "2026-04-08T17:04:33.551Z" }, - { url = "https://files.pythonhosted.org/packages/d4/8f/18d72b629783f5e8d045a76f5325c1e938e659a9e4da79c7dcd10169a48d/greenlet-3.4.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d70012e51df2dbbccfaf63a40aaf9b40c8bed37c3e3a38751c926301ce538ece", size = 294681, upload-time = "2026-04-08T15:52:35.778Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ad/5fa86ec46769c4153820d58a04062285b3b9e10ba3d461ee257b68dcbf53/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a58bec0751f43068cd40cff31bb3ca02ad6000b3a51ca81367af4eb5abc480c8", size = 658899, upload-time = "2026-04-08T16:24:43.32Z" }, - { url = "https://files.pythonhosted.org/packages/43/f0/4e8174ca0e87ae748c409f055a1ba161038c43cc0a5a6f1433a26ac2e5bf/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05fa0803561028f4b2e3b490ee41216a842eaee11aed004cc343a996d9523aa2", size = 665284, upload-time = "2026-04-08T16:31:02.833Z" }, - { url = "https://files.pythonhosted.org/packages/19/da/991cf7cd33662e2df92a1274b7eb4d61769294d38a1bba8a45f31364845e/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e60d38719cb80b3ab5e85f9f1aed4960acfde09868af6762ccb27b260d68f4ed", size = 661861, upload-time = "2026-04-08T15:56:37.269Z" }, - { url = "https://files.pythonhosted.org/packages/36/c5/6c2c708e14db3d9caea4b459d8464f58c32047451142fe2cfd90e7458f41/greenlet-3.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f50c804733b43eded05ae694691c9aa68bca7d0a867d67d4a3f514742a2d53f", size = 1622182, upload-time = "2026-04-08T16:26:24.777Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4c/50c5fed19378e11a29fabab1f6be39ea95358f4a0a07e115a51ca93385d8/greenlet-3.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2d4f0635dc4aa638cda4b2f5a07ae9a2cff9280327b581a3fcb6f317b4fbc38a", size = 1685050, upload-time = "2026-04-08T15:57:36.453Z" }, - { url = "https://files.pythonhosted.org/packages/db/72/85ae954d734703ab48e622c59d4ce35d77ce840c265814af9c078cacc7aa/greenlet-3.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1a4a48f24681300c640f143ba7c404270e1ebbbcf34331d7104a4ff40f8ea705", size = 245554, upload-time = "2026-04-08T17:03:50.044Z" }, -] - [[package]] name = "griffelib" version = "2.0.2" @@ -1200,24 +1141,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/79/d3bbab197e86e0ff4f9c07122895b66a3e0d024247fcff7f12c473cb36d9/llvmlite-0.47.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6842cf6f707ec4be3d985a385ad03f72b2d724439e118fcbe99b2929964f0453", size = 39153839, upload-time = "2026-03-31T18:29:51.004Z" }, ] -[[package]] -name = "logfire" -version = "4.32.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "executing" }, - { name = "opentelemetry-exporter-otlp-proto-http" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-sdk" }, - { name = "protobuf" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/d7/70c6def7f3f459b2d57aa7fb37863d31b8d877e391547f200ee8c31d2e30/logfire-4.32.1.tar.gz", hash = "sha256:8e7ff418b5f2629c8a8e9426283ff82c760a30f24516c4c389d6cbb1d9768c58", size = 1089612, upload-time = "2026-04-15T14:11:57.518Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/77/70f6d97d7d74d2f2eeb695fe491b28906ae5c350b48516bb237ace9a1778/logfire-4.32.1-py3-none-any.whl", hash = "sha256:cb7873efec0e94a3de6e603539daaa6509a454599621c80dd227fbfa0ade37d4", size = 313021, upload-time = "2026-04-15T14:11:54.024Z" }, -] - [[package]] name = "logfire-api" version = "4.32.1" @@ -1759,90 +1682,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, ] -[[package]] -name = "opentelemetry-exporter-otlp-proto-common" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-proto" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde", size = 18366, upload-time = "2025-12-11T13:32:20.2Z" }, -] - -[[package]] -name = "opentelemetry-exporter-otlp-proto-http" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-exporter-otlp-proto-common" }, - { name = "opentelemetry-proto" }, - { name = "opentelemetry-sdk" }, - { name = "requests" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641, upload-time = "2025-12-11T13:32:22.248Z" }, -] - -[[package]] -name = "opentelemetry-instrumentation" -version = "0.60b1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "packaging" }, - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, -] - -[[package]] -name = "opentelemetry-proto" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, -] - -[[package]] -name = "opentelemetry-sdk" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.60b1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, -] - [[package]] name = "orjson" version = "3.11.8" @@ -2116,21 +1955,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/80/368139067603e590a000122355f9c8576c8ebed4fb0b8849feaa2698489d/preshed-3.0.13-cp314-cp314t-win_arm64.whl", hash = "sha256:b980f3ea9bb74b7f94464bc3d6eb3c9162b6b79b531febd14c6465c24344d2cc", size = 119339, upload-time = "2026-03-23T08:57:18.882Z" }, ] -[[package]] -name = "protobuf" -version = "6.33.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, - { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, - { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, - { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, - { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, - { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, -] - [[package]] name = "psutil" version = "7.2.2" @@ -3233,66 +3057,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/78/d1a1a026ef3af911159398c939b1509d5c36fe524c7b644f34a5146c4e16/spacy_loggers-1.0.5-py3-none-any.whl", hash = "sha256:196284c9c446cc0cdb944005384270d775fdeaf4f494d8e269466cfa497ef645", size = 22343, upload-time = "2023-09-11T12:26:50.586Z" }, ] -[[package]] -name = "sqlalchemy" -version = "2.0.49" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/b3/2de412451330756aaaa72d27131db6dde23995efe62c941184e15242a5fa/sqlalchemy-2.0.49-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4bbccb45260e4ff1b7db0be80a9025bb1e6698bdb808b83fff0000f7a90b2c0b", size = 2157681, upload-time = "2026-04-03T16:53:07.132Z" }, - { url = "https://files.pythonhosted.org/packages/50/84/b2a56e2105bd11ebf9f0b93abddd748e1a78d592819099359aa98134a8bf/sqlalchemy-2.0.49-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb37f15714ec2652d574f021d479e78cd4eb9d04396dca36568fdfffb3487982", size = 3338976, upload-time = "2026-04-03T17:07:40Z" }, - { url = "https://files.pythonhosted.org/packages/2c/fa/65fcae2ed62f84ab72cf89536c7c3217a156e71a2c111b1305ab6f0690e2/sqlalchemy-2.0.49-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb9ec6436a820a4c006aad1ac351f12de2f2dbdaad171692ee457a02429b672", size = 3351937, upload-time = "2026-04-03T17:12:23.374Z" }, - { url = "https://files.pythonhosted.org/packages/f8/2f/6fd118563572a7fe475925742eb6b3443b2250e346a0cc27d8d408e73773/sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8d6efc136f44a7e8bc8088507eaabbb8c2b55b3dbb63fe102c690da0ddebe55e", size = 3281646, upload-time = "2026-04-03T17:07:41.949Z" }, - { url = "https://files.pythonhosted.org/packages/c5/d7/410f4a007c65275b9cf82354adb4bb8ba587b176d0a6ee99caa16fe638f8/sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e06e617e3d4fd9e51d385dfe45b077a41e9d1b033a7702551e3278ac597dc750", size = 3316695, upload-time = "2026-04-03T17:12:25.642Z" }, - { url = "https://files.pythonhosted.org/packages/d9/95/81f594aa60ded13273a844539041ccf1e66c5a7bed0a8e27810a3b52d522/sqlalchemy-2.0.49-cp312-cp312-win32.whl", hash = "sha256:83101a6930332b87653886c01d1ee7e294b1fe46a07dd9a2d2b4f91bcc88eec0", size = 2117483, upload-time = "2026-04-03T17:05:40.896Z" }, - { url = "https://files.pythonhosted.org/packages/47/9e/fd90114059175cac64e4fafa9bf3ac20584384d66de40793ae2e2f26f3bb/sqlalchemy-2.0.49-cp312-cp312-win_amd64.whl", hash = "sha256:618a308215b6cececb6240b9abde545e3acdabac7ae3e1d4e666896bf5ba44b4", size = 2144494, upload-time = "2026-04-03T17:05:42.282Z" }, - { url = "https://files.pythonhosted.org/packages/ae/81/81755f50eb2478eaf2049728491d4ea4f416c1eb013338682173259efa09/sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120", size = 2154547, upload-time = "2026-04-03T16:53:08.64Z" }, - { url = "https://files.pythonhosted.org/packages/a2/bc/3494270da80811d08bcfa247404292428c4fe16294932bce5593f215cad9/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2", size = 3280782, upload-time = "2026-04-03T17:07:43.508Z" }, - { url = "https://files.pythonhosted.org/packages/cd/f5/038741f5e747a5f6ea3e72487211579d8cbea5eb9827a9cbd61d0108c4bd/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3", size = 3297156, upload-time = "2026-04-03T17:12:27.697Z" }, - { url = "https://files.pythonhosted.org/packages/88/50/a6af0ff9dc954b43a65ca9b5367334e45d99684c90a3d3413fc19a02d43c/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7", size = 3228832, upload-time = "2026-04-03T17:07:45.38Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d1/5f6bdad8de0bf546fc74370939621396515e0cdb9067402d6ba1b8afbe9a/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33", size = 3267000, upload-time = "2026-04-03T17:12:29.657Z" }, - { url = "https://files.pythonhosted.org/packages/f7/30/ad62227b4a9819a5e1c6abff77c0f614fa7c9326e5a3bdbee90f7139382b/sqlalchemy-2.0.49-cp313-cp313-win32.whl", hash = "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b", size = 2115641, upload-time = "2026-04-03T17:05:43.989Z" }, - { url = "https://files.pythonhosted.org/packages/17/3a/7215b1b7d6d49dc9a87211be44562077f5f04f9bb5a59552c1c8e2d98173/sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl", hash = "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148", size = 2141498, upload-time = "2026-04-03T17:05:45.7Z" }, - { url = "https://files.pythonhosted.org/packages/28/4b/52a0cb2687a9cd1648252bb257be5a1ba2c2ded20ba695c65756a55a15a4/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518", size = 3560807, upload-time = "2026-04-03T16:58:31.666Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d8/fda95459204877eed0458550d6c7c64c98cc50c2d8d618026737de9ed41a/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d", size = 3527481, upload-time = "2026-04-03T17:06:00.155Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0a/2aac8b78ac6487240cf7afef8f203ca783e8796002dc0cf65c4ee99ff8bb/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0", size = 3468565, upload-time = "2026-04-03T16:58:33.414Z" }, - { url = "https://files.pythonhosted.org/packages/a5/3d/ce71cfa82c50a373fd2148b3c870be05027155ce791dc9a5dcf439790b8b/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08", size = 3477769, upload-time = "2026-04-03T17:06:02.787Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e8/0a9f5c1f7c6f9ca480319bf57c2d7423f08d31445974167a27d14483c948/sqlalchemy-2.0.49-cp313-cp313t-win32.whl", hash = "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d", size = 2143319, upload-time = "2026-04-03T17:02:04.328Z" }, - { url = "https://files.pythonhosted.org/packages/0e/51/fb5240729fbec73006e137c4f7a7918ffd583ab08921e6ff81a999d6517a/sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl", hash = "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba", size = 2175104, upload-time = "2026-04-03T17:02:05.989Z" }, - { url = "https://files.pythonhosted.org/packages/55/33/bf28f618c0a9597d14e0b9ee7d1e0622faff738d44fe986ee287cdf1b8d0/sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e", size = 2156356, upload-time = "2026-04-03T16:53:09.914Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a7/5f476227576cb8644650eff68cc35fa837d3802b997465c96b8340ced1e2/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a", size = 3276486, upload-time = "2026-04-03T17:07:46.9Z" }, - { url = "https://files.pythonhosted.org/packages/2e/84/efc7c0bf3a1c5eef81d397f6fddac855becdbb11cb38ff957888603014a7/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066", size = 3281479, upload-time = "2026-04-03T17:12:32.226Z" }, - { url = "https://files.pythonhosted.org/packages/91/68/bb406fa4257099c67bd75f3f2261b129c63204b9155de0d450b37f004698/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187", size = 3226269, upload-time = "2026-04-03T17:07:48.678Z" }, - { url = "https://files.pythonhosted.org/packages/67/84/acb56c00cca9f251f437cb49e718e14f7687505749ea9255d7bd8158a6df/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401", size = 3248260, upload-time = "2026-04-03T17:12:34.381Z" }, - { url = "https://files.pythonhosted.org/packages/56/19/6a20ea25606d1efd7bd1862149bb2a22d1451c3f851d23d887969201633f/sqlalchemy-2.0.49-cp314-cp314-win32.whl", hash = "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5", size = 2118463, upload-time = "2026-04-03T17:05:47.093Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4f/8297e4ed88e80baa1f5aa3c484a0ee29ef3c69c7582f206c916973b75057/sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl", hash = "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5", size = 2144204, upload-time = "2026-04-03T17:05:48.694Z" }, - { url = "https://files.pythonhosted.org/packages/1f/33/95e7216df810c706e0cd3655a778604bbd319ed4f43333127d465a46862d/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977", size = 3565474, upload-time = "2026-04-03T16:58:35.128Z" }, - { url = "https://files.pythonhosted.org/packages/0c/a4/ed7b18d8ccf7f954a83af6bb73866f5bc6f5636f44c7731fbb741f72cc4f/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01", size = 3530567, upload-time = "2026-04-03T17:06:04.587Z" }, - { url = "https://files.pythonhosted.org/packages/73/a3/20faa869c7e21a827c4a2a42b41353a54b0f9f5e96df5087629c306df71e/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61", size = 3474282, upload-time = "2026-04-03T16:58:37.131Z" }, - { url = "https://files.pythonhosted.org/packages/b7/50/276b9a007aa0764304ad467eceb70b04822dc32092492ee5f322d559a4dc/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a", size = 3480406, upload-time = "2026-04-03T17:06:07.176Z" }, - { url = "https://files.pythonhosted.org/packages/e5/c3/c80fcdb41905a2df650c2a3e0337198b6848876e63d66fe9188ef9003d24/sqlalchemy-2.0.49-cp314-cp314t-win32.whl", hash = "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158", size = 2149151, upload-time = "2026-04-03T17:02:07.281Z" }, - { url = "https://files.pythonhosted.org/packages/05/52/9f1a62feab6ed368aff068524ff414f26a6daebc7361861035ae00b05530/sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl", hash = "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7", size = 2184178, upload-time = "2026-04-03T17:02:08.623Z" }, - { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, -] - -[[package]] -name = "sqlmodel" -version = "0.0.38" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "sqlalchemy" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/0d/26ec1329960ea9430131fe63f63a95ea4cb8971d49c891ff7e1f3255421c/sqlmodel-0.0.38.tar.gz", hash = "sha256:d583ec237b14103809f74e8630032bc40ab68cd6b754a610f0813c56911a547b", size = 86710, upload-time = "2026-04-02T21:03:55.571Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/c7/10c60af0607ab6fa136264f7f39d205932218516226d38585324ffda705d/sqlmodel-0.0.38-py3-none-any.whl", hash = "sha256:84e3fa990a77395461ded72a6c73173438ce8449d5c1c4d97fbff1b1df692649", size = 27294, upload-time = "2026-04-02T21:03:56.406Z" }, -] - [[package]] name = "srsly" version = "2.5.3"