032: fix final sync→async cascade (dataset_review, parsing, validation)
- _parsing.py: parse_superset_link + _recover_dataset_binding → async
(await get_dashboard_detail, get_chart)
- dataset_review/orchestrator.py: start_session + _build_recovery_bootstrap → async
(await get_dataset_detail, parse_superset_link)
- _routes.py (dataset_review): await orchestrator.start_session()
- validation_tasks.py: await parse_superset_link + get_dashboard_detail
This commit is contained in:
@@ -161,7 +161,7 @@ async def start_session(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
result = orchestrator.start_session(
|
result = await orchestrator.start_session(
|
||||||
StartSessionCommand(
|
StartSessionCommand(
|
||||||
user=current_user,
|
user=current_user,
|
||||||
environment_id=request.environment_id,
|
environment_id=request.environment_id,
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ async def parse_superset_url(
|
|||||||
from ...core.utils.superset_context_extractor import SupersetContextExtractor
|
from ...core.utils.superset_context_extractor import SupersetContextExtractor
|
||||||
|
|
||||||
extractor = SupersetContextExtractor(environment=env)
|
extractor = SupersetContextExtractor(environment=env)
|
||||||
parsed = extractor.parse_superset_link(payload.url)
|
parsed = await extractor.parse_superset_link(payload.url)
|
||||||
|
|
||||||
dashboard_id = str(parsed.dashboard_id) if parsed.dashboard_id is not None else None
|
dashboard_id = str(parsed.dashboard_id) if parsed.dashboard_id is not None else None
|
||||||
title: str | None = None
|
title: str | None = None
|
||||||
@@ -420,7 +420,7 @@ async def parse_superset_url(
|
|||||||
# Resolve dashboard title from Superset API when possible
|
# Resolve dashboard title from Superset API when possible
|
||||||
if parsed.dashboard_id:
|
if parsed.dashboard_id:
|
||||||
try:
|
try:
|
||||||
dashboard = extractor.client.get_dashboard_detail(parsed.dashboard_id)
|
dashboard = await extractor.client.get_dashboard_detail(parsed.dashboard_id)
|
||||||
title = dashboard.get("dashboard_title", str(parsed.dashboard_id))
|
title = dashboard.get("dashboard_title", str(parsed.dashboard_id))
|
||||||
except Exception:
|
except Exception:
|
||||||
title = str(parsed.dashboard_id)
|
title = str(parsed.dashboard_id)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class SupersetContextParsingMixin:
|
|||||||
# @POST returns resolved dataset/dashboard context, preserving explicit partial-recovery state if some identifiers cannot be confirmed.
|
# @POST returns resolved dataset/dashboard context, preserving explicit partial-recovery state if some identifiers cannot be confirmed.
|
||||||
# @SIDE_EFFECT may issue Superset API reads to resolve dataset references from dashboard or chart URLs.
|
# @SIDE_EFFECT may issue Superset API reads to resolve dataset references from dashboard or chart URLs.
|
||||||
# @DATA_CONTRACT Input[link:str] -> Output[SupersetParsedContext]
|
# @DATA_CONTRACT Input[link:str] -> Output[SupersetParsedContext]
|
||||||
def parse_superset_link(self, link: str) -> SupersetParsedContext:
|
async def parse_superset_link(self, link: str) -> SupersetParsedContext:
|
||||||
with belief_scope("SupersetContextExtractor.parse_superset_link"):
|
with belief_scope("SupersetContextExtractor.parse_superset_link"):
|
||||||
normalized_link = str(link or "").strip()
|
normalized_link = str(link or "").strip()
|
||||||
if not normalized_link:
|
if not normalized_link:
|
||||||
@@ -106,7 +106,7 @@ class SupersetContextParsingMixin:
|
|||||||
!= "dashboard_permalink_dataset_binding_unresolved"
|
!= "dashboard_permalink_dataset_binding_unresolved"
|
||||||
]
|
]
|
||||||
dataset_id, unresolved_references = (
|
dataset_id, unresolved_references = (
|
||||||
self._recover_dataset_binding_from_dashboard(
|
await self._recover_dataset_binding_from_dashboard(
|
||||||
dashboard_id=dashboard_id,
|
dashboard_id=dashboard_id,
|
||||||
dataset_ref=dataset_ref,
|
dataset_ref=dataset_ref,
|
||||||
unresolved_references=unresolved_references,
|
unresolved_references=unresolved_references,
|
||||||
@@ -123,7 +123,7 @@ class SupersetContextParsingMixin:
|
|||||||
!= "dashboard_permalink_dataset_binding_unresolved"
|
!= "dashboard_permalink_dataset_binding_unresolved"
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
chart_payload = self.client.get_chart(chart_id)
|
chart_payload = await self.client.get_chart(chart_id)
|
||||||
chart_data = (
|
chart_data = (
|
||||||
chart_payload.get("result", chart_payload)
|
chart_payload.get("result", chart_payload)
|
||||||
if isinstance(chart_payload, dict)
|
if isinstance(chart_payload, dict)
|
||||||
@@ -170,7 +170,7 @@ class SupersetContextParsingMixin:
|
|||||||
)
|
)
|
||||||
# Resolve dashboard detail first — handles both numeric ID and slug,
|
# Resolve dashboard detail first — handles both numeric ID and slug,
|
||||||
# ensuring dashboard_id is available for the native_filters_key fetch below.
|
# ensuring dashboard_id is available for the native_filters_key fetch below.
|
||||||
dashboard_detail = self.client.get_dashboard_detail(
|
dashboard_detail = await self.client.get_dashboard_detail(
|
||||||
resolved_dashboard_ref
|
resolved_dashboard_ref
|
||||||
)
|
)
|
||||||
resolved_dashboard_id = dashboard_detail.get("id")
|
resolved_dashboard_id = dashboard_detail.get("id")
|
||||||
@@ -317,13 +317,13 @@ class SupersetContextParsingMixin:
|
|||||||
# #region SupersetContextParsingMixin._recover_dataset_binding_from_dashboard [TYPE Function] [C:3]
|
# #region SupersetContextParsingMixin._recover_dataset_binding_from_dashboard [TYPE Function] [C:3]
|
||||||
# @PURPOSE: Recover a dataset binding from resolved dashboard context while preserving explicit unresolved markers.
|
# @PURPOSE: Recover a dataset binding from resolved dashboard context while preserving explicit unresolved markers.
|
||||||
# @RELATION CALLS -> [EXT:method:SupersetClient.get_dashboard_detail]
|
# @RELATION CALLS -> [EXT:method:SupersetClient.get_dashboard_detail]
|
||||||
def _recover_dataset_binding_from_dashboard(
|
async def _recover_dataset_binding_from_dashboard(
|
||||||
self,
|
self,
|
||||||
dashboard_id: int,
|
dashboard_id: int,
|
||||||
dataset_ref: str | None,
|
dataset_ref: str | None,
|
||||||
unresolved_references: list[str],
|
unresolved_references: list[str],
|
||||||
) -> tuple[int | None, list[str]]:
|
) -> tuple[int | None, list[str]]:
|
||||||
dashboard_detail = self.client.get_dashboard_detail(dashboard_id)
|
dashboard_detail = await self.client.get_dashboard_detail(dashboard_id)
|
||||||
datasets = dashboard_detail.get("datasets") or []
|
datasets = dashboard_detail.get("datasets") or []
|
||||||
if datasets:
|
if datasets:
|
||||||
first_dataset = datasets[0]
|
first_dataset = datasets[0]
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class DatasetReviewOrchestrator:
|
|||||||
# @SIDE_EFFECT persists session and may enqueue recovery task.
|
# @SIDE_EFFECT persists session and may enqueue recovery task.
|
||||||
# @DATA_CONTRACT Input[StartSessionCommand] -> Output[StartSessionResult]
|
# @DATA_CONTRACT Input[StartSessionCommand] -> Output[StartSessionResult]
|
||||||
# @INVARIANT no cross-user session leakage occurs; session and follow-up task remain owned by the authenticated user.
|
# @INVARIANT no cross-user session leakage occurs; session and follow-up task remain owned by the authenticated user.
|
||||||
def start_session(self, command: StartSessionCommand) -> StartSessionResult:
|
async def start_session(self, command: StartSessionCommand) -> StartSessionResult:
|
||||||
with belief_scope("DatasetReviewOrchestrator.start_session"):
|
with belief_scope("DatasetReviewOrchestrator.start_session"):
|
||||||
normalized_source_kind = str(command.source_kind or "").strip()
|
normalized_source_kind = str(command.source_kind or "").strip()
|
||||||
normalized_source_input = str(command.source_input or "").strip()
|
normalized_source_input = str(command.source_input or "").strip()
|
||||||
@@ -155,7 +155,7 @@ class DatasetReviewOrchestrator:
|
|||||||
|
|
||||||
if normalized_source_kind == "superset_link":
|
if normalized_source_kind == "superset_link":
|
||||||
extractor = SupersetContextExtractor(environment)
|
extractor = SupersetContextExtractor(environment)
|
||||||
parsed_context = extractor.parse_superset_link(normalized_source_input)
|
parsed_context = await extractor.parse_superset_link(normalized_source_input)
|
||||||
dataset_ref = parsed_context.dataset_ref
|
dataset_ref = parsed_context.dataset_ref
|
||||||
dataset_id = parsed_context.dataset_id
|
dataset_id = parsed_context.dataset_id
|
||||||
dashboard_id = parsed_context.dashboard_id
|
dashboard_id = parsed_context.dashboard_id
|
||||||
@@ -190,8 +190,8 @@ class DatasetReviewOrchestrator:
|
|||||||
template_variables: list[TemplateVariable] = []
|
template_variables: list[TemplateVariable] = []
|
||||||
execution_mappings: list[ExecutionMapping] = []
|
execution_mappings: list[ExecutionMapping] = []
|
||||||
if normalized_source_kind == "superset_link" and parsed_context is not None:
|
if normalized_source_kind == "superset_link" and parsed_context is not None:
|
||||||
recovered_filters, template_variables, execution_mappings, findings = (
|
recovered_filters, template_variables, execution_mappings, findings = (
|
||||||
self._build_recovery_bootstrap(
|
await self._build_recovery_bootstrap(
|
||||||
environment=environment,
|
environment=environment,
|
||||||
session=persisted_session,
|
session=persisted_session,
|
||||||
parsed_context=parsed_context,
|
parsed_context=parsed_context,
|
||||||
@@ -451,7 +451,7 @@ class DatasetReviewOrchestrator:
|
|||||||
# @PRE session belongs to the just-created review aggregate and parsed_context was produced for the same environment scope.
|
# @PRE session belongs to the just-created review aggregate and parsed_context was produced for the same environment scope.
|
||||||
# @POST Returns bootstrap imported filters, template variables, execution mappings, and updated findings without persisting them directly.
|
# @POST Returns bootstrap imported filters, template variables, execution mappings, and updated findings without persisting them directly.
|
||||||
# @SIDE_EFFECT Performs Superset reads through the extractor and may append warning findings for incomplete recovery.
|
# @SIDE_EFFECT Performs Superset reads through the extractor and may append warning findings for incomplete recovery.
|
||||||
def _build_recovery_bootstrap(
|
async def _build_recovery_bootstrap(
|
||||||
self,
|
self,
|
||||||
environment,
|
environment,
|
||||||
session: DatasetReviewSession,
|
session: DatasetReviewSession,
|
||||||
@@ -487,7 +487,7 @@ class DatasetReviewOrchestrator:
|
|||||||
try:
|
try:
|
||||||
dataset_payload = parsed_context.dataset_payload
|
dataset_payload = parsed_context.dataset_payload
|
||||||
if not isinstance(dataset_payload, dict):
|
if not isinstance(dataset_payload, dict):
|
||||||
dataset_payload = extractor.client.get_dataset_detail(session_record.dataset_id)
|
dataset_payload = await extractor.client.get_dataset_detail(session_record.dataset_id)
|
||||||
discovered_variables = extractor.discover_template_variables(dataset_payload)
|
discovered_variables = extractor.discover_template_variables(dataset_payload)
|
||||||
template_variables = [
|
template_variables = [
|
||||||
TemplateVariable(
|
TemplateVariable(
|
||||||
|
|||||||
Reference in New Issue
Block a user