chore: update semantic contracts and git merge handling
This commit is contained in:
@@ -57,7 +57,7 @@ class SupersetClient:
|
||||
)
|
||||
self.delete_before_reimport: bool = False
|
||||
app_logger.info("[SupersetClient.__init__][Exit] SupersetClient initialized.")
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.__init__:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.authenticate:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -69,7 +69,7 @@ class SupersetClient:
|
||||
def authenticate(self) -> Dict[str, str]:
|
||||
with belief_scope("SupersetClient.authenticate"):
|
||||
return self.network.authenticate()
|
||||
# [/DEF:authenticate:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.authenticate:Function]
|
||||
|
||||
@property
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.headers:Function]
|
||||
@@ -80,7 +80,7 @@ class SupersetClient:
|
||||
def headers(self) -> dict:
|
||||
with belief_scope("headers"):
|
||||
return self.network.headers
|
||||
# [/DEF:headers:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.headers:Function]
|
||||
|
||||
# [SECTION: DASHBOARD OPERATIONS]
|
||||
|
||||
@@ -116,7 +116,7 @@ class SupersetClient:
|
||||
total_count = len(paginated_data)
|
||||
app_logger.info("[get_dashboards][Exit] Found %d dashboards.", total_count)
|
||||
return total_count, paginated_data
|
||||
# [/DEF:get_dashboards:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboards:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_page:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -153,7 +153,7 @@ class SupersetClient:
|
||||
result = response_json.get("result", [])
|
||||
total_count = response_json.get("count", len(result))
|
||||
return total_count, result
|
||||
# [/DEF:get_dashboards_page:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_page:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_summary:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -238,7 +238,7 @@ class SupersetClient:
|
||||
f"sampled={min(len(result), max_debug_samples)})"
|
||||
)
|
||||
return result
|
||||
# [/DEF:get_dashboards_summary:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_summary:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_summary_page:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -311,7 +311,7 @@ class SupersetClient:
|
||||
})
|
||||
|
||||
return total_count, result
|
||||
# [/DEF:get_dashboards_summary_page:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_summary_page:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._extract_owner_labels:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -339,7 +339,7 @@ class SupersetClient:
|
||||
if label and label not in normalized:
|
||||
normalized.append(label)
|
||||
return normalized
|
||||
# [/DEF:_extract_owner_labels:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._extract_owner_labels:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._extract_user_display:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -368,7 +368,7 @@ class SupersetClient:
|
||||
if email:
|
||||
return email
|
||||
return None
|
||||
# [/DEF:_extract_user_display:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._extract_user_display:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._sanitize_user_text:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -382,7 +382,7 @@ class SupersetClient:
|
||||
if not normalized:
|
||||
return None
|
||||
return normalized
|
||||
# [/DEF:_sanitize_user_text:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._sanitize_user_text:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboard:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -395,7 +395,7 @@ class SupersetClient:
|
||||
with belief_scope("SupersetClient.get_dashboard", f"id={dashboard_id}"):
|
||||
response = self.network.request(method="GET", endpoint=f"/dashboard/{dashboard_id}")
|
||||
return cast(Dict, response)
|
||||
# [/DEF:get_dashboard:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboard:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_chart:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -408,7 +408,7 @@ class SupersetClient:
|
||||
with belief_scope("SupersetClient.get_chart", f"id={chart_id}"):
|
||||
response = self.network.request(method="GET", endpoint=f"/chart/{chart_id}")
|
||||
return cast(Dict, response)
|
||||
# [/DEF:get_chart:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_chart:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboard_detail:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -426,6 +426,7 @@ class SupersetClient:
|
||||
charts: List[Dict] = []
|
||||
datasets: List[Dict] = []
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboard_detail.extract_dataset_id_from_form_data:Function]
|
||||
def extract_dataset_id_from_form_data(form_data: Optional[Dict]) -> Optional[int]:
|
||||
if not isinstance(form_data, dict):
|
||||
return None
|
||||
@@ -448,6 +449,7 @@ class SupersetClient:
|
||||
return int(ds_id) if ds_id is not None else None
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboard_detail.extract_dataset_id_from_form_data:Function]
|
||||
|
||||
# Canonical endpoints from Superset OpenAPI:
|
||||
# /dashboard/{id_or_slug}/charts and /dashboard/{id_or_slug}/datasets.
|
||||
@@ -603,7 +605,7 @@ class SupersetClient:
|
||||
"chart_count": len(unique_charts),
|
||||
"dataset_count": len(unique_datasets),
|
||||
}
|
||||
# [/DEF:get_dashboard_detail:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dashboard_detail:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_charts:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -623,7 +625,7 @@ class SupersetClient:
|
||||
pagination_options={"base_query": validated_query, "results_field": "result"},
|
||||
)
|
||||
return len(paginated_data), paginated_data
|
||||
# [/DEF:get_charts:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_charts:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._extract_chart_ids_from_layout:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -656,7 +658,7 @@ class SupersetClient:
|
||||
|
||||
walk(payload)
|
||||
return found
|
||||
# [/DEF:_extract_chart_ids_from_layout:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._extract_chart_ids_from_layout:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.export_dashboard:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -681,7 +683,7 @@ class SupersetClient:
|
||||
filename = self._resolve_export_filename(response, dashboard_id)
|
||||
app_logger.info("[export_dashboard][Exit] Exported dashboard %s to %s.", dashboard_id, filename)
|
||||
return response.content, filename
|
||||
# [/DEF:export_dashboard:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.export_dashboard:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.import_dashboard:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -713,7 +715,7 @@ class SupersetClient:
|
||||
self.delete_dashboard(target_id)
|
||||
app_logger.info("[import_dashboard][State] Deleted dashboard ID %s, retrying import.", target_id)
|
||||
return self._do_import(file_path)
|
||||
# [/DEF:import_dashboard:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.import_dashboard:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.delete_dashboard:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -731,11 +733,7 @@ class SupersetClient:
|
||||
app_logger.info("[delete_dashboard][Success] Dashboard %s deleted.", dashboard_id)
|
||||
else:
|
||||
app_logger.warning("[delete_dashboard][Warning] Unexpected response while deleting %s: %s", dashboard_id, response)
|
||||
# [/DEF:delete_dashboard:Function]
|
||||
|
||||
# [/SECTION]
|
||||
|
||||
# [SECTION: DATASET OPERATIONS]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.delete_dashboard:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_datasets:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -756,7 +754,7 @@ class SupersetClient:
|
||||
total_count = len(paginated_data)
|
||||
app_logger.info("[get_datasets][Exit] Found %d datasets.", total_count)
|
||||
return total_count, paginated_data
|
||||
# [/DEF:get_datasets:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_datasets:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_datasets_summary:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -781,7 +779,7 @@ class SupersetClient:
|
||||
"database": ds.get("database", {}).get("database_name", "Unknown")
|
||||
})
|
||||
return result
|
||||
# [/DEF:get_datasets_summary:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_datasets_summary:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dataset_detail:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -894,7 +892,7 @@ class SupersetClient:
|
||||
|
||||
app_logger.info(f"[get_dataset_detail][Exit] Got dataset {dataset_id} with {len(column_info)} columns and {len(linked_dashboards)} linked dashboards")
|
||||
return result
|
||||
# [/DEF:get_dataset_detail:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dataset_detail:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dataset:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -910,7 +908,7 @@ class SupersetClient:
|
||||
response = cast(Dict, response)
|
||||
app_logger.info("[get_dataset][Exit] Got dataset %s.", dataset_id)
|
||||
return response
|
||||
# [/DEF:get_dataset:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_dataset:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.update_dataset:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -932,11 +930,7 @@ class SupersetClient:
|
||||
response = cast(Dict, response)
|
||||
app_logger.info("[update_dataset][Exit] Updated dataset %s.", dataset_id)
|
||||
return response
|
||||
# [/DEF:update_dataset:Function]
|
||||
|
||||
# [/SECTION]
|
||||
|
||||
# [SECTION: DATABASE OPERATIONS]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.update_dataset:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_databases:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -959,7 +953,7 @@ class SupersetClient:
|
||||
total_count = len(paginated_data)
|
||||
app_logger.info("[get_databases][Exit] Found %d databases.", total_count)
|
||||
return total_count, paginated_data
|
||||
# [/DEF:get_databases:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_databases:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_database:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -975,7 +969,7 @@ class SupersetClient:
|
||||
response = cast(Dict, response)
|
||||
app_logger.info("[get_database][Exit] Got database %s.", database_id)
|
||||
return response
|
||||
# [/DEF:get_database:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_database:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_databases_summary:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -996,7 +990,7 @@ class SupersetClient:
|
||||
db['engine'] = db.pop('backend', None)
|
||||
|
||||
return databases
|
||||
# [/DEF:get_databases_summary:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_databases_summary:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_database_by_uuid:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -1012,11 +1006,7 @@ class SupersetClient:
|
||||
}
|
||||
_, databases = self.get_databases(query=query)
|
||||
return databases[0] if databases else None
|
||||
# [/DEF:get_database_by_uuid:Function]
|
||||
|
||||
# [/SECTION]
|
||||
|
||||
# [SECTION: HELPERS]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_database_by_uuid:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._resolve_target_id_for_delete:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1039,7 +1029,7 @@ class SupersetClient:
|
||||
except Exception as e:
|
||||
app_logger.warning("[_resolve_target_id_for_delete][Warning] Could not resolve slug '%s' to ID: %s", dash_slug, e)
|
||||
return None
|
||||
# [/DEF:_resolve_target_id_for_delete:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._resolve_target_id_for_delete:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._do_import:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1061,7 +1051,7 @@ class SupersetClient:
|
||||
extra_data={"overwrite": "true"},
|
||||
timeout=self.env.timeout * 2,
|
||||
)
|
||||
# [/DEF:_do_import:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._do_import:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._validate_export_response:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1075,7 +1065,7 @@ class SupersetClient:
|
||||
raise SupersetAPIError(f"Получен не ZIP-архив (Content-Type: {content_type})")
|
||||
if not response.content:
|
||||
raise SupersetAPIError("Получены пустые данные при экспорте")
|
||||
# [/DEF:_validate_export_response:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._validate_export_response:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._resolve_export_filename:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1091,7 +1081,7 @@ class SupersetClient:
|
||||
filename = f"dashboard_export_{dashboard_id}_{timestamp}.zip"
|
||||
app_logger.warning("[_resolve_export_filename][Warning] Generated filename: %s", filename)
|
||||
return filename
|
||||
# [/DEF:_resolve_export_filename:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._resolve_export_filename:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._validate_query_params:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1104,7 +1094,7 @@ class SupersetClient:
|
||||
# Using 100 avoids partial fetches when larger values are silently truncated.
|
||||
base_query = {"page": 0, "page_size": 100}
|
||||
return {**base_query, **(query or {})}
|
||||
# [/DEF:_validate_query_params:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._validate_query_params:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._fetch_total_object_count:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1119,7 +1109,7 @@ class SupersetClient:
|
||||
query_params={"page": 0, "page_size": 1},
|
||||
count_field="count",
|
||||
)
|
||||
# [/DEF:_fetch_total_object_count:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._fetch_total_object_count:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._fetch_all_pages:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1129,7 +1119,7 @@ class SupersetClient:
|
||||
def _fetch_all_pages(self, endpoint: str, pagination_options: Dict) -> List[Dict]:
|
||||
with belief_scope("_fetch_all_pages"):
|
||||
return self.network.fetch_paginated_data(endpoint=endpoint, pagination_options=pagination_options)
|
||||
# [/DEF:_fetch_all_pages:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._fetch_all_pages:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._validate_import_file:Function]
|
||||
# @COMPLEXITY: 1
|
||||
@@ -1146,7 +1136,7 @@ class SupersetClient:
|
||||
with zipfile.ZipFile(path, "r") as zf:
|
||||
if not any(n.endswith("metadata.yaml") for n in zf.namelist()):
|
||||
raise SupersetAPIError(f"Архив {zip_path} не содержит 'metadata.yaml'")
|
||||
# [/DEF:_validate_import_file:Function]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient._validate_import_file:Function]
|
||||
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_all_resources:Function]
|
||||
# @COMPLEXITY: 3
|
||||
@@ -1170,12 +1160,8 @@ class SupersetClient:
|
||||
query = {"columns": config["columns"]}
|
||||
|
||||
if since_dttm:
|
||||
# Format to ISO 8601 string for Superset filter
|
||||
# e.g. "2026-02-25T13:24:32.186" or integer milliseconds.
|
||||
# Assuming standard ISO string works:
|
||||
# The user's example had value: 0 (which might imply ms or int) but often it accepts strings.
|
||||
import math
|
||||
# Use int milliseconds to be safe, as "0" was in the user example
|
||||
# Use int milliseconds to be safe
|
||||
timestamp_ms = math.floor(since_dttm.timestamp() * 1000)
|
||||
|
||||
query["filters"] = [
|
||||
@@ -1185,7 +1171,6 @@ class SupersetClient:
|
||||
"value": timestamp_ms
|
||||
}
|
||||
]
|
||||
# Also we must request `changed_on_dttm` just in case, though API usually filters regardless of columns
|
||||
|
||||
validated = self._validate_query_params(query)
|
||||
data = self._fetch_all_pages(
|
||||
@@ -1194,9 +1179,7 @@ class SupersetClient:
|
||||
)
|
||||
app_logger.info("[get_all_resources][Exit] Fetched %d %s resources.", len(data), resource_type)
|
||||
return data
|
||||
# [/DEF:get_all_resources:Function]
|
||||
|
||||
# [/SECTION]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient.get_all_resources:Function]
|
||||
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient:Class]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user