Skip to content

Commit 7ac47c2

Browse files
julian-rischclaude
andauthored
chore: add ANN ruff ruleset to llama_cpp, llama_stack, mcp, meta_llama, mistral, mongodb_atlas, nvidia, ollama, openrouter, opensearch (#2991)
Adds the flake8-annotations (ANN) ruleset to enforce return type annotations, while excluding ANN401 (Any) globally and ANN from test and example files. Fixes all ANN violations by adding missing return type annotations to __init__, warm_up, close, __del__, __post_init__, and other public/private methods. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b3f17e0 commit 7ac47c2

39 files changed

Lines changed: 97 additions & 63 deletions

File tree

integrations/llama_cpp/pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ line-length = 120
9494
[tool.ruff.lint]
9595
select = [
9696
"A",
97+
"ANN",
9798
"ARG",
9899
"B",
99100
"C",
@@ -131,14 +132,16 @@ ignore = [
131132
"PLR0912",
132133
"PLR0913",
133134
"PLR0915",
135+
# Allow `Any` - used legitimately for dynamic types and SDK boundaries
136+
"ANN401",
134137
]
135138

136139
[tool.ruff.lint.flake8-tidy-imports]
137140
ban-relative-imports = "parents"
138141

139142
[tool.ruff.lint.per-file-ignores]
140143
# Tests can use magic values, assertions, and relative imports
141-
"tests/**/*" = ["PLR2004", "S101", "TID252"]
144+
"tests/**/*" = ["PLR2004", "S101", "TID252", "ANN"]
142145
# Examples can print their output
143146
"examples/**" = ["T201"]
144147
"tests/**" = ["T201"]

integrations/llama_stack/examples/llama-stack-with-tools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ def weather(city: str):
4141

4242
response = client.run(messages=messages, tools=[weather_tool])["replies"]
4343

44-
print(f"assistant messages: {response[0]}\n") # noqa: T201
44+
print(f"assistant messages: {response[0]}\n")
4545

4646
# If the assistant message contains a tool call, run the tool invoker
4747
if response[0].tool_calls:
4848
tool_messages = tool_invoker.run(messages=response)["tool_messages"]
49-
print(f"tool messages: {tool_messages}") # noqa: T201
49+
print(f"tool messages: {tool_messages}")

integrations/llama_stack/pyproject.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ line-length = 120
7979
[tool.ruff.lint]
8080
select = [
8181
"A",
82+
"ANN",
8283
"ARG",
8384
"B",
8485
"C",
@@ -119,6 +120,8 @@ ignore = [
119120
# Misc
120121
"B008",
121122
"S101",
123+
# Allow `Any` - used legitimately for dynamic types and SDK boundaries
124+
"ANN401",
122125
]
123126
unfixable = [
124127
# Don't touch unused imports
@@ -133,7 +136,9 @@ ban-relative-imports = "parents"
133136

134137
[tool.ruff.lint.per-file-ignores]
135138
# Tests can use magic values, assertions, and relative imports
136-
"tests/**/*" = ["PLR2004", "S101", "TID252", "E501", "F841"]
139+
"tests/**/*" = ["PLR2004", "S101", "TID252", "ANN", "E501", "F841"]
140+
# Examples can print their output and don't need type annotations
141+
"examples/**/*" = ["T201", "ANN"]
137142

138143
[tool.coverage.run]
139144
source = ["haystack_integrations"]

integrations/llama_stack/src/haystack_integrations/components/generators/llama_stack/chat/chat_generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def __init__(
6868
tools_strict: bool = False,
6969
max_retries: int | None = None,
7070
http_client_kwargs: dict[str, Any] | None = None,
71-
):
71+
) -> None:
7272
"""
7373
Creates an instance of LlamaStackChatGenerator. To use this chat generator,
7474
you need to setup Llama Stack Server with an inference provider and have a model available.

integrations/mcp/pyproject.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ line-length = 120
9494
[tool.ruff.lint]
9595
select = [
9696
"A",
97+
"ANN",
9798
"ARG",
9899
"B",
99100
"C",
@@ -135,6 +136,8 @@ ignore = [
135136
"RUF005",
136137
"S603",
137138
"S607",
139+
# Allow `Any` - used legitimately for dynamic types and SDK boundaries
140+
"ANN401",
138141
]
139142
unfixable = [
140143
# Don't touch unused imports
@@ -149,8 +152,8 @@ ban-relative-imports = "parents"
149152

150153
[tool.ruff.lint.per-file-ignores]
151154
# Tests can use magic values, assertions, and relative imports
152-
"tests/**/*" = ["PLR2004", "S101", "TID252"]
153-
"examples/**/*" = ["T201", "E501"]
155+
"tests/**/*" = ["PLR2004", "S101", "TID252", "ANN"]
156+
"examples/**/*" = ["T201", "E501", "ANN"]
154157

155158
[tool.coverage.run]
156159
source = ["haystack_integrations"]

integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def get_instance(cls) -> "AsyncExecutor":
7474
cls._singleton_instance = cls()
7575
return cls._singleton_instance
7676

77-
def __init__(self):
77+
def __init__(self) -> None:
7878
"""Initialize a dedicated event loop"""
7979
self._loop: asyncio.AbstractEventLoop = asyncio.new_event_loop()
8080
self._thread: threading.Thread = threading.Thread(target=self._run_loop, daemon=True)
@@ -84,7 +84,7 @@ def __init__(self):
8484
message = "AsyncExecutor failed to start background event loop"
8585
raise RuntimeError(message)
8686

87-
def _run_loop(self):
87+
def _run_loop(self) -> None:
8888
"""Run the event loop"""
8989
asyncio.set_event_loop(self._loop)
9090
self._started.set()
@@ -107,7 +107,7 @@ def run(self, coro: Coroutine[Any, Any, Any], timeout: float | None = None) -> A
107107
message = f"Operation timed out after {timeout} seconds"
108108
raise TimeoutError(message) from e
109109

110-
def get_loop(self):
110+
def get_loop(self) -> asyncio.AbstractEventLoop:
111111
"""
112112
Get the event loop.
113113
@@ -135,7 +135,7 @@ def run_background(
135135
# correct loop and can safely be set from other threads via *call_soon_threadsafe*.
136136
stop_event_promise: Future[asyncio.Event] = Future()
137137

138-
async def _coroutine_with_stop_event():
138+
async def _coroutine_with_stop_event() -> None:
139139
stop_event = asyncio.Event()
140140
stop_event_promise.set_result(stop_event)
141141
await coro_factory(stop_event)
@@ -155,7 +155,7 @@ def shutdown(self, timeout: float = 2) -> None:
155155
:param timeout: Timeout in seconds for shutting down the event loop
156156
"""
157157

158-
def _stop_loop():
158+
def _stop_loop() -> None:
159159
self._loop.stop()
160160

161161
asyncio.run_coroutine_threadsafe(asyncio.sleep(0), self._loop).result(timeout=timeout)
@@ -680,7 +680,7 @@ class SSEServerInfo(MCPServerInfo):
680680
base_delay: float = 1.0
681681
max_delay: float = 30.0
682682

683-
def __post_init__(self):
683+
def __post_init__(self) -> None:
684684
"""Validate that either url or base_url is provided."""
685685
if not self.url and not self.base_url:
686686
message = "Either url or base_url must be provided"
@@ -766,7 +766,7 @@ class StreamableHttpServerInfo(MCPServerInfo):
766766
base_delay: float = 1.0
767767
max_delay: float = 30.0
768768

769-
def __post_init__(self):
769+
def __post_init__(self) -> None:
770770
"""Validate the URL."""
771771
if not is_valid_http_url(self.url):
772772
message = f"Invalid url: {self.url}"
@@ -911,7 +911,7 @@ def __init__(
911911
outputs_to_string: dict[str, Any] | None = None,
912912
inputs_from_state: dict[str, str] | None = None,
913913
outputs_to_state: dict[str, dict[str, Any]] | None = None,
914-
):
914+
) -> None:
915915
"""
916916
Initialize the MCP tool.
917917
@@ -1062,7 +1062,7 @@ def _invoke_tool(self, **kwargs: Any) -> str | dict[str, Any]:
10621062
# Connect on first use if eager_connect is turned off
10631063
self.warm_up()
10641064

1065-
async def invoke():
1065+
async def invoke() -> Any:
10661066
logger.debug(f"TOOL: Inside invoke coroutine for '{self.name}'")
10671067
client = cast(MCPClient, self._client)
10681068
result = await asyncio.wait_for(client.call_tool(self.name, kwargs), timeout=self._invocation_timeout)
@@ -1274,7 +1274,7 @@ def from_dict(cls, data: dict[str, Any]) -> "Tool":
12741274
outputs_to_state=outputs_to_state,
12751275
)
12761276

1277-
def close(self):
1277+
def close(self) -> None:
12781278
"""Close the tool synchronously."""
12791279
if hasattr(self, "_client") and self._client:
12801280
try:
@@ -1284,7 +1284,7 @@ def close(self):
12841284
except Exception as e:
12851285
logger.debug(f"TOOL: Error during synchronous worker stop: {e!s}")
12861286

1287-
def __del__(self):
1287+
def __del__(self) -> None:
12881288
"""Cleanup resources when the tool is garbage collected."""
12891289
logger.debug(f"TOOL: __del__ called for MCPTool '{self.name if hasattr(self, 'name') else 'unknown'}'")
12901290

@@ -1309,7 +1309,7 @@ class _MCPClientSessionManager:
13091309
# Maximum time to wait for worker shutdown in seconds
13101310
WORKER_SHUTDOWN_TIMEOUT = 2.0
13111311

1312-
def __init__(self, client: "MCPClient", *, timeout: float | None = None):
1312+
def __init__(self, client: "MCPClient", *, timeout: float | None = None) -> None:
13131313
self._client = client
13141314
self.executor = AsyncExecutor.get_instance()
13151315

integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ def __init__(
232232
inputs_from_state: dict[str, dict[str, str]] | None = None,
233233
outputs_to_state: dict[str, dict[str, dict[str, Any]]] | None = None,
234234
outputs_to_string: dict[str, dict[str, Any]] | None = None,
235-
):
235+
) -> None:
236236
"""
237237
Initialize the MCP toolset.
238238
@@ -531,13 +531,13 @@ def from_dict(cls, data: dict[str, Any]) -> "MCPToolset":
531531
outputs_to_string=outputs_to_string if outputs_to_string else None,
532532
)
533533

534-
def close(self):
534+
def close(self) -> None:
535535
"""Close the underlying MCP client safely."""
536536
if hasattr(self, "_worker") and self._worker:
537537
try:
538538
self._worker.stop()
539539
except Exception as e:
540540
logger.debug(f"TOOLSET: error during worker stop: {e!s}")
541541

542-
def __del__(self):
542+
def __del__(self) -> None:
543543
self.close()

integrations/meta_llama/pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ line-length = 120
7979
[tool.ruff.lint]
8080
select = [
8181
"A",
82+
"ANN",
8283
"ARG",
8384
"B",
8485
"C",
@@ -119,6 +120,8 @@ ignore = [
119120
# Misc
120121
"B008",
121122
"S101",
123+
# Allow `Any` - used legitimately for dynamic types and SDK boundaries
124+
"ANN401",
122125
]
123126

124127
[tool.ruff.lint.isort]
@@ -129,7 +132,7 @@ ban-relative-imports = "parents"
129132

130133
[tool.ruff.lint.per-file-ignores]
131134
# Tests can use magic values, assertions, and relative imports
132-
"tests/**/*" = ["PLR2004", "S101", "TID252"]
135+
"tests/**/*" = ["PLR2004", "S101", "TID252", "ANN"]
133136

134137
[tool.coverage.run]
135138
source = ["haystack_integrations"]

integrations/meta_llama/src/haystack_integrations/components/generators/meta_llama/chat/chat_generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def __init__(
7474
timeout: float | None = None,
7575
max_retries: int | None = None,
7676
tools: ToolsType | None = None,
77-
):
77+
) -> None:
7878
"""
7979
Creates an instance of LlamaChatGenerator. Unless specified otherwise in the `model`, this is for Llama's
8080
`Llama-4-Scout-17B-16E-Instruct-FP8` model.

integrations/mistral/pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ line-length = 120
8282
[tool.ruff.lint]
8383
select = [
8484
"A",
85+
"ANN",
8586
"ARG",
8687
"B",
8788
"C",
@@ -122,6 +123,8 @@ ignore = [
122123
# Misc
123124
"B008",
124125
"S101",
126+
# Allow `Any` - used legitimately for dynamic types and SDK boundaries
127+
"ANN401",
125128
]
126129

127130
[tool.ruff.lint.isort]
@@ -132,7 +135,7 @@ ban-relative-imports = "parents"
132135

133136
[tool.ruff.lint.per-file-ignores]
134137
# Tests can use magic values, assertions, and relative imports
135-
"tests/**/*" = ["PLR2004", "S101", "TID252"]
138+
"tests/**/*" = ["PLR2004", "S101", "TID252", "ANN"]
136139

137140
[tool.coverage.run]
138141
source = ["haystack_integrations"]

0 commit comments

Comments
 (0)