mirror of
https://github.com/run-llama/workflows-py.git
synced 2026-08-24 20:01:34 -04:00
add ty check (#205)
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"llama-index-utils-workflow": patch
|
||||
"llama-index-workflows": patch
|
||||
---
|
||||
|
||||
Update typechecking to support ty
|
||||
@@ -23,6 +23,13 @@ repos:
|
||||
- id: ruff-check
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: ty
|
||||
name: ty
|
||||
language: system
|
||||
entry: uv run ty check packages
|
||||
exclude: ^examples/|^docs/
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.15.0
|
||||
hooks:
|
||||
|
||||
@@ -501,7 +501,11 @@ def _process_tools_and_handoffs(
|
||||
if agent.name == root_agent:
|
||||
edges.append(DrawWorkflowEdge("user", root_agent))
|
||||
for t in agent.tools or []:
|
||||
fn_name = t.metadata.get_name() if isinstance(t, BaseTool) else t.__name__
|
||||
if isinstance(t, BaseTool):
|
||||
fn_name = t.metadata.get_name()
|
||||
else:
|
||||
# Fallback for non-BaseTool callables or objects without __name__
|
||||
fn_name = getattr(t, "__name__", type(t).__name__)
|
||||
node_id = f"{agent.name}_{fn_name}"
|
||||
nodes.append(
|
||||
DrawWorkflowNode(
|
||||
|
||||
@@ -215,13 +215,14 @@ class Context(Generic[MODEL_T]):
|
||||
# Initialize a runtime plugin (asyncio-based by default)
|
||||
runtime: WorkflowRuntime = plugin or self._plugin.new_runtime(str(uuid.uuid4()))
|
||||
# Initialize the new broker implementation (broker2)
|
||||
self._broker_run = WorkflowBroker(
|
||||
broker: WorkflowBroker[MODEL_T] = WorkflowBroker(
|
||||
workflow=workflow,
|
||||
context=self,
|
||||
context=cast("Context[MODEL_T]", self),
|
||||
runtime=runtime,
|
||||
plugin=self._plugin,
|
||||
)
|
||||
return self._broker_run
|
||||
self._broker_run = broker
|
||||
return broker
|
||||
|
||||
def _workflow_run(
|
||||
self,
|
||||
|
||||
@@ -31,7 +31,7 @@ class _Resource(Generic[T]):
|
||||
def __init__(self, factory: Callable[..., T | Awaitable[T]], cache: bool) -> None:
|
||||
self._factory = factory
|
||||
self._is_async = inspect.iscoroutinefunction(factory)
|
||||
self.name = factory.__qualname__
|
||||
self.name = getattr(factory, "__qualname__", type(factory).__name__)
|
||||
self.cache = cache
|
||||
|
||||
async def call(self) -> T:
|
||||
|
||||
@@ -9,16 +9,13 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import (
|
||||
AsyncGenerator,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Generic,
|
||||
Protocol,
|
||||
TYPE_CHECKING,
|
||||
cast,
|
||||
)
|
||||
|
||||
|
||||
from workflows.decorators import P, R
|
||||
from workflows.events import Event, StopEvent
|
||||
|
||||
from workflows.runtime.types.internal_state import BrokerState
|
||||
@@ -30,8 +27,8 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
@dataclass
|
||||
class RegisteredWorkflow(Generic[P, R]):
|
||||
workflow_function: Callable[P, R]
|
||||
class RegisteredWorkflow:
|
||||
workflow_function: ControlLoopFunction
|
||||
steps: dict[str, StepWorkerFunction]
|
||||
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class Returns(Generic[R]):
|
||||
step function has completed (including errors!)
|
||||
"""
|
||||
|
||||
return_values: list[StepFunctionResult[R, Any]]
|
||||
return_values: list[StepFunctionResult[R]]
|
||||
|
||||
|
||||
class WaitingForEvent(Exception, Generic[EventType]):
|
||||
@@ -177,6 +177,6 @@ StepFunctionResult = Union[
|
||||
StepWorkerFailed[R],
|
||||
AddCollectedEvent,
|
||||
DeleteCollectedEvent,
|
||||
AddWaiter[EventType],
|
||||
AddWaiter[Event],
|
||||
DeleteWaiter,
|
||||
]
|
||||
|
||||
@@ -40,7 +40,7 @@ class StepWorkerFunction(Protocol, Generic[R]):
|
||||
event: Event,
|
||||
context: Context, # TODO - pass an identifier and re-hydrate from the plugin for distributed step workers
|
||||
workflow: Workflow,
|
||||
) -> Awaitable[list[StepFunctionResult[R, Any]]]: ...
|
||||
) -> Awaitable[list[StepFunctionResult[R]]]: ...
|
||||
|
||||
|
||||
async def partial(
|
||||
@@ -81,7 +81,7 @@ def as_step_worker_function(func: Callable[P, Awaitable[R]]) -> StepWorkerFuncti
|
||||
event: Event,
|
||||
context: Context,
|
||||
workflow: Workflow,
|
||||
) -> list[StepFunctionResult[R, Any]]:
|
||||
) -> list[StepFunctionResult[R]]:
|
||||
returns = Returns[R](return_values=[])
|
||||
|
||||
token = StepWorkerStateContextVar.set(
|
||||
|
||||
@@ -17,7 +17,7 @@ events that can occur during workflow execution:
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Generic, Union
|
||||
from typing import Generic, Union
|
||||
|
||||
from workflows.events import Event
|
||||
from workflows.decorators import R
|
||||
@@ -31,7 +31,7 @@ class TickStepResult(Generic[R]):
|
||||
step_name: str
|
||||
worker_id: int
|
||||
event: Event
|
||||
result: list[StepFunctionResult[R, Any]]
|
||||
result: list[StepFunctionResult[R]]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -55,6 +55,9 @@ def run_server() -> None:
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# At this point, a WorkflowServer instance is guaranteed to exist
|
||||
assert server is not None
|
||||
|
||||
host = os.environ.get("WORKFLOWS_PY_SERVER_HOST", "0.0.0.0")
|
||||
port = int(os.environ.get("WORKFLOWS_PY_SERVER_PORT", 8080))
|
||||
uvicorn.run(server.app, host=host, port=port)
|
||||
|
||||
@@ -9,7 +9,7 @@ import json
|
||||
import logging
|
||||
from importlib.metadata import version
|
||||
from pathlib import Path
|
||||
from typing import Any, AsyncGenerator, Callable, Awaitable
|
||||
from typing import Any, AsyncGenerator, Callable, Awaitable, cast
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from llama_index_instrumentation.dispatcher import instrument_tags
|
||||
@@ -90,7 +90,7 @@ class WorkflowServer:
|
||||
|
||||
self._middleware = middleware or [
|
||||
Middleware(
|
||||
CORSMiddleware,
|
||||
CORSMiddleware, # type: ignore[arg-type]
|
||||
# regex echoes the origin header back, which some browsers require (rather than "*") when credentials are required
|
||||
allow_origin_regex=".*",
|
||||
allow_methods=["*"],
|
||||
@@ -1036,12 +1036,14 @@ class WorkflowServer:
|
||||
"cancelled",
|
||||
}
|
||||
|
||||
status_in = (
|
||||
list(set(allowed_status_values).intersection(status_values))
|
||||
status_in: list[Status] | None = (
|
||||
cast(
|
||||
list[Status],
|
||||
list(set(allowed_status_values).intersection(status_values)),
|
||||
)
|
||||
if status_values is not None
|
||||
else None
|
||||
)
|
||||
|
||||
persistent_handlers = await self._workflow_store.query(
|
||||
HandlerQuery(status_in=status_in, workflow_name_in=workflow_name_in)
|
||||
)
|
||||
|
||||
@@ -93,6 +93,9 @@ class Workflow(metaclass=WorkflowMeta):
|
||||
- [RetryPolicy][workflows.retry_policy.RetryPolicy]
|
||||
"""
|
||||
|
||||
# Populated by the metaclass; declared here for type checkers.
|
||||
_step_functions: dict[str, StepFunction]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
timeout: float | None = 45.0,
|
||||
|
||||
@@ -5,7 +5,7 @@ from httpx import ASGITransport, AsyncClient
|
||||
from workflows.protocol.serializable_events import EventEnvelopeWithMetadata
|
||||
from workflows.server.server import WorkflowServer
|
||||
from workflows.client import WorkflowClient
|
||||
from .client_workflows import (
|
||||
from .client_workflows import ( # type: ignore[import]
|
||||
greeting_wf,
|
||||
crashing_wf,
|
||||
InputEvent,
|
||||
|
||||
@@ -31,7 +31,11 @@ from workflows.events import (
|
||||
from workflows.testing import WorkflowTestRunner
|
||||
from workflows.workflow import Workflow
|
||||
|
||||
from ..conftest import AnotherTestEvent, LastEvent, OneTestEvent
|
||||
from ..conftest import ( # type: ignore[import]
|
||||
AnotherTestEvent,
|
||||
LastEvent,
|
||||
OneTestEvent,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -36,7 +36,7 @@ from workflows.runtime.workflow_registry import workflow_registry
|
||||
from workflows.runtime.types.ticks import TickAddEvent, TickCancelRun
|
||||
from workflows.retry_policy import ConstantDelayRetryPolicy
|
||||
|
||||
from .conftest import MockRuntimePlugin
|
||||
from .conftest import MockRuntimePlugin # type: ignore[import]
|
||||
|
||||
|
||||
class IntermediateEvent(Event):
|
||||
|
||||
@@ -17,6 +17,7 @@ def test_no_file_path_argument(capsys: Any) -> None:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_server()
|
||||
|
||||
assert isinstance(exc_info.value, SystemExit)
|
||||
assert exc_info.value.code == 1
|
||||
captured = capsys.readouterr()
|
||||
assert (
|
||||
@@ -30,6 +31,7 @@ def test_nonexistent_file(capsys: Any) -> None:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_server()
|
||||
|
||||
assert isinstance(exc_info.value, SystemExit)
|
||||
assert exc_info.value.code == 1
|
||||
captured = capsys.readouterr()
|
||||
assert "Error: File '/nonexistent/file.py' not found" in captured.err
|
||||
@@ -44,6 +46,7 @@ def test_directory_instead_of_file(capsys: Any, tmp_path: Path) -> None:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_server()
|
||||
|
||||
assert isinstance(exc_info.value, SystemExit)
|
||||
assert exc_info.value.code == 1
|
||||
captured = capsys.readouterr()
|
||||
assert f"Error: '{test_dir}' is not a file" in captured.err
|
||||
@@ -63,6 +66,7 @@ another_variable = 42
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_server()
|
||||
|
||||
assert isinstance(exc_info.value, SystemExit)
|
||||
assert exc_info.value.code == 1
|
||||
captured = capsys.readouterr()
|
||||
assert (
|
||||
@@ -157,6 +161,7 @@ def invalid_syntax(
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_server()
|
||||
|
||||
assert isinstance(exc_info.value, SystemExit)
|
||||
assert exc_info.value.code == 1
|
||||
captured = capsys.readouterr()
|
||||
assert "Error loading or running server:" in captured.err
|
||||
@@ -172,6 +177,7 @@ def test_spec_creation_failure(capsys: Any, tmp_path: Path) -> None:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_server()
|
||||
|
||||
assert isinstance(exc_info.value, SystemExit)
|
||||
assert exc_info.value.code == 1
|
||||
captured = capsys.readouterr()
|
||||
assert "Unable to get spec from module" in captured.err
|
||||
|
||||
+5
-5
@@ -21,7 +21,7 @@ def test_stop_event_round_trip() -> None:
|
||||
dumped = handler.model_dump(mode="python")
|
||||
restored = PersistentHandler(**dumped)
|
||||
assert isinstance(restored.result, StopEvent)
|
||||
assert cast(StopEvent, restored.result).result == 1
|
||||
assert restored.result.result == 1
|
||||
|
||||
|
||||
def test_legacy_result_dict_is_coerced_to_stop_event() -> None:
|
||||
@@ -31,13 +31,13 @@ def test_legacy_result_dict_is_coerced_to_stop_event() -> None:
|
||||
)
|
||||
|
||||
assert isinstance(handler.result, StopEvent)
|
||||
assert cast(StopEvent, handler.result).result == legacy_payload
|
||||
assert handler.result.result == legacy_payload
|
||||
|
||||
dumped = handler.model_dump(mode="python")
|
||||
|
||||
restored = PersistentHandler(**dumped)
|
||||
assert isinstance(restored.result, StopEvent)
|
||||
assert cast(StopEvent, restored.result).result == legacy_payload
|
||||
assert restored.result.result == legacy_payload
|
||||
|
||||
|
||||
class MyStop(StopEvent):
|
||||
@@ -55,10 +55,10 @@ def test_stop_event_subclass_round_trip() -> None:
|
||||
|
||||
restored = PersistentHandler(**dumped)
|
||||
assert isinstance(restored.result, MyStop)
|
||||
assert cast(MyStop, restored.result).result == payload
|
||||
assert restored.result.result == payload
|
||||
|
||||
|
||||
def test_converts_to_stop_event() -> None:
|
||||
handler = PersistentHandler(**_base_handler_kwargs(), result=123) # type: ignore[arg-type]
|
||||
assert isinstance(handler.result, StopEvent)
|
||||
assert cast(StopEvent, handler.result).result == 123
|
||||
assert handler.result.result == 123
|
||||
|
||||
@@ -15,7 +15,7 @@ from httpx import ASGITransport, AsyncClient, Response
|
||||
|
||||
from workflows.events import StopEvent, StartEvent
|
||||
|
||||
from .util import wait_for_passing
|
||||
from .util import wait_for_passing # type: ignore[import]
|
||||
from workflows import Context, step
|
||||
from workflows.server import WorkflowServer
|
||||
from workflows.server.abstract_workflow_store import HandlerQuery, PersistentHandler
|
||||
@@ -24,7 +24,7 @@ from datetime import datetime
|
||||
|
||||
# Prepare the event to send
|
||||
from workflows.context.serializers import JsonSerializer
|
||||
from .conftest import ExternalEvent
|
||||
from .conftest import ExternalEvent # type: ignore[import]
|
||||
from workflows.server.memory_workflow_store import MemoryWorkflowStore
|
||||
from llama_index_instrumentation.dispatcher import active_instrument_tags
|
||||
|
||||
|
||||
@@ -17,8 +17,11 @@ from workflows import Workflow
|
||||
from workflows.events import StopEvent
|
||||
from workflows.server import WorkflowServer
|
||||
from workflows.client.client import WorkflowClient
|
||||
from .conftest import ExternalEvent, RequestedExternalEvent
|
||||
from .util import wait_for_passing
|
||||
from .conftest import ( # type: ignore[import]
|
||||
ExternalEvent,
|
||||
RequestedExternalEvent,
|
||||
)
|
||||
from .util import wait_for_passing # type: ignore[import]
|
||||
|
||||
|
||||
def _get_free_port() -> int:
|
||||
|
||||
@@ -6,7 +6,10 @@ from typing import AsyncGenerator
|
||||
from httpx import AsyncClient, ASGITransport
|
||||
|
||||
|
||||
from .conftest import ExternalEvent, RequestedExternalEvent
|
||||
from .conftest import ( # type: ignore[import]
|
||||
ExternalEvent,
|
||||
RequestedExternalEvent,
|
||||
)
|
||||
from workflows.events import Event, InternalDispatchEvent, StopEvent
|
||||
from workflows.server import WorkflowServer
|
||||
from workflows import Context
|
||||
@@ -14,7 +17,7 @@ from workflows.workflow import Workflow
|
||||
from workflows.server.abstract_workflow_store import HandlerQuery, PersistentHandler
|
||||
|
||||
from workflows.server.memory_workflow_store import MemoryWorkflowStore
|
||||
from .util import wait_for_passing
|
||||
from .util import wait_for_passing # type: ignore[import]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -23,6 +23,7 @@ async def wait_for_passing(
|
||||
if last_exception:
|
||||
raise last_exception
|
||||
else:
|
||||
func_name = getattr(func, "__name__", repr(func))
|
||||
raise TimeoutError(
|
||||
f"Function {func.__name__} timed out after {max_duration} seconds"
|
||||
f"Function {func_name} timed out after {max_duration} seconds"
|
||||
)
|
||||
|
||||
@@ -12,6 +12,11 @@ from workflows.events import Event, StartEvent, StopEvent
|
||||
from workflows.resource import Resource, ResourceManager
|
||||
from workflows.workflow import Workflow
|
||||
|
||||
# Global counters used in resource workflow tests
|
||||
cc: int
|
||||
cc1: int
|
||||
cc2: int
|
||||
|
||||
|
||||
class SecondEvent(Event):
|
||||
msg: str = Field(description="A message")
|
||||
|
||||
@@ -13,7 +13,7 @@ from workflows.errors import WorkflowRuntimeError, WorkflowTimeoutError
|
||||
from workflows.events import Event, StartEvent, StopEvent
|
||||
from workflows.workflow import Workflow
|
||||
|
||||
from .conftest import OneTestEvent
|
||||
from .conftest import OneTestEvent # type: ignore[import]
|
||||
|
||||
|
||||
class StreamingWorkflow(Workflow):
|
||||
|
||||
@@ -20,7 +20,10 @@ from workflows.utils import (
|
||||
validate_step_signature,
|
||||
)
|
||||
|
||||
from .conftest import AnotherTestEvent, OneTestEvent
|
||||
from .conftest import ( # type: ignore[import]
|
||||
AnotherTestEvent,
|
||||
OneTestEvent,
|
||||
)
|
||||
|
||||
|
||||
def test_validate_step_signature_of_method() -> None:
|
||||
|
||||
@@ -9,7 +9,7 @@ import logging
|
||||
import pickle
|
||||
import threading
|
||||
import weakref
|
||||
from typing import Any, Callable, Union
|
||||
from typing import Any, Callable, Union, cast
|
||||
from unittest import mock
|
||||
|
||||
from llama_index_instrumentation.dispatcher import active_instrument_tags
|
||||
@@ -36,7 +36,7 @@ from workflows.runtime.types.ticks import TickAddEvent
|
||||
from workflows.testing import WorkflowTestRunner
|
||||
from workflows.workflow import Workflow
|
||||
|
||||
from .conftest import (
|
||||
from .conftest import ( # type: ignore[import]
|
||||
AnotherTestEvent,
|
||||
DummyWorkflow,
|
||||
LastEvent,
|
||||
@@ -374,9 +374,10 @@ def test_workflow_disable_validation() -> None:
|
||||
raise ValueError("The step raised an error!")
|
||||
|
||||
w = DummyWorkflow(disable_validation=True)
|
||||
w._get_steps = mock.MagicMock() # type:ignore
|
||||
w._get_steps = mock.MagicMock() # type: ignore[assignment]
|
||||
mock_get_steps = cast(mock.MagicMock, w._get_steps)
|
||||
w._validate()
|
||||
w._get_steps.assert_not_called()
|
||||
mock_get_steps.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -872,7 +873,10 @@ async def test_workflow_instances_garbage_collected_after_completion() -> None:
|
||||
|
||||
for _ in range(10):
|
||||
wf = TinyWorkflow()
|
||||
refs.append(weakref.ref(wf))
|
||||
wf_ref: weakref.ReferenceType[Workflow] = cast(
|
||||
weakref.ReferenceType[Workflow], weakref.ref(wf)
|
||||
)
|
||||
refs.append(wf_ref)
|
||||
await WorkflowTestRunner(wf).run()
|
||||
# Drop strong reference before next iteration
|
||||
del wf
|
||||
|
||||
@@ -13,7 +13,7 @@ from workflows.events import (
|
||||
from workflows.workflow import Workflow
|
||||
from workflows.testing import WorkflowTestRunner
|
||||
|
||||
from .conftest import OneTestEvent
|
||||
from .conftest import OneTestEvent # type: ignore[import]
|
||||
|
||||
|
||||
class PostponedAnnotationsWorkflow(Workflow):
|
||||
|
||||
@@ -5,7 +5,8 @@ build-backend = "uv_build"
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=8.4.2",
|
||||
"pytest-cov>=7.0.0"
|
||||
"pytest-cov>=7.0.0",
|
||||
"ty>=0.0.1a26"
|
||||
]
|
||||
|
||||
[project]
|
||||
|
||||
@@ -5,8 +5,12 @@ from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from packaging.version import Version
|
||||
import sys
|
||||
|
||||
import tomllib
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else:
|
||||
import tomli as tomllib
|
||||
|
||||
|
||||
class VersionMismatchError(ValueError):
|
||||
|
||||
@@ -3933,6 +3933,31 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/85/a4ff8758c66f1fc32aa5e9a145908394bf9cf1c79ffd1113cfdeb77e74e4/trove_classifiers-2025.9.11.17-py3-none-any.whl", hash = "sha256:5d392f2d244deb1866556457d6f3516792124a23d1c3a463a2e8668a5d1c15dd", size = 14158, upload-time = "2025-09-11T17:07:49.886Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty"
|
||||
version = "0.0.1a26"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/39/39/b4b4ecb6ca6d7e937fa56f0b92a8f48d7719af8fe55bdbf667638e9f93e2/ty-0.0.1a26.tar.gz", hash = "sha256:65143f8efeb2da1644821b710bf6b702a31ddcf60a639d5a576db08bded91db4", size = 4432154, upload-time = "2025-11-10T18:02:30.142Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/6a/661833ecacc4d994f7e30a7f1307bfd3a4a91392a6b03fb6a018723e75b8/ty-0.0.1a26-py3-none-linux_armv6l.whl", hash = "sha256:09208dca99bb548e9200136d4d42618476bfe1f4d2066511f2c8e2e4dfeced5e", size = 9173869, upload-time = "2025-11-10T18:01:46.012Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/a8/32ea50f064342de391a7267f84349287e2f1c2eb0ad4811d6110916179d6/ty-0.0.1a26-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:91d12b66c91a1b82e698a2aa73fe043a1a9da83ff0dfd60b970500bee0963b91", size = 8973420, upload-time = "2025-11-10T18:01:49.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/f6/6659d55940cd5158a6740ae46a65be84a7ee9167738033a9b1259c36eef5/ty-0.0.1a26-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5bc6dfcea5477c81ad01d6a29ebc9bfcbdb21c34664f79c9e1b84be7aa8f289", size = 8528888, upload-time = "2025-11-10T18:01:51.511Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/c9/4cbe7295013cc412b4f100b509aaa21982c08c59764a2efa537ead049345/ty-0.0.1a26-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40e5d15635e9918924138e8d3fb1cbf80822dfb8dc36ea8f3e72df598c0c4bea", size = 8801867, upload-time = "2025-11-10T18:01:53.888Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/b3/25099b219a6444c4b29f175784a275510c1cd85a23a926d687ab56915027/ty-0.0.1a26-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:86dc147ed0790c7c8fd3f0d6c16c3c5135b01e99c440e89c6ca1e0e592bb6682", size = 8975519, upload-time = "2025-11-10T18:01:56.231Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/3e/3ad570f4f592cb1d11982dd2c426c90d2aa9f3d38bf77a7e2ce8aa614302/ty-0.0.1a26-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbe0e07c9d5e624edfc79a468f2ef191f9435581546a5bb6b92713ddc86ad4a6", size = 9331932, upload-time = "2025-11-10T18:01:58.476Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/fa/62c72eead0302787f9cc0d613fc671107afeecdaf76ebb04db8f91bb9f7e/ty-0.0.1a26-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0dcebbfe9f24b43d98a078f4a41321ae7b08bea40f5c27d81394b3f54e9f7fb5", size = 9921353, upload-time = "2025-11-10T18:02:00.749Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/1f/3b329c4b60d878704e09eb9d05467f911f188e699961c044b75932893e0a/ty-0.0.1a26-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0901b75afc7738224ffc98bbc8ea03a20f167a2a83a4b23a6550115e8b3ddbc6", size = 9700800, upload-time = "2025-11-10T18:02:03.544Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/24/13fcba20dd86a7c3f83c814279aa3eb6a29c5f1b38a3b3a4a0fd22159189/ty-0.0.1a26-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4788f34d384c132977958d76fef7f274f8d181b22e33933c4d16cff2bb5ca3b9", size = 9728289, upload-time = "2025-11-10T18:02:06.386Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/7a/798894ff0b948425570b969be35e672693beeb6b852815b7340bc8de1575/ty-0.0.1a26-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b98851c11c560ce63cd972ed9728aa079d9cf40483f2cdcf3626a55849bfe107", size = 9279735, upload-time = "2025-11-10T18:02:09.425Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/54/71261cc1b8dc7d3c4ad92a83b4d1681f5cb7ea5965ebcbc53311ae8c6424/ty-0.0.1a26-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c20b4625a20059adecd86fe2c4df87cd6115fea28caee45d3bdcf8fb83d29510", size = 8767428, upload-time = "2025-11-10T18:02:11.956Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/07/b248b73a640badba2b301e6845699b7dd241f40a321b9b1bce684d440f70/ty-0.0.1a26-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d9909e96276f8d16382d285db92ae902174cae842aa953003ec0c06642db2f8a", size = 9009170, upload-time = "2025-11-10T18:02:14.878Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/35/ec8353f2bb7fd2f41bca6070b29ecb58e2de9af043e649678b8c132d5439/ty-0.0.1a26-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a76d649ceefe9baa9bbae97d217bee076fd8eeb2a961f66f1dff73cc70af4ac8", size = 9119215, upload-time = "2025-11-10T18:02:18.329Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/48/db49fe1b7e66edf90dc285869043f99c12aacf7a99c36ee760e297bac6d5/ty-0.0.1a26-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0ee0f6366bcf70fae114e714d45335cacc8daa936037441e02998a9110b7a29", size = 9398655, upload-time = "2025-11-10T18:02:21.031Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/f8/d869492bdbb21ae8cf4c99b02f20812bbbf49aa187cfeb387dfaa03036a8/ty-0.0.1a26-py3-none-win32.whl", hash = "sha256:86689b90024810cac7750bf0c6e1652e4b4175a9de7b82b8b1583202aeb47287", size = 8645669, upload-time = "2025-11-10T18:02:23.23Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/18/8a907575d2b335afee7556cb92233ebb5efcefe17752fc9dcab21cffb23b/ty-0.0.1a26-py3-none-win_amd64.whl", hash = "sha256:829e6e6dbd7d9d370f97b2398b4804552554bdcc2d298114fed5e2ea06cbc05c", size = 9442975, upload-time = "2025-11-10T18:02:25.68Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/22/af92dcfdd84b78dd97ac6b7154d6a763781f04a400140444885c297cc213/ty-0.0.1a26-py3-none-win_arm64.whl", hash = "sha256:b8f431c784d4cf5b4195a3521b2eca9c15902f239b91154cb920da33f943c62b", size = 8958958, upload-time = "2025-11-10T18:02:28.071Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
@@ -4110,6 +4135,7 @@ dependencies = [
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-cov" },
|
||||
{ name = "ty" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
@@ -4125,6 +4151,7 @@ requires-dist = [
|
||||
dev = [
|
||||
{ name = "pytest", specifier = ">=8.4.2" },
|
||||
{ name = "pytest-cov", specifier = ">=7.0.0" },
|
||||
{ name = "ty", specifier = ">=0.0.1a26" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user