032: T019 — remaining route files migrated to async SupersetClient

All routes (assistant, migration, datasets, git) now use AsyncSupersetClient.
_helpers.py sync->async for dashboard ref resolution.
_detail_routes.py import fixed.

Known residual: MigrationDryRunService and IdMappingService still sync.
This commit is contained in:
2026-06-04 20:02:33 +03:00
parent 51afbee470
commit 846d2cb9a9
17 changed files with 66 additions and 66 deletions

View File

@@ -161,11 +161,11 @@ async def _async_confirmation_summary(intent: dict[str, Any], config_manager: Co
if dry_run_enabled:
try:
from src.core.migration.dry_run_orchestrator import MigrationDryRunService
from src.core.superset_client import SupersetClient
from src.core.async_superset_client import AsyncSupersetClient
from src.models.dashboard import DashboardSelection
src_token = entities.get('source_env')
tgt_token = entities.get('target_env')
dashboard_id = _resolve_dashboard_id_entity(entities, config_manager, env_hint=src_token)
dashboard_id = await _resolve_dashboard_id_entity(entities, config_manager, env_hint=src_token)
if dashboard_id and src_token and tgt_token:
src_env_id = _resolve_env_id(src_token, config_manager)
tgt_env_id = _resolve_env_id(tgt_token, config_manager)
@@ -176,8 +176,8 @@ async def _async_confirmation_summary(intent: dict[str, Any], config_manager: Co
if source_env and target_env and (source_env.id != target_env.id):
selection = DashboardSelection(source_env_id=source_env.id, target_env_id=target_env.id, selected_ids=[dashboard_id], replace_db_config=_coerce_query_bool(entities.get('replace_db_config', False)), fix_cross_filters=_coerce_query_bool(entities.get('fix_cross_filters', True)))
service = MigrationDryRunService()
source_client = SupersetClient(source_env)
target_client = SupersetClient(target_env)
source_client = AsyncSupersetClient(source_env)
target_client = AsyncSupersetClient(target_env)
report = service.run(selection, source_client, target_client, db)
s = report.get('summary', {})
dash_s = s.get('dashboards', {})

View File

@@ -137,7 +137,7 @@ def _get_default_environment_id(config_manager: ConfigManager) -> str | None:
# @BRIEF Resolve dashboard id by title or slug reference in selected environment.
# @PRE dashboard_ref is a non-empty string-like token.
# @POST Returns dashboard id when uniquely matched, otherwise None.
def _resolve_dashboard_id_by_ref(
async def _resolve_dashboard_id_by_ref(
dashboard_ref: str | None,
env_id: str | None,
config_manager: ConfigManager,
@@ -153,7 +153,7 @@ def _resolve_dashboard_id_by_ref(
needle = dashboard_ref.strip().lower()
try:
client = SupersetClient(env)
_, dashboards = client.get_dashboards(query={"page_size": 200})
_, dashboards = await client.get_dashboards(query={"page_size": 200})
except Exception as exc:
logger.warning(
f"[assistant.dashboard_resolve][failed] ref={dashboard_ref} env={env_id} error={exc}"
@@ -189,7 +189,7 @@ def _resolve_dashboard_id_by_ref(
# @BRIEF Resolve dashboard id from intent entities using numeric id or dashboard_ref fallback.
# @PRE entities may contain dashboard_id as int/str and optional dashboard_ref.
# @POST Returns resolved dashboard id or None when ambiguous/unresolvable.
def _resolve_dashboard_id_entity(
async def _resolve_dashboard_id_entity(
entities: dict[str, Any],
config_manager: ConfigManager,
env_hint: str | None = None,
@@ -221,7 +221,7 @@ def _resolve_dashboard_id_entity(
if env_token
else _get_default_environment_id(config_manager)
)
return _resolve_dashboard_id_by_ref(str(dashboard_ref), env_id, config_manager)
return await _resolve_dashboard_id_by_ref(str(dashboard_ref), env_id, config_manager)
# #endregion _resolve_dashboard_id_entity

View File

@@ -59,7 +59,7 @@ async def handle_run_backup(
raise HTTPException(status_code=400, detail="Missing or unknown environment")
params: dict[str, Any] = {"environment_id": env_id}
if entities.get("dashboard_id") or entities.get("dashboard_ref"):
dashboard_id = _resolve_dashboard_id_entity(
dashboard_id = await _resolve_dashboard_id_entity(
entities, config_manager, env_hint=env_token
)
if not dashboard_id:
@@ -77,7 +77,7 @@ async def handle_run_backup(
),
]
if entities.get("dashboard_id") or entities.get("dashboard_ref"):
dashboard_id = _resolve_dashboard_id_entity(
dashboard_id = await _resolve_dashboard_id_entity(
entities, config_manager, env_hint=env_token
)
if dashboard_id:

View File

@@ -44,7 +44,7 @@ async def handle_commit_changes(
"""Commit dashboard repository changes."""
_check_any_permission(current_user, [("plugin:git", "EXECUTE")])
entities = intent.get("entities", {})
dashboard_id = _resolve_dashboard_id_entity(entities, config_manager)
dashboard_id = await _resolve_dashboard_id_entity(entities, config_manager)
commit_message = entities.get("message")
if not dashboard_id:
raise HTTPException(status_code=422, detail="Missing dashboard_id/dashboard_ref")

View File

@@ -45,7 +45,7 @@ async def handle_create_branch(
"""Create git branch for dashboard by id/slug/title."""
_check_any_permission(current_user, [("plugin:git", "EXECUTE")])
entities = intent.get("entities", {})
dashboard_id = _resolve_dashboard_id_entity(entities, config_manager)
dashboard_id = await _resolve_dashboard_id_entity(entities, config_manager)
branch_name = entities.get("branch_name")
if not dashboard_id or not branch_name:
raise HTTPException(

View File

@@ -45,7 +45,7 @@ async def handle_deploy_dashboard(
entities = intent.get("entities", {})
env_token = entities.get("environment")
env_id = _resolve_env_id(env_token, config_manager)
dashboard_id = _resolve_dashboard_id_entity(
dashboard_id = await _resolve_dashboard_id_entity(
entities, config_manager, env_hint=env_token
)
if not dashboard_id or not env_id:

View File

@@ -59,7 +59,7 @@ async def handle_run_llm_validation(
env_id = _resolve_env_id(env_token, config_manager) or _resolve_env_id(
None, config_manager
)
dashboard_id = _resolve_dashboard_id_entity(
dashboard_id = await _resolve_dashboard_id_entity(
entities, config_manager, env_hint=env_token
)
provider_id = _resolve_provider_id(

View File

@@ -64,7 +64,7 @@ async def handle_execute_migration(
entities = intent.get("entities", {})
src_token = entities.get("source_env")
dashboard_ref = entities.get("dashboard_ref")
dashboard_id = _resolve_dashboard_id_entity(
dashboard_id = await _resolve_dashboard_id_entity(
entities, config_manager, env_hint=src_token
)
src = _resolve_env_id(src_token, config_manager)

View File

@@ -66,7 +66,7 @@ async def handle_search_dashboards(
return (f"Окружение {env_id} не найдено.", None, [])
client = SupersetClient(env)
all_dashboards = client.get_dashboards_summary(require_slug=True)
all_dashboards = await client.get_dashboards_summary(require_slug=True)
# Filter by search term
if search:

View File

@@ -13,7 +13,7 @@ from urllib.parse import urlparse
from fastapi import Depends, HTTPException, Query, Response
from fastapi.responses import JSONResponse
from src.core.async_superset_client import AsyncSupersetClient
from src.core.superset_client import SupersetClient
from src.core.logger import belief_scope, logger
from src.core.utils.client_registry import get_client as get_superset_client
from src.core.utils.network import DashboardNotFoundError
@@ -110,7 +110,7 @@ async def get_database_mappings(
# @BRIEF Fetch detailed dashboard info with related charts and datasets
# @PRE env_id must be valid and dashboard ref (slug or id) must exist
# @POST Returns dashboard detail payload for overview page
# @RELATION CALLS -> [AsyncSupersetClient]
# @RELATION CALLS -> [SupersetClient]
@router.get("/{dashboard_ref}", response_model=DashboardDetailResponse)
async def get_dashboard_detail(
dashboard_ref: str,
@@ -142,7 +142,7 @@ async def get_dashboard_detail(
"verify_ssl": env.verify_ssl,
}
async_client = await get_superset_client(env_config)
client = AsyncSupersetClient(env)
client = SupersetClient(env)
dashboard_id = await _resolve_dashboard_id_from_ref_async(
dashboard_ref, client
)
@@ -183,7 +183,7 @@ async def get_dashboard_tasks_history(
f"dashboard_ref={dashboard_ref}, env_id={env_id}, limit={limit}",
):
dashboard_id: int | None = None
client: AsyncSupersetClient | None = None
client: SupersetClient | None = None
try:
if dashboard_ref.isdigit():
dashboard_id = int(dashboard_ref)
@@ -195,7 +195,7 @@ async def get_dashboard_tasks_history(
f"[get_dashboard_tasks_history][Coherence:Failed] Environment not found: {env_id}"
)
raise HTTPException(status_code=404, detail="Environment not found")
client = AsyncSupersetClient(env)
client = SupersetClient(env)
dashboard_id = await _resolve_dashboard_id_from_ref_async(
dashboard_ref, client
)
@@ -305,7 +305,7 @@ async def get_dashboard_thumbnail(
"verify_ssl": env.verify_ssl,
}
async_client = await get_superset_client(env_config)
client = AsyncSupersetClient(env)
client = SupersetClient(env)
dashboard_id = await _resolve_dashboard_id_from_ref_async(
dashboard_ref, client
)

View File

@@ -19,7 +19,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, ConfigDict, Field
from ...core.logger import belief_scope, logger
from ...core.superset_client import SupersetClient
from ...core.async_superset_client import AsyncSupersetClient
from ...dependencies import get_config_manager, get_resource_service, get_task_manager, has_permission
router = APIRouter(prefix="/api/datasets", tags=["Datasets"])
@@ -468,9 +468,9 @@ async def get_dataset_detail(
raise HTTPException(status_code=404, detail="Environment not found")
try:
# Fetch detailed dataset info using SupersetClient
client = SupersetClient(env)
dataset_detail = client.get_dataset_detail(dataset_id)
# Fetch detailed dataset info using AsyncSupersetClient
client = AsyncSupersetClient(env)
dataset_detail = await client.get_dataset_detail(dataset_id)
# Normalize 'database' field: Superset returns an object, model expects a string
if isinstance(dataset_detail.get("database"), dict):
@@ -536,13 +536,13 @@ async def update_column_description(
raise HTTPException(status_code=404, detail="Environment not found")
try:
client = SupersetClient(env)
client = AsyncSupersetClient(env)
# GET full dataset
logger.reason("Fetching full dataset from Superset for column description update",
extra={"src": "update_column_description"})
try:
response = client.get_dataset(dataset_id)
response = await client.get_dataset(dataset_id)
except Exception as e:
logger.error(f"[update_column_description][Coherence:Failed] Superset GET failed: {e}")
raise HTTPException(status_code=502, detail=f"Failed to fetch dataset from Superset: {e!s}")
@@ -572,7 +572,7 @@ async def update_column_description(
# PUT back with override_columns=false
put_payload = dataset
try:
client.update_dataset(dataset_id, put_payload, override_columns=False)
await client.update_dataset(dataset_id, put_payload, override_columns=False)
except Exception as e:
logger.error(f"[update_column_description][Coherence:Failed] Superset PUT failed: {e}")
raise HTTPException(status_code=502, detail=f"Failed to update dataset in Superset: {e!s}")
@@ -623,13 +623,13 @@ async def update_metric_description(
raise HTTPException(status_code=404, detail="Environment not found")
try:
client = SupersetClient(env)
client = AsyncSupersetClient(env)
# GET full dataset
logger.reason("Fetching full dataset from Superset for metric description update",
extra={"src": "update_metric_description"})
try:
response = client.get_dataset(dataset_id)
response = await client.get_dataset(dataset_id)
except Exception as e:
logger.error(f"[update_metric_description][Coherence:Failed] Superset GET failed: {e}")
raise HTTPException(status_code=502, detail=f"Failed to fetch dataset from Superset: {e!s}")
@@ -658,7 +658,7 @@ async def update_metric_description(
# PUT back with override_columns=false
try:
client.update_dataset(dataset_id, dataset, override_columns=False)
await client.update_dataset(dataset_id, dataset, override_columns=False)
except Exception as e:
logger.error(f"[update_metric_description][Coherence:Failed] Superset PUT failed: {e}")
raise HTTPException(status_code=502, detail=f"Failed to update dataset in Superset: {e!s}")

View File

@@ -90,7 +90,7 @@ def _get_git_config_or_404(db: Session, config_id: str) -> GitServerConfig:
# #region _find_dashboard_id_by_slug [C:2] [TYPE Function]
# @BRIEF Resolve dashboard numeric ID by slug in a specific environment.
def _find_dashboard_id_by_slug(
async def _find_dashboard_id_by_slug(
client: SupersetClient,
dashboard_slug: str,
) -> int | None:
@@ -109,7 +109,7 @@ def _find_dashboard_id_by_slug(
for query in query_variants:
try:
_count, dashboards = client.get_dashboards_page(query=query)
_count, dashboards = await client.get_dashboards_page(query=query)
if dashboards:
resolved_id = dashboards[0].get("id")
if resolved_id is not None:
@@ -122,7 +122,7 @@ def _find_dashboard_id_by_slug(
# #region _resolve_dashboard_id_from_ref [C:2] [TYPE Function]
# @BRIEF Resolve dashboard ID from slug-or-id reference for Git routes.
def _resolve_dashboard_id_from_ref(
async def _resolve_dashboard_id_from_ref(
dashboard_ref: str,
config_manager,
env_id: str | None = None,
@@ -145,7 +145,7 @@ def _resolve_dashboard_id_from_ref(
if not env:
raise HTTPException(status_code=404, detail="Environment not found")
dashboard_id = _find_dashboard_id_by_slug(SupersetClient(env), normalized_ref)
dashboard_id = await _find_dashboard_id_by_slug(SupersetClient(env), normalized_ref)
if dashboard_id is None:
raise HTTPException(
status_code=404, detail=f"Dashboard slug '{normalized_ref}' not found"
@@ -228,7 +228,7 @@ async def _resolve_dashboard_id_from_ref_async(
# #region _resolve_repo_key_from_ref [C:2] [TYPE Function]
# @BRIEF Resolve repository folder key with slug-first strategy and deterministic fallback.
def _resolve_repo_key_from_ref(
async def _resolve_repo_key_from_ref(
dashboard_ref: str,
dashboard_id: int,
config_manager,
@@ -243,7 +243,7 @@ def _resolve_repo_key_from_ref(
environments = config_manager.get_environments()
env = next((e for e in environments if e.id == env_id), None)
if env:
payload = SupersetClient(env).get_dashboard(dashboard_id)
payload = await SupersetClient(env).get_dashboard(dashboard_id)
dashboard_data = (
payload.get("result", payload) if isinstance(payload, dict) else {}
)

View File

@@ -37,7 +37,7 @@ async def get_merge_status(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.get_merge_status(dashboard_id)
@@ -65,7 +65,7 @@ async def get_merge_conflicts(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.get_merge_conflicts(dashboard_id)
@@ -92,7 +92,7 @@ async def resolve_merge_conflicts(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
resolved_files = _gs.resolve_merge_conflicts(
@@ -121,7 +121,7 @@ async def abort_merge(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.abort_merge(dashboard_id)
@@ -148,7 +148,7 @@ async def continue_merge(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.continue_merge(dashboard_id, continue_data.message)

View File

@@ -41,7 +41,7 @@ async def sync_dashboard(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
from src.plugins.git_plugin import GitPlugin
@@ -78,7 +78,7 @@ async def promote_dashboard(
with belief_scope("promote_dashboard"):
from . import _resolve_dashboard_id_from_ref
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
db_repo = (
@@ -199,7 +199,7 @@ async def deploy_dashboard(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
from src.plugins.git_plugin import GitPlugin

View File

@@ -45,7 +45,7 @@ async def commit_changes(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
_apply_git_identity_from_profile(dashboard_id, db, current_user)
@@ -74,7 +74,7 @@ async def push_changes(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
_gs.push_changes(dashboard_id)
@@ -103,7 +103,7 @@ async def pull_changes(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
db_repo = None
@@ -161,7 +161,7 @@ async def get_repository_status(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _resolve_repository_status(dashboard_id)
@@ -227,7 +227,7 @@ async def get_repository_diff(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.get_diff(dashboard_id, file_path, staged)
@@ -253,7 +253,7 @@ async def get_history(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.get_commit_history(dashboard_id, limit)
@@ -280,7 +280,7 @@ async def generate_commit_message(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
diff = _gs.get_diff(dashboard_id, staged=True)

View File

@@ -44,10 +44,10 @@ async def init_repository(
with belief_scope("init_repository"):
from . import _resolve_dashboard_id_from_ref, _resolve_repo_key_from_ref
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
repo_key = _resolve_repo_key_from_ref(
repo_key = await _resolve_repo_key_from_ref(
dashboard_ref, dashboard_id, config_manager, env_id
)
config = (
@@ -122,7 +122,7 @@ async def get_repository_binding(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
db_repo = (
@@ -163,7 +163,7 @@ async def delete_repository(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
_gs.delete_repo(dashboard_id)
@@ -189,7 +189,7 @@ async def get_branches(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
return _gs.list_branches(dashboard_id)
@@ -217,7 +217,7 @@ async def create_branch(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
_apply_git_identity_from_profile(dashboard_id, db, current_user)
@@ -247,7 +247,7 @@ async def checkout_branch(
from . import _resolve_dashboard_id_from_ref
try:
dashboard_id = _resolve_dashboard_id_from_ref(
dashboard_id = await _resolve_dashboard_id_from_ref(
dashboard_ref, config_manager, env_id
)
_gs.checkout_branch(dashboard_id, checkout_data.name)

View File

@@ -30,7 +30,7 @@ from ...core.database import get_db
from ...core.logger import belief_scope, logger
from ...core.mapping_service import IdMappingService
from ...core.migration.dry_run_orchestrator import MigrationDryRunService
from ...core.superset_client import SupersetClient
from ...core.async_superset_client import AsyncSupersetClient
from ...dependencies import get_config_manager, get_task_manager, has_permission
from ...models.dashboard import DashboardMetadata, DashboardSelection
from ...models.mapping import ResourceMapping
@@ -62,8 +62,8 @@ async def get_dashboards(
logger.explore(f"Environment {env_id} not found in configuration")
raise HTTPException(status_code=404, detail="Environment not found")
client = SupersetClient(env)
dashboards = client.get_dashboards_summary()
client = AsyncSupersetClient(env)
dashboards = await client.get_dashboards_summary()
logger.reflect(f"Retrieved {len(dashboards)} dashboards from {env_id}")
return dashboards
@@ -180,8 +180,8 @@ async def dry_run_migration(
)
service = MigrationDryRunService()
source_client = SupersetClient(source_env)
target_client = SupersetClient(target_env)
source_client = AsyncSupersetClient(source_env)
target_client = AsyncSupersetClient(target_env)
try:
result = service.run(
@@ -373,7 +373,7 @@ async def trigger_sync_now(
for env in environments:
try:
client = SupersetClient(env)
client = AsyncSupersetClient(env)
service.sync_environment(env.id, client)
results["synced"].append(env.id)
logger.reason(f"Synced environment {env.id}", extra={"src": "trigger_sync_now"})