Skip to content

Commit 6170d95

Browse files
committed
feat(types): add strict typing to config, logging_utils, and models modules
1 parent 74c2f2b commit 6170d95

7 files changed

Lines changed: 98 additions & 10 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,5 @@ browser_utils/generated_*.js
260260
# Docker 环境的实际配置文件(保留示例文件)
261261
docker/.env
262262
docker/my_*.json
263+
264+
monkeytype.sqlite3

config/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
try:
4343
DEFAULT_STOP_SEQUENCES = json.loads(os.environ.get("DEFAULT_STOP_SEQUENCES", "[]"))
4444
except (json.JSONDecodeError, TypeError):
45-
DEFAULT_STOP_SEQUENCES = [] # 回退到默认值 (空列表)
45+
DEFAULT_STOP_SEQUENCES = [] # type: ignore[reportConstantRedefinition] # 回退到默认值 (空列表)
4646

4747
# --- URL模式 ---
4848
AI_STUDIO_URL_PATTERN = os.environ.get("AI_STUDIO_URL_PATTERN", "aistudio.google.com/")

models/exceptions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"""
1818

1919
import time
20-
from typing import Any, Optional
20+
from typing import Any, Dict, List, Optional
2121

2222
from fastapi import HTTPException
2323

@@ -63,7 +63,7 @@ def to_http_exception(self) -> HTTPException:
6363
Returns:
6464
HTTPException with appropriate status code and headers
6565
"""
66-
headers = {}
66+
headers: Dict[str, str] = {}
6767
if self.retry_after is not None:
6868
headers["Retry-After"] = str(self.retry_after)
6969

@@ -165,7 +165,7 @@ class InvalidModelError(ModelError):
165165
"""Requested model does not exist or is not available."""
166166

167167
def __init__(
168-
self, model_id: str, available_models: Optional[list] = None, **kwargs: Any
168+
self, model_id: str, available_models: Optional[List[str]] = None, **kwargs: Any
169169
):
170170
message = f"Invalid model '{model_id}'"
171171
if available_models:

models/logging.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
import json
44
import logging
55
import sys
6-
from typing import Dict
6+
from typing import Dict, List
77

88
from fastapi import WebSocket, WebSocketDisconnect
99

1010

1111
class StreamToLogger:
12-
def __init__(self, logger_instance, log_level=logging.INFO):
12+
def __init__(self, logger_instance: logging.Logger, log_level: int = logging.INFO):
1313
self.logger = logger_instance
1414
self.log_level = log_level
1515
self.linebuf = ""
1616

17-
def write(self, buf):
17+
def write(self, buf: str):
1818
try:
1919
temp_linebuf = self.linebuf + buf
2020
self.linebuf = ""
@@ -70,7 +70,7 @@ def disconnect(self, client_id: str):
7070
async def broadcast(self, message: str):
7171
if not self.active_connections:
7272
return
73-
disconnected_clients = []
73+
disconnected_clients: List[str] = []
7474
active_conns_copy = list(self.active_connections.items())
7575
logger = logging.getLogger("AIStudioProxyServer")
7676
for client_id, connection in active_conns_copy:

monkeytype_config.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""MonkeyType configuration for AIStudioProxyAPI.
2+
3+
This config:
4+
- Filters to only trace project modules (exclude tests, external libs)
5+
- Enables TypedDict generation for config dicts
6+
- Applies type rewriters to clean up messy unions
7+
- Increases query limit for comprehensive coverage
8+
"""
9+
10+
from monkeytype.config import DefaultConfig
11+
from monkeytype.typing import (
12+
ChainedRewriter,
13+
RemoveEmptyContainers,
14+
RewriteConfigDict,
15+
RewriteLargeUnion,
16+
)
17+
18+
19+
class AIStudioProxyConfig(DefaultConfig):
20+
"""Custom MonkeyType configuration for this project."""
21+
22+
def code_filter(self):
23+
"""Only trace project modules, exclude tests and external libraries."""
24+
25+
def should_trace(code):
26+
# Normalize Windows path separators
27+
filename = code.co_filename.replace("\\", "/")
28+
29+
# Project modules to trace
30+
project_modules = [
31+
"api_utils",
32+
"browser_utils",
33+
"stream",
34+
"config",
35+
"models",
36+
"launcher",
37+
"logging_utils",
38+
]
39+
40+
# Check if file is in any project module
41+
for module in project_modules:
42+
if f"/{module}/" in filename or filename.endswith(f"/{module}.py"):
43+
# Exclude test files
44+
if "/tests/" not in filename and "/test_" not in filename:
45+
return True
46+
47+
return False
48+
49+
return should_trace
50+
51+
def type_rewriter(self):
52+
"""Clean up generated types with chained rewriters."""
53+
return ChainedRewriter(
54+
[
55+
RemoveEmptyContainers(), # Union[List[Any], List[int]] -> List[int]
56+
RewriteConfigDict(), # Union[Dict[K,V1], Dict[K,V2]] -> Dict[K, Union[V1,V2]]
57+
RewriteLargeUnion(
58+
max_union_len=3
59+
), # Large unions -> Any (strict: max 3 elements)
60+
]
61+
)
62+
63+
def max_typed_dict_size(self) -> int:
64+
"""Enable TypedDict generation for dictionaries.
65+
66+
Since 19.11.2, TypedDict generation is disabled by default.
67+
This enables it for dicts with up to 50 keys, which is critical
68+
for config.settings and similar modules.
69+
"""
70+
return 50
71+
72+
def query_limit(self) -> int:
73+
"""Increase query limit for comprehensive type inference.
74+
75+
Default is 2000. We increase to 5000 to capture more traces
76+
and improve type accuracy, especially for polymorphic functions.
77+
"""
78+
return 5000
79+
80+
81+
# MonkeyType will automatically find and use this CONFIG instance
82+
CONFIG = AIStudioProxyConfig()

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ build-backend = "poetry.core.masonry.api"
4848
asyncio_mode = "auto"
4949
testpaths = ["tests"]
5050
python_files = "test_*.py"
51-
addopts = "-v --cov=api_utils --cov=browser_utils --cov=stream --cov=config --cov=models --cov-report=term-missing"
51+
# Coverage disabled by default for MonkeyType compatibility (uses same sys.setprofile hook)
52+
# To re-enable coverage: pytest --cov=api_utils --cov=browser_utils --cov=stream --cov=config --cov=models --cov-report=term-missing
53+
addopts = "-v"
5254
timeout = 10
5355
env = [
5456
"LAUNCH_MODE=test",

pytest.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
asyncio_mode = auto
33
testpaths = tests
44
python_files = test_*.py
5-
addopts = -v --cov=api_utils --cov=browser_utils --cov=stream --cov=config --cov=models --cov-report=term-missing
5+
# Coverage disabled by default for MonkeyType compatibility (uses same sys.setprofile hook)
6+
# To re-enable coverage: pytest --cov=api_utils --cov=browser_utils --cov=stream --cov=config --cov=models --cov-report=term-missing
7+
addopts = -v
68
timeout = 30
79
markers =
810
integration: Integration tests that use real components (locks, queues, state) instead of mocks

0 commit comments

Comments
 (0)