diff --git a/superset/commands/explore/get.py b/superset/commands/explore/get.py index d9712741e8b..78142eb5ec1 100644 --- a/superset/commands/explore/get.py +++ b/superset/commands/explore/get.py @@ -37,7 +37,7 @@ from superset.exceptions import SupersetException from superset.explore.exceptions import WrongEndpointError from superset.explore.permalink.exceptions import ExplorePermalinkGetFailedError from superset.extensions import security_manager -from superset.superset_typing import BaseDatasourceData +from superset.superset_typing import ExplorableData from superset.utils import core as utils, json from superset.views.utils import ( get_datasource_info, @@ -136,7 +136,7 @@ class GetExploreCommand(BaseCommand, ABC): utils.merge_extra_filters(form_data) utils.merge_request_params(form_data, request.args) - datasource_data: BaseDatasourceData = { + datasource_data: ExplorableData = { "type": self._datasource_type or "unknown", "name": datasource_name, "columns": [], diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 304cb8ba411..e7c93e1ab98 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -85,6 +85,7 @@ from superset.exceptions import ( SupersetSecurityException, SupersetSyntaxErrorException, ) +from superset.explorables.base import TimeGrainDict from superset.jinja_context import ( BaseTemplateProcessor, ExtraCache, @@ -102,11 +103,10 @@ from superset.models.helpers import ( ) from superset.models.slice import Slice from superset.sql.parse import Table -from superset.explorables.base import TimeGrainDict from superset.superset_typing import ( AdhocColumn, AdhocMetric, - BaseDatasourceData, + ExplorableData, Metric, QueryObjectDict, ResultSetColumnType, @@ -436,7 +436,7 @@ class BaseDatasource( return verb_map @property - def data(self) -> BaseDatasourceData: + def data(self) -> ExplorableData: """Data representation of the datasource sent to the frontend""" return { # simple fields @@ -1429,7 +1429,7 @@ class SqlaTable( return [(g.duration, g.name) for g in self.database.grains() or []] @property - def data(self) -> BaseDatasourceData: + def data(self) -> ExplorableData: data_ = super().data if self.type == "table": data_["granularity_sqla"] = self.granularity_sqla diff --git a/superset/explorables/base.py b/superset/explorables/base.py index 2c4e170b5a5..2d534b72099 100644 --- a/superset/explorables/base.py +++ b/superset/explorables/base.py @@ -25,11 +25,12 @@ from __future__ import annotations from collections.abc import Hashable from datetime import datetime -from typing import Any, Protocol, runtime_checkable, TypedDict +from typing import Any, Protocol, runtime_checkable, TYPE_CHECKING, TypedDict -from superset.common.query_object import QueryObject -from superset.models.helpers import QueryResult -from superset.superset_typing import BaseDatasourceData, QueryObjectDict +if TYPE_CHECKING: + from superset.common.query_object import QueryObject + from superset.models.helpers import QueryResult + from superset.superset_typing import ExplorableData, QueryObjectDict class TimeGrainDict(TypedDict): @@ -173,7 +174,7 @@ class Explorable(Protocol): """ @property - def data(self) -> BaseDatasourceData: + def data(self) -> ExplorableData: """ Full metadata representation sent to the frontend. diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py index 35e3f126ad6..956d33053bc 100644 --- a/superset/models/sql_lab.py +++ b/superset/models/sql_lab.py @@ -50,8 +50,8 @@ from superset_core.api.models import Query as CoreQuery, SavedQuery as CoreSaved from superset import security_manager from superset.exceptions import SupersetParseError, SupersetSecurityException -from superset.jinja_context import BaseTemplateProcessor, get_template_processor from superset.explorables.base import TimeGrainDict +from superset.jinja_context import BaseTemplateProcessor, get_template_processor from superset.models.helpers import ( AuditMixinNullable, ExploreMixin, @@ -64,7 +64,7 @@ from superset.sql.parse import ( Table, ) from superset.sqllab.limiting_factor import LimitingFactor -from superset.superset_typing import BaseDatasourceData, QueryObjectDict +from superset.superset_typing import ExplorableData, QueryObjectDict from superset.utils import json from superset.utils.core import ( get_column_name, @@ -240,7 +240,7 @@ class Query( return None @property - def data(self) -> BaseDatasourceData: + def data(self) -> ExplorableData: """Returns query data for the frontend""" order_by_choices = [] for col in self.columns: diff --git a/superset/superset_typing.py b/superset/superset_typing.py index e2bacda72ec..5841dc245ee 100644 --- a/superset/superset_typing.py +++ b/superset/superset_typing.py @@ -195,7 +195,7 @@ class QueryObjectDict(TypedDict, total=False): timeseries_limit_metric: Metric | None -class BaseDatasourceData(TypedDict, total=False): +class ExplorableData(TypedDict, total=False): """ TypedDict for explorable data returned to the frontend. diff --git a/superset/utils/core.py b/superset/utils/core.py index 02756bf1607..1dbdb52ca6d 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -96,6 +96,7 @@ from superset.exceptions import ( SupersetException, SupersetTimeoutException, ) +from superset.explorables.base import Explorable from superset.sql.parse import sanitize_clause from superset.superset_typing import ( AdhocColumn, @@ -115,7 +116,6 @@ from superset.utils.pandas import detect_datetime_format if TYPE_CHECKING: from superset.connectors.sqla.models import TableColumn - from superset.explorables.base import Explorable from superset.models.core import Database logging.getLogger("MARKDOWN").setLevel(logging.INFO) @@ -1656,9 +1656,7 @@ def map_sql_type_to_inferred_type(sql_type: Optional[str]) -> str: return "string" # If no match is found, return "string" as default -def get_metric_type_from_column( - column: Any, datasource: "Explorable" -) -> str: +def get_metric_type_from_column(column: Any, datasource: Explorable) -> str: """ Determine the metric type from a given column in a datasource. @@ -1700,7 +1698,7 @@ def get_metric_type_from_column( def extract_dataframe_dtypes( df: pd.DataFrame, - datasource: "Explorable | None" = None, + datasource: Explorable | None = None, ) -> list[GenericDataType]: """Serialize pandas/numpy dtypes to generic types""" @@ -1771,7 +1769,7 @@ def is_test() -> bool: def get_time_filter_status( - datasource: "Explorable", + datasource: Explorable, applied_time_extras: dict[str, str], ) -> tuple[list[dict[str, str]], list[dict[str, str]]]: temporal_columns: set[Any] = { diff --git a/superset/views/core.py b/superset/views/core.py index de33f26dc8d..ced2078b14a 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -78,7 +78,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.models.user_attributes import UserAttribute from superset.superset_typing import ( - BaseDatasourceData, + ExplorableData, FlaskResponse, ) from superset.tasks.utils import get_current_user @@ -530,14 +530,14 @@ class Superset(BaseSupersetView): ) standalone_mode = ReservedUrlParameters.is_standalone_mode() force = request.args.get("force") in {"force", "1", "true"} - dummy_datasource_data: BaseDatasourceData = { + dummy_datasource_data: ExplorableData = { "type": datasource_type or "unknown", "name": datasource_name, "columns": [], "metrics": [], "database": {"id": 0, "backend": ""}, } - datasource_data: BaseDatasourceData + datasource_data: ExplorableData try: datasource_data = datasource.data if datasource else dummy_datasource_data except (SupersetException, SQLAlchemyError): diff --git a/superset/views/utils.py b/superset/views/utils.py index 22da8a3aad8..e61f131cad0 100644 --- a/superset/views/utils.py +++ b/superset/views/utils.py @@ -46,7 +46,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.models.sql_lab import Query from superset.superset_typing import ( - BaseDatasourceData, + ExplorableData, FlaskResponse, FormData, ) @@ -91,7 +91,7 @@ def redirect_to_login(next_target: str | None = None) -> FlaskResponse: def sanitize_datasource_data( - datasource_data: BaseDatasourceData, + datasource_data: ExplorableData, ) -> dict[str, Any]: """ Sanitize datasource data by removing sensitive database parameters.