Skip to content

Commit 7c51609

Browse files
committed
refactor: comprehensive type safety and mypy compliance pass
- Standardized imports: Moved many method-level imports to the top-level across service.py, orchestrator.py, and monitor.py. - Mypy resolution: Fixed numerous typing errors, including missing return types, Any annotations, and cast operations. - Watchdog integration: Refined monitor.py to gracefully handle watchdog imports and type callbacks. - Logic refinements: Updated evaluation scripts and added explicit assertions for VoyageAI clients.
1 parent 39290dd commit 7c51609

17 files changed

Lines changed: 52 additions & 56 deletions

.DS_Store

0 Bytes
Binary file not shown.

src/knowcode/api/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def create_app(store_path: str = ".", watch: bool = False) -> FastAPI:
5353

5454
return app
5555

56-
def start_server(host: str = "127.0.0.1", port: int = 8000, store_path: str = ".", watch: bool = False): # type: ignore
56+
def start_server(host: str = "127.0.0.1", port: int = 8000, store_path: str = ".", watch: bool = False) -> None:
5757
"""Start the uvicorn server with the configured app.
5858
5959
Args:

src/knowcode/indexing/monitor.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55
from pathlib import Path
66
from knowcode.indexing.scanner import Scanner
7-
from typing import Optional, TYPE_CHECKING
7+
from typing import Optional, TYPE_CHECKING, Any
88

99

1010
try:
1111
from watchdog.observers import Observer
1212
from watchdog.events import FileSystemEventHandler
1313
except ImportError:
14-
Observer = None # type: ignore
15-
FileSystemEventHandler = object # type: ignore
14+
Observer = None # type: ignore[assignment]
15+
class FileSystemEventHandler:
16+
pass # type: ignore[no-redef]
1617

1718
if TYPE_CHECKING:
1819
from knowcode.indexing.background_indexer import BackgroundIndexer
@@ -30,7 +31,7 @@ def __init__(self, root_dir: str | Path, background_indexer: Optional["Backgroun
3031
"""
3132
self.root_dir = Path(root_dir)
3233
self.background_indexer = background_indexer
33-
self.observer = None
34+
self.observer: Any = None
3435

3536
def start(self) -> None:
3637
"""Start watching the directory for changes."""
@@ -39,9 +40,9 @@ def start(self) -> None:
3940
return
4041

4142
event_handler = IndexingHandler(self.background_indexer)
42-
self.observer = Observer() # type: ignore
43-
self.observer.schedule(event_handler, str(self.root_dir), recursive=True) # type: ignore
44-
self.observer.start() # type: ignore
43+
self.observer = Observer()
44+
self.observer.schedule(event_handler, str(self.root_dir), recursive=True)
45+
self.observer.start()
4546

4647
def stop(self) -> None:
4748
"""Stop watching and join the observer thread."""
@@ -61,17 +62,17 @@ def __init__(self, background_indexer: Optional["BackgroundIndexer"]) -> None:
6162
"""
6263
self.background_indexer = background_indexer
6364

64-
def on_modified(self, event): # type: ignore
65+
def on_modified(self, event: Any) -> None:
6566
"""Handle modified file events."""
6667
if not event.is_directory:
6768
self._handle_change(event.src_path)
6869

69-
def on_created(self, event): # type: ignore
70+
def on_created(self, event: Any) -> None:
7071
"""Handle created file events."""
7172
if not event.is_directory:
7273
self._handle_change(event.src_path)
7374

74-
def on_deleted(self, event): # type: ignore
75+
def on_deleted(self, event: Any) -> None:
7576
"""Handle deleted file events."""
7677
if not event.is_directory and self.background_indexer:
7778
path = Path(event.src_path)
@@ -81,7 +82,7 @@ def on_deleted(self, event): # type: ignore
8182
else:
8283
self._handle_change(event.src_path)
8384

84-
def on_moved(self, event): # type: ignore
85+
def on_moved(self, event: Any) -> None:
8586
"""Handle moved file events."""
8687
if not event.is_directory and self.background_indexer:
8788
src_path = Path(event.src_path)

src/knowcode/llm/embedding.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import hashlib
77
import math
88
import os
9-
from typing import Any
9+
from typing import Any, cast
1010

1111
from knowcode.config import AppConfig
1212
from knowcode.data_models import EmbeddingConfig
@@ -135,14 +135,14 @@ def __init__(
135135
"""
136136
super().__init__(config)
137137
self.api_key_env = api_key_env
138-
self.client = None
138+
self.client: Any = None
139139

140-
def _get_client(self): # type: ignore
140+
def _get_client(self) -> Any:
141141
"""Return an initialized VoyageAI client, loading credentials if needed."""
142142
if self.client is None:
143143
from knowcode.llm.voyageai_client import get_voyageai_client
144144

145-
self.client = get_voyageai_client(self.api_key_env) # type: ignore
145+
self.client = get_voyageai_client(self.api_key_env)
146146

147147
if self.client is None:
148148
raise ValueError(
@@ -157,7 +157,7 @@ def embed(self, texts: list[str]) -> list[list[float]]:
157157
if not texts:
158158
return []
159159

160-
client = self._get_client() # type: ignore
160+
client = self._get_client()
161161
embeddings = client.embed(
162162
texts=texts,
163163
model=self.config.model_name,
@@ -169,11 +169,11 @@ def embed(self, texts: list[str]) -> list[list[float]]:
169169
if self.config.normalize:
170170
embeddings = [self._normalize(e) for e in embeddings]
171171

172-
return embeddings # type: ignore
172+
return cast(list[list[float]], embeddings)
173173

174174
def embed_single(self, text: str) -> list[float]:
175175
"""Generate a query embedding for a single text input."""
176-
client = self._get_client() # type: ignore
176+
client = self._get_client()
177177
embeddings = client.embed(
178178
texts=[text],
179179
model=self.config.model_name,

src/knowcode/llm/query_classifier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def classify_query(query: str) -> Tuple[TaskType, float]:
8080
if max_score == 0:
8181
return TaskType.GENERAL, 0.0
8282

83-
best_type = max(scores, key=scores.get) # type: ignore
83+
best_type = max(scores, key=scores.__getitem__)
8484

8585
# Calculate confidence based on score relative to maximum possible
8686
# and gap to second-best

src/knowcode/llm/voyageai_client.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
- rerank-2.5: Cross-encoder reranking for improved relevance
66
"""
77

8-
from typing import Any
8+
from typing import Any, Optional, cast
99
import os
10-
from typing import Optional
1110

1211
# VoyageAI imports - requires: pip install voyageai
1312
try:
@@ -42,7 +41,7 @@ def __init__(
4241
f"VoyageAI API key not found. Set {api_key_env} or pass api_key."
4342
)
4443

45-
self.client = voyageai.Client(api_key=self.api_key) # type: ignore
44+
self.client = voyageai.Client(api_key=self.api_key) # type: ignore[attr-defined]
4645

4746
def embed(
4847
self,
@@ -65,7 +64,7 @@ def embed(
6564
model=model,
6665
input_type=input_type,
6766
)
68-
return result.embeddings # type: ignore
67+
return cast(list[list[float]], result.embeddings)
6968

7069
def rerank(
7170
self,

src/knowcode/parsers/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def _extract_entities(
131131

132132
def _get_text(self, node: Any) -> str:
133133
"""Get text content of a node."""
134-
return node.text.decode("utf8") # type: ignore
134+
return str(node.text.decode("utf8"))
135135

136136
def _get_location(self, node: Any, file_path: Path) -> Location:
137137
"""Get location object for a node."""

src/knowcode/parsers/java_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def _parse_method(
173173

174174
return entities, rels
175175

176-
def _walk_for_calls(self, node, source_id) -> Any: # type: ignore
176+
def _walk_for_calls(self, node: Any, source_id: str) -> Any:
177177
rels = []
178178
cursor = node.walk()
179179
visited_children = False

src/knowcode/parsers/javascript_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ def _parse_arrow_function(
289289

290290
return entity, relationships
291291

292-
def _walk_for_calls(self, node, source_id) -> Any: # type: ignore
292+
def _walk_for_calls(self, node: Any, source_id: str) -> Any:
293293
"""Recursive walk to find call_expression.
294294
295295
Note: We use a cursor walk here which is significantly more performant
@@ -325,7 +325,7 @@ def _walk_for_calls(self, node, source_id) -> Any: # type: ignore
325325

326326
return rels
327327

328-
def _extract_call(self, node, source_id) -> Any: # type: ignore
328+
def _extract_call(self, node: Any, source_id: str) -> Any:
329329
# call_expression: function: (identifier) arguments: (arguments)
330330
func_node = node.child_by_field_name("function")
331331
if not func_node:

src/knowcode/protocols.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import annotations
44

55
from pathlib import Path
6-
from typing import Protocol, Optional, TYPE_CHECKING
6+
from typing import Protocol, TYPE_CHECKING
77

88
if TYPE_CHECKING:
9-
from knowcode.retrieval.orchestrator import SearchEngineProtocol
9+
pass
1010

1111

1212
from knowcode.data_models import EmbeddingConfig, Entity

0 commit comments

Comments
 (0)