chore: eliminate all deprecation warnings from tests and linter
Warnings fixed: - datetime.utcnow() → datetime.now(UTC) across 48+ files (src/ + tests/) - datetime.utcnow (callback ref) → lambda: datetime.now(UTC) in model fields (18 files) - Pydantic class Config → model_config = ConfigDict(...) (16 files) - Pydantic .dict() → .model_dump() (8 files) - ConfigDict(allow_population_by_field_name=True) → validate_by_name=True - SQLAlchemy declarative_base() import path updated - FastAPI on_event → lifespan context manager (app.py) - Import sorting (ruff I001) auto-fixed across all files - Fixed broken re-export chains that ruff F401 cleanup broke: _validate_bcp47: service.py now imports from dictionary_validation directly job_to_response: _job_routes.py and test imports from service_utils directly fetch_datasource_metadata: restored re-export in service.py - Added missing TranslateJobService import in _job_routes.py (was deleted by F401) - Added ConfigDict(protected_namespaces=()) for DashboardDatasetItem schema field - pytest.ini: replaced deprecated importmode with asyncio_mode All 440 tests pass with zero deprecation warnings.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
# @LAYER Domain
|
||||
# @RELATION DEPENDS_ON -> [EXT:Library:pydantic]
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -53,7 +53,7 @@ class DetectedIssue(BaseModel):
|
||||
class ValidationResult(BaseModel):
|
||||
id: str | None = None
|
||||
dashboard_id: str
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
||||
status: ValidationStatus
|
||||
screenshot_path: str | None = None
|
||||
issues: list[DetectedIssue]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# @INVARIANT All LLM interactions must be executed as asynchronous tasks.
|
||||
# @DATA_CONTRACT AnalysisRequest -> AnalysisResult
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import UTC, datetime, timedelta
|
||||
import json
|
||||
import os
|
||||
from typing import Any
|
||||
@@ -99,7 +99,7 @@ class DashboardValidationPlugin(PluginBase):
|
||||
# @SIDE_EFFECT Captures a screenshot, calls LLM API, and writes to the database.
|
||||
async def execute(self, params: dict[str, Any], context: TaskContext | None = None):
|
||||
with belief_scope("execute", f"plugin_id={self.id}"):
|
||||
validation_started_at = datetime.utcnow()
|
||||
validation_started_at = datetime.now(UTC)
|
||||
# Use TaskContext logger if available, otherwise fall back to app logger
|
||||
log = context.logger if context else logger
|
||||
|
||||
@@ -165,15 +165,15 @@ class DashboardValidationPlugin(PluginBase):
|
||||
filename = f"{dashboard_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
|
||||
screenshot_path = os.path.join(screenshots_dir, filename)
|
||||
|
||||
screenshot_started_at = datetime.utcnow()
|
||||
screenshot_started_at = datetime.now(UTC)
|
||||
screenshot_log.info(f"Capturing screenshot for dashboard {dashboard_id}")
|
||||
await screenshot_service.capture_dashboard(dashboard_id, screenshot_path)
|
||||
screenshot_log.debug(f"Screenshot saved to: {screenshot_path}")
|
||||
screenshot_finished_at = datetime.utcnow()
|
||||
screenshot_finished_at = datetime.now(UTC)
|
||||
|
||||
# 4. Fetch Logs (from Environment /api/v1/log/)
|
||||
logs = []
|
||||
logs_fetch_started_at = datetime.utcnow()
|
||||
logs_fetch_started_at = datetime.now(UTC)
|
||||
try:
|
||||
client = SupersetClient(env)
|
||||
|
||||
@@ -214,7 +214,7 @@ class DashboardValidationPlugin(PluginBase):
|
||||
except Exception as e:
|
||||
superset_log.warning(f"Failed to fetch logs from environment: {e}")
|
||||
logs = [f"Error fetching remote logs: {e!s}"]
|
||||
logs_fetch_finished_at = datetime.utcnow()
|
||||
logs_fetch_finished_at = datetime.now(UTC)
|
||||
|
||||
# 5. Analyze with LLM
|
||||
llm_client = LLMClient(
|
||||
@@ -230,13 +230,13 @@ class DashboardValidationPlugin(PluginBase):
|
||||
"dashboard_validation_prompt",
|
||||
DEFAULT_LLM_PROMPTS["dashboard_validation_prompt"],
|
||||
)
|
||||
llm_call_started_at = datetime.utcnow()
|
||||
llm_call_started_at = datetime.now(UTC)
|
||||
analysis = await llm_client.analyze_dashboard(
|
||||
screenshot_path,
|
||||
logs,
|
||||
prompt_template=dashboard_prompt,
|
||||
)
|
||||
llm_call_finished_at = datetime.utcnow()
|
||||
llm_call_finished_at = datetime.now(UTC)
|
||||
|
||||
# Log analysis summary to task logs for better visibility
|
||||
llm_log.info(f"[ANALYSIS_SUMMARY] Status: {analysis['status']}")
|
||||
@@ -254,9 +254,9 @@ class DashboardValidationPlugin(PluginBase):
|
||||
screenshot_path=screenshot_path,
|
||||
raw_response=str(analysis)
|
||||
)
|
||||
validation_finished_at = datetime.utcnow()
|
||||
validation_finished_at = datetime.now(UTC)
|
||||
|
||||
result_payload = _json_safe_value(validation_result.dict())
|
||||
result_payload = _json_safe_value(validation_result.model_dump())
|
||||
result_payload["screenshot_paths"] = [screenshot_path]
|
||||
result_payload["logs_sent_to_llm"] = logs
|
||||
result_payload["logs_sent_count"] = len(logs)
|
||||
@@ -291,7 +291,7 @@ class DashboardValidationPlugin(PluginBase):
|
||||
environment_id=env_id,
|
||||
status=validation_result.status.value,
|
||||
summary=validation_result.summary,
|
||||
issues=[issue.dict() for issue in validation_result.issues],
|
||||
issues=[issue.model_dump() for issue in validation_result.issues],
|
||||
screenshot_path=validation_result.screenshot_path,
|
||||
raw_response=json.dumps(result_payload, ensure_ascii=False)
|
||||
)
|
||||
|
||||
@@ -842,7 +842,7 @@ class ScreenshotService:
|
||||
await asyncio.sleep(0.5)
|
||||
except Exception:
|
||||
pass
|
||||
except asyncio.TimeoutError:
|
||||
except TimeoutError:
|
||||
logger.error(f"Screenshot capture timed out after {SCREENSHOT_SERVICE_TIMEOUT_MS}ms")
|
||||
try:
|
||||
await page.screenshot(path=output_path, timeout=PLAYWRIGHT_SHORT_TIMEOUT_MS)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
# @TEST_EDGE non_timestamp_string -> passed through unchanged
|
||||
|
||||
import logging
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from src.plugins.translate.sql_generator import (
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
# @REJECTED Keeping 1199-line test module violates module < 400 lines constraint.
|
||||
|
||||
# All tests have been migrated to the following modules:
|
||||
from .test_dictionary_correction import * # noqa: F401, F403
|
||||
from .test_dictionary_crud import * # noqa: F401, F403
|
||||
from .test_dictionary_filter import * # noqa: F401, F403
|
||||
from .test_dictionary_import import * # noqa: F401, F403
|
||||
from .test_dictionary_prompt_builder import * # noqa: F401, F403
|
||||
from .test_dictionary_utils import * # noqa: F401, F403
|
||||
from .test_dictionary_correction import * # noqa: F403
|
||||
from .test_dictionary_crud import * # noqa: F403
|
||||
from .test_dictionary_filter import * # noqa: F403
|
||||
from .test_dictionary_import import * # noqa: F403
|
||||
from .test_dictionary_prompt_builder import * # noqa: F403
|
||||
from .test_dictionary_utils import * # noqa: F403
|
||||
# #endregion TestDictionaryLegacyHub
|
||||
|
||||
@@ -10,7 +10,6 @@ from sqlalchemy.orm import Session, sessionmaker
|
||||
from src.models.translate import (
|
||||
Base,
|
||||
DictionaryEntry,
|
||||
TerminologyDictionary,
|
||||
TranslationBatch,
|
||||
TranslationJob,
|
||||
TranslationLanguage,
|
||||
|
||||
@@ -12,7 +12,7 @@ import pytest
|
||||
from sqlalchemy import create_engine, event
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
|
||||
from src.models.translate import Base, DictionaryEntry, TerminologyDictionary, TranslationJob, TranslationJobDictionary
|
||||
from src.models.translate import Base, TranslationJob, TranslationJobDictionary
|
||||
from src.plugins.translate.dictionary import DictionaryManager
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ from src.models.translate import (
|
||||
TranslationJob,
|
||||
TranslationRun,
|
||||
)
|
||||
from src.plugins.translate._batch_sizer import AdaptiveBatchSizer
|
||||
from src.plugins.translate.executor import TranslationExecutor, estimate_row_tokens
|
||||
|
||||
|
||||
|
||||
@@ -298,9 +298,7 @@ class TestBulkFindReplaceService:
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from src.models.translate import TranslationLanguage, TranslationRecord
|
||||
from src.plugins.translate.prompt_builder import ContextAwarePromptBuilder
|
||||
from src.plugins.translate.service import InlineCorrectionService
|
||||
|
||||
|
||||
# region TestContextCapture [TYPE Class]
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
from datetime import UTC, datetime
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from src.models.translate import (
|
||||
TranslationJob,
|
||||
|
||||
@@ -18,7 +18,6 @@ from src.plugins.translate.service_target_schema import (
|
||||
validate_target_table_schema,
|
||||
)
|
||||
from src.schemas.translate import (
|
||||
TargetSchemaColumnInfo,
|
||||
TargetSchemaValidationRequest,
|
||||
)
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# @REJECTED Inline insert logic in process_batch — made the function 583 lines.
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ from ...core.logger import belief_scope, logger
|
||||
from ...models.translate import TranslationBatch, TranslationJob, TranslationLanguage, TranslationRecord
|
||||
from ...services.llm_provider import LLMProviderService
|
||||
from ._batch_insert import insert_batch_to_target
|
||||
from ._lang_detect import batch_detect, get_detector
|
||||
from ._lang_detect import batch_detect
|
||||
from ._llm_call import LLMTranslationService
|
||||
from ._token_budget import estimate_token_budget
|
||||
from ._utils import _check_translation_cache, _compute_key_hash, _compute_source_hash
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
# @REJECTED Fixed batch_size of 50 — causes truncation on long-content rows.
|
||||
# Single monolithic batch — would lose all progress on any failure.
|
||||
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ from ...services.llm_prompt_templates import render_prompt
|
||||
from ...services.llm_provider import LLMProviderService
|
||||
from ._llm_http import call_openai_compatible
|
||||
from ._llm_parse import parse_llm_response
|
||||
from ._token_budget import estimate_token_budget
|
||||
from ._utils import _enforce_dictionary
|
||||
from .preview import DEFAULT_EXECUTION_PROMPT_TEMPLATE
|
||||
from .prompt_builder import ContextAwarePromptBuilder
|
||||
|
||||
@@ -35,7 +35,6 @@ def call_openai_compatible(
|
||||
if not base_url:
|
||||
raise ValueError("LLM provider has no base_url configured")
|
||||
|
||||
import requests as http_requests
|
||||
|
||||
url = f"{base_url.rstrip('/')}/chat/completions"
|
||||
headers = {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from ...core.logger import logger
|
||||
|
||||
|
||||
@@ -12,15 +12,13 @@
|
||||
# @REJECTED Keeping all run orchestration inside TranslationExecutor — caused class to exceed INV_7.
|
||||
|
||||
from collections.abc import Callable
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.config_manager import ConfigManager
|
||||
from ...core.logger import belief_scope, logger
|
||||
from ...models.translate import TranslationJob, TranslationRecord, TranslationRun, TranslationRunLanguageStats
|
||||
from ._batch_sizer import AdaptiveBatchSizer
|
||||
from ...models.translate import TranslationRecord, TranslationRun, TranslationRunLanguageStats
|
||||
from ._run_source import _extract_chart_data_rows, fetch_source_rows
|
||||
|
||||
|
||||
@@ -97,7 +95,7 @@ class RunExecutionService:
|
||||
|
||||
def _load_preview_edits(self, job_id: str) -> None:
|
||||
"""Load preview edits for carry-forward during execution."""
|
||||
from ...models.translate import TranslationPreviewLanguage, TranslationPreviewRecord, TranslationPreviewSession
|
||||
from ...models.translate import TranslationPreviewRecord, TranslationPreviewSession
|
||||
|
||||
with belief_scope("RunExecutionService._load_preview_edits"):
|
||||
session = (
|
||||
|
||||
@@ -17,7 +17,7 @@ import unicodedata
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
|
||||
from ...core.logger import logger
|
||||
from ...models.translate import TranslationLanguage, TranslationRecord
|
||||
from ...models.translate import TranslationRecord
|
||||
|
||||
|
||||
# #region _normalize_term [TYPE Function]
|
||||
|
||||
@@ -12,18 +12,13 @@
|
||||
# @PRE Database session is open and valid.
|
||||
# @SIDE_EFFECT Creates, updates, deletes TerminologyDictionary and DictionaryEntry rows; enforces deletion guards.
|
||||
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.logger import belief_scope
|
||||
from ...models.translate import DictionaryEntry, TerminologyDictionary
|
||||
from .dictionary_correction import DictionaryCorrectionService
|
||||
from .dictionary_crud import DictionaryCRUD
|
||||
from .dictionary_entries import DictionaryEntryCRUD
|
||||
from .dictionary_filter import DictionaryBatchFilter
|
||||
from .dictionary_import_export import DictionaryImportExport
|
||||
from .dictionary_validation import _validate_bcp47
|
||||
|
||||
|
||||
# #region DictionaryManager [C:4] [TYPE Class]
|
||||
|
||||
@@ -28,12 +28,14 @@ from ...core.logger import logger
|
||||
from ...models.translate import TranslationJob, TranslationRun, TranslationRunLanguageStats
|
||||
from ...services.llm_provider import LLMProviderService
|
||||
from ._run_service import RunExecutionService
|
||||
from ._token_budget import estimate_token_budget
|
||||
from ._utils import _check_translation_cache, _compute_source_hash, _enforce_dictionary, estimate_row_tokens
|
||||
|
||||
__all__ = [
|
||||
"TranslationExecutor", "estimate_row_tokens",
|
||||
"_enforce_dictionary", "_compute_source_hash", "_check_translation_cache",
|
||||
"TranslationExecutor",
|
||||
"_check_translation_cache",
|
||||
"_compute_source_hash",
|
||||
"_enforce_dictionary",
|
||||
"estimate_row_tokens",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
# @REJECTED Querying all events for all time — would be slow; MetricSnapshot provides historical summary.
|
||||
# @COMPLEXITY 4
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import func
|
||||
@@ -20,7 +19,6 @@ from sqlalchemy.orm import Session
|
||||
from ...core.logger import belief_scope
|
||||
from ...models.translate import (
|
||||
MetricSnapshot,
|
||||
TranslationEvent,
|
||||
TranslationRun,
|
||||
TranslationRunLanguageStats,
|
||||
TranslationSchedule,
|
||||
|
||||
@@ -23,12 +23,11 @@ from typing import Any
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.config_manager import ConfigManager
|
||||
from ...core.logger import belief_scope, logger
|
||||
from ...core.logger import belief_scope
|
||||
from ...models.translate import (
|
||||
TranslationRun,
|
||||
)
|
||||
from .events import TranslationEventLog
|
||||
from .executor import TranslationExecutor
|
||||
from .orchestrator_aggregator import TranslationResultAggregator
|
||||
from .orchestrator_planner import TranslationPlanner
|
||||
from .orchestrator_runner import TranslationStageRunner
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
# @RELATION DEPENDS_ON -> [TranslationRunLanguageStats]
|
||||
|
||||
from collections import defaultdict
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ from sqlalchemy.orm import Session
|
||||
from ...core.logger import belief_scope, logger
|
||||
from ...models.translate import (
|
||||
TranslationJob,
|
||||
TranslationPreviewSession,
|
||||
TranslationRun,
|
||||
)
|
||||
from .events import TranslationEventLog
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
# @RELATION DEPENDS_ON -> [TranslationEventLog]
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
from ...core.logger import logger
|
||||
from ...models.translate import TranslationJob, TranslationRun, TranslationRunLanguageStats
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
# @RELATION DEPENDS_ON -> [TranslationJob]
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from ...models.translate import TranslationJob, TranslationRecord
|
||||
from .sql_generator import _normalize_timestamp_value
|
||||
|
||||
@@ -40,7 +40,6 @@ from .preview_response_parser import (
|
||||
parse_llm_response as _parse_llm_response_module,
|
||||
)
|
||||
from .preview_review import PreviewSessionManager
|
||||
from .preview_token_estimator import TokenEstimator
|
||||
|
||||
|
||||
# #region TranslationPreview [C:4] [TYPE Class]
|
||||
@@ -272,5 +271,4 @@ class TranslationPreview:
|
||||
# #endregion TranslationPreview
|
||||
|
||||
# Re-export for backward compatibility
|
||||
from .preview_token_estimator import TokenEstimator # noqa: E402, F401
|
||||
# #endregion TranslationPreview
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.logger import logger
|
||||
from ...models.translate import TranslationJob
|
||||
from ._token_budget import DEFAULT_CONTEXT_WINDOW, estimate_token_budget
|
||||
|
||||
@@ -10,9 +10,8 @@ from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.logger import belief_scope, logger
|
||||
from ...core.logger import belief_scope
|
||||
from ...models.translate import (
|
||||
TranslationJob,
|
||||
TranslationPreviewLanguage,
|
||||
TranslationPreviewRecord,
|
||||
TranslationPreviewSession,
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
# @REJECTED Monolithic service.py — violated INV_7. Decomposed into service_datasource, service_inline_correction, service_bulk_replace, service_utils.
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
import uuid
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -21,9 +20,9 @@ from ...core.config_manager import ConfigManager
|
||||
from ...core.logger import logger
|
||||
from ...models.translate import TranslationJob, TranslationJobDictionary
|
||||
from ...schemas.translate import TranslateJobCreate, TranslateJobUpdate
|
||||
from .dictionary import _validate_bcp47
|
||||
from .dictionary_validation import _validate_bcp47
|
||||
from .service_datasource import fetch_datasource_metadata
|
||||
from .service_utils import _extract_dialect, job_to_response
|
||||
from .service_utils import _extract_dialect
|
||||
|
||||
|
||||
# #region TranslateJobService [TYPE Class]
|
||||
@@ -267,10 +266,8 @@ class TranslateJobService:
|
||||
from .service_bulk_replace import BulkFindReplaceService # noqa: E402, F401
|
||||
from .service_datasource import ( # noqa: E402, F401
|
||||
detect_virtual_columns,
|
||||
fetch_datasource_metadata,
|
||||
get_datasource_columns,
|
||||
get_dialect_from_database,
|
||||
)
|
||||
from .service_inline_correction import InlineCorrectionService # noqa: E402, F401
|
||||
from .service_utils import _extract_dialect, job_to_response # noqa: E402, F401
|
||||
# #endregion TranslateJobService
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
# @RELATION DEPENDS_ON -> [DictionaryEntry]
|
||||
# @RELATION DEPENDS_ON -> [_normalize_term]
|
||||
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# #region ServiceUtils [C:1] [TYPE Module] [SEMANTICS utils, dialect, response]
|
||||
# @BRIEF Utility functions for the translate service layer.
|
||||
|
||||
from typing import Any
|
||||
|
||||
from ...models.translate import TranslationJob
|
||||
from ...schemas.translate import TranslateJobResponse
|
||||
|
||||
Reference in New Issue
Block a user