mirror of
https://github.com/apache/superset.git
synced 2024-09-12 08:39:45 -04:00
chore: move TypedDict from typing_extensions to typing (#25121)
This commit is contained in:
parent
46a0a6e08a
commit
067bfbf950
@ -19,13 +19,12 @@ from __future__ import annotations
|
|||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Any, ClassVar, TYPE_CHECKING
|
from typing import Any, ClassVar, TYPE_CHECKING, TypedDict
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from pandas import DateOffset
|
from pandas import DateOffset
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset import app
|
from superset import app
|
||||||
from superset.common.chart_data import ChartDataResultFormat
|
from superset.common.chart_data import ChartDataResultFormat
|
||||||
@ -169,7 +168,7 @@ class QueryContextProcessor:
|
|||||||
cache.error_message = str(ex)
|
cache.error_message = str(ex)
|
||||||
cache.status = QueryStatus.FAILED
|
cache.status = QueryStatus.FAILED
|
||||||
|
|
||||||
# the N-dimensional DataFrame has converteds into flat DataFrame
|
# the N-dimensional DataFrame has converted into flat DataFrame
|
||||||
# by `flatten operator`, "comma" in the column is escaped by `escape_separator`
|
# by `flatten operator`, "comma" in the column is escaped by `escape_separator`
|
||||||
# the result DataFrame columns should be unescaped
|
# the result DataFrame columns should be unescaped
|
||||||
label_map = {
|
label_map = {
|
||||||
@ -632,11 +631,6 @@ class QueryContextProcessor:
|
|||||||
return generate_cache_key(cache_dict, key_prefix)
|
return generate_cache_key(cache_dict, key_prefix)
|
||||||
|
|
||||||
def get_annotation_data(self, query_obj: QueryObject) -> dict[str, Any]:
|
def get_annotation_data(self, query_obj: QueryObject) -> dict[str, Any]:
|
||||||
"""
|
|
||||||
:param query_context:
|
|
||||||
:param query_obj:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
annotation_data: dict[str, Any] = self.get_native_annotation_data(query_obj)
|
annotation_data: dict[str, Any] = self.get_native_annotation_data(query_obj)
|
||||||
for annotation_layer in [
|
for annotation_layer in [
|
||||||
layer
|
layer
|
||||||
|
@ -23,7 +23,16 @@ import logging
|
|||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from re import Match, Pattern
|
from re import Match, Pattern
|
||||||
from typing import Any, Callable, cast, ContextManager, NamedTuple, TYPE_CHECKING, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
cast,
|
||||||
|
ContextManager,
|
||||||
|
NamedTuple,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
TypedDict,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import sqlparse
|
import sqlparse
|
||||||
@ -46,7 +55,6 @@ from sqlalchemy.sql import quoted_name, text
|
|||||||
from sqlalchemy.sql.expression import ColumnClause, Select, TextAsFrom, TextClause
|
from sqlalchemy.sql.expression import ColumnClause, Select, TextAsFrom, TextClause
|
||||||
from sqlalchemy.types import TypeEngine
|
from sqlalchemy.types import TypeEngine
|
||||||
from sqlparse.tokens import CTE
|
from sqlparse.tokens import CTE
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset import security_manager, sql_parse
|
from superset import security_manager, sql_parse
|
||||||
from superset.constants import TimeGrain as TimeGrainConstants
|
from superset.constants import TimeGrain as TimeGrainConstants
|
||||||
@ -114,8 +122,8 @@ class TimestampExpression(
|
|||||||
ColumnClause
|
ColumnClause
|
||||||
): # pylint: disable=abstract-method, too-many-ancestors
|
): # pylint: disable=abstract-method, too-many-ancestors
|
||||||
def __init__(self, expr: str, col: ColumnClause, **kwargs: Any) -> None:
|
def __init__(self, expr: str, col: ColumnClause, **kwargs: Any) -> None:
|
||||||
"""Sqlalchemy class that can be can be used to render native column elements
|
"""Sqlalchemy class that can be used to render native column elements respecting
|
||||||
respecting engine-specific quoting rules as part of a string-based expression.
|
engine-specific quoting rules as part of a string-based expression.
|
||||||
|
|
||||||
:param expr: Sql expression with '{col}' denoting the locations where the col
|
:param expr: Sql expression with '{col}' denoting the locations where the col
|
||||||
object will be rendered.
|
object will be rendered.
|
||||||
@ -331,7 +339,7 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
|
|||||||
allows_alias_to_source_column = True
|
allows_alias_to_source_column = True
|
||||||
|
|
||||||
# Whether ORDER BY clause must appear in SELECT
|
# Whether ORDER BY clause must appear in SELECT
|
||||||
# if TRUE, then it doesn't have to.
|
# if True, then it doesn't have to.
|
||||||
allows_hidden_orderby_agg = True
|
allows_hidden_orderby_agg = True
|
||||||
|
|
||||||
# Whether ORDER BY clause can use sql calculated expression
|
# Whether ORDER BY clause can use sql calculated expression
|
||||||
@ -1000,7 +1008,7 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
|
|||||||
to_sql_kwargs["name"] = table.table
|
to_sql_kwargs["name"] = table.table
|
||||||
|
|
||||||
if table.schema:
|
if table.schema:
|
||||||
# Only add schema when it is preset and non empty.
|
# Only add schema when it is preset and non-empty.
|
||||||
to_sql_kwargs["schema"] = table.schema
|
to_sql_kwargs["schema"] = table.schema
|
||||||
|
|
||||||
with cls.get_engine(database) as engine:
|
with cls.get_engine(database) as engine:
|
||||||
@ -1049,8 +1057,7 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
|
|||||||
|
|
||||||
context = context or {}
|
context = context or {}
|
||||||
for regex, (message, error_type, extra) in cls.custom_errors.items():
|
for regex, (message, error_type, extra) in cls.custom_errors.items():
|
||||||
match = regex.search(raw_message)
|
if match := regex.search(raw_message):
|
||||||
if match:
|
|
||||||
params = {**context, **match.groupdict()}
|
params = {**context, **match.groupdict()}
|
||||||
extra["engine_name"] = cls.engine_name
|
extra["engine_name"] = cls.engine_name
|
||||||
return [
|
return [
|
||||||
@ -1832,7 +1839,7 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
|
|||||||
"""
|
"""
|
||||||
Construct an impersonation key, by default it's the given username.
|
Construct an impersonation key, by default it's the given username.
|
||||||
|
|
||||||
:param user: logged in user
|
:param user: logged-in user
|
||||||
|
|
||||||
:returns: username if given user is not null
|
:returns: username if given user is not null
|
||||||
"""
|
"""
|
||||||
|
@ -20,7 +20,7 @@ import re
|
|||||||
import urllib
|
import urllib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from re import Pattern
|
from re import Pattern
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING, TypedDict
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from apispec import APISpec
|
from apispec import APISpec
|
||||||
@ -33,7 +33,6 @@ from sqlalchemy import column, types
|
|||||||
from sqlalchemy.engine.base import Engine
|
from sqlalchemy.engine.base import Engine
|
||||||
from sqlalchemy.engine.reflection import Inspector
|
from sqlalchemy.engine.reflection import Inspector
|
||||||
from sqlalchemy.sql import sqltypes
|
from sqlalchemy.sql import sqltypes
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset import sql_parse
|
from superset import sql_parse
|
||||||
from superset.constants import PASSWORD_MASK, TimeGrain
|
from superset.constants import PASSWORD_MASK, TimeGrain
|
||||||
@ -66,7 +65,6 @@ except ModuleNotFoundError:
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from superset.models.core import Database # pragma: no cover
|
from superset.models.core import Database # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
CONNECTION_DATABASE_PERMISSIONS_REGEX = re.compile(
|
CONNECTION_DATABASE_PERMISSIONS_REGEX = re.compile(
|
||||||
"Access Denied: Project (?P<project_name>.+?): User does not have "
|
"Access Denied: Project (?P<project_name>.+?): User does not have "
|
||||||
+ "bigquery.jobs.create permission in project (?P<project>.+?)"
|
+ "bigquery.jobs.create permission in project (?P<project>.+?)"
|
||||||
|
@ -18,7 +18,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING, TypedDict
|
||||||
|
|
||||||
from apispec import APISpec
|
from apispec import APISpec
|
||||||
from apispec.ext.marshmallow import MarshmallowPlugin
|
from apispec.ext.marshmallow import MarshmallowPlugin
|
||||||
@ -27,7 +27,6 @@ from marshmallow import fields, Schema
|
|||||||
from marshmallow.validate import Range
|
from marshmallow.validate import Range
|
||||||
from sqlalchemy.engine.reflection import Inspector
|
from sqlalchemy.engine.reflection import Inspector
|
||||||
from sqlalchemy.engine.url import URL
|
from sqlalchemy.engine.url import URL
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset.constants import TimeGrain, USER_AGENT
|
from superset.constants import TimeGrain, USER_AGENT
|
||||||
from superset.databases.utils import make_url_safe
|
from superset.databases.utils import make_url_safe
|
||||||
|
@ -22,7 +22,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from re import Pattern
|
from re import Pattern
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING, TypedDict
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from apispec import APISpec
|
from apispec import APISpec
|
||||||
@ -34,7 +34,6 @@ from marshmallow.exceptions import ValidationError
|
|||||||
from requests import Session
|
from requests import Session
|
||||||
from sqlalchemy.engine import create_engine
|
from sqlalchemy.engine import create_engine
|
||||||
from sqlalchemy.engine.url import URL
|
from sqlalchemy.engine.url import URL
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset import db, security_manager
|
from superset import db, security_manager
|
||||||
from superset.constants import PASSWORD_MASK
|
from superset.constants import PASSWORD_MASK
|
||||||
|
@ -19,7 +19,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from re import Pattern
|
from re import Pattern
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING, TypedDict
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
|
|
||||||
from apispec import APISpec
|
from apispec import APISpec
|
||||||
@ -32,7 +32,6 @@ from marshmallow import fields, Schema
|
|||||||
from sqlalchemy import types
|
from sqlalchemy import types
|
||||||
from sqlalchemy.engine.reflection import Inspector
|
from sqlalchemy.engine.reflection import Inspector
|
||||||
from sqlalchemy.engine.url import URL
|
from sqlalchemy.engine.url import URL
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset.constants import TimeGrain, USER_AGENT
|
from superset.constants import TimeGrain, USER_AGENT
|
||||||
from superset.databases.utils import make_url_safe
|
from superset.databases.utils import make_url_safe
|
||||||
|
@ -14,9 +14,7 @@
|
|||||||
# KIND, either express or implied. See the License for the
|
# KIND, either express or implied. See the License for the
|
||||||
# specific language governing permissions and limitations
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
from typing import Optional
|
from typing import Optional, TypedDict
|
||||||
|
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset.utils.core import DatasourceType
|
from superset.utils.core import DatasourceType
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from functools import lru_cache, partial
|
from functools import lru_cache, partial
|
||||||
from typing import Any, Callable, cast, Optional, TYPE_CHECKING, Union
|
from typing import Any, Callable, cast, Optional, TYPE_CHECKING, TypedDict, Union
|
||||||
|
|
||||||
from flask import current_app, g, has_request_context, request
|
from flask import current_app, g, has_request_context, request
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
@ -26,7 +26,6 @@ from jinja2 import DebugUndefined
|
|||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
from sqlalchemy.engine.interfaces import Dialect
|
from sqlalchemy.engine.interfaces import Dialect
|
||||||
from sqlalchemy.types import String
|
from sqlalchemy.types import String
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset.constants import LRU_CACHE_MAX_SIZE
|
from superset.constants import LRU_CACHE_MAX_SIZE
|
||||||
from superset.datasets.commands.exceptions import DatasetNotFoundError
|
from superset.datasets.commands.exceptions import DatasetNotFoundError
|
||||||
@ -597,7 +596,7 @@ def get_template_processors() -> dict[str, Any]:
|
|||||||
processors = current_app.config.get("CUSTOM_TEMPLATE_PROCESSORS", {})
|
processors = current_app.config.get("CUSTOM_TEMPLATE_PROCESSORS", {})
|
||||||
for engine, processor in DEFAULT_PROCESSORS.items():
|
for engine, processor in DEFAULT_PROCESSORS.items():
|
||||||
# do not overwrite engine-specific CUSTOM_TEMPLATE_PROCESSORS
|
# do not overwrite engine-specific CUSTOM_TEMPLATE_PROCESSORS
|
||||||
if not engine in processors:
|
if engine not in processors:
|
||||||
processors[engine] = processor
|
processors[engine] = processor
|
||||||
|
|
||||||
return processors
|
return processors
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Literal, Optional, TYPE_CHECKING, Union
|
from typing import Any, Literal, Optional, TYPE_CHECKING, TypedDict, Union
|
||||||
|
|
||||||
from typing_extensions import NotRequired, TypedDict
|
from typing_extensions import NotRequired
|
||||||
from werkzeug.wrappers import Response
|
from werkzeug.wrappers import Response
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -14,9 +14,7 @@
|
|||||||
# KIND, either express or implied. See the License for the
|
# KIND, either express or implied. See the License for the
|
||||||
# specific language governing permissions and limitations
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
from typing import Optional
|
from typing import Optional, TypedDict
|
||||||
|
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
|
|
||||||
class Entry(TypedDict):
|
class Entry(TypedDict):
|
||||||
|
@ -49,7 +49,7 @@ from enum import Enum, IntEnum
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from timeit import default_timer
|
from timeit import default_timer
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Any, Callable, cast, NamedTuple, TYPE_CHECKING, TypeVar
|
from typing import Any, Callable, cast, NamedTuple, TYPE_CHECKING, TypedDict, TypeVar
|
||||||
from urllib.parse import unquote_plus
|
from urllib.parse import unquote_plus
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ from sqlalchemy.engine import Connection, Engine
|
|||||||
from sqlalchemy.engine.reflection import Inspector
|
from sqlalchemy.engine.reflection import Inspector
|
||||||
from sqlalchemy.sql.type_api import Variant
|
from sqlalchemy.sql.type_api import Variant
|
||||||
from sqlalchemy.types import TEXT, TypeDecorator, TypeEngine
|
from sqlalchemy.types import TEXT, TypeDecorator, TypeEngine
|
||||||
from typing_extensions import TypedDict, TypeGuard
|
from typing_extensions import TypeGuard
|
||||||
|
|
||||||
from superset.constants import (
|
from superset.constants import (
|
||||||
EXTRA_FORM_DATA_APPEND_KEYS,
|
EXTRA_FORM_DATA_APPEND_KEYS,
|
||||||
@ -368,9 +368,9 @@ def flasher(msg: str, severity: str = "message") -> None:
|
|||||||
def parse_js_uri_path_item(
|
def parse_js_uri_path_item(
|
||||||
item: str | None, unquote: bool = True, eval_undefined: bool = False
|
item: str | None, unquote: bool = True, eval_undefined: bool = False
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
"""Parse a uri path item made with js.
|
"""Parse an uri path item made with js.
|
||||||
|
|
||||||
:param item: a uri path component
|
:param item: an uri path component
|
||||||
:param unquote: Perform unquoting of string using urllib.parse.unquote_plus()
|
:param unquote: Perform unquoting of string using urllib.parse.unquote_plus()
|
||||||
:param eval_undefined: When set to True and item is either 'null' or 'undefined',
|
:param eval_undefined: When set to True and item is either 'null' or 'undefined',
|
||||||
assume item is undefined and return None.
|
assume item is undefined and return None.
|
||||||
@ -1162,16 +1162,14 @@ def merge_extra_filters(form_data: dict[str, Any]) -> None:
|
|||||||
filtr["isExtra"] = True
|
filtr["isExtra"] = True
|
||||||
# Pull out time filters/options and merge into form data
|
# Pull out time filters/options and merge into form data
|
||||||
filter_column = filtr["col"]
|
filter_column = filtr["col"]
|
||||||
time_extra = date_options.get(filter_column)
|
if time_extra := date_options.get(filter_column):
|
||||||
if time_extra:
|
|
||||||
time_extra_value = filtr.get("val")
|
time_extra_value = filtr.get("val")
|
||||||
if time_extra_value and time_extra_value != NO_TIME_RANGE:
|
if time_extra_value and time_extra_value != NO_TIME_RANGE:
|
||||||
form_data[time_extra] = time_extra_value
|
form_data[time_extra] = time_extra_value
|
||||||
form_data["applied_time_extras"][filter_column] = time_extra_value
|
form_data["applied_time_extras"][filter_column] = time_extra_value
|
||||||
elif filtr["val"]:
|
elif filtr["val"]:
|
||||||
# Merge column filters
|
# Merge column filters
|
||||||
filter_key = get_filter_key(filtr)
|
if (filter_key := get_filter_key(filtr)) in existing_filters:
|
||||||
if filter_key in existing_filters:
|
|
||||||
# Check if the filter already exists
|
# Check if the filter already exists
|
||||||
if isinstance(filtr["val"], list):
|
if isinstance(filtr["val"], list):
|
||||||
if isinstance(existing_filters[filter_key], list):
|
if isinstance(existing_filters[filter_key], list):
|
||||||
@ -1268,11 +1266,9 @@ def get_column_name(column: Column, verbose_map: dict[str, Any] | None = None) -
|
|||||||
:raises ValueError: if metric object is invalid
|
:raises ValueError: if metric object is invalid
|
||||||
"""
|
"""
|
||||||
if isinstance(column, dict):
|
if isinstance(column, dict):
|
||||||
label = column.get("label")
|
if label := column.get("label"):
|
||||||
if label:
|
|
||||||
return label
|
return label
|
||||||
expr = column.get("sqlExpression")
|
if expr := column.get("sqlExpression"):
|
||||||
if expr:
|
|
||||||
return expr
|
return expr
|
||||||
|
|
||||||
if isinstance(column, str):
|
if isinstance(column, str):
|
||||||
@ -1293,13 +1289,10 @@ def get_metric_name(metric: Metric, verbose_map: dict[str, Any] | None = None) -
|
|||||||
:raises ValueError: if metric object is invalid
|
:raises ValueError: if metric object is invalid
|
||||||
"""
|
"""
|
||||||
if is_adhoc_metric(metric):
|
if is_adhoc_metric(metric):
|
||||||
label = metric.get("label")
|
if label := metric.get("label"):
|
||||||
if label:
|
|
||||||
return label
|
return label
|
||||||
expression_type = metric.get("expressionType")
|
if (expression_type := metric.get("expressionType")) == "SQL":
|
||||||
if expression_type == "SQL":
|
if sql_expression := metric.get("sqlExpression"):
|
||||||
sql_expression = metric.get("sqlExpression")
|
|
||||||
if sql_expression:
|
|
||||||
return sql_expression
|
return sql_expression
|
||||||
if expression_type == "SIMPLE":
|
if expression_type == "SIMPLE":
|
||||||
column: AdhocMetricColumn = metric.get("column") or {}
|
column: AdhocMetricColumn = metric.get("column") or {}
|
||||||
@ -1753,9 +1746,8 @@ def get_time_filter_status(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
time_range = applied_time_extras.get(ExtraFiltersTimeColumnType.TIME_RANGE)
|
if applied_time_extras.get(ExtraFiltersTimeColumnType.TIME_RANGE):
|
||||||
if time_range:
|
# are there any temporal columns to assign the time range to?
|
||||||
# are there any temporal columns to assign the time grain to?
|
|
||||||
if temporal_columns:
|
if temporal_columns:
|
||||||
applied.append({"column": ExtraFiltersTimeColumnType.TIME_RANGE})
|
applied.append({"column": ExtraFiltersTimeColumnType.TIME_RANGE})
|
||||||
else:
|
else:
|
||||||
|
@ -23,7 +23,7 @@ import string
|
|||||||
import sys
|
import sys
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
from datetime import date, datetime, time, timedelta
|
from datetime import date, datetime, time, timedelta
|
||||||
from typing import Any, Callable, cast, Optional
|
from typing import Any, Callable, cast, Optional, TypedDict
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import sqlalchemy.sql.sqltypes
|
import sqlalchemy.sql.sqltypes
|
||||||
@ -34,7 +34,6 @@ from sqlalchemy.dialects import postgresql
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from sqlalchemy.sql.visitors import VisitableType
|
from sqlalchemy.sql.visitors import VisitableType
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset import db
|
from superset import db
|
||||||
|
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
# KIND, either express or implied. See the License for the
|
# KIND, either express or implied. See the License for the
|
||||||
# specific language governing permissions and limitations
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional, TypedDict
|
||||||
|
|
||||||
from marshmallow import fields, post_load, pre_load, Schema, validate
|
from marshmallow import fields, post_load, pre_load, Schema, validate
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from superset import app
|
from superset import app
|
||||||
from superset.charts.schemas import ChartDataExtrasSchema, ChartDataFilterSchema
|
from superset.charts.schemas import ChartDataExtrasSchema, ChartDataFilterSchema
|
||||||
|
Loading…
Reference in New Issue
Block a user