Skip to content

Commit a0bfef1

Browse files
committed
feat: improve type safety and dependency management
- Add type safety fixes for mcp_servers dictionary access in options.py and claude.py - Remove unused tomli-w dependency from pyproject.toml - Update pre-commit hooks: ruff v0.12.2→v0.12.8, mypy v1.16.1→v1.17.1, pre-commit-hooks v5.0.0→v6.0.0 - Add pyjwt>=2.10.0 to mypy additional dependencies for proper type checking - Update anthropic SDK to v0.63.0 and charset-normalizer to v3.4.3 - Enhance test type safety with proper casting for mcp_servers dictionary access These changes fix type safety issues where mcp_servers could be None but was accessed as a dictionary, remove an unused dependency, and update development tooling for better reliability.
1 parent c3db446 commit a0bfef1

File tree

6 files changed

+306
-307
lines changed

6 files changed

+306
-307
lines changed

.pre-commit-config.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
repos:
22
# Ruff linting and formatting
33
- repo: https://github.com/astral-sh/ruff-pre-commit
4-
rev: v0.12.2
4+
rev: v0.12.8
55
hooks:
66
# Ruff linting (matches: make lint -> uv run ruff check .)
77
- id: ruff
@@ -16,7 +16,7 @@ repos:
1616

1717
# MyPy type checking (matches: make typecheck -> uv run mypy .)
1818
- repo: https://github.com/pre-commit/mirrors-mypy
19-
rev: v1.16.1
19+
rev: v1.17.1
2020
hooks:
2121
- id: mypy
2222
name: mypy type check
@@ -58,6 +58,7 @@ repos:
5858
- textual>=3.7.1
5959
- aiofiles>=24.1.0
6060
- types-aiofiles>=24.0.0
61+
- pyjwt>=2.10.0
6162
args: [--config-file=pyproject.toml]
6263
exclude: ^(docs/|examples/)
6364

@@ -81,7 +82,7 @@ repos:
8182

8283
# General file checks
8384
- repo: https://github.com/pre-commit/pre-commit-hooks
84-
rev: v5.0.0
85+
rev: v6.0.0
8586
hooks:
8687
# Basic file checks
8788
- id: trailing-whitespace

ccproxy/claude_sdk/options.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def create_options(
6161
# Extract configuration values with proper types
6262
mcp_servers = (
6363
configured_opts.mcp_servers.copy()
64-
if configured_opts.mcp_servers
64+
if isinstance(configured_opts.mcp_servers, dict)
6565
else {}
6666
)
6767
permission_prompt_tool_name = configured_opts.permission_prompt_tool_name

ccproxy/config/claude.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def validate_claude_code_options(cls, v: Any, info: Any) -> Any:
226226
# Extract default values as a dict for merging
227227
default_values = {
228228
"mcp_servers": dict(defaults.mcp_servers)
229-
if defaults.mcp_servers
229+
if isinstance(defaults.mcp_servers, dict)
230230
else {},
231231
"permission_prompt_tool_name": defaults.permission_prompt_tool_name,
232232
}

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ dependencies = [
3131
"textual>=3.7.1",
3232
"claude-code-sdk>=0.0.19",
3333
"pyjwt>=2.10.1",
34-
"tomli-w>=1.2.0",
3534
]
3635

3736
[build-system]

tests/unit/config/test_claude_sdk_options.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Tests for Claude SDK options handling."""
22

3+
from typing import Any, cast
4+
35
from ccproxy.claude_sdk.options import OptionsHandler
46
from ccproxy.config.claude import ClaudeSettings
57
from ccproxy.config.settings import Settings
@@ -38,12 +40,10 @@ def test_create_options_with_default_mcp_configuration(self):
3840
# Should have the default MCP server configuration
3941
assert hasattr(options, "mcp_servers")
4042
assert options.mcp_servers is not None
41-
assert "confirmation" in options.mcp_servers
42-
assert options.mcp_servers["confirmation"].get("type") == "sse"
43-
assert (
44-
options.mcp_servers["confirmation"].get("url")
45-
== "http://127.0.0.1:8000/mcp"
46-
)
43+
mcp_servers = cast(dict[str, Any], options.mcp_servers)
44+
assert "confirmation" in mcp_servers
45+
assert mcp_servers["confirmation"].get("type") == "sse"
46+
assert mcp_servers["confirmation"].get("url") == "http://127.0.0.1:8000/mcp"
4747
# Should have the default permission tool name
4848
assert hasattr(options, "permission_prompt_tool_name")
4949
assert (
@@ -68,8 +68,9 @@ def test_create_options_with_custom_configuration(self):
6868

6969
assert options.model == "claude-3-5-sonnet-20241022"
7070
# Should have the custom MCP server configuration
71-
assert "custom" in options.mcp_servers
72-
assert options.mcp_servers["custom"].get("url") == "http://localhost:9000/mcp"
71+
mcp_servers = cast(dict[str, Any], options.mcp_servers)
72+
assert "custom" in mcp_servers
73+
assert mcp_servers["custom"].get("url") == "http://localhost:9000/mcp"
7374
# Should have the custom permission tool name
7475
assert options.permission_prompt_tool_name == "custom_permission_tool"
7576
# Should have the custom max thinking tokens
@@ -94,7 +95,8 @@ def test_create_options_api_parameters_override_settings(self):
9495
assert options.system_prompt == "Custom system prompt"
9596
assert options.max_thinking_tokens == 20000
9697
# Should still have the default MCP configuration
97-
assert "confirmation" in options.mcp_servers
98+
mcp_servers = cast(dict[str, Any], options.mcp_servers)
99+
assert "confirmation" in mcp_servers
98100
assert (
99101
options.permission_prompt_tool_name == "mcp__confirmation__check_permission"
100102
)
@@ -118,7 +120,9 @@ def test_create_options_with_kwargs_override(self):
118120
# Should override the default permission tool name
119121
assert options.permission_prompt_tool_name == "override_tool"
120122
# Should still have the default MCP configuration
121-
assert "confirmation" in options.mcp_servers
123+
124+
mcp_servers = cast(dict[str, Any], options.mcp_servers)
125+
assert "confirmation" in mcp_servers
122126

123127
def test_create_options_preserves_all_configuration_attributes(self):
124128
"""Test that all attributes from configuration are properly copied."""
@@ -146,9 +150,10 @@ def test_create_options_preserves_all_configuration_attributes(self):
146150
options = handler.create_options(model="claude-3-5-sonnet-20241022")
147151

148152
# Verify all attributes are preserved
149-
assert len(options.mcp_servers) == 2
150-
assert "confirmation" in options.mcp_servers
151-
assert "filesystem" in options.mcp_servers
153+
mcp_servers = cast(dict[str, Any], options.mcp_servers)
154+
assert len(mcp_servers) == 2
155+
assert "confirmation" in mcp_servers
156+
assert "filesystem" in mcp_servers
152157
assert (
153158
options.permission_prompt_tool_name == "mcp__confirmation__check_permission"
154159
)

0 commit comments

Comments
 (0)