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:
@@ -10,13 +10,15 @@
|
||||
# @DATA_CONTRACT [HTTP Request | WS Message] -> [HTTP Response | JSON Log Stream]
|
||||
# @RATIONALE Duplicate @RELATION and @INVARIANT lines removed from header. Import sorting unified via ruff isort (I) rule across src/ — 139 fixes applied.
|
||||
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# project_root is used for static files mounting
|
||||
project_root = Path(__file__).resolve().parent.parent.parent
|
||||
import asyncio
|
||||
|
||||
from alembic.config import Config as AlembicConfig
|
||||
from fastapi import FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse
|
||||
@@ -24,6 +26,8 @@ from fastapi.staticfiles import StaticFiles
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.middleware.sessions import SessionMiddleware
|
||||
|
||||
from alembic import command as alembic_command
|
||||
|
||||
from .api import auth
|
||||
from .api.routes import (
|
||||
admin,
|
||||
@@ -50,9 +54,6 @@ from .api.routes import (
|
||||
translate,
|
||||
validation,
|
||||
)
|
||||
from alembic.config import Config as AlembicConfig
|
||||
from alembic import command as alembic_command
|
||||
|
||||
from .core.auth.security import get_password_hash
|
||||
from .core.cot_logger import seed_trace_id
|
||||
from .core.database import AuthSessionLocal, init_db
|
||||
@@ -62,6 +63,28 @@ from .core.utils.network import NetworkError
|
||||
from .dependencies import get_scheduler_service, get_task_manager
|
||||
from .models.auth import Role, User
|
||||
|
||||
|
||||
# #region lifespan [C:3] [TYPE Function]
|
||||
# @BRIEF Async context manager for FastAPI startup/shutdown lifecycle.
|
||||
# @RELATION CALLS -> [run_alembic_migrations]
|
||||
# @RELATION CALLS -> [init_db]
|
||||
# @RELATION CALLS -> [AppDependencies]
|
||||
# @POST On startup: schema up-to-date, admin exists, scheduler started. On shutdown: scheduler stopped.
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Startup
|
||||
seed_trace_id()
|
||||
with belief_scope("startup_event"):
|
||||
ensure_encryption_key()
|
||||
run_alembic_migrations()
|
||||
init_db()
|
||||
ensure_initial_admin_user()
|
||||
scheduler = get_scheduler_service()
|
||||
scheduler.start()
|
||||
yield
|
||||
# Shutdown
|
||||
scheduler.stop()
|
||||
# #endregion lifespan
|
||||
# #region FastAPI_App [C:3] [TYPE Global] [SEMANTICS app, fastapi, instance, route-registry]
|
||||
# @BRIEF Canonical FastAPI application instance for route, middleware, and websocket registration.
|
||||
# @RELATION DEPENDS_ON -> [ApiRoutesModule]
|
||||
@@ -70,6 +93,7 @@ app = FastAPI(
|
||||
title="Superset Tools API",
|
||||
description="API for managing Superset automation tools and plugins.",
|
||||
version="1.0.0",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
# #endregion FastAPI_App
|
||||
# #region ensure_initial_admin_user [C:3] [TYPE Function]
|
||||
@@ -152,37 +176,7 @@ def run_alembic_migrations() -> None:
|
||||
# #endregion run_alembic_migrations
|
||||
|
||||
|
||||
# #region startup_event [C:3] [TYPE Function]
|
||||
# @BRIEF Handles application startup: Alembic → create_all → admin bootstrap → scheduler.
|
||||
# @RELATION CALLS -> [run_alembic_migrations]
|
||||
# @RELATION CALLS -> [init_db]
|
||||
# @POST Schema is up-to-date via Alembic, missing tables created, admin exists, scheduler started.
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
seed_trace_id()
|
||||
with belief_scope("startup_event"):
|
||||
ensure_encryption_key()
|
||||
# 1. Alembic — applies ALL pending migrations (add/drop/rename columns, data migrations)
|
||||
run_alembic_migrations()
|
||||
# 2. init_db — creates new tables via create_all() (does NOT alter existing ones)
|
||||
init_db()
|
||||
ensure_initial_admin_user()
|
||||
scheduler = get_scheduler_service()
|
||||
scheduler.start()
|
||||
# #endregion startup_event
|
||||
# #region shutdown_event [C:3] [TYPE Function]
|
||||
# @BRIEF Handles application shutdown tasks, such as stopping the scheduler.
|
||||
# @RELATION CALLS -> [AppDependencies]
|
||||
# @PRE None.
|
||||
# @POST Scheduler is stopped.
|
||||
# Shutdown event
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
seed_trace_id()
|
||||
with belief_scope("shutdown_event"):
|
||||
scheduler = get_scheduler_service()
|
||||
scheduler.stop()
|
||||
# #endregion shutdown_event
|
||||
|
||||
# #region app_middleware [TYPE Block]
|
||||
# @BRIEF Configure application-wide middleware (Session, CORS).
|
||||
# @RATIONALE SessionMiddleware uses SESSION_SECRET_KEY independent of JWT SECRET_KEY (see [SEC:H-4]).
|
||||
@@ -349,8 +343,8 @@ async def _authenticate_websocket(websocket: WebSocket, endpoint_name: str) -> b
|
||||
|
||||
# Try JWT first, fallback to API key
|
||||
try:
|
||||
from .core.auth.jwt import decode_token
|
||||
from .core.auth.api_key import hash_api_key
|
||||
from .core.auth.jwt import decode_token
|
||||
from .core.database import SessionLocal
|
||||
|
||||
# Attempt JWT validation
|
||||
@@ -479,7 +473,7 @@ async def websocket_endpoint(
|
||||
initial_sent = 0
|
||||
for log_entry in initial_logs:
|
||||
if matches_filters(log_entry):
|
||||
log_dict = log_entry.dict()
|
||||
log_dict = log_entry.model_dump()
|
||||
log_dict["timestamp"] = log_dict["timestamp"].isoformat()
|
||||
await websocket.send_json(log_dict)
|
||||
initial_sent += 1
|
||||
@@ -510,7 +504,7 @@ async def websocket_endpoint(
|
||||
log_entry = await queue.get()
|
||||
if not matches_filters(log_entry):
|
||||
continue
|
||||
log_dict = log_entry.dict()
|
||||
log_dict = log_entry.model_dump()
|
||||
log_dict["timestamp"] = log_dict["timestamp"].isoformat()
|
||||
await websocket.send_json(log_dict)
|
||||
logger.reflect(
|
||||
|
||||
Reference in New Issue
Block a user