From 5e55c0df54f8f6fc3bda632176bb8000758be815 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Mon, 19 Jan 2026 15:50:14 +0200 Subject: [PATCH 1/3] replace pyright with ty type checker --- .github/workflows/test.yml | 2 +- .pre-commit-config.yaml | 10 +++-- CHANGELOG.md | 6 +++ app/backend/main.py | 2 +- evaluations/evaluations/datasets/hotpotqa.py | 6 +-- evaluations/evaluations/datasets/repliqa.py | 8 ++-- evaluations/evaluations/datasets/wix.py | 12 +++--- evaluations/evaluations/evaluators/judge.py | 2 +- haiku_rag_slim/haiku/rag/agents/qa/agent.py | 7 ++-- .../haiku/rag/agents/research/graph.py | 13 +++--- haiku_rag_slim/haiku/rag/app.py | 2 +- haiku_rag_slim/haiku/rag/chat/app.py | 2 +- haiku_rag_slim/haiku/rag/inspector/app.py | 2 +- haiku_rag_slim/haiku/rag/store/engine.py | 4 +- haiku_rag_slim/haiku/rag/utils.py | 4 +- pyproject.toml | 12 +++--- tests/agents/chat/test_chat_agent.py | 2 +- tests/conftest.py | 6 +-- tests/test_client.py | 2 +- tests/test_mcp.py | 32 +++++--------- tests/test_rebuild.py | 2 +- tests/test_search.py | 4 +- tests/test_versioning.py | 10 ++--- uv.lock | 42 ++++++++++++------- 24 files changed, 104 insertions(+), 90 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79a9ed52..eac409f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: - name: Lint run: uv run ruff check - name: Type check - run: uv run pyright + run: uv run ty check lint-frontend: runs-on: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 46a4d4a1..8261b617 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,10 +16,14 @@ repos: # Run the formatter. - id: ruff-format - - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.407 + - repo: local hooks: - - id: pyright + - id: ty + name: ty check + entry: uvx ty check + language: system + types: [python] + pass_filenames: false - repo: local hooks: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d056a5c..393fa96c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog ## [Unreleased] +### Changed + +- **Type Checker**: Replaced pyright with [ty](https://github.com/astral-sh/ty), Astral's extremely fast Python type checker + - Added explicit `Agent[Deps, Output]` type annotations to all pydantic-ai agents for better type inference + - Removed ~24 unnecessary `# type: ignore` comments that ty correctly infers + ## [0.26.6] - 2026-01-19 ### Changed diff --git a/app/backend/main.py b/app/backend/main.py index e8c4309a..6288f75e 100644 --- a/app/backend/main.py +++ b/app/backend/main.py @@ -226,7 +226,7 @@ app = Starlette( ], middleware=[ Middleware( - CORSMiddleware, + CORSMiddleware, # type: ignore[invalid-argument-type] allow_origins=["http://localhost:3000", "http://frontend:3000"], allow_credentials=True, allow_methods=["*"], diff --git a/evaluations/evaluations/datasets/hotpotqa.py b/evaluations/evaluations/datasets/hotpotqa.py index 2f0a9b1c..d47f939e 100644 --- a/evaluations/evaluations/datasets/hotpotqa.py +++ b/evaluations/evaluations/datasets/hotpotqa.py @@ -1,7 +1,7 @@ from collections.abc import Mapping from typing import Any, cast -from datasets import Dataset, DatasetDict, load_dataset +from datasets import Dataset, load_dataset from pydantic_evals import Case from evaluations.config import DatasetSpec, DocumentPayload, RetrievalSample @@ -9,8 +9,8 @@ from evaluations.evaluators import MAPEvaluator def load_hotpotqa_validation() -> Dataset: - dataset_dict = cast(DatasetDict, load_dataset("hotpotqa/hotpot_qa", "distractor")) - return cast(Dataset, dataset_dict["validation"]) + dataset_dict = load_dataset("hotpotqa/hotpot_qa", "distractor") + return dataset_dict["validation"] def extract_unique_documents(dataset: Dataset) -> list[dict[str, Any]]: diff --git a/evaluations/evaluations/datasets/repliqa.py b/evaluations/evaluations/datasets/repliqa.py index 16ef964e..ba6a1ec8 100644 --- a/evaluations/evaluations/datasets/repliqa.py +++ b/evaluations/evaluations/datasets/repliqa.py @@ -1,7 +1,7 @@ from collections.abc import Mapping -from typing import Any, cast +from typing import Any -from datasets import Dataset, DatasetDict, load_dataset +from datasets import Dataset, load_dataset from pydantic_evals import Case from evaluations.config import DatasetSpec, DocumentPayload, RetrievalSample @@ -9,8 +9,8 @@ from evaluations.evaluators import MRREvaluator def load_repliqa_corpus() -> Dataset: - dataset_dict = cast(DatasetDict, load_dataset("ServiceNow/repliqa")) - dataset = cast(Dataset, dataset_dict["repliqa_3"]) + dataset_dict = load_dataset("ServiceNow/repliqa") + dataset = dataset_dict["repliqa_3"] return dataset.filter(lambda doc: doc["document_topic"] == "News Stories") diff --git a/evaluations/evaluations/datasets/wix.py b/evaluations/evaluations/datasets/wix.py index c6f01c3f..7e81fb8f 100644 --- a/evaluations/evaluations/datasets/wix.py +++ b/evaluations/evaluations/datasets/wix.py @@ -1,8 +1,8 @@ import json from collections.abc import Iterable, Mapping -from typing import Any, cast +from typing import Any -from datasets import Dataset, DatasetDict, load_dataset +from datasets import Dataset, load_dataset from pydantic_evals import Case from evaluations.config import DatasetSpec, DocumentPayload, RetrievalSample @@ -10,8 +10,8 @@ from evaluations.evaluators import MAPEvaluator def load_wix_corpus() -> Dataset: - dataset_dict = cast(DatasetDict, load_dataset("Wix/WixQA", "wix_kb_corpus")) - return cast(Dataset, dataset_dict["train"]) + dataset_dict = load_dataset("Wix/WixQA", "wix_kb_corpus") + return dataset_dict["train"] def map_wix_document(doc: Mapping[str, Any]) -> DocumentPayload: @@ -35,8 +35,8 @@ def map_wix_document(doc: Mapping[str, Any]) -> DocumentPayload: def load_wix_qa() -> Dataset: - dataset_dict = cast(DatasetDict, load_dataset("Wix/WixQA", "wixqa_expertwritten")) - return cast(Dataset, dataset_dict["train"]) + dataset_dict = load_dataset("Wix/WixQA", "wixqa_expertwritten") + return dataset_dict["train"] def map_wix_retrieval(doc: Mapping[str, Any]) -> RetrievalSample | None: diff --git a/evaluations/evaluations/evaluators/judge.py b/evaluations/evaluations/evaluators/judge.py index e2b020ad..df471484 100644 --- a/evaluations/evaluations/evaluators/judge.py +++ b/evaluations/evaluations/evaluators/judge.py @@ -40,7 +40,7 @@ class LLMJudge: model_obj = get_model(model_config, config) # Create Pydantic AI agent - self._agent = Agent( + self._agent: Agent[None, LLMJudgeResponseSchema] = Agent( model=model_obj, output_type=LLMJudgeResponseSchema, system_prompt=ANSWER_EQUIVALENCE_RUBRIC, diff --git a/haiku_rag_slim/haiku/rag/agents/qa/agent.py b/haiku_rag_slim/haiku/rag/agents/qa/agent.py index d2b5194b..18be8a77 100644 --- a/haiku_rag_slim/haiku/rag/agents/qa/agent.py +++ b/haiku_rag_slim/haiku/rag/agents/qa/agent.py @@ -32,7 +32,7 @@ class QuestionAnswerAgent: self._client = client model_obj = get_model(model_config, config) - self._agent = Agent( + self._agent: Agent[Dependencies, RawSearchAnswer] = Agent( model=model_obj, deps_type=Dependencies, output_type=ToolOutput(RawSearchAnswer, max_retries=3), @@ -75,5 +75,6 @@ class QuestionAnswerAgent: """ deps = Dependencies(client=self._client, search_filter=filter) result = await self._agent.run(question, deps=deps) - citations = resolve_citations(result.output.cited_chunks, deps.search_results) - return result.output.answer, citations + output = result.output + citations = resolve_citations(output.cited_chunks, deps.search_results) + return output.answer, citations diff --git a/haiku_rag_slim/haiku/rag/agents/research/graph.py b/haiku_rag_slim/haiku/rag/agents/research/graph.py index 8023ba52..13e958f9 100644 --- a/haiku_rag_slim/haiku/rag/agents/research/graph.py +++ b/haiku_rag_slim/haiku/rag/agents/research/graph.py @@ -105,7 +105,7 @@ async def _plan_step_logic( else plan_prompt ) - plan_agent = Agent( + plan_agent: Agent[ResearchDependencies, ResearchPlan] = Agent( model=get_model(model_config, config), output_type=ResearchPlan, instructions=effective_plan_prompt, @@ -151,7 +151,8 @@ async def _plan_step_logic( agent_deps = ResearchDependencies(client=deps.client, context=state.context) plan_result = await plan_agent.run(prompt, deps=agent_deps) - state.context.sub_questions = list(plan_result.output.sub_questions) + output = plan_result.output + state.context.sub_questions = list(output.sub_questions) async def _search_one_step_logic( @@ -168,7 +169,7 @@ async def _search_one_step_logic( deps.semaphore = asyncio.Semaphore(state.max_concurrency) async with deps.semaphore: - agent = Agent( + agent: Agent[ResearchDependencies, RawSearchAnswer] = Agent( model=get_model(model_config, config), output_type=ToolOutput(RawSearchAnswer, max_retries=3), instructions=search_prompt, @@ -289,7 +290,7 @@ def build_research_graph( state = ctx.state deps = ctx.deps - agent = Agent( + agent: Agent[ResearchDependencies, EvaluationResult] = Agent( model=get_model(model_config, config), output_type=EvaluationResult, instructions=decision_prompt, @@ -350,7 +351,7 @@ def build_research_graph( state = ctx.state deps = ctx.deps - agent = Agent( + agent: Agent[ResearchDependencies, ResearchReport] = Agent( model=get_model(model_config, config), output_type=ResearchReport, instructions=synthesis_prompt, @@ -488,7 +489,7 @@ def build_conversational_graph( state = ctx.state deps = ctx.deps - agent = Agent( + agent: Agent[ResearchDependencies, ConversationalAnswer] = Agent( model=get_model(config.research.model, config), output_type=ConversationalAnswer, instructions=conversational_prompt, diff --git a/haiku_rag_slim/haiku/rag/app.py b/haiku_rag_slim/haiku/rag/app.py index 48a31a44..ece96e40 100644 --- a/haiku_rag_slim/haiku/rag/app.py +++ b/haiku_rag_slim/haiku/rag/app.py @@ -494,7 +494,7 @@ class HaikuRAGApp: # Confidence (from last evaluation) if state.last_eval: - conf = state.last_eval.confidence_score # type: ignore[attr-defined] + conf = state.last_eval.confidence_score self.console.print(f"[bold cyan]Confidence:[/bold cyan] {conf:.1%}") self.console.print() diff --git a/haiku_rag_slim/haiku/rag/chat/app.py b/haiku_rag_slim/haiku/rag/chat/app.py index 24365fb4..c4fa7f9a 100644 --- a/haiku_rag_slim/haiku/rag/chat/app.py +++ b/haiku_rag_slim/haiku/rag/chat/app.py @@ -51,7 +51,7 @@ except ImportError: App = object # type: ignore -class ChatApp(App): # type: ignore[misc] +class ChatApp(App): """Textual TUI for conversational RAG.""" TITLE = "haiku.rag Chat" diff --git a/haiku_rag_slim/haiku/rag/inspector/app.py b/haiku_rag_slim/haiku/rag/inspector/app.py index fd1b761d..67c45dda 100644 --- a/haiku_rag_slim/haiku/rag/inspector/app.py +++ b/haiku_rag_slim/haiku/rag/inspector/app.py @@ -26,7 +26,7 @@ except ImportError: App = object # type: ignore -class InspectorApp(App): # type: ignore[misc] # pragma: no cover +class InspectorApp(App): # pragma: no cover """Textual TUI for inspecting LanceDB data.""" TITLE = "haiku.rag DB Inspector" diff --git a/haiku_rag_slim/haiku/rag/store/engine.py b/haiku_rag_slim/haiku/rag/store/engine.py index f89acd4e..305271cd 100644 --- a/haiku_rag_slim/haiku/rag/store/engine.py +++ b/haiku_rag_slim/haiku/rag/store/engine.py @@ -258,7 +258,7 @@ class Store: } # Documents table stats - doc_stats: dict = self.documents_table.stats() # type: ignore[assignment] + doc_stats: dict = self.documents_table.stats() stats_dict["documents"] = { "exists": True, "num_rows": doc_stats.get("num_rows", 0), @@ -266,7 +266,7 @@ class Store: } # Chunks table stats - chunk_stats: dict = self.chunks_table.stats() # type: ignore[assignment] + chunk_stats: dict = self.chunks_table.stats() stats_dict["chunks"] = { "exists": True, "num_rows": chunk_stats.get("num_rows", 0), diff --git a/haiku_rag_slim/haiku/rag/utils.py b/haiku_rag_slim/haiku/rag/utils.py index 49424643..f51770f7 100644 --- a/haiku_rag_slim/haiku/rag/utils.py +++ b/haiku_rag_slim/haiku/rag/utils.py @@ -185,11 +185,11 @@ def get_model( if model_config.enable_thinking is not None: if model_config.enable_thinking: anthropic_settings = AnthropicModelSettings( - anthropic_thinking={"type": "enabled", "budget_tokens": 4096} + anthropic_thinking={"type": "enabled", "budget_tokens": 4096} # ty: ignore[invalid-argument-type] ) else: anthropic_settings = AnthropicModelSettings( - anthropic_thinking={"type": "disabled"} + anthropic_thinking={"type": "disabled"} # ty: ignore[invalid-argument-type] ) anthropic_settings = apply_common_settings( diff --git a/pyproject.toml b/pyproject.toml index 816ddf80..c107078e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ dev = [ "pydantic-ai-slim[bedrock]", "pydantic-ai-slim[google]", "pydantic-ai-slim[groq]", - "pyright>=1.1.408", + "ty>=0.0.1a17", "pytest>=9.0.2", "pytest-asyncio>=1.3.0", "pytest-cov>=7.0.0", @@ -110,10 +110,12 @@ indent-style = "space" skip-magic-trailing-comma = false line-ending = "auto" -[tool.pyright] -venvPath = "." -venv = ".venv" -pythonVersion = "3.12" +[tool.ty.src] +exclude = ["examples/**"] + +[tool.ty.environment] +python-version = "3.12" +python = ".venv" [tool.pytest.ini_options] asyncio_default_fixture_loop_scope = "session" diff --git a/tests/agents/chat/test_chat_agent.py b/tests/agents/chat/test_chat_agent.py index 2592002c..0dba3637 100644 --- a/tests/agents/chat/test_chat_agent.py +++ b/tests/agents/chat/test_chat_agent.py @@ -83,7 +83,7 @@ def test_chat_agent_has_dynamic_system_prompt(): # (the add_background_context function) assert len(agent._system_prompt_functions) >= 1 # Verify it's the add_background_context function - func_names = [r.function.__name__ for r in agent._system_prompt_functions] + func_names = [r.function.__name__ for r in agent._system_prompt_functions] # ty: ignore[unresolved-attribute] assert "add_background_context" in func_names diff --git a/tests/conftest.py b/tests/conftest.py index 796745bd..c92956b4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,7 +26,7 @@ from datasets import Dataset, load_dataset, load_from_disk # noqa: E402 if TYPE_CHECKING: from vcr import VCR -pydantic_ai.models.ALLOW_MODEL_REQUESTS = False +pydantic_ai.models.ALLOW_MODEL_REQUESTS = False # ty: ignore[invalid-assignment] logging.getLogger("vcr.cassette").setLevel(logging.WARNING) @@ -35,10 +35,10 @@ def qa_corpus() -> Dataset: ds_path = Path(__file__).parent / "data" / "dataset" ds_path.mkdir(parents=True, exist_ok=True) try: - ds: Dataset = load_from_disk(ds_path) # type: ignore + ds: Dataset = load_from_disk(ds_path) # ty: ignore[invalid-assignment] return ds except FileNotFoundError: - ds: Dataset = load_dataset("ServiceNow/repliqa")["repliqa_3"] # type: ignore + ds: Dataset = load_dataset("ServiceNow/repliqa")["repliqa_3"] corpus = ds.filter(lambda doc: doc["document_topic"] == "News Stories") corpus.save_to_disk(ds_path) return corpus diff --git a/tests/test_client.py b/tests/test_client.py index b4099636..198c0b30 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -58,7 +58,7 @@ async def test_client_document_crud(qa_corpus: Dataset, temp_db_path): # Test update_document updated_doc = await client.update_document( - document_id=retrieved_doc.id, # type: ignore[arg-type] + document_id=retrieved_doc.id, content="Updated content", ) assert updated_doc.content == "Updated content" diff --git a/tests/test_mcp.py b/tests/test_mcp.py index cae8c528..dee34e18 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -30,8 +30,7 @@ async def test_mcp_add_document_from_file(): t for t in tools.values() if t.name == "add_document_from_file" ) - result = await add_file_tool.fn(file_path="/test.txt") # type: ignore[attr-defined] - + result = await add_file_tool.fn(file_path="/test.txt") assert result == "doc123" mock_rag.create_document_from_source.assert_called_once() @@ -52,9 +51,7 @@ async def test_mcp_ask_question(): tools = await mcp.get_tools() ask_tool = next(t for t in tools.values() if t.name == "ask_question") - result = await ask_tool.fn( # type: ignore[attr-defined] - question="What is this?", cite=False, deep=False - ) + result = await ask_tool.fn(question="What is this?", cite=False, deep=False) assert result == "This is the answer" mock_rag.ask.assert_called_once_with("What is this?") @@ -81,8 +78,7 @@ async def test_mcp_add_document_from_url(): t for t in tools.values() if t.name == "add_document_from_url" ) - result = await add_url_tool.fn(url="https://example.com") # type: ignore[attr-defined] - + result = await add_url_tool.fn(url="https://example.com") assert result == "doc456" mock_rag.create_document_from_source.assert_called_once() @@ -108,9 +104,7 @@ async def test_mcp_add_document_from_text(): t for t in tools.values() if t.name == "add_document_from_text" ) - result = await add_text_tool.fn( # type: ignore[attr-defined] - content="test content", uri="text://test" - ) + result = await add_text_tool.fn(content="test content", uri="text://test") assert result == "doc789" mock_rag.create_document.assert_called_once() @@ -141,8 +135,7 @@ async def test_mcp_search_documents(): t for t in tools.values() if t.name == "search_documents" ) - result = await search_tool.fn(query="test query", limit=5) # type: ignore[attr-defined] - + result = await search_tool.fn(query="test query", limit=5) assert len(result) == 2 assert result[0].document_id == "doc1" assert result[0].content == "Result 1" @@ -174,8 +167,7 @@ async def test_mcp_get_document(): tools = await mcp.get_tools() get_tool = next(t for t in tools.values() if t.name == "get_document") - result = await get_tool.fn(document_id="doc123") # type: ignore[attr-defined] - + result = await get_tool.fn(document_id="doc123") assert result is not None assert result.id == "doc123" assert result.content == "test" @@ -211,8 +203,7 @@ async def test_mcp_list_documents(): tools = await mcp.get_tools() list_tool = next(t for t in tools.values() if t.name == "list_documents") - result = await list_tool.fn(limit=10, offset=0) # type: ignore[attr-defined] - + result = await list_tool.fn(limit=10, offset=0) assert len(result) == 2 assert result[0].id == "doc1" assert result[1].id == "doc2" @@ -235,8 +226,7 @@ async def test_mcp_delete_document(): tools = await mcp.get_tools() delete_tool = next(t for t in tools.values() if t.name == "delete_document") - result = await delete_tool.fn(document_id="doc123") # type: ignore[attr-defined] - + result = await delete_tool.fn(document_id="doc123") assert result is True mock_rag.delete_document.assert_called_once_with("doc123") @@ -268,9 +258,7 @@ async def test_mcp_ask_question_deep(): ask_tool = next(t for t in tools.values() if t.name == "ask_question") # cite=False to avoid citation formatting in output - result = await ask_tool.fn( # type: ignore[attr-defined] - question="Deep question?", cite=False, deep=True - ) + result = await ask_tool.fn(question="Deep question?", cite=False, deep=True) assert result == "Deep answer from research" mock_graph.run.assert_called_once() @@ -311,7 +299,7 @@ async def test_mcp_research_question(): t for t in tools.values() if t.name == "research_question" ) - result = await research_tool.fn( # type: ignore[attr-defined] + result = await research_tool.fn( question="Research question?", ) diff --git a/tests/test_rebuild.py b/tests/test_rebuild.py index 2e33e962..6dfa0b90 100644 --- a/tests/test_rebuild.py +++ b/tests/test_rebuild.py @@ -167,7 +167,7 @@ async def test_rebuild_embed_only_with_changed_vector_dim( content=c["content"], content_fts=c["content_fts"], metadata=c["metadata"], - order=c["order"], + order=c["order"], # ty: ignore[invalid-argument-type] vector=[0.1] * 4096, ) for c in chunk_data diff --git a/tests/test_search.py b/tests/test_search.py index ff81b4da..c302d25e 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -19,8 +19,8 @@ async def test_search_qa_corpus(qa_corpus: Dataset, temp_db_path): for doc_data in qa_corpus: if len(seen_documents) >= 10: break - document_text = doc_data["document_extracted"] # type: ignore - document_id = doc_data.get("document_id", "") # type: ignore + document_text = doc_data["document_extracted"] + document_id = doc_data.get("document_id", "") if document_id in seen_documents: continue diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 2a302a61..2e7be9f6 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -14,7 +14,7 @@ async def test_version_rollback_on_create_failure(temp_db_path): await orig_create(chunks) raise RuntimeError("boom") - client.chunk_repository.create = succeed_then_fail # type: ignore[method-assign] + client.chunk_repository.create = succeed_then_fail # Attempt to create document; expect failure and rollback content = "Hello, rollback!" @@ -43,20 +43,20 @@ async def test_version_rollback_on_update_failure(temp_db_path): await orig_create(chunks) raise RuntimeError("update fail") - client.chunk_repository.create = succeed_then_fail # type: ignore[method-assign] + client.chunk_repository.create = succeed_then_fail # Attempt update with pytest.raises(RuntimeError): await client.update_document( - document_id=created.id, # type: ignore[arg-type] + document_id=created.id, content="Updated content", ) # Content and chunks should remain the original - persisted = await client.get_document_by_id(created.id) # type: ignore[arg-type] + persisted = await client.get_document_by_id(created.id) assert persisted is not None assert persisted.content == base_content - original_chunks = await client.chunk_repository.get_by_document_id(created.id) # type: ignore[arg-type] + original_chunks = await client.chunk_repository.get_by_document_id(created.id) assert len(original_chunks) > 0 diff --git a/uv.lock b/uv.lock index 79879e9e..c94f642e 100644 --- a/uv.lock +++ b/uv.lock @@ -1304,12 +1304,12 @@ dev = [ { name = "mkdocs-material" }, { name = "pre-commit" }, { name = "pydantic-ai-slim", extra = ["anthropic", "bedrock", "google", "groq"] }, - { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-recording" }, { name = "ruff" }, + { name = "ty" }, ] [package.metadata] @@ -1330,12 +1330,12 @@ dev = [ { name = "pydantic-ai-slim", extras = ["bedrock"] }, { name = "pydantic-ai-slim", extras = ["google"] }, { name = "pydantic-ai-slim", extras = ["groq"] }, - { name = "pyright", specifier = ">=1.1.408" }, { name = "pytest", specifier = ">=9.0.2" }, { name = "pytest-asyncio", specifier = ">=1.3.0" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-recording", specifier = ">=0.13.4" }, { name = "ruff", specifier = ">=0.14.11" }, + { name = "ty", specifier = ">=0.0.1a17" }, ] [[package]] @@ -3843,19 +3843,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" }, ] -[[package]] -name = "pyright" -version = "1.1.408" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, -] - [[package]] name = "pytest" version = "9.0.2" @@ -4992,6 +4979,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/b5/b0d3d8b901b6a04ca38df5e24c27e53afb15b93624d7fd7d658c7cd9352a/triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478", size = 170582192, upload-time = "2025-11-11T17:41:23.963Z" }, ] +[[package]] +name = "ty" +version = "0.0.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/78/ba1a4ad403c748fbba8be63b7e774a90e80b67192f6443d624c64fe4aaab/ty-0.0.12.tar.gz", hash = "sha256:cd01810e106c3b652a01b8f784dd21741de9fdc47bd595d02c122a7d5cefeee7", size = 4981303, upload-time = "2026-01-14T22:30:48.537Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/8f/c21314d074dda5fb13d3300fa6733fd0d8ff23ea83a721818740665b6314/ty-0.0.12-py3-none-linux_armv6l.whl", hash = "sha256:eb9da1e2c68bd754e090eab39ed65edf95168d36cbeb43ff2bd9f86b4edd56d1", size = 9614164, upload-time = "2026-01-14T22:30:44.016Z" }, + { url = "https://files.pythonhosted.org/packages/09/28/f8a4d944d13519d70c486e8f96d6fa95647ac2aa94432e97d5cfec1f42f6/ty-0.0.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c181f42aa19b0ed7f1b0c2d559980b1f1d77cc09419f51c8321c7ddf67758853", size = 9542337, upload-time = "2026-01-14T22:30:05.687Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9c/f576e360441de7a8201daa6dc4ebc362853bc5305e059cceeb02ebdd9a48/ty-0.0.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1f829e1eecd39c3e1b032149db7ae6a3284f72fc36b42436e65243a9ed1173db", size = 8909582, upload-time = "2026-01-14T22:30:46.089Z" }, + { url = "https://files.pythonhosted.org/packages/d6/13/0898e494032a5d8af3060733d12929e3e7716db6c75eac63fa125730a3e7/ty-0.0.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45162e7826e1789cf3374627883cdeb0d56b82473a0771923e4572928e90be3", size = 9384932, upload-time = "2026-01-14T22:30:13.769Z" }, + { url = "https://files.pythonhosted.org/packages/e4/1a/b35b6c697008a11d4cedfd34d9672db2f0a0621ec80ece109e13fca4dfef/ty-0.0.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d11fec40b269bec01e751b2337d1c7ffa959a2c2090a950d7e21c2792442cccd", size = 9453140, upload-time = "2026-01-14T22:30:11.131Z" }, + { url = "https://files.pythonhosted.org/packages/dd/1e/71c9edbc79a3c88a0711324458f29c7dbf6c23452c6e760dc25725483064/ty-0.0.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09d99e37e761a4d2651ad9d5a610d11235fbcbf35dc6d4bc04abf54e7cf894f1", size = 9960680, upload-time = "2026-01-14T22:30:33.621Z" }, + { url = "https://files.pythonhosted.org/packages/0e/75/39375129f62dd22f6ad5a99cd2a42fd27d8b91b235ce2db86875cdad397d/ty-0.0.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d9ca0cdb17bd37397da7b16a7cd23423fc65c3f9691e453ad46c723d121225a1", size = 10904518, upload-time = "2026-01-14T22:30:08.464Z" }, + { url = "https://files.pythonhosted.org/packages/32/5e/26c6d88fafa11a9d31ca9f4d12989f57782ec61e7291d4802d685b5be118/ty-0.0.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcf2757b905e7eddb7e456140066335b18eb68b634a9f72d6f54a427ab042c64", size = 10525001, upload-time = "2026-01-14T22:30:16.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a5/2f0b91894af13187110f9ad7ee926d86e4e6efa755c9c88a820ed7f84c85/ty-0.0.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00cf34c1ebe1147efeda3021a1064baa222c18cdac114b7b050bbe42deb4ca80", size = 10307103, upload-time = "2026-01-14T22:30:41.221Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/13d0410827e4bc713ebb7fdaf6b3590b37dcb1b82e0a81717b65548f2442/ty-0.0.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb3a655bd869352e9a22938d707631ac9fbca1016242b1f6d132d78f347c851", size = 10072737, upload-time = "2026-01-14T22:30:51.783Z" }, + { url = "https://files.pythonhosted.org/packages/e1/dd/fc36d8bac806c74cf04b4ca735bca14d19967ca84d88f31e121767880df1/ty-0.0.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4658e282c7cb82be304052f8f64f9925f23c3c4f90eeeb32663c74c4b095d7ba", size = 9368726, upload-time = "2026-01-14T22:30:18.683Z" }, + { url = "https://files.pythonhosted.org/packages/54/70/9e8e461647550f83e2fe54bc632ccbdc17a4909644783cdbdd17f7296059/ty-0.0.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c167d838eaaa06e03bb66a517f75296b643d950fbd93c1d1686a187e5a8dbd1f", size = 9454704, upload-time = "2026-01-14T22:30:22.759Z" }, + { url = "https://files.pythonhosted.org/packages/04/9b/6292cf7c14a0efeca0539cf7d78f453beff0475cb039fbea0eb5d07d343d/ty-0.0.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2956e0c9ab7023533b461d8a0e6b2ea7b78e01a8dde0688e8234d0fce10c4c1c", size = 9649829, upload-time = "2026-01-14T22:30:31.234Z" }, + { url = "https://files.pythonhosted.org/packages/49/bd/472a5d2013371e4870886cff791c94abdf0b92d43d305dd0f8e06b6ff719/ty-0.0.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c6a3fd7479580009f21002f3828320621d8a82d53b7ba36993234e3ccad58c8", size = 10162814, upload-time = "2026-01-14T22:30:36.174Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/2ecbe56826759845a7c21d80aa28187865ea62bc9757b056f6cbc06f78ed/ty-0.0.12-py3-none-win32.whl", hash = "sha256:a91c24fd75c0f1796d8ede9083e2c0ec96f106dbda73a09fe3135e075d31f742", size = 9140115, upload-time = "2026-01-14T22:30:38.903Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/d9531eff35a5c0ec9dbc10231fac21f9dd6504814048e81d6ce1c84dc566/ty-0.0.12-py3-none-win_amd64.whl", hash = "sha256:df151894be55c22d47068b0f3b484aff9e638761e2267e115d515fcc9c5b4a4b", size = 9884532, upload-time = "2026-01-14T22:30:25.112Z" }, + { url = "https://files.pythonhosted.org/packages/e9/f3/20b49e75967023b123a221134548ad7000f9429f13fdcdda115b4c26305f/ty-0.0.12-py3-none-win_arm64.whl", hash = "sha256:cea99d334b05629de937ce52f43278acf155d3a316ad6a35356635f886be20ea", size = 9313974, upload-time = "2026-01-14T22:30:27.44Z" }, +] + [[package]] name = "typer" version = "0.19.2" From f05159859cf2320763751891be67e4e912cf91a2 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Mon, 19 Jan 2026 16:00:18 +0200 Subject: [PATCH 2/3] Additional fixes to remove type ignores --- haiku_rag_slim/haiku/rag/utils.py | 15 ++++++++++++-- tests/agents/chat/test_chat_agent.py | 5 +++-- tests/conftest.py | 7 +++---- tests/test_rebuild.py | 31 +++++++++++++++++++--------- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/haiku_rag_slim/haiku/rag/utils.py b/haiku_rag_slim/haiku/rag/utils.py index f51770f7..b038dde0 100644 --- a/haiku_rag_slim/haiku/rag/utils.py +++ b/haiku_rag_slim/haiku/rag/utils.py @@ -177,6 +177,10 @@ def get_model( return OpenAIChatModel(model_name=model, settings=openai_settings) elif provider == "anthropic": + from anthropic.types.beta import ( + BetaThinkingConfigDisabledParam, + BetaThinkingConfigEnabledParam, + ) from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelSettings anthropic_settings: Any = None @@ -184,12 +188,19 @@ def get_model( # Apply thinking control if model_config.enable_thinking is not None: if model_config.enable_thinking: + thinking_config: BetaThinkingConfigEnabledParam = { + "type": "enabled", + "budget_tokens": 4096, + } anthropic_settings = AnthropicModelSettings( - anthropic_thinking={"type": "enabled", "budget_tokens": 4096} # ty: ignore[invalid-argument-type] + anthropic_thinking=thinking_config ) else: + thinking_disabled: BetaThinkingConfigDisabledParam = { + "type": "disabled" + } anthropic_settings = AnthropicModelSettings( - anthropic_thinking={"type": "disabled"} # ty: ignore[invalid-argument-type] + anthropic_thinking=thinking_disabled ) anthropic_settings = apply_common_settings( diff --git a/tests/agents/chat/test_chat_agent.py b/tests/agents/chat/test_chat_agent.py index 0dba3637..392ced22 100644 --- a/tests/agents/chat/test_chat_agent.py +++ b/tests/agents/chat/test_chat_agent.py @@ -81,9 +81,10 @@ def test_chat_agent_has_dynamic_system_prompt(): agent = create_chat_agent(Config) # The agent should have at least one system prompt function registered # (the add_background_context function) - assert len(agent._system_prompt_functions) >= 1 + system_prompt_functions = getattr(agent, "_system_prompt_functions") + assert len(system_prompt_functions) >= 1 # Verify it's the add_background_context function - func_names = [r.function.__name__ for r in agent._system_prompt_functions] # ty: ignore[unresolved-attribute] + func_names = [r.function.__name__ for r in system_prompt_functions] assert "add_background_context" in func_names diff --git a/tests/conftest.py b/tests/conftest.py index c92956b4..5362a6cf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ import logging import os import tempfile from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast # Prevent tests from loading user's local haiku.rag.yaml by setting env var # to a test config file BEFORE any haiku.rag imports. @@ -26,7 +26,7 @@ from datasets import Dataset, load_dataset, load_from_disk # noqa: E402 if TYPE_CHECKING: from vcr import VCR -pydantic_ai.models.ALLOW_MODEL_REQUESTS = False # ty: ignore[invalid-assignment] +setattr(pydantic_ai.models, "ALLOW_MODEL_REQUESTS", False) logging.getLogger("vcr.cassette").setLevel(logging.WARNING) @@ -35,8 +35,7 @@ def qa_corpus() -> Dataset: ds_path = Path(__file__).parent / "data" / "dataset" ds_path.mkdir(parents=True, exist_ok=True) try: - ds: Dataset = load_from_disk(ds_path) # ty: ignore[invalid-assignment] - return ds + return cast(Dataset, load_from_disk(ds_path)) except FileNotFoundError: ds: Dataset = load_dataset("ServiceNow/repliqa")["repliqa_3"] corpus = ds.filter(lambda doc: doc["document_topic"] == "News Stories") diff --git a/tests/test_rebuild.py b/tests/test_rebuild.py index 6dfa0b90..43e56304 100644 --- a/tests/test_rebuild.py +++ b/tests/test_rebuild.py @@ -1,9 +1,20 @@ +from typing import TypedDict + import pytest from datasets import Dataset from haiku.rag.client import HaikuRAG, RebuildMode +class ChunkData(TypedDict): + id: str + document_id: str + content: str + content_fts: str + metadata: str + order: int + + @pytest.mark.vcr() async def test_rebuild_full(qa_corpus: Dataset, temp_db_path): """Test full rebuild: converts, chunks, and embeds all documents.""" @@ -132,15 +143,15 @@ async def test_rebuild_embed_only_with_changed_vector_dim( chunks_before = await client.chunk_repository.get_by_document_id(doc.id) assert len(chunks_before) > 0 - chunk_data = [ - { - "id": c.id, - "document_id": c.document_id, - "content": c.content, - "content_fts": c.content, - "metadata": json.dumps(c.metadata), - "order": c.order, - } + chunk_data: list[ChunkData] = [ + ChunkData( + id=c.id or "", + document_id=c.document_id or "", + content=c.content, + content_fts=c.content, + metadata=json.dumps(c.metadata), + order=c.order, + ) for c in chunks_before ] @@ -167,7 +178,7 @@ async def test_rebuild_embed_only_with_changed_vector_dim( content=c["content"], content_fts=c["content_fts"], metadata=c["metadata"], - order=c["order"], # ty: ignore[invalid-argument-type] + order=c["order"], vector=[0.1] * 4096, ) for c in chunk_data From 1022d5dafdd42b02c70b3ec0848d1d7d6ec1f446 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Mon, 19 Jan 2026 16:23:26 +0200 Subject: [PATCH 3/3] Update dependencies --- CHANGELOG.md | 8 ++ evaluations/pyproject.toml | 4 +- haiku_rag_slim/haiku/rag/monitor.py | 5 +- haiku_rag_slim/pyproject.toml | 8 +- pyproject.toml | 6 +- uv.lock | 119 ++++++++++++++-------------- 6 files changed, 79 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 393fa96c..11441fc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ - **Type Checker**: Replaced pyright with [ty](https://github.com/astral-sh/ty), Astral's extremely fast Python type checker - Added explicit `Agent[Deps, Output]` type annotations to all pydantic-ai agents for better type inference - Removed ~24 unnecessary `# type: ignore` comments that ty correctly infers +- **Dependencies**: Updated to latest versions + - `pydantic-ai-slim`: 1.39.0 → 1.44.0 + - `docling`: 2.67.0 → 2.68.0 + - `pathspec`: 0.12.1 → 1.0.3 + - `textual`: 7.0.0 → 7.3.0 + - `datasets`: 4.4.2 → 4.5.0 + - `ruff`: 0.14.11 → 0.14.13 + - `opencv-python-headless`: 4.12.0.88 → 4.13.0.90 ## [0.26.6] - 2026-01-19 diff --git a/evaluations/pyproject.toml b/evaluations/pyproject.toml index 160082fd..d8e4f2d2 100644 --- a/evaluations/pyproject.toml +++ b/evaluations/pyproject.toml @@ -9,8 +9,8 @@ requires-python = ">=3.12" dependencies = [ "haiku.rag-slim", - "pydantic-ai-slim[evals,logfire]>=1.39.0", - "datasets>=4.4.2", + "pydantic-ai-slim[evals,logfire]>=1.44.0", + "datasets>=4.5.0", "typer>=0.19.2,<0.20.0", "python-dotenv>=1.2.1", ] diff --git a/haiku_rag_slim/haiku/rag/monitor.py b/haiku_rag_slim/haiku/rag/monitor.py index 45a1178e..a8ca8bdb 100644 --- a/haiku_rag_slim/haiku/rag/monitor.py +++ b/haiku_rag_slim/haiku/rag/monitor.py @@ -4,7 +4,6 @@ from pathlib import Path from typing import TYPE_CHECKING import pathspec -from pathspec.patterns.gitwildmatch import GitWildMatchPattern from watchfiles import Change, DefaultFilter, awatch from haiku.rag.client import HaikuRAG @@ -37,12 +36,12 @@ class FileFilter(DefaultFilter): self.extensions = tuple(supported_extensions) self.ignore_spec = ( - pathspec.PathSpec.from_lines(GitWildMatchPattern, ignore_patterns) + pathspec.PathSpec.from_lines("gitwildmatch", ignore_patterns) if ignore_patterns else None ) self.include_spec = ( - pathspec.PathSpec.from_lines(GitWildMatchPattern, include_patterns) + pathspec.PathSpec.from_lines("gitwildmatch", include_patterns) if include_patterns else None ) diff --git a/haiku_rag_slim/pyproject.toml b/haiku_rag_slim/pyproject.toml index a90c676e..6f141517 100644 --- a/haiku_rag_slim/pyproject.toml +++ b/haiku_rag_slim/pyproject.toml @@ -25,9 +25,9 @@ dependencies = [ "docling-core==2.59.0", "httpx>=0.28.1", "lancedb==0.26.1", - "pathspec>=0.12.1", + "pathspec>=1.0.3", "pydantic>=2.12.5", - "pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.39.0", + "pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.44.0", "python-dotenv>=1.2.1", "pyyaml>=6.0.3", "rich>=14.2.0", @@ -37,7 +37,7 @@ dependencies = [ [project.optional-dependencies] # Document processing -docling = ["docling==2.67.0", "opencv-python-headless>=4.12.0.88"] +docling = ["docling==2.68.0", "opencv-python-headless>=4.13.0.90"] # Embedding providers voyageai = ["voyageai>=0.3.7"] # Rerankers @@ -45,7 +45,7 @@ mxbai = ["mxbai-rerank>=0.1.6"] cohere = ["cohere>=5.20.1"] zeroentropy = ["zeroentropy>=0.1.0a7"] # TUI (chat and inspect commands) -tui = ["textual>=7.0.0", "textual-image>=0.8.5"] +tui = ["textual>=7.3.0", "textual-image>=0.8.5"] # Model providers (delegated to pydantic-ai-slim) anthropic = ["pydantic-ai-slim[anthropic]"] groq = ["pydantic-ai-slim[groq]"] diff --git a/pyproject.toml b/pyproject.toml index c107078e..16b4f2eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,7 @@ members = ["haiku_rag_slim", "evaluations"] [dependency-groups] dev = [ "haiku.rag-evals", - "datasets>=4.4.2", + "datasets>=4.5.0", "mkdocs>=1.6.1", "mkdocs-material>=9.7.1", "pre-commit>=4.5.1", @@ -75,12 +75,12 @@ dev = [ "pydantic-ai-slim[bedrock]", "pydantic-ai-slim[google]", "pydantic-ai-slim[groq]", - "ty>=0.0.1a17", + "ty>=0.0.12", "pytest>=9.0.2", "pytest-asyncio>=1.3.0", "pytest-cov>=7.0.0", "pytest-recording>=0.13.4", - "ruff>=0.14.11", + "ruff>=0.14.13", ] [tool.ruff] diff --git a/uv.lock b/uv.lock index c94f642e..b00e6910 100644 --- a/uv.lock +++ b/uv.lock @@ -659,7 +659,7 @@ wheels = [ [[package]] name = "datasets" -version = "4.4.2" +version = "4.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, @@ -677,9 +677,9 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/54/9359803da96bc65439a28fbb014dc2c90b7d4d8034a93b72362b0d40191f/datasets-4.4.2.tar.gz", hash = "sha256:9de16e415c4ba4713eac0493f7c7dc74f3aa21599297f00cc6ddab409cb7b24b", size = 586474, upload-time = "2025-12-19T15:03:09.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/bf/bb927bde63d649296c83e883171ae77074717c1b80fe2868b328bd0dbcbb/datasets-4.5.0.tar.gz", hash = "sha256:00c698ce1c2452e646cc5fad47fef39d3fe78dd650a8a6eb205bb45eb63cd500", size = 588384, upload-time = "2026-01-14T18:27:54.297Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/b5/fefa518c809de7bced5cddb7c21c010da66fa2ae494bda96844a280cc6ce/datasets-4.4.2-py3-none-any.whl", hash = "sha256:6f5ef3417504d9cd663c71c1b90b9a494ff4c2076a2cd6a6e40ceee6ad95befc", size = 512268, upload-time = "2025-12-19T15:03:07.087Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d5/0d563ea3c205eee226dc8053cf7682a8ac588db8acecd0eda2b587987a0b/datasets-4.5.0-py3-none-any.whl", hash = "sha256:b5d7e08096ffa407dd69e58b1c0271c9b2506140839b8d99af07375ad31b6726", size = 515196, upload-time = "2026-01-14T18:27:52.419Z" }, ] [[package]] @@ -741,7 +741,7 @@ wheels = [ [[package]] name = "docling" -version = "2.67.0" +version = "2.68.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "accelerate" }, @@ -773,9 +773,9 @@ dependencies = [ { name = "tqdm" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/eb/1900eaf576ab935d5b630a5ba6eb0e7063a2e1d36542df2f9ba572505d57/docling-2.67.0.tar.gz", hash = "sha256:d8c1992bbc090cee8c3f602fa63ac0c3127a65e3cabdf509d23ebb4e14feaf38", size = 259923, upload-time = "2026-01-09T08:37:37.984Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/cb/5dcda48a739e18c3d087de55be064d1fe9dfa802132aba274d55466ced01/docling-2.68.0.tar.gz", hash = "sha256:fabadc7aa807b96ac9bf85cc78f4fe343b5df658857386bc23541a9a6c116132", size = 265952, upload-time = "2026-01-13T10:47:35.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/99/fa9ac2cffaa77cf46b6414d0a32490b2580c8f3753ab1c65d983ee27f3a0/docling-2.67.0-py3-none-any.whl", hash = "sha256:d3ea4c0d7a64fce4b8f8b38415e075f6637384eaadb27acbf5621673e0da7669", size = 277794, upload-time = "2026-01-09T08:37:36.52Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a5/08716dcbf93e350f0595b58ece138b3b78606ef2f6a5a5058b1642cfe142/docling-2.68.0-py3-none-any.whl", hash = "sha256:97b2a4957e221973c69f1706da326fda8e973707d041778df12c01a5279e3e7e", size = 282854, upload-time = "2026-01-13T10:47:34.325Z" }, ] [[package]] @@ -1321,7 +1321,7 @@ provides-extras = ["tui"] [package.metadata.requires-dev] dev = [ - { name = "datasets", specifier = ">=4.4.2" }, + { name = "datasets", specifier = ">=4.5.0" }, { name = "haiku-rag-evals", editable = "evaluations" }, { name = "mkdocs", specifier = ">=1.6.1" }, { name = "mkdocs-material", specifier = ">=9.7.1" }, @@ -1334,8 +1334,8 @@ dev = [ { name = "pytest-asyncio", specifier = ">=1.3.0" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-recording", specifier = ">=0.13.4" }, - { name = "ruff", specifier = ">=0.14.11" }, - { name = "ty", specifier = ">=0.0.1a17" }, + { name = "ruff", specifier = ">=0.14.13" }, + { name = "ty", specifier = ">=0.0.12" }, ] [[package]] @@ -1352,9 +1352,9 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "datasets", specifier = ">=4.4.2" }, + { name = "datasets", specifier = ">=4.5.0" }, { name = "haiku-rag-slim", editable = "haiku_rag_slim" }, - { name = "pydantic-ai-slim", extras = ["evals", "logfire"], specifier = ">=1.39.0" }, + { name = "pydantic-ai-slim", extras = ["evals", "logfire"], specifier = ">=1.44.0" }, { name = "python-dotenv", specifier = ">=1.2.1" }, { name = "typer", specifier = ">=0.19.2,<0.20.0" }, ] @@ -1420,25 +1420,25 @@ zeroentropy = [ [package.metadata] requires-dist = [ { name = "cohere", marker = "extra == 'cohere'", specifier = ">=5.20.1" }, - { name = "docling", marker = "extra == 'docling'", specifier = "==2.67.0" }, + { name = "docling", marker = "extra == 'docling'", specifier = "==2.68.0" }, { name = "docling-core", specifier = "==2.59.0" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "lancedb", specifier = "==0.26.1" }, { name = "mxbai-rerank", marker = "extra == 'mxbai'", specifier = ">=0.1.6" }, - { name = "opencv-python-headless", marker = "extra == 'docling'", specifier = ">=4.12.0.88" }, - { name = "pathspec", specifier = ">=0.12.1" }, + { name = "opencv-python-headless", marker = "extra == 'docling'", specifier = ">=4.13.0.90" }, + { name = "pathspec", specifier = ">=1.0.3" }, { name = "pydantic", specifier = ">=2.12.5" }, { name = "pydantic-ai-slim", extras = ["anthropic"], marker = "extra == 'anthropic'" }, { name = "pydantic-ai-slim", extras = ["bedrock"], marker = "extra == 'bedrock'" }, { name = "pydantic-ai-slim", extras = ["google"], marker = "extra == 'google'" }, { name = "pydantic-ai-slim", extras = ["groq"], marker = "extra == 'groq'" }, { name = "pydantic-ai-slim", extras = ["mistral"], marker = "extra == 'mistral'" }, - { name = "pydantic-ai-slim", extras = ["openai", "fastmcp", "logfire", "ag-ui"], specifier = ">=1.39.0" }, + { name = "pydantic-ai-slim", extras = ["openai", "fastmcp", "logfire", "ag-ui"], specifier = ">=1.44.0" }, { name = "pydantic-ai-slim", extras = ["vertexai"], marker = "extra == 'vertexai'" }, { name = "python-dotenv", specifier = ">=1.2.1" }, { name = "pyyaml", specifier = ">=6.0.3" }, { name = "rich", specifier = ">=14.2.0" }, - { name = "textual", marker = "extra == 'tui'", specifier = ">=7.0.0" }, + { name = "textual", marker = "extra == 'tui'", specifier = ">=7.3.0" }, { name = "textual-image", marker = "extra == 'tui'", specifier = ">=0.8.5" }, { name = "typer", specifier = ">=0.19.2,<0.20.0" }, { name = "voyageai", marker = "extra == 'voyageai'", specifier = ">=0.3.7" }, @@ -2773,19 +2773,20 @@ wheels = [ [[package]] name = "opencv-python-headless" -version = "4.12.0.88" +version = "4.13.0.90" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a4/63/6861102ec149c3cd298f4d1ea7ce9d6adbc7529221606ff1dab991a19adb/opencv-python-headless-4.12.0.88.tar.gz", hash = "sha256:cfdc017ddf2e59b6c2f53bc12d74b6b0be7ded4ec59083ea70763921af2b6c09", size = 95379675, upload-time = "2025-07-07T09:21:06.815Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/7d/414e243c5c8216a5277afd104a319cc1291c5e23f5eeef512db5629ee7f4/opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:1e58d664809b3350c1123484dd441e1667cd7bed3086db1b9ea1b6f6cb20b50e", size = 37877864, upload-time = "2025-07-07T09:14:41.693Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/7e162714beed1cd5e7b5eb66fcbcba2f065c51b1d9da2463024c84d2f7c0/opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:365bb2e486b50feffc2d07a405b953a8f3e8eaa63865bc650034e5c71e7a5154", size = 57326608, upload-time = "2025-07-07T09:14:51.885Z" }, - { url = "https://files.pythonhosted.org/packages/69/4e/116720df7f1f7f3b59abc608ca30fbec9d2b3ae810afe4e4d26483d9dfa0/opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:aeb4b13ecb8b4a0beb2668ea07928160ea7c2cd2d9b5ef571bbee6bafe9cc8d0", size = 33145800, upload-time = "2025-07-07T09:15:00.367Z" }, - { url = "https://files.pythonhosted.org/packages/89/53/e19c21e0c4eb1275c3e2c97b081103b6dfb3938172264d283a519bf728b9/opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:236c8df54a90f4d02076e6f9c1cc763d794542e886c576a6fee46ec8ff75a7a9", size = 54023419, upload-time = "2025-07-07T09:15:10.164Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9c/a76fd5414de6ec9f21f763a600058a0c3e290053cea87e0275692b1375c0/opencv_python_headless-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:fde2cf5c51e4def5f2132d78e0c08f9c14783cd67356922182c6845b9af87dbd", size = 30225230, upload-time = "2025-07-07T09:15:17.045Z" }, - { url = "https://files.pythonhosted.org/packages/f2/35/0858e9e71b36948eafbc5e835874b63e515179dc3b742cbe3d76bc683439/opencv_python_headless-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:86b413bdd6c6bf497832e346cd5371995de148e579b9774f8eba686dee3f5528", size = 38923559, upload-time = "2025-07-07T09:15:25.229Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/38c4cbb5ccfce7aaf36fd9be9fc74a15c85a48ef90bfaca2049b486e10c5/opencv_python_headless-4.13.0.90-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:12a28674f215542c9bf93338de1b5bffd76996d32da9acb9e739fdb9c8bbd738", size = 46020414, upload-time = "2026-01-18T09:07:10.801Z" }, + { url = "https://files.pythonhosted.org/packages/93/c5/4b40daa5003b45aa8397f160324a091ed323733e2446dc0bdf3655e77b84/opencv_python_headless-4.13.0.90-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:32255203040dc98803be96362e13f9e4bce20146898222d2e5c242f80de50da5", size = 32568519, upload-time = "2026-01-18T09:07:52.368Z" }, + { url = "https://files.pythonhosted.org/packages/da/65/920e64a7f03cf5917cd2c6a3046293843c1a16ad89f0ed0f1c683979c9de/opencv_python_headless-4.13.0.90-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e13790342591557050157713af17a7435ac1b50c65282715093c9297fa045d8f", size = 35191272, upload-time = "2026-01-18T09:08:49.235Z" }, + { url = "https://files.pythonhosted.org/packages/fc/13/af150685be342dc09bfb0824e2a280020ccf1c7fc64e15a31d9209016aa9/opencv_python_headless-4.13.0.90-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dbc1f4625e5af3a80ebdbd84380227c0f445228588f2521b11af47710caca1ba", size = 57683677, upload-time = "2026-01-18T09:10:23.588Z" }, + { url = "https://files.pythonhosted.org/packages/cd/47/baab2a3b6d8da8c52e73d00207d1ed3155601c2c332ea855455b3fbc8ff4/opencv_python_headless-4.13.0.90-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eba38bc255d0b7d1969c5bcc90a060ca2b61a3403b613872c750bfa5dfe9e03b", size = 36590019, upload-time = "2026-01-18T09:10:49.053Z" }, + { url = "https://files.pythonhosted.org/packages/81/a1/facfe2801a861b424c4221d66e1281cf19735c00e07f063a337a208c11b5/opencv_python_headless-4.13.0.90-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f46b17ea0aa7e4124ca6ad71143f89233ae9557f61d2326bcdb34329a1ddf9bd", size = 62535926, upload-time = "2026-01-18T09:12:47.229Z" }, + { url = "https://files.pythonhosted.org/packages/06/d2/5e9ee7512306c1caa518be929d1f44bb1c189f342f538f73bea6fb94919f/opencv_python_headless-4.13.0.90-cp37-abi3-win32.whl", hash = "sha256:96060fc57a1abb1144b0b8129e2ff3bfcdd0ccd8e8bd05bd85256ff4ed587d3b", size = 30811665, upload-time = "2026-01-18T09:13:44.517Z" }, + { url = "https://files.pythonhosted.org/packages/a0/09/0a4d832448dccd03b2b1bdee70b9fc2e02c147cc7e06975e9cd729569d90/opencv_python_headless-4.13.0.90-cp37-abi3-win_amd64.whl", hash = "sha256:0e0c8c9f620802fddc4fa7f471a1d263c7b0dca16cd9e7e2f996bb8bd2128c0c", size = 40070035, upload-time = "2026-01-18T09:15:14.652Z" }, ] [[package]] @@ -3065,11 +3066,11 @@ wheels = [ [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] [[package]] @@ -3496,7 +3497,7 @@ email = [ [[package]] name = "pydantic-ai-slim" -version = "1.39.0" +version = "1.44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "genai-prices" }, @@ -3507,9 +3508,9 @@ dependencies = [ { name = "pydantic-graph" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/cb/542ad43e06da09104ef3443556e629d9aa260f9d584da8f7a410fb3a07e5/pydantic_ai_slim-1.39.0.tar.gz", hash = "sha256:e8cea9fc8f6149347c3e1d489b0ed2d541b4789e0583819f116284145d22fa69", size = 368962, upload-time = "2025-12-24T03:34:11.306Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/73/122aafb9bcad78042e2799649db745c357fc594e112c0ad0d8d183fdc447/pydantic_ai_slim-1.44.0.tar.gz", hash = "sha256:1bda6dbec4b94d8e52e32eb1e4c1da14f4f0202414306c65e2c3b43bebd82407", size = 378362, upload-time = "2026-01-17T01:26:09.64Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/df/86381632be07b7df2e8e5880a1f18c6ee98122adf5848d329fee239a03b2/pydantic_ai_slim-1.39.0-py3-none-any.whl", hash = "sha256:8669d1781eba7713870bf76783e1e853577d5e55eb2986a27d49bc600889aaaf", size = 484906, upload-time = "2025-12-24T03:34:03.179Z" }, + { url = "https://files.pythonhosted.org/packages/1a/18/2f68a9718843a95c0b4724ab3821ef8f60f7b8ef50e70b3769db3259da81/pydantic_ai_slim-1.44.0-py3-none-any.whl", hash = "sha256:3bf412f43d3ae787350d671f873706ad74603777e04f42411c8fbdf7dced8031", size = 496441, upload-time = "2026-01-17T01:26:00.184Z" }, ] [package.optional-dependencies] @@ -3623,7 +3624,7 @@ wheels = [ [[package]] name = "pydantic-evals" -version = "1.39.0" +version = "1.44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -3633,14 +3634,14 @@ dependencies = [ { name = "pyyaml" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/20/ec455c7d32fde2022805870daf78581c9c493a4fcae6f32204fae5025658/pydantic_evals-1.39.0.tar.gz", hash = "sha256:6f8a754ca84afff3f2b2de9802fb0e12f69d9fc0a0411e2f7c9709fc09fb43b3", size = 47179, upload-time = "2025-12-24T03:34:12.477Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/0c/3a11101799972833585458caa5c0aa1b1cc8045acaaaec70846cb5dfdb3a/pydantic_evals-1.44.0.tar.gz", hash = "sha256:d93733e1d042c8f312645a969d7496b97d18d0030cb47174e57047ac56a2fc81", size = 47174, upload-time = "2026-01-17T01:26:10.745Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/c1/6d43ecd3f7acb78a3f683178d40008d486c08583ca848891f000d62c142e/pydantic_evals-1.39.0-py3-none-any.whl", hash = "sha256:18470ade5fea15d17911a517e37ea98700702d9ba011ef2facb707e87eae0564", size = 56347, upload-time = "2025-12-24T03:34:05.111Z" }, + { url = "https://files.pythonhosted.org/packages/20/4a/0bb5c78a0c82eaa2fe4b4caf15afa676aa37cad8b3dfeabb7766f7f651df/pydantic_evals-1.44.0-py3-none-any.whl", hash = "sha256:6eed03e42cc0e6f9fd022345dce3db0113614052321037efeb47a408a95f460c", size = 56346, upload-time = "2026-01-17T01:26:02.053Z" }, ] [[package]] name = "pydantic-graph" -version = "1.39.0" +version = "1.44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, @@ -3648,9 +3649,9 @@ dependencies = [ { name = "pydantic" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/d5/2f45d1fd2ae0ba89b5a70b3bec8c2e910c4891fe0ed7e4fc896ca7e126a0/pydantic_graph-1.39.0.tar.gz", hash = "sha256:08c6f349dbbade6f4cdaaed02de4e8d75b9a37d44f8238e40a14f94f6a31761f", size = 58453, upload-time = "2025-12-24T03:34:13.766Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/d9/83f1921633634cb1fd5947ebdc48a992cd1e660d9d0ba10f23450af654b8/pydantic_graph-1.44.0.tar.gz", hash = "sha256:81bb14bb47d3313fd7114f3ae9650dab77729451659e0247d298e1800f997c23", size = 58454, upload-time = "2026-01-17T01:26:12.113Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/e2/719de1af767863359278e8b69c538dba9a7dbd19bb94111206e57ca34648/pydantic_graph-1.39.0-py3-none-any.whl", hash = "sha256:e0f89fc2c7ab111ae5f38dd2d88c5d26a0784eaabe95735c2b4087b0b512cc2d", size = 72327, upload-time = "2025-12-24T03:34:06.476Z" }, + { url = "https://files.pythonhosted.org/packages/6f/e6/f9ed700171435309e214cf19012cf3b391d10ec28786d4a567ee315b1acd/pydantic_graph-1.44.0-py3-none-any.whl", hash = "sha256:5affbfe5779f79946de2c6a6524b98e2344982a129b2a1e19d031e76a5bc1e51", size = 72324, upload-time = "2026-01-17T01:26:04.119Z" }, ] [[package]] @@ -4344,28 +4345,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.11" +version = "0.14.13" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/77/9a7fe084d268f8855d493e5031ea03fa0af8cc05887f638bf1c4e3363eb8/ruff-0.14.11.tar.gz", hash = "sha256:f6dc463bfa5c07a59b1ff2c3b9767373e541346ea105503b4c0369c520a66958", size = 5993417, upload-time = "2026-01-08T19:11:58.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/a6/a4c40a5aaa7e331f245d2dc1ac8ece306681f52b636b40ef87c88b9f7afd/ruff-0.14.11-py3-none-linux_armv6l.whl", hash = "sha256:f6ff2d95cbd335841a7217bdfd9c1d2e44eac2c584197ab1385579d55ff8830e", size = 12951208, upload-time = "2026-01-08T19:12:09.218Z" }, - { url = "https://files.pythonhosted.org/packages/5c/5c/360a35cb7204b328b685d3129c08aca24765ff92b5a7efedbdd6c150d555/ruff-0.14.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f6eb5c1c8033680f4172ea9c8d3706c156223010b8b97b05e82c59bdc774ee6", size = 13330075, upload-time = "2026-01-08T19:12:02.549Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9e/0cc2f1be7a7d33cae541824cf3f95b4ff40d03557b575912b5b70273c9ec/ruff-0.14.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2fc34cc896f90080fca01259f96c566f74069a04b25b6205d55379d12a6855e", size = 12257809, upload-time = "2026-01-08T19:12:00.366Z" }, - { url = "https://files.pythonhosted.org/packages/a7/e5/5faab97c15bb75228d9f74637e775d26ac703cc2b4898564c01ab3637c02/ruff-0.14.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53386375001773ae812b43205d6064dae49ff0968774e6befe16a994fc233caa", size = 12678447, upload-time = "2026-01-08T19:12:13.899Z" }, - { url = "https://files.pythonhosted.org/packages/1b/33/e9767f60a2bef779fb5855cab0af76c488e0ce90f7bb7b8a45c8a2ba4178/ruff-0.14.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a697737dce1ca97a0a55b5ff0434ee7205943d4874d638fe3ae66166ff46edbe", size = 12758560, upload-time = "2026-01-08T19:11:42.55Z" }, - { url = "https://files.pythonhosted.org/packages/eb/84/4c6cf627a21462bb5102f7be2a320b084228ff26e105510cd2255ea868e5/ruff-0.14.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6845ca1da8ab81ab1dce755a32ad13f1db72e7fba27c486d5d90d65e04d17b8f", size = 13599296, upload-time = "2026-01-08T19:11:30.371Z" }, - { url = "https://files.pythonhosted.org/packages/88/e1/92b5ed7ea66d849f6157e695dc23d5d6d982bd6aa8d077895652c38a7cae/ruff-0.14.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e36ce2fd31b54065ec6f76cb08d60159e1b32bdf08507862e32f47e6dde8bcbf", size = 15048981, upload-time = "2026-01-08T19:12:04.742Z" }, - { url = "https://files.pythonhosted.org/packages/61/df/c1bd30992615ac17c2fb64b8a7376ca22c04a70555b5d05b8f717163cf9f/ruff-0.14.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:590bcc0e2097ecf74e62a5c10a6b71f008ad82eb97b0a0079e85defe19fe74d9", size = 14633183, upload-time = "2026-01-08T19:11:40.069Z" }, - { url = "https://files.pythonhosted.org/packages/04/e9/fe552902f25013dd28a5428a42347d9ad20c4b534834a325a28305747d64/ruff-0.14.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53fe71125fc158210d57fe4da26e622c9c294022988d08d9347ec1cf782adafe", size = 14050453, upload-time = "2026-01-08T19:11:37.555Z" }, - { url = "https://files.pythonhosted.org/packages/ae/93/f36d89fa021543187f98991609ce6e47e24f35f008dfe1af01379d248a41/ruff-0.14.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a35c9da08562f1598ded8470fcfef2afb5cf881996e6c0a502ceb61f4bc9c8a3", size = 13757889, upload-time = "2026-01-08T19:12:07.094Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9f/c7fb6ecf554f28709a6a1f2a7f74750d400979e8cd47ed29feeaa1bd4db8/ruff-0.14.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0f3727189a52179393ecf92ec7057c2210203e6af2676f08d92140d3e1ee72c1", size = 13955832, upload-time = "2026-01-08T19:11:55.064Z" }, - { url = "https://files.pythonhosted.org/packages/db/a0/153315310f250f76900a98278cf878c64dfb6d044e184491dd3289796734/ruff-0.14.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:eb09f849bd37147a789b85995ff734a6c4a095bed5fd1608c4f56afc3634cde2", size = 12586522, upload-time = "2026-01-08T19:11:35.356Z" }, - { url = "https://files.pythonhosted.org/packages/2f/2b/a73a2b6e6d2df1d74bf2b78098be1572191e54bec0e59e29382d13c3adc5/ruff-0.14.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c61782543c1231bf71041461c1f28c64b961d457d0f238ac388e2ab173d7ecb7", size = 12724637, upload-time = "2026-01-08T19:11:47.796Z" }, - { url = "https://files.pythonhosted.org/packages/f0/41/09100590320394401cd3c48fc718a8ba71c7ddb1ffd07e0ad6576b3a3df2/ruff-0.14.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:82ff352ea68fb6766140381748e1f67f83c39860b6446966cff48a315c3e2491", size = 13145837, upload-time = "2026-01-08T19:11:32.87Z" }, - { url = "https://files.pythonhosted.org/packages/3b/d8/e035db859d1d3edf909381eb8ff3e89a672d6572e9454093538fe6f164b0/ruff-0.14.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:728e56879df4ca5b62a9dde2dd0eb0edda2a55160c0ea28c4025f18c03f86984", size = 13850469, upload-time = "2026-01-08T19:12:11.694Z" }, - { url = "https://files.pythonhosted.org/packages/4e/02/bb3ff8b6e6d02ce9e3740f4c17dfbbfb55f34c789c139e9cd91985f356c7/ruff-0.14.11-py3-none-win32.whl", hash = "sha256:337c5dd11f16ee52ae217757d9b82a26400be7efac883e9e852646f1557ed841", size = 12851094, upload-time = "2026-01-08T19:11:45.163Z" }, - { url = "https://files.pythonhosted.org/packages/58/f1/90ddc533918d3a2ad628bc3044cdfc094949e6d4b929220c3f0eb8a1c998/ruff-0.14.11-py3-none-win_amd64.whl", hash = "sha256:f981cea63d08456b2c070e64b79cb62f951aa1305282974d4d5216e6e0178ae6", size = 14001379, upload-time = "2026-01-08T19:11:52.591Z" }, - { url = "https://files.pythonhosted.org/packages/c4/1c/1dbe51782c0e1e9cfce1d1004752672d2d4629ea46945d19d731ad772b3b/ruff-0.14.11-py3-none-win_arm64.whl", hash = "sha256:649fb6c9edd7f751db276ef42df1f3df41c38d67d199570ae2a7bd6cbc3590f0", size = 12938644, upload-time = "2026-01-08T19:11:50.027Z" }, + { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, + { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, + { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, + { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, + { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, + { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, + { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, + { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, + { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, + { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, ] [[package]] @@ -4659,7 +4660,7 @@ wheels = [ [[package]] name = "textual" -version = "7.0.0" +version = "7.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py", extra = ["linkify"] }, @@ -4669,9 +4670,9 @@ dependencies = [ { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/9c/ebc9ca1f95366bef4c0e8360f4a77400d47a79aeecc08747de1990ef8bdc/textual-7.0.0.tar.gz", hash = "sha256:617638a2be74fb7507aff3ea6ec9374148be02e5a7bb1d02396d1d557b66c0a9", size = 1582005, upload-time = "2026-01-03T11:48:10.909Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/ee/620c887bfad9d6eba062dfa3b6b0e735e0259102e2667b19f21625ef598d/textual-7.3.0.tar.gz", hash = "sha256:3169e8ba5518a979b0771e60be380ab1a6c344f30a2126e360e6f38d009a3de4", size = 1590692, upload-time = "2026-01-15T16:32:02.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/f8/a1ef9034b2a7f334f91b2f673f2ec03020a2529bb30a9437a6beb855beee/textual-7.0.0-py3-none-any.whl", hash = "sha256:190de0f65e5f4bc820fae46f32f591e509621d76688b36400ce01fa63dc6b623", size = 715156, upload-time = "2026-01-03T11:48:09.067Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1f/abeb4e5cb36b99dd37db72beb2a74d58598ccb35aaadf14624ee967d4a6b/textual-7.3.0-py3-none-any.whl", hash = "sha256:db235cecf969c87fe5a9c04d83595f506affc9db81f3a53ab849534d726d330a", size = 716374, upload-time = "2026-01-15T16:31:58.233Z" }, ] [[package]]