mirror of
https://github.com/apache/superset.git
synced 2026-07-14 18:55:47 +00:00
149 lines
5.5 KiB
Python
Executable File
149 lines
5.5 KiB
Python
Executable File
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""
|
|
Runtime validation module for chart configurations.
|
|
Validates performance, compatibility, and user experience issues.
|
|
"""
|
|
|
|
import logging
|
|
from typing import Any, Dict, List, Tuple
|
|
|
|
from superset.mcp_service.chart.schemas import ChartConfig
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class RuntimeValidator:
|
|
"""Orchestrates runtime validations for chart configurations."""
|
|
|
|
@staticmethod
|
|
def validate_runtime_issues(
|
|
config: ChartConfig, dataset_id: int | str
|
|
) -> Tuple[bool, Dict[str, Any] | None]:
|
|
"""
|
|
Validate runtime issues that could affect chart rendering or performance.
|
|
|
|
Warnings are returned as informational metadata, NOT as errors.
|
|
Chart generation proceeds regardless of warnings.
|
|
|
|
Args:
|
|
config: Chart configuration to validate
|
|
dataset_id: Dataset identifier
|
|
|
|
Returns:
|
|
Tuple of (is_valid, warnings_metadata)
|
|
- is_valid: Always True (warnings don't block generation)
|
|
- warnings_metadata: Dict with warnings and suggestions, or None
|
|
"""
|
|
warnings: List[str] = []
|
|
suggestions: List[str] = []
|
|
|
|
# Per-plugin runtime warnings (format, cardinality, etc.)
|
|
plugin_warnings, plugin_suggestions = RuntimeValidator._validate_plugin_runtime(
|
|
config, dataset_id
|
|
)
|
|
if plugin_warnings:
|
|
warnings.extend(plugin_warnings)
|
|
if plugin_suggestions:
|
|
suggestions.extend(plugin_suggestions)
|
|
|
|
# Chart type appropriateness validation (for all chart types)
|
|
type_warnings, type_suggestions = RuntimeValidator._validate_chart_type(
|
|
config, dataset_id
|
|
)
|
|
if type_warnings:
|
|
warnings.extend(type_warnings)
|
|
suggestions.extend(type_suggestions)
|
|
|
|
# Return warnings as metadata, NOT as errors
|
|
# Warnings should inform, not block chart generation
|
|
if warnings:
|
|
logger.info(
|
|
"Runtime validation warnings for dataset %s: %s",
|
|
dataset_id,
|
|
warnings[:3],
|
|
)
|
|
return (
|
|
True,
|
|
{
|
|
"warnings": warnings[:5], # Limit to 5 warnings
|
|
"suggestions": suggestions[:5], # Limit to 5 suggestions
|
|
},
|
|
)
|
|
|
|
return True, None
|
|
|
|
@staticmethod
|
|
def _validate_plugin_runtime(
|
|
config: ChartConfig, dataset_id: int | str
|
|
) -> Tuple[List[str], List[str]]:
|
|
"""Delegate per-chart-type runtime warnings to the plugin registry.
|
|
|
|
Each plugin's get_runtime_warnings() method returns chart-type-specific
|
|
warnings and suggestions (e.g. format/cardinality for XY). The registry
|
|
dispatch removes the previous isinstance(config, XYChartConfig) hardcoding.
|
|
"""
|
|
try:
|
|
from superset.mcp_service.chart.registry import get_registry
|
|
|
|
chart_type = getattr(config, "chart_type", None)
|
|
if chart_type is None:
|
|
return [], []
|
|
plugin = get_registry().get(chart_type)
|
|
if plugin is None:
|
|
return [], []
|
|
return plugin.get_runtime_warnings(config, dataset_id)
|
|
except Exception as exc: # noqa: BLE001 — plugin code is third-party-extensible
|
|
logger.warning("Plugin runtime validation failed: %s", exc)
|
|
return [], []
|
|
|
|
@staticmethod
|
|
def _validate_chart_type(
|
|
config: ChartConfig, dataset_id: int | str
|
|
) -> Tuple[List[str], List[str]]:
|
|
"""Validate chart type appropriateness."""
|
|
warnings: List[str] = []
|
|
suggestions: List[str] = []
|
|
|
|
try:
|
|
# Import here to avoid circular imports
|
|
from .chart_type_suggester import ChartTypeSuggester
|
|
|
|
is_appropriate, suggestion_info = ChartTypeSuggester.analyze_and_suggest(
|
|
config, dataset_id
|
|
)
|
|
|
|
if not is_appropriate and suggestion_info:
|
|
warnings.extend(suggestion_info.get("issues", []))
|
|
suggestions.extend(suggestion_info.get("suggestions", []))
|
|
|
|
# Add recommended chart types
|
|
recommended = suggestion_info.get("recommended_types", [])
|
|
if recommended:
|
|
recommendations = ", ".join(recommended)
|
|
suggestions.append(
|
|
f"Recommended chart types for this data: {recommendations}"
|
|
)
|
|
|
|
except ImportError:
|
|
logger.warning("Chart type suggester not available")
|
|
except Exception as e: # noqa: BLE001 — non-blocking warning path
|
|
logger.warning("Chart type validation failed: %s", e)
|
|
|
|
return warnings, suggestions
|