chore: bump ty to >=0.0.15 (#468)

This commit is contained in:
Adrian Lyjak
2026-04-03 18:30:56 -04:00
committed by GitHub
parent 48c9847325
commit f2e7f96a79
34 changed files with 88 additions and 80 deletions
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type, not-iterable]
from __future__ import annotations
from contextlib import asynccontextmanager
@@ -1,6 +1,8 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
import json
import pytest
+1 -1
View File
@@ -12,7 +12,7 @@ dev = [
"pytest-cov>=6.1.1",
"pytest-timeout>=2.4.0",
"pytest-xdist>=3.0.0",
"ty>=0.0.1,<0.0.9"
"ty>=0.0.15"
]
[project]
@@ -170,10 +170,10 @@ class DBOSIdleReleaseDecorator(BaseRuntimeDecorator):
if self._lifecycle_lock_instance is None:
result = self._lifecycle_lock_factory()
if isinstance(result, Awaitable):
self._lifecycle_lock_instance = await result
self._lifecycle_lock_instance = await result # type: ignore[ty:invalid-assignment]
else:
self._lifecycle_lock_instance = result
return self._lifecycle_lock_instance
return self._lifecycle_lock_instance # type: ignore[ty:invalid-return-type]
@override
def track_workflow(self, workflow: Workflow) -> None:
@@ -290,7 +290,7 @@ class DBOSRuntime(Runtime):
replica reclaims the slot.
"""
super().__init__()
self.config: DBOSRuntimeConfig = dict(kwargs) # type: ignore[assignment]
self.config: DBOSRuntimeConfig = dict(kwargs) # type: ignore[assignment] # ty: ignore[invalid-assignment]
# Workflow tracking state
self._tracked_workflows: list[Workflow] = []
+9 -18
View File
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
from __future__ import annotations
@@ -104,11 +105,8 @@ def run_scenario(
except subprocess.TimeoutExpired as e:
stdout = e.stdout.decode() if isinstance(e.stdout, bytes) else (e.stdout or "")
stderr = e.stderr.decode() if isinstance(e.stderr, bytes) else (e.stderr or "")
pytest.fail(
f"Subprocess timed out after {timeout}s\n"
f"stdout:\n{stdout}\n"
f"stderr:\n{stderr}"
)
msg = f"Subprocess timed out after {timeout}s\nstdout:\n{stdout}\nstderr:\n{stderr}"
pytest.fail(msg)
raise AssertionError("unreachable") # noqa: B904
@@ -117,23 +115,16 @@ def assert_no_determinism_errors(result: subprocess.CompletedProcess[str]) -> No
combined = result.stdout + result.stderr
if result.returncode != 0:
pytest.fail(
f"Subprocess exited with code {result.returncode}\n"
f"stdout: {result.stdout}\n"
f"stderr: {result.stderr}"
)
msg = f"Subprocess exited with code {result.returncode}\nstdout: {result.stdout}\nstderr: {result.stderr}"
pytest.fail(msg)
if "Traceback (most recent call last)" in result.stdout:
pytest.fail(
f"Subprocess exception!\nstdout: {result.stdout}\nstderr: {result.stderr}"
)
msg = f"Subprocess exception!\nstdout: {result.stdout}\nstderr: {result.stderr}"
pytest.fail(msg)
if "DBOSUnexpectedStepError" in combined or "Error 11" in combined:
pytest.fail(
f"DBOS determinism error on resume!\n"
f"stdout: {result.stdout}\n"
f"stderr: {result.stderr}"
)
msg = f"DBOS determinism error on resume!\nstdout: {result.stdout}\nstderr: {result.stderr}"
pytest.fail(msg)
def log_on_failure(result: subprocess.CompletedProcess[str], label: str) -> None:
+1
View File
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
"""Subprocess runner for workflow tests with DBOS isolation.
@@ -1,3 +1,4 @@
# ty: ignore[invalid-assignment]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
"""Unit tests for DBOSIdleReleaseDecorator."""
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
"""End-to-end DBOS + WorkflowServer + PostgresWorkflowStore integration tests.
@@ -58,10 +59,8 @@ def run_server_scenario(
def assert_no_errors(result: subprocess.CompletedProcess[str]) -> None:
"""Check subprocess result for crashes and errors."""
if result.returncode != 0:
pytest.fail(
f"Subprocess exited with code {result.returncode}\n"
f"stdout: {result.stdout}\nstderr: {result.stderr}"
)
msg = f"Subprocess exited with code {result.returncode}\nstdout: {result.stdout}\nstderr: {result.stderr}"
pytest.fail(msg)
# Only fail on tracebacks in stdout — stderr tracebacks during DBOS
# shutdown are noisy but harmless when exit code is 0.
if "Traceback (most recent call last)" in result.stdout:
@@ -13,7 +13,7 @@ dev = [
"pytest-xdist>=3.8.0",
"sqlalchemy>=2.0.0",
"testcontainers[postgres]>=4.0.0",
"ty>=0.0.1,<0.0.9"
"ty>=0.0.15"
]
[project]
@@ -1,3 +1,4 @@
# ty: ignore[unknown-argument]
"""Tests for human-in-the-loop (HITL) workflow patterns.
These tests verify that wait_for_event works correctly inside tool
@@ -1,3 +1,4 @@
# ty: ignore[unknown-argument]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
"""Parameterized live HTTP server integration tests across storage backends."""
@@ -112,7 +112,7 @@ class _WorkflowAPI:
routes=self._routes(),
middleware=middleware,
lifespan=lifespan,
exception_handlers=exception_handlers, # type: ignore[arg-type]
exception_handlers=exception_handlers, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
)
self.app.mount(
"/", app=StaticFiles(directory=assets_path, html=True), name="ui"
@@ -1030,7 +1030,7 @@ class _WorkflowAPI:
}
status_in: list[Status] | None = (
cast(
cast( # type: ignore[ty:invalid-argument-type]
list[Status],
list(set(allowed_status_values).intersection(status_values)),
)
@@ -68,7 +68,7 @@ class AgentDataStateStore(Generic[MODEL_T]):
) -> None:
self._client = client
self._run_id = run_id
self.state_type = state_type or DictState # type: ignore[assignment]
self.state_type = state_type or DictState # type: ignore[assignment] # ty: ignore[invalid-assignment]
self._collection = collection
self._serializer = serializer or JsonSerializer()
# Cache the agent data item ID once found
@@ -97,8 +97,8 @@ class AgentDataStateStore(Generic[MODEL_T]):
def _deserialize_state(self, state_json: str) -> MODEL_T:
if issubclass(self.state_type, DictState):
data = json.loads(state_json)
return deserialize_dict_state_data(data, self._serializer) # type: ignore[return-value]
return self._serializer.deserialize(state_json)
return deserialize_dict_state_data(data, self._serializer) # type: ignore[return-value] # ty: ignore[invalid-return-type]
return self._serializer.deserialize(state_json) # type: ignore[ty:invalid-return-type]
def _create_default_state(self) -> MODEL_T:
return self.state_type()
@@ -161,7 +161,7 @@ class AgentDataStateStore(Generic[MODEL_T]):
else:
result = await self._client.create(self._collection, payload)
self._item_id = result["id"]
self._cached_state = state.model_copy() # type: ignore[assignment]
self._cached_state = state.model_copy() # type: ignore[assignment] # ty: ignore[invalid-assignment]
# ------------------------------------------------------------------
# StateStore protocol
@@ -220,7 +220,7 @@ class AgentDataStateStore(Generic[MODEL_T]):
return cls(
client=client,
run_id=effective_run_id,
state_type=state_type, # type: ignore[arg-type]
state_type=state_type, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
collection=parsed.collection,
serializer=serializer,
)
@@ -3,9 +3,13 @@
from __future__ import annotations
try:
from importlib.resources.abc import Traversable # type: ignore
from importlib.resources.abc import ( # type: ignore # ty: ignore[unresolved-import]
Traversable,
)
except ImportError: # pre 3.11
from importlib.abc import Traversable # type: ignore
from importlib.abc import ( # type: ignore # ty: ignore[unresolved-import]
Traversable,
)
import re
from importlib import import_module, resources
@@ -17,7 +21,7 @@ def iter_migration_files(source_pkg: str) -> list[Traversable]:
pkg = import_module(source_pkg)
root = resources.files(pkg)
files = (p for p in root.iterdir() if p.name.endswith(".sql"))
return sorted(files, key=lambda p: p.name) # type: ignore
return sorted(files, key=lambda p: p.name) # type: ignore # ty: ignore[invalid-return-type]
def parse_target_version(sql_text: str) -> int | None:
@@ -63,7 +63,7 @@ class PostgresStateStore(Generic[MODEL_T]):
) -> None:
self._pool = pool
self._run_id = run_id
self.state_type = state_type or DictState # type: ignore[assignment]
self.state_type = state_type or DictState # type: ignore[assignment] # ty: ignore[invalid-assignment]
self._serializer = serializer or JsonSerializer()
self._schema = schema
self._pending_seed: tuple[dict[str, Any], BaseSerializer] | None = None
@@ -93,8 +93,8 @@ class PostgresStateStore(Generic[MODEL_T]):
"""Deserialize state from JSON string."""
if issubclass(self.state_type, DictState):
data = json.loads(state_json)
return deserialize_dict_state_data(data, self._serializer) # type: ignore[return-value]
return self._serializer.deserialize(state_json)
return deserialize_dict_state_data(data, self._serializer) # type: ignore[return-value] # ty: ignore[invalid-return-type]
return self._serializer.deserialize(state_json) # type: ignore[ty:invalid-return-type]
def _create_default_state(self) -> MODEL_T:
return self.state_type()
@@ -273,7 +273,7 @@ class PostgresStateStore(Generic[MODEL_T]):
return cls(
pool=pool,
run_id=effective_run_id,
state_type=state_type, # type: ignore[arg-type]
state_type=state_type, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
serializer=serializer,
schema=schema,
)
@@ -285,7 +285,7 @@ class PostgresStateStore(Generic[MODEL_T]):
store = cls(
pool=pool,
run_id=effective_run_id,
state_type=state_type, # type: ignore[arg-type]
state_type=state_type, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
serializer=serializer,
schema=schema,
)
@@ -132,7 +132,7 @@ class PostgresWorkflowStore(AbstractWorkflowStore):
except Exception:
logger.debug("Failed to remove listener during close", exc_info=True)
try:
await self._pool.release(self._listen_conn) # type: ignore[union-attr]
await self._pool.release(self._listen_conn) # type: ignore[union-attr] # ty: ignore[unresolved-attribute]
except Exception:
logger.debug(
"Failed to release listen connection during close", exc_info=True
@@ -62,7 +62,7 @@ class SqliteStateStore(Generic[MODEL_T]):
) -> None:
self._db_path = db_path
self._run_id = run_id
self.state_type = state_type or DictState # type: ignore[assignment]
self.state_type = state_type or DictState # type: ignore[assignment] # ty: ignore[invalid-assignment]
self._serializer = serializer or JsonSerializer()
@property
@@ -124,8 +124,8 @@ class SqliteStateStore(Generic[MODEL_T]):
"""Deserialize state from JSON string."""
if issubclass(self.state_type, DictState):
data = json.loads(state_json)
return deserialize_dict_state_data(data, self._serializer) # type: ignore[return-value]
return self._serializer.deserialize(state_json)
return deserialize_dict_state_data(data, self._serializer) # type: ignore[return-value] # ty: ignore[invalid-return-type]
return self._serializer.deserialize(state_json) # type: ignore[ty:invalid-return-type]
def _create_default_state(self) -> MODEL_T:
return self.state_type()
@@ -269,7 +269,7 @@ class SqliteStateStore(Generic[MODEL_T]):
return cls(
db_path=db_path,
run_id=effective_run_id,
state_type=state_type, # type: ignore[arg-type]
state_type=state_type, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
serializer=serializer,
)
@@ -282,7 +282,7 @@ class SqliteStateStore(Generic[MODEL_T]):
store = cls(
db_path=db_path,
run_id=effective_run_id,
state_type=state_type, # type: ignore[arg-type]
state_type=state_type, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
serializer=serializer,
)
store._write_in_memory_state(serialized_state)
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type, invalid-assignment]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
"""Tests for idle workflow release and reload functionality."""
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type, unknown-argument]
from __future__ import annotations
from typing import Any, cast
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
@@ -156,7 +156,7 @@ class Context(Generic[MODEL_T]):
def _require_pre(self, fn: str) -> PreContext[MODEL_T]:
"""Require context to be in pre-run state. Raises ContextStateError if not."""
if isinstance(self._face, PreContext):
return self._face # type: ignore[invalid-return-type]
return self._face # type: ignore[ty:invalid-return-type]
raise ContextStateError(
f"{fn} requires a pre-run context. The workflow has already started."
)
@@ -176,7 +176,7 @@ class Context(Generic[MODEL_T]):
def _require_internal(self, fn: str) -> InternalContext[MODEL_T]:
"""Require context to be in internal state. Raises ContextStateError if not."""
if isinstance(self._face, InternalContext):
return self._face # type: ignore[invalid-return-type]
return self._face # type: ignore[ty:invalid-return-type]
if isinstance(self._face, PreContext):
raise ContextStateError(
f"{fn} requires a running workflow. Call workflow.run() first."
@@ -7,7 +7,7 @@ from typing_extensions import TypeVar
from workflows.context.state_store import DictState
MODEL_T = TypeVar("MODEL_T", bound=BaseModel, default=DictState) # type: ignore
MODEL_T = TypeVar("MODEL_T", bound=BaseModel, default=DictState) # type: ignore # ty: ignore[invalid-return-type]
class SerializedContextV0(BaseModel):
@@ -342,7 +342,7 @@ class DictState(DictLikeModel):
# Default state type is DictState for the generic type
MODEL_T = TypeVar("MODEL_T", bound=BaseModel, default=DictState) # type: ignore
MODEL_T = TypeVar("MODEL_T", bound=BaseModel, default=DictState) # type: ignore # ty: ignore[invalid-return-type]
@runtime_checkable
@@ -520,13 +520,13 @@ class InMemoryStateStore(Generic[MODEL_T]):
ValueError: If the payload is not in_memory format.
"""
if not serialized_state:
return cls(DictState()) # type: ignore
return cls(DictState()) # type: ignore[arg-type] # ty: ignore[invalid-assignment]
# Validate it's in_memory format (raises ValueError if not)
parse_in_memory_state(serialized_state)
state_instance = deserialize_state_from_dict(serialized_state, serializer)
return cls(state_instance) # type: ignore
return cls(state_instance) # type: ignore[arg-type] # ty: ignore[invalid-assignment]
@asynccontextmanager
async def edit_state(self) -> AsyncGenerator[MODEL_T, None]:
@@ -816,7 +816,7 @@ def _process_step_result_tick(
new_waiter = StepWorkerWaiter(
waiter_id=result.waiter_id,
event=this_execution.event,
waiting_for_event=result.event_type, # ty: ignore[invalid-argument-type] - ty choking here, with result.event_type resolved as "object"
waiting_for_event=result.event_type, # type: ignore[ty:invalid-argument-type]
requirements=result.requirements,
has_requirements=bool(len(result.requirements)),
resolved_event=None,
@@ -175,7 +175,7 @@ class AddWaiter(BaseModel, Generic[EventType]):
data["requirements"] = {}
return data
@model_validator(mode="wrap")
@model_validator(mode="wrap") # type: ignore[ty:invalid-argument-type]
@classmethod
def _validate(cls, data: Any, handler: Any) -> AddWaiter:
if isinstance(data, dict):
@@ -251,7 +251,7 @@ def as_step_worker_function(
None,
lambda: copy.run(
lambda: _run_with_tags(merged_tags, partial_func)
), # type: ignore
), # type: ignore[ty:invalid-return-type]
)
)
else:
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type]
"""
Tests for workflow state inheritance behavior.
@@ -1,3 +1,4 @@
# ty: ignore[unknown-argument]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
@@ -1,3 +1,4 @@
# ty: ignore[invalid-argument-type, invalid-assignment, unknown-argument]
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 LlamaIndex Inc.
+1 -1
View File
@@ -10,7 +10,7 @@ dev = [
"pytest-timeout>=2.4.0",
"pytest-xdist>=3.8.0",
"ruff>=0.14.5",
"ty>=0.0.1,<0.0.9"
"ty>=0.0.15"
]
[project]
Generated
+21 -22
View File
@@ -1599,7 +1599,7 @@ dev = [
{ name = "pytest-timeout", specifier = ">=2.4.0" },
{ name = "pytest-xdist", specifier = ">=3.0.0" },
{ name = "testcontainers", extras = ["postgres"], specifier = ">=4.0.0" },
{ name = "ty", specifier = ">=0.0.1,<0.0.9" },
{ name = "ty", specifier = ">=0.0.15" },
]
[[package]]
@@ -1646,7 +1646,7 @@ dev = [
{ name = "pytest-timeout", specifier = ">=2.4.0" },
{ name = "pytest-xdist", specifier = ">=3.8.0" },
{ name = "ruff", specifier = ">=0.14.5" },
{ name = "ty", specifier = ">=0.0.1,<0.0.9" },
{ name = "ty", specifier = ">=0.0.15" },
]
[[package]]
@@ -1695,7 +1695,7 @@ dev = [
{ name = "pytest-xdist", specifier = ">=3.8.0" },
{ name = "sqlalchemy", specifier = ">=2.0.0" },
{ name = "testcontainers", extras = ["postgres"], specifier = ">=4.0.0" },
{ name = "ty", specifier = ">=0.0.1,<0.0.9" },
{ name = "ty", specifier = ">=0.0.15" },
]
[[package]]
@@ -4186,27 +4186,26 @@ wheels = [
[[package]]
name = "ty"
version = "0.0.8"
version = "0.0.28"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/9d/59e955cc39206a0d58df5374808785c45ec2a8a2a230eb1638fbb4fe5c5d/ty-0.0.8.tar.gz", hash = "sha256:352ac93d6e0050763be57ad1e02087f454a842887e618ec14ac2103feac48676", size = 4828477, upload-time = "2025-12-29T13:50:07.193Z" }
sdist = { url = "https://files.pythonhosted.org/packages/19/c2/a60543fb172ac7adaa3ae43b8db1d0dcd70aa67df254b70bf42f852a24f6/ty-0.0.28.tar.gz", hash = "sha256:1fbde7bc5d154d6f047b570d95665954fa83b75a0dce50d88cf081b40a27ea32", size = 5447781, upload-time = "2026-04-02T21:34:33.556Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/69/2b/dd61f7e50a69c72f72c625d026e9ab64a0db62b2dd32e7426b520e2429c6/ty-0.0.8-py3-none-linux_armv6l.whl", hash = "sha256:a289d033c5576fa3b4a582b37d63395edf971cdbf70d2d2e6b8c95638d1a4fcd", size = 9853417, upload-time = "2025-12-29T13:50:08.979Z" },
{ url = "https://files.pythonhosted.org/packages/90/72/3f1d3c64a049a388e199de4493689a51fc6aa5ff9884c03dea52b4966657/ty-0.0.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:788ea97dc8153a94e476c4d57b2551a9458f79c187c4aba48fcb81f05372924a", size = 9657890, upload-time = "2025-12-29T13:50:27.867Z" },
{ url = "https://files.pythonhosted.org/packages/71/d1/08ac676bd536de3c2baba0deb60e67b3196683a2fabebfd35659d794b5e9/ty-0.0.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1b5f1f3d3e230f35a29e520be7c3d90194a5229f755b721e9092879c00842d31", size = 9180129, upload-time = "2025-12-29T13:50:22.842Z" },
{ url = "https://files.pythonhosted.org/packages/af/93/610000e2cfeea1875900f73a375ba917624b0a008d4b8a6c18c894c8dbbc/ty-0.0.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6da9ed377fbbcec0a3b60b2ca5fd30496e15068f47cef2344ba87923e78ba996", size = 9683517, upload-time = "2025-12-29T13:50:18.658Z" },
{ url = "https://files.pythonhosted.org/packages/05/04/bef50ba7d8580b0140be597de5cc0ba9a63abe50d3f65560235f23658762/ty-0.0.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7d0a2bdce5e701d19eb8d46d9da0fe31340f079cecb7c438f5ac6897c73fc5ba", size = 9676279, upload-time = "2025-12-29T13:50:25.207Z" },
{ url = "https://files.pythonhosted.org/packages/aa/b9/2aff1ef1f41b25898bc963173ae67fc8f04ca666ac9439a9c4e78d5cc0ff/ty-0.0.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef9078799d26d3cc65366e02392e2b78f64f72911b599e80a8497d2ec3117ddb", size = 10073015, upload-time = "2025-12-29T13:50:35.422Z" },
{ url = "https://files.pythonhosted.org/packages/df/0e/9feb6794b6ff0a157c3e6a8eb6365cbfa3adb9c0f7976e2abdc48615dd72/ty-0.0.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:54814ac39b4ab67cf111fc0a236818155cf49828976152378347a7678d30ee89", size = 10961649, upload-time = "2025-12-29T13:49:58.717Z" },
{ url = "https://files.pythonhosted.org/packages/f4/3b/faf7328b14f00408f4f65c9d01efe52e11b9bcc4a79e06187b370457b004/ty-0.0.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4baf0a80398e8b6c68fa36ff85045a50ede1906cd4edb41fb4fab46d471f1d4", size = 10676190, upload-time = "2025-12-29T13:50:01.11Z" },
{ url = "https://files.pythonhosted.org/packages/64/a5/cfeca780de7eeab7852c911c06a84615a174d23e9ae08aae42a645771094/ty-0.0.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac8e23c3faefc579686799ef1649af8d158653169ad5c3a7df56b152781eeb67", size = 10438641, upload-time = "2025-12-29T13:50:29.664Z" },
{ url = "https://files.pythonhosted.org/packages/0e/8d/8667c7e0ac9f13c461ded487c8d7350f440cd39ba866d0160a8e1b1efd6c/ty-0.0.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b558a647a073d0c25540aaa10f8947de826cb8757d034dd61ecf50ab8dbd77bf", size = 10214082, upload-time = "2025-12-29T13:50:31.531Z" },
{ url = "https://files.pythonhosted.org/packages/f8/11/e563229870e2c1d089e7e715c6c3b7605a34436dddf6f58e9205823020c2/ty-0.0.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8c0104327bf480508bd81f320e22074477df159d9eff85207df39e9c62ad5e96", size = 9664364, upload-time = "2025-12-29T13:50:05.443Z" },
{ url = "https://files.pythonhosted.org/packages/b1/ad/05b79b778bf5237bcd7ee08763b226130aa8da872cbb151c8cfa2e886203/ty-0.0.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:496f1cb87261dd1a036a5609da80ee13de2e6ee4718a661bfa2afb91352fe528", size = 9679440, upload-time = "2025-12-29T13:50:11.289Z" },
{ url = "https://files.pythonhosted.org/packages/12/b5/23ba887769c4a7b8abfd1b6395947dc3dcc87533fbf86379d3a57f87ae8f/ty-0.0.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2c488031f92a075ae39d13ac6295fdce2141164ec38c5d47aa8dc24ee3afa37e", size = 9808201, upload-time = "2025-12-29T13:50:21.003Z" },
{ url = "https://files.pythonhosted.org/packages/f8/90/5a82ac0a0707db55376922aed80cd5fca6b2e6d6e9bcd8c286e6b43b4084/ty-0.0.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90d6f08c5982fa3e802b8918a32e326153519077b827f91c66eea4913a86756a", size = 10313262, upload-time = "2025-12-29T13:50:03.306Z" },
{ url = "https://files.pythonhosted.org/packages/14/f7/ff97f37f0a75db9495ddbc47738ec4339837867c4bfa145bdcfbd0d1eb2f/ty-0.0.8-py3-none-win32.whl", hash = "sha256:d7f460ad6fc9325e9cc8ea898949bbd88141b4609d1088d7ede02ce2ef06e776", size = 9254675, upload-time = "2025-12-29T13:50:33.35Z" },
{ url = "https://files.pythonhosted.org/packages/af/51/eba5d83015e04630002209e3590c310a0ff1d26e1815af204a322617a42e/ty-0.0.8-py3-none-win_amd64.whl", hash = "sha256:1641fb8dedc3d2da43279d21c3c7c1f80d84eae5c264a1e8daa544458e433c19", size = 10131382, upload-time = "2025-12-29T13:50:13.719Z" },
{ url = "https://files.pythonhosted.org/packages/38/1c/0d8454ff0f0f258737ecfe84f6e508729191d29663b404832f98fa5626b7/ty-0.0.8-py3-none-win_arm64.whl", hash = "sha256:ec74f022f315bede478ecae1277a01ab618e6500c1d68450d7883f5cd6ed554a", size = 9636374, upload-time = "2025-12-29T13:50:16.344Z" },
{ url = "https://files.pythonhosted.org/packages/fe/15/c2aa3d4633e6153a2e300d7dd0ebdedf904a60241d1922566f31c5f7f211/ty-0.0.28-py3-none-linux_armv6l.whl", hash = "sha256:6dbfb27524195ab1715163d7be065cc45037509fe529d9763aff6732c919f0d8", size = 10556282, upload-time = "2026-04-02T21:35:04.165Z" },
{ url = "https://files.pythonhosted.org/packages/60/9c/f6183838df89e9692235a71a69a9d4e0f12481bbdf1883f47010075793b0/ty-0.0.28-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8c72a899ba94f7438bd07e897a84b36526b385aaf01d6f3eb6504e869232b3a6", size = 10425770, upload-time = "2026-04-02T21:34:49.144Z" },
{ url = "https://files.pythonhosted.org/packages/68/82/e9208383412f8a320537ef4c44a768d2cb6c1330d9ab33087f0b932ccd1b/ty-0.0.28-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eef67f9cdfd31677bde801b611741dde779271ec6f471f818c7c6eccf515237f", size = 9899999, upload-time = "2026-04-02T21:34:40.297Z" },
{ url = "https://files.pythonhosted.org/packages/4d/26/0442f49589ba393fbd3b50751f8bb82137b036bc509762884f7b21c511d1/ty-0.0.28-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70e7b98a91d8245641be1e4b55af8bc9b1ae82ec189794d35e14e546f1e15e66", size = 10400725, upload-time = "2026-04-02T21:34:42.779Z" },
{ url = "https://files.pythonhosted.org/packages/57/d9/64128f1a7ceba72e49f35dd562533f44d4c56d0cf62efb21692377819dbc/ty-0.0.28-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd83d4ad9f99078b830aabb47792fac6dc39368bb0f72f3cc14607173ed6e25", size = 10387410, upload-time = "2026-04-02T21:34:46.889Z" },
{ url = "https://files.pythonhosted.org/packages/cc/52/498b6bdd1d0a985fd14ce83c31186f3b838ad79efdf68ce928f441a6962b/ty-0.0.28-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0172984fc2fcd3e47ccd5da69f36f632cddc410f9a093144a05ad07d67cf06ed", size = 10880982, upload-time = "2026-04-02T21:34:53.687Z" },
{ url = "https://files.pythonhosted.org/packages/f4/c8/fefd616f38a250b28f62ba73728cb6061715f03df0a610dce558a0fdfc0a/ty-0.0.28-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0bbf47d2bea82a09cab2ca4f48922d6c16a36608447acdc64163cd19beb28d3", size = 11459056, upload-time = "2026-04-02T21:34:31.642Z" },
{ url = "https://files.pythonhosted.org/packages/16/15/9e18d763a5ef9c6a69396876586589fd5e0fd0acba35fae8a9a169680f48/ty-0.0.28-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1774c9a0fb071607e3bdfa0ce8365488ac46809fc04ad1706562a8709a023247", size = 11156341, upload-time = "2026-04-02T21:35:01.824Z" },
{ url = "https://files.pythonhosted.org/packages/89/29/8ac0281fc44c3297f0e58699ebf993c13621e32a0fab1025439d3ea8a2f1/ty-0.0.28-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2849d6d212af78175430e8cc51a962a53851458182eb44a981b0e3981163177", size = 11006089, upload-time = "2026-04-02T21:34:38.111Z" },
{ url = "https://files.pythonhosted.org/packages/dd/de/5b5fdbe3bdb5c6f4918b33f1c55cd975b3d606057089a822439d5151bf93/ty-0.0.28-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3c576c15b867b3913c4a1d9be30ade4682303e24a576d2cc99bfd8f25ae838e9", size = 10367739, upload-time = "2026-04-02T21:34:57.679Z" },
{ url = "https://files.pythonhosted.org/packages/80/82/abdfb27ab988e6bd09502a4573f64a7e72db3e83acd7886af54448703c97/ty-0.0.28-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e5f13d10b3436bee3ea35851e5af400123f6693bfae48294ddfbbf553fa51ef", size = 10399528, upload-time = "2026-04-02T21:34:51.398Z" },
{ url = "https://files.pythonhosted.org/packages/ba/74/3ccbe468e8480ba53f83a1e52481d3e11756415f0ca1297fb2da65e29612/ty-0.0.28-py3-none-musllinux_1_2_i686.whl", hash = "sha256:759db467e399faedc7d5f1ca4b383dd8ecc71d7d79b2ca6ea6db4ac8e643378a", size = 10586771, upload-time = "2026-04-02T21:34:35.912Z" },
{ url = "https://files.pythonhosted.org/packages/ee/79/545c76dcef0c3f89fb733ec46118aed2a700e79d4e22cb142e3b5a80286c/ty-0.0.28-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0cd44e3c857951cbf3f8647722ca87475614fac8ac0371eb1f200a942315a2c2", size = 11110550, upload-time = "2026-04-02T21:34:55.65Z" },
{ url = "https://files.pythonhosted.org/packages/2c/e4/e3c6f71c95a2cbabd7d88fd698b00b8af48e39aa10e0b10b839410fc3c6d/ty-0.0.28-py3-none-win32.whl", hash = "sha256:88e2c784ec5e0e2fb01b137d92fd595cdc27b98a553f4bb34b8bf138bac1be1e", size = 9985411, upload-time = "2026-04-02T21:34:44.763Z" },
{ url = "https://files.pythonhosted.org/packages/8c/e5/79dbab4856d3d15e5173314ff1846be65d58b31de6efe62ef1c25c663b32/ty-0.0.28-py3-none-win_amd64.whl", hash = "sha256:faaffbef127cb67560ad6dbc6a8f8845a4033b818bcc78ad7af923e02df199db", size = 10986548, upload-time = "2026-04-02T21:34:59.886Z" },
{ url = "https://files.pythonhosted.org/packages/01/b2/cc987aaf5babacc55caf0aeb751c83401e86e05e22ce82dace5a7e7e5354/ty-0.0.28-py3-none-win_arm64.whl", hash = "sha256:34a18ea09ee09612fb6555deccf1eed810e6f770b61a41243b494bcb7f624a1c", size = 10388573, upload-time = "2026-04-02T21:34:29.219Z" },
]
[[package]]