diff --git a/superset/charts/schemas.py b/superset/charts/schemas.py index 4f37a810223..81b9509cd0a 100644 --- a/superset/charts/schemas.py +++ b/superset/charts/schemas.py @@ -459,7 +459,7 @@ class ChartDataAggregateOptionsSchema(ChartDataPostProcessingOperationOptionsSch allow_none=False, metadata={"description": "Columns by which to group by"}, ), - minLength=1, + metadata={"minLength": 1}, required=True, ), ) @@ -656,8 +656,8 @@ class ChartDataProphetOptionsSchema(ChartDataPostProcessingOperationOptionsSchem "description": "Time periods (in units of `time_grain`) to predict into " "the future", "example": 7, + "min": 0, }, - min=0, required=True, ) confidence_interval = fields.Float( @@ -790,8 +790,10 @@ class ChartDataPivotOptionsSchema(ChartDataPostProcessingOperationOptionsSchema) index = ( fields.List( fields.String(allow_none=False), - metadata={"description": "Columns to group by on the table index (=rows)"}, - minLength=1, + metadata={ + "description": "Columns to group by on the table index (=rows)", + "minLength": 1, + }, required=True, ), ) @@ -1681,7 +1683,7 @@ class DashboardSchema(Schema): class ChartGetResponseSchema(Schema): - id = fields.Int(description=id_description) + id = fields.Int(metadata={"description": id_description}) url = fields.String() cache_timeout = fields.String() certified_by = fields.String() diff --git a/superset/db_engine_specs/databend.py b/superset/db_engine_specs/databend.py index e0e06b2b10a..9df1d241519 100644 --- a/superset/db_engine_specs/databend.py +++ b/superset/db_engine_specs/databend.py @@ -194,20 +194,27 @@ class DatabendEngineSpec(DatabendBaseEngineSpec): class DatabendParametersSchema(Schema): - username = fields.String(allow_none=True, description=__("Username")) - password = fields.String(allow_none=True, description=__("Password")) - host = fields.String(required=True, description=__("Hostname or IP address")) + username = fields.String(allow_none=True, metadata={"description": __("Username")}) + password = fields.String(allow_none=True, metadata={"description": __("Password")}) + host = fields.String( + required=True, metadata={"description": __("Hostname or IP address")} + ) port = fields.Integer( allow_none=True, - description=__("Database port"), + metadata={"description": __("Database port")}, validate=Range(min=0, max=65535), ) - database = fields.String(allow_none=True, description=__("Database name")) + database = fields.String( + allow_none=True, metadata={"description": __("Database name")} + ) encryption = fields.Boolean( - default=True, description=__("Use an encrypted connection to the database") + dump_default=True, + metadata={"description": __("Use an encrypted connection to the database")}, ) query = fields.Dict( - keys=fields.Str(), values=fields.Raw(), description=__("Additional parameters") + keys=fields.Str(), + values=fields.Raw(), + metadata={"description": __("Additional parameters")}, ) diff --git a/superset/models/core.py b/superset/models/core.py index b9b7b605911..0a954b36742 100755 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -1183,10 +1183,11 @@ class Database(CoreDatabase, AuditMixinNullable, ImportExportMixin): # pylint: def has_table(self, table: Table) -> bool: with self.get_sqla_engine(catalog=table.catalog, schema=table.schema) as engine: + inspector = sqla.inspect(engine) # do not pass "" as an empty schema; force null - if engine.has_table(table.table, table.schema or None): + if inspector.has_table(table.table, table.schema or None): return True - return engine.has_table(table.table.lower(), table.schema or None) + return inspector.has_table(table.table.lower(), table.schema or None) def has_view(self, table: Table) -> bool: with self.get_sqla_engine(catalog=table.catalog, schema=table.schema) as engine: diff --git a/superset/models/helpers.py b/superset/models/helpers.py index a1c92adaa14..46ae374fd57 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -2414,7 +2414,7 @@ class ExploreMixin: # pylint: disable=too-many-public-methods self.dttm_sql_literal(end_dttm, time_col) ) ) - return and_(*l) + return and_(True, *l) def values_for_column( # pylint: disable=too-many-locals self, diff --git a/superset/utils/logging_configurator.py b/superset/utils/logging_configurator.py index 2d53d535cda..86399689994 100644 --- a/superset/utils/logging_configurator.py +++ b/superset/utils/logging_configurator.py @@ -45,6 +45,13 @@ class DefaultLoggingConfigurator( # pylint: disable=too-few-public-methods logging.basicConfig(format=app_config["LOG_FORMAT"]) logging.getLogger().setLevel(app_config["LOG_LEVEL"]) + # Route Python warnings through the logging framework so they get + # proper log-level formatting instead of raw stderr output. Without + # this, the warnings module writes multi-line text to stderr where + # the source-code context line has no level prefix, causing log + # aggregators to misclassify it as an error. + logging.captureWarnings(True) + if app_config["ENABLE_TIME_ROTATE"]: logging.getLogger().setLevel(app_config["TIME_ROTATE_LOG_LEVEL"]) handler = TimedRotatingFileHandler( diff --git a/superset/utils/pandas_postprocessing/resample.py b/superset/utils/pandas_postprocessing/resample.py index a689895bd62..d394ce0f138 100644 --- a/superset/utils/pandas_postprocessing/resample.py +++ b/superset/utils/pandas_postprocessing/resample.py @@ -54,5 +54,5 @@ def resample( else: _df = getattr(df.resample(rule), method)() if method in ("ffill", "bfill"): - _df = _df.fillna(method=method) + _df = getattr(_df, method)() return _df diff --git a/superset/viz.py b/superset/viz.py index c6c7cf699b7..21ddf85c233 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -2817,15 +2817,19 @@ class PartitionViz(NVD3TimeSeriesViz): return self.nest_values(levels) +def _get_subclasses(cls: type[BaseViz]) -> set[type[BaseViz]]: + return set(cls.__subclasses__()).union( + [sc for c in cls.__subclasses__() for sc in _get_subclasses(c)] + ) + + @deprecated(deprecated_in="3.0") def get_subclasses(cls: type[BaseViz]) -> set[type[BaseViz]]: - return set(cls.__subclasses__()).union( - [sc for c in cls.__subclasses__() for sc in get_subclasses(c)] - ) + return _get_subclasses(cls) viz_types = { o.viz_type: o - for o in get_subclasses(BaseViz) + for o in _get_subclasses(BaseViz) if o.viz_type not in current_app.config["VIZ_TYPE_DENYLIST"] }