Skip to content

Commit 577cd34

Browse files
committed
move to uv and ruff
1 parent 32940ca commit 577cd34

74 files changed

Lines changed: 830 additions & 930 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ ignore = [
105105
"E501", # line too long, handled by formatter
106106
"B008", # do not perform function calls in argument defaults
107107
"C901", # too complex
108+
"B904", # raise ... from err - not needed for our error patterns
109+
"E722", # bare except - allowed in test cleanup
110+
"E402", # module level import not at top - conditional imports needed
111+
"B023", # function definition does not bind loop variable - false positive
108112
]
109113

110114
[tool.ruff.format]

rmcp/bidirectional.py

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import json
2323
import logging
2424
import uuid
25-
from typing import Any, Dict, Optional, Set
25+
from typing import Any
2626

2727
from .core.context import Context
2828
from .registries.tools import tool
@@ -39,15 +39,15 @@ class CallbackManager:
3939
"""
4040

4141
def __init__(self):
42-
self.active_callbacks: Dict[str, Dict[str, Any]] = {}
43-
self.callback_permissions: Dict[str, Set[str]] = {}
42+
self.active_callbacks: dict[str, dict[str, Any]] = {}
43+
self.callback_permissions: dict[str, set[str]] = {}
4444
self.callback_timeout = 300.0 # 5 minutes default
4545

4646
def register_callback(
4747
self,
4848
callback_id: str,
4949
context: Context,
50-
allowed_tools: Optional[Set[str]] = None,
50+
allowed_tools: set[str] | None = None,
5151
) -> None:
5252
"""Register a callback session for R → Python communication."""
5353
self.active_callbacks[callback_id] = {
@@ -66,8 +66,8 @@ def unregister_callback(self, callback_id: str) -> None:
6666
logger.info(f"Unregistered callback session: {callback_id}")
6767

6868
async def handle_callback(
69-
self, callback_id: str, tool_name: str, parameters: Dict[str, Any]
70-
) -> Dict[str, Any]:
69+
self, callback_id: str, tool_name: str, parameters: dict[str, Any]
70+
) -> dict[str, Any]:
7171
"""Handle a callback request from R."""
7272
if callback_id not in self.active_callbacks:
7373
return {
@@ -99,7 +99,6 @@ async def handle_callback(
9999
context = callback_info["context"]
100100

101101
# Import here to avoid circular imports
102-
from .core.server import MCPServer
103102

104103
server = context._server
105104

@@ -174,8 +173,8 @@ def get_callback_manager() -> CallbackManager:
174173
},
175174
)
176175
async def create_r_callback_session(
177-
context: Context, params: Dict[str, Any]
178-
) -> Dict[str, Any]:
176+
context: Context, params: dict[str, Any]
177+
) -> dict[str, Any]:
179178
"""
180179
Create a callback session that allows R scripts to call back to Python MCP tools.
181180
@@ -235,7 +234,7 @@ async def create_r_callback_session(
235234
"required": ["callback_id", "tool_name", "parameters"],
236235
},
237236
)
238-
async def handle_r_callback(context: Context, params: Dict[str, Any]) -> Dict[str, Any]:
237+
async def handle_r_callback(context: Context, params: dict[str, Any]) -> dict[str, Any]:
239238
"""
240239
Handle a callback request from an R script.
241240
@@ -269,14 +268,14 @@ def create_r_callback_utilities() -> str:
269268
# Initialize callback system
270269
rmcp_init_callback <- function(callback_config) {
271270
.rmcp_callback_config <<- callback_config
272-
271+
273272
# Create temporary file for callback communication
274273
.rmcp_callback_file <<- tempfile(pattern = "rmcp_callback_", fileext = ".json")
275-
274+
276275
cat("RMCP callback system initialized\\n")
277276
cat("Callback ID:", callback_config$callback_id, "\\n")
278277
cat("Allowed tools:", paste(callback_config$allowed_tools, collapse = ", "), "\\n")
279-
278+
280279
return(TRUE)
281280
}
282281
@@ -285,28 +284,28 @@ def create_r_callback_utilities() -> str:
285284
if (is.null(.rmcp_callback_config)) {
286285
stop("Callback system not initialized. Call rmcp_init_callback() first.")
287286
}
288-
287+
289288
# Check if tool is allowed
290-
if (length(.rmcp_callback_config$allowed_tools) > 0 &&
289+
if (length(.rmcp_callback_config$allowed_tools) > 0 &&
291290
!tool_name %in% .rmcp_callback_config$allowed_tools) {
292291
stop(paste("Tool", tool_name, "not allowed for callbacks"))
293292
}
294-
293+
295294
# Prepare callback request
296295
callback_request <- list(
297296
callback_id = .rmcp_callback_config$callback_id,
298297
tool_name = tool_name,
299298
parameters = parameters,
300299
timestamp = as.numeric(Sys.time())
301300
)
302-
301+
303302
# Write request to file
304303
write(toJSON(callback_request, auto_unbox = TRUE), .rmcp_callback_file)
305-
304+
306305
# Signal Python to handle callback (this is a simplified version)
307306
# In practice, this would use a more sophisticated IPC mechanism
308307
cat("RMCP_CALLBACK:", .rmcp_callback_file, "\\n", file = stderr())
309-
308+
310309
# For now, return a placeholder response
311310
# Real implementation would wait for Python response
312311
return(list(
@@ -327,10 +326,10 @@ def create_r_callback_utilities() -> str:
327326
timestamp = as.numeric(Sys.time()),
328327
callback_id = .rmcp_callback_config$callback_id
329328
)
330-
329+
331330
cat("RMCP_PROGRESS_CALLBACK:", toJSON(progress_data, auto_unbox = TRUE), "\\n", file = stderr())
332331
}
333-
332+
334333
# Also call regular progress function
335334
if (exists("rmcp_progress")) {
336335
rmcp_progress(message, current, total)
@@ -359,10 +358,10 @@ def create_r_callback_utilities() -> str:
359358
if (!is.null(.rmcp_callback_file) && file.exists(.rmcp_callback_file)) {
360359
unlink(.rmcp_callback_file)
361360
}
362-
361+
363362
.rmcp_callback_config <<- NULL
364363
.rmcp_callback_file <<- NULL
365-
364+
366365
cat("RMCP callback system cleaned up\\n")
367366
}
368367
@@ -398,8 +397,8 @@ def create_r_callback_utilities() -> str:
398397
},
399398
)
400399
async def setup_r_bidirectional(
401-
context: Context, params: Dict[str, Any]
402-
) -> Dict[str, Any]:
400+
context: Context, params: dict[str, Any]
401+
) -> dict[str, Any]:
403402
"""
404403
Set up bidirectional communication in an R session.
405404
@@ -428,19 +427,19 @@ async def setup_r_bidirectional(
428427
setup_script = f"""
429428
# Load RMCP callback utilities
430429
{create_r_callback_utilities()}
431-
430+
432431
# Initialize callback system
433432
callback_config <- {json.dumps(callback_config)}
434433
rmcp_init_callback(callback_config)
435-
434+
436435
# Test callback system
437436
cat("Bidirectional communication ready\\n")
438-
437+
439438
result <- list(
440439
bidirectional_enabled = TRUE,
441440
callback_id = callback_config$callback_id,
442441
allowed_tools = callback_config$allowed_tools,
443-
session_id = "{session_id or 'default'}"
442+
session_id = "{session_id or "default"}"
444443
)
445444
"""
446445

@@ -469,8 +468,8 @@ async def setup_r_bidirectional(
469468
input_schema={"type": "object", "properties": {}},
470469
)
471470
async def list_callback_sessions(
472-
context: Context, params: Dict[str, Any]
473-
) -> Dict[str, Any]:
471+
context: Context, params: dict[str, Any]
472+
) -> dict[str, Any]:
474473
"""
475474
List all active callback sessions.
476475

rmcp/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ def _load_config(config_file: str) -> dict:
597597
import json
598598

599599
try:
600-
with open(config_file, "r") as f:
600+
with open(config_file) as f:
601601
return json.load(f)
602602
except Exception as e:
603603
logger.error(f"Failed to load config file {config_file}: {e}")

rmcp/config/defaults.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
"""
77

88
from pathlib import Path
9-
from typing import Any, Dict
9+
from typing import Any
1010

1111
# Default configuration as a dictionary for easy serialization
12-
DEFAULT_CONFIG: Dict[str, Any] = {
12+
DEFAULT_CONFIG: dict[str, Any] = {
1313
"http": {
1414
"host": "localhost",
1515
"port": 8000,

rmcp/config/loader.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@
5757
"""
5858

5959
import copy
60-
import functools
6160
import json
6261
import os
6362
from pathlib import Path
64-
from typing import Any, Dict, Optional, Union
63+
from typing import Any
6564

6665
try:
6766
import jsonschema
@@ -127,12 +126,12 @@ def __init__(self):
127126
Creates a new configuration loader with empty cache.
128127
The cache will be populated on first load_config() call.
129128
"""
130-
self._config_cache: Optional[RMCPConfig] = None
129+
self._config_cache: RMCPConfig | None = None
131130

132131
def load_config(
133132
self,
134-
config_file: Optional[Union[str, Path]] = None,
135-
overrides: Optional[Dict[str, Any]] = None,
133+
config_file: str | Path | None = None,
134+
overrides: dict[str, Any] | None = None,
136135
validate: bool = True,
137136
) -> RMCPConfig:
138137
"""
@@ -175,8 +174,8 @@ def load_config(
175174
return self._dict_to_config(config_dict)
176175

177176
def _load_config_file(
178-
self, config_file: Optional[Union[str, Path]] = None
179-
) -> Optional[Dict[str, Any]]:
177+
self, config_file: str | Path | None = None
178+
) -> dict[str, Any] | None:
180179
"""Load configuration from JSON file."""
181180
config_paths = []
182181

@@ -190,10 +189,10 @@ def _load_config_file(
190189
for config_path in config_paths:
191190
if config_path.exists() and config_path.is_file():
192191
try:
193-
with open(config_path, "r", encoding="utf-8") as f:
192+
with open(config_path, encoding="utf-8") as f:
194193
config_data = json.load(f)
195194
return config_data
196-
except (json.JSONDecodeError, IOError) as e:
195+
except (OSError, json.JSONDecodeError) as e:
197196
if config_file:
198197
# If explicitly specified, raise error
199198
raise ConfigError(
@@ -207,7 +206,7 @@ def _load_config_file(
207206

208207
return None
209208

210-
def _load_environment_config(self) -> Dict[str, Any]:
209+
def _load_environment_config(self) -> dict[str, Any]:
211210
"""Load configuration from environment variables."""
212211
env_config = {}
213212

@@ -242,7 +241,7 @@ def _convert_env_value(self, env_var: str, value: str) -> Any:
242241
# String value
243242
return value
244243

245-
def _set_nested_value(self, config_dict: Dict[str, Any], path: str, value: Any):
244+
def _set_nested_value(self, config_dict: dict[str, Any], path: str, value: Any):
246245
"""Set a nested dictionary value using dot notation."""
247246
keys = path.split(".")
248247
current = config_dict
@@ -255,8 +254,8 @@ def _set_nested_value(self, config_dict: Dict[str, Any], path: str, value: Any):
255254
current[keys[-1]] = value
256255

257256
def _merge_config(
258-
self, base: Dict[str, Any], override: Dict[str, Any]
259-
) -> Dict[str, Any]:
257+
self, base: dict[str, Any], override: dict[str, Any]
258+
) -> dict[str, Any]:
260259
"""Recursively merge configuration dictionaries."""
261260
result = copy.deepcopy(base)
262261

@@ -272,14 +271,14 @@ def _merge_config(
272271

273272
return result
274273

275-
def _validate_config(self, config_dict: Dict[str, Any]):
274+
def _validate_config(self, config_dict: dict[str, Any]):
276275
"""Validate configuration against JSON schema."""
277276
try:
278277
jsonschema.validate(config_dict, CONFIG_SCHEMA)
279278
except jsonschema.ValidationError as e:
280279
raise ConfigError(f"Configuration validation failed: {e.message}")
281280

282-
def _dict_to_config(self, config_dict: Dict[str, Any]) -> RMCPConfig:
281+
def _dict_to_config(self, config_dict: dict[str, Any]) -> RMCPConfig:
283282
"""Convert configuration dictionary to typed RMCPConfig object."""
284283
try:
285284
http_config = HTTPConfig(**config_dict.get("http", {}))
@@ -302,7 +301,7 @@ def _dict_to_config(self, config_dict: Dict[str, Any]) -> RMCPConfig:
302301

303302
# Global configuration instance
304303
_config_loader = ConfigLoader()
305-
_global_config: Optional[RMCPConfig] = None
304+
_global_config: RMCPConfig | None = None
306305

307306

308307
def get_config(reload: bool = False) -> RMCPConfig:
@@ -324,8 +323,8 @@ def get_config(reload: bool = False) -> RMCPConfig:
324323

325324

326325
def load_config(
327-
config_file: Optional[Union[str, Path]] = None,
328-
overrides: Optional[Dict[str, Any]] = None,
326+
config_file: str | Path | None = None,
327+
overrides: dict[str, Any] | None = None,
329328
validate: bool = True,
330329
) -> RMCPConfig:
331330
"""

0 commit comments

Comments
 (0)