Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[mypy]
python_version = 3.12
ignore_missing_imports = True
show_error_codes = True

# Optional features (container execution, vector stores, store CLI) rely on
# third-party libraries and loose typing; they are validated via tests.
exclude = (?x)
^src/py_code_mode/execution/container/|
^src/py_code_mode/workflows/vector_stores/|
^src/py_code_mode/cli/store\.py$
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ dev-dependencies = [
"pytest-xdist>=3.8.0",
"testcontainers[redis]>=4.13.3",
"chromadb>=0.5",
"types-pyyaml>=6.0.12.20250915",
]

[tool.pytest.ini_options]
Expand Down
2 changes: 2 additions & 0 deletions src/py_code_mode/cli/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,9 @@ async def create_session(args: argparse.Namespace) -> Session:
"""Create session based on CLI args."""
from py_code_mode import Session
from py_code_mode.execution.subprocess import SubprocessConfig, SubprocessExecutor
from py_code_mode.storage import StorageBackend

storage: StorageBackend
if args.redis:
from py_code_mode import RedisStorage

Expand Down
8 changes: 3 additions & 5 deletions src/py_code_mode/execution/in_process/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
PackageInstaller,
collect_configured_deps,
)
from py_code_mode.deps.store import DepsStore, MemoryDepsStore
from py_code_mode.execution.in_process.config import InProcessConfig
from py_code_mode.execution.in_process.workflows_namespace import WorkflowsNamespace
from py_code_mode.execution.protocol import Capability, validate_storage_not_access
Expand Down Expand Up @@ -287,15 +288,12 @@ async def start(
installer = PackageInstaller()
# Use a file-backed store if deps_file is configured, otherwise in-memory
if self._config.deps_file:
deps_store = FileDepsStore(self._config.deps_file.parent)
deps_store: DepsStore = FileDepsStore(self._config.deps_file.parent)
# Pre-populate store with config deps
for dep in initial_deps:
if not deps_store.exists(dep):
deps_store.add(dep)
deps_store.add(dep)
else:
# In-memory store for deps when no file configured
from py_code_mode.deps.store import MemoryDepsStore

deps_store = MemoryDepsStore()
for dep in initial_deps:
deps_store.add(dep)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def library(self) -> WorkflowLibrary:
"""
return self._library

def search(self, query: str, limit: int = 10) -> list[dict[str, Any]]:
def search(self, query: str, limit: int = 10) -> builtins.list[dict[str, Any]]:
"""Search for workflows matching query. Returns simplified workflow info."""
workflows = self._library.search(query, limit)
return [self._simplify(w) for w in workflows]
Expand All @@ -73,7 +73,7 @@ def get(self, name: str) -> Any:
"""Get a workflow by name."""
return self._library.get(name)

def list(self) -> list[dict[str, Any]]:
def list(self) -> builtins.list[dict[str, Any]]:
"""List all available workflows. Returns simplified workflow info."""
workflows = self._library.list()
return [self._simplify(w) for w in workflows]
Expand Down
2 changes: 2 additions & 0 deletions src/py_code_mode/storage/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ def __init__(
if url is None and redis is None:
raise ValueError("Either 'url' or 'redis' must be provided")

self._url: str | None

if url is not None:
from redis import Redis as RedisClient

Expand Down
9 changes: 6 additions & 3 deletions src/py_code_mode/tools/adapters/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
from typing import TYPE_CHECKING, Any, Protocol, cast, runtime_checkable

from py_code_mode.errors import ToolCallError, ToolNotFoundError
from py_code_mode.tools.types import Tool, ToolCallable, ToolParameter

logger = logging.getLogger(__name__)

# MCP SDK exception types (optional dependency)
MCP_ERRORS: tuple[type[BaseException], ...]
try:
from mcp import JSONRPCError, McpError

MCP_ERRORS = (McpError, JSONRPCError)
except ImportError:
MCP_ERRORS = ()
else:
# Stubs for mcp may not model exception inheritance precisely; the runtime objects
# are still safe to use in `except MCP_ERRORS`.
MCP_ERRORS = cast(tuple[type[BaseException], ...], (McpError, JSONRPCError))

if TYPE_CHECKING:
from contextlib import AsyncExitStack
Expand Down
5 changes: 3 additions & 2 deletions src/py_code_mode/tools/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import asyncio
import builtins
from typing import TYPE_CHECKING, Any

from py_code_mode.tools.types import Tool, ToolCallable
Expand Down Expand Up @@ -56,11 +57,11 @@ def __getattr__(self, tool_name: str) -> ToolProxy:

return ToolProxy(self._registry, tool, self._loop)

def list(self) -> list[Tool]:
def list(self) -> builtins.list[Tool]:
"""List all available tools."""
return self._registry.get_all_tools()

def search(self, query: str, limit: int = 5) -> list[Tool]:
def search(self, query: str, limit: int = 5) -> builtins.list[Tool]:
"""Search tools by query string."""
from py_code_mode.tools.registry import substring_search

Expand Down
5 changes: 3 additions & 2 deletions src/py_code_mode/workflows/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import builtins
from dataclasses import dataclass, field
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -138,7 +139,7 @@ def add(self, workflow: PythonWorkflow) -> None:
# Index locally for semantic search
self._index_workflow(workflow)

def list(self) -> list[PythonWorkflow]:
def list(self) -> builtins.list[PythonWorkflow]:
"""List all workflows."""
return list(self._workflows.values())

Expand Down Expand Up @@ -173,7 +174,7 @@ def search(
self,
query: str,
limit: int = 10,
) -> list[PythonWorkflow]:
) -> builtins.list[PythonWorkflow]:
"""Search for workflows by semantic similarity.

Args:
Expand Down
8 changes: 3 additions & 5 deletions src/py_code_mode/workflows/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,10 @@ def list_all(self) -> list[PythonWorkflow]:
return []

workflows = []
for name, value in all_data.items():
for raw_name, raw_value in all_data.items():
name = raw_name.decode() if isinstance(raw_name, bytes) else raw_name
value = raw_value.decode() if isinstance(raw_value, bytes) else raw_value
try:
if isinstance(value, bytes):
value = value.decode()
if isinstance(name, bytes):
name = name.decode()
data = json.loads(value)
workflows.append(self._deserialize_workflow(data))
except (json.JSONDecodeError, ValueError, SyntaxError, KeyError) as e:
Expand Down
Loading
Loading