diff --git a/src/agent_execution/docker_sandbox.py b/src/agent_execution/docker_sandbox.py index 4e6ac49..7487ebf 100644 --- a/src/agent_execution/docker_sandbox.py +++ b/src/agent_execution/docker_sandbox.py @@ -26,14 +26,15 @@ # Docker SDK try: - from docker.errors import DockerException, NotFound + from docker.errors import DockerException, NotFound # type: ignore[attr-defined] - import docker + import docker # type: ignore[attr-defined] DOCKER_AVAILABLE = True except ImportError: DOCKER_AVAILABLE = False DockerException = Exception + docker = None # type: ignore[assignment] # ============================================================================= @@ -142,7 +143,7 @@ def __init__( self._client = None - def _get_docker_client(self) -> "docker.DockerClient": + def _get_docker_client(self) -> "docker.DockerClient": # type: ignore[misc] """Get or create Docker client.""" if not DOCKER_AVAILABLE: raise ImportError( @@ -152,9 +153,9 @@ def _get_docker_client(self) -> "docker.DockerClient": if self._client is None: try: # Try to connect to Docker daemon - self._client = docker.from_env() + self._client = docker.from_env() # type: ignore[union-attr] # Verify connection - self._client.ping() + self._client.ping() # type: ignore[union-attr] except DockerException as e: raise RuntimeError( f"Failed to connect to Docker daemon: {e}. " diff --git a/src/utils/error_tracking.py b/src/utils/error_tracking.py index ff72452..77ec0be 100644 --- a/src/utils/error_tracking.py +++ b/src/utils/error_tracking.py @@ -22,13 +22,15 @@ capture_exception(e) """ +from __future__ import annotations + import logging import os import sys -from typing import Any, ClassVar +from typing import TYPE_CHECKING, Any, ClassVar -# Optional Sentry dependency -try: +# Optional Sentry dependency - only import for type hints when available +if TYPE_CHECKING: import sentry_sdk from sentry_sdk import capture_exception, capture_message from sentry_sdk.integrations import ( @@ -38,30 +40,17 @@ ) from sentry_sdk.integrations.logging import ignore_logger from sentry_sdk.tracing import Transaction - SENTRY_AVAILABLE = True -except ImportError: - SENTRY_AVAILABLE = False - # Mock classes and functions for when Sentry is not available - sentry_sdk = None # type: ignore - def capture_exception(*args, **kwargs): return None - def capture_message(*args, **kwargs): return None - - class Transaction: - def __init__(self, *args, **kwargs): pass - def __enter__(self): return self - def __exit__(self, *args): pass - - # Mock integration classes for type hints - class FastApiIntegration: # type: ignore - def __init__(self, *args, **kwargs): pass - - class LoggingIntegration: # type: ignore - def __init__(self, *args, **kwargs): pass - - class SqlalchemyIntegration: # type: ignore - def __init__(self, *args, **kwargs): pass - - def ignore_logger(*args, **kwargs): pass +else: + sentry_sdk = None + capture_exception = None + capture_message = None + Transaction = None + FastApiIntegration = None + LoggingIntegration = None + SqlalchemyIntegration = None + ignore_logger = None + +SENTRY_AVAILABLE = sentry_sdk is not None from src.utils.logger import get_logger @@ -279,10 +268,10 @@ def add_breadcrumb( ) -def capture_exception( +def capture_exception( # type: ignore[no-redef] exc: BaseException | None = None, extra: dict[str, Any] | None = None, - **tags, + **tags: Any, ) -> str | None: """Capture an exception with optional context. @@ -318,11 +307,11 @@ def capture_exception( return event_id -def capture_message( +def capture_message( # type: ignore[no-redef] message: str, level: str = "info", extra: dict[str, Any] | None = None, - **tags, + **tags: Any, ) -> str | None: """Capture a message with optional context. diff --git a/src/utils/logger.py b/src/utils/logger.py index db9d9ec..0d81452 100644 --- a/src/utils/logger.py +++ b/src/utils/logger.py @@ -19,6 +19,7 @@ from contextlib import suppress from logging.handlers import RotatingFileHandler from pathlib import Path +from typing import Any # Import error tracking for automatic error capture in logs (Issue #230) try: @@ -31,9 +32,15 @@ except ImportError: SENTRY_AVAILABLE = False # Mock functions when error_tracking is not available - def add_breadcrumb(*args, **kwargs): pass - def capture_exception(*args, **kwargs): return None - def capture_message(*args, **kwargs): return None + def add_breadcrumb( + message: str, + category: str = "default", + level: str = "info", + **data: Any, + ) -> None: + pass + def capture_exception(*args: Any, **kwargs: Any) -> None: pass + def capture_message(*args: Any, **kwargs: Any) -> None: pass def setup_logging( diff --git a/tests/test_oauth_manager.py b/tests/test_oauth_manager.py index 6e2e061..a9db23f 100644 --- a/tests/test_oauth_manager.py +++ b/tests/test_oauth_manager.py @@ -9,7 +9,7 @@ """ import pytest -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from unittest.mock import AsyncMock, patch, Mock import httpx @@ -84,7 +84,7 @@ def test_token_expired(self): expires_in=1, ) # Manually set expiration to past - token.expires_at = datetime.utcnow() - timedelta(seconds=10) + token.expires_at = datetime.now(timezone.utc) - timedelta(seconds=10) assert token.is_expired() is True @@ -117,7 +117,7 @@ def test_token_from_dict(self): def test_token_from_dict_with_timestamps(self): """Test creating token from dictionary with timestamps.""" - now = datetime.utcnow() + now = datetime.now(timezone.utc) token_data = { "access_token": "test", "refresh_token": "refresh", @@ -267,7 +267,7 @@ async def test_get_valid_token_auto_refresh(self, oauth_manager): refresh_token="refresh", expires_in=1, ) - expired_token.expires_at = datetime.utcnow() - timedelta(seconds=10) + expired_token.expires_at = datetime.now(timezone.utc) - timedelta(seconds=10) oauth_manager.set_token(expired_token) # Mock refresh response @@ -430,7 +430,7 @@ async def test_refresh_all_tokens(self): refresh_token="refresh", expires_in=1, ) - expired_token.expires_at = datetime.utcnow() - timedelta(seconds=10) + expired_token.expires_at = datetime.now(timezone.utc) - timedelta(seconds=10) manager.set_token(expired_token) # Mock refresh response diff --git a/tests/test_performance_improvements.py b/tests/test_performance_improvements.py index 9fcb565..94cbafb 100644 --- a/tests/test_performance_improvements.py +++ b/tests/test_performance_improvements.py @@ -40,8 +40,15 @@ @pytest.fixture def test_db(): """Create in-memory SQLite database for testing.""" + from src.api.models import Base + from src.api.user_models import Base as UserBase + engine = create_engine("sqlite:///:memory:", echo=False) + + # Create all tables from all model bases Base.metadata.create_all(engine) + UserBase.metadata.create_all(engine) + SessionLocal = sessionmaker(bind=engine) db = SessionLocal() try: diff --git a/tests/test_training_mode_simulation.py b/tests/test_training_mode_simulation.py index 0989e65..ad98d39 100644 --- a/tests/test_training_mode_simulation.py +++ b/tests/test_training_mode_simulation.py @@ -19,6 +19,13 @@ def reset_config(): """Reset config before each test.""" reset_instance() reset_simulation_engine() + # Clean up database to ensure test isolation + session = SessionLocal() + try: + session.query(SimulationBid).delete() + session.commit() + finally: + session.close() yield