replace pyright with ty type checker
This commit is contained in:
parent
2c264f4afc
commit
5e55c0df54
24 changed files with 104 additions and 90 deletions
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=["*"],
|
||||
|
|
|
|||
|
|
@ -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]]:
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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?",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
42
uv.lock
42
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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue