From be7065faf8e00ea0304b5380b2347f2ea9e4b39b Mon Sep 17 00:00:00 2001 From: John Bodley <4567245+john-bodley@users.noreply.github.com> Date: Mon, 16 Aug 2021 15:26:10 -0700 Subject: [PATCH] chore(pylint): Reenable raise-missing-from check (#16266) Co-authored-by: John Bodley --- .pylintrc | 1 - .../annotations/commands/bulk_delete.py | 2 +- .../annotations/commands/create.py | 2 +- .../annotations/commands/delete.py | 2 +- .../annotations/commands/update.py | 2 +- superset/annotation_layers/annotations/dao.py | 4 ++-- .../annotation_layers/annotations/schemas.py | 4 ++-- .../annotation_layers/commands/bulk_delete.py | 2 +- superset/annotation_layers/commands/create.py | 2 +- superset/annotation_layers/commands/delete.py | 2 +- superset/annotation_layers/commands/update.py | 2 +- superset/annotation_layers/dao.py | 4 ++-- superset/charts/commands/bulk_delete.py | 6 +++--- superset/charts/commands/create.py | 2 +- superset/charts/commands/data.py | 8 ++++---- superset/charts/commands/delete.py | 6 +++--- superset/charts/commands/update.py | 6 +++--- superset/commands/importers/v1/__init__.py | 4 ++-- superset/commands/importers/v1/examples.py | 4 ++-- superset/commands/importers/v1/utils.py | 14 ++++++------- superset/commands/utils.py | 4 ++-- superset/common/query_context.py | 4 ++-- superset/connectors/druid/views.py | 2 +- superset/connectors/sqla/models.py | 10 +++++----- superset/connectors/sqla/utils.py | 4 ++-- .../css_templates/commands/bulk_delete.py | 2 +- superset/css_templates/dao.py | 4 ++-- superset/dao/base.py | 6 +++--- superset/dashboards/commands/bulk_delete.py | 6 +++--- superset/dashboards/commands/create.py | 2 +- superset/dashboards/commands/delete.py | 6 +++--- superset/dashboards/commands/update.py | 6 +++--- superset/dashboards/schemas.py | 8 ++++---- superset/databases/api.py | 6 +++--- superset/databases/commands/create.py | 4 ++-- superset/databases/commands/delete.py | 2 +- .../databases/commands/test_connection.py | 8 ++++---- superset/databases/commands/update.py | 4 ++-- superset/databases/commands/validate.py | 2 +- superset/databases/schemas.py | 14 ++++++------- superset/datasets/columns/commands/delete.py | 6 +++--- superset/datasets/commands/bulk_delete.py | 6 +++--- superset/datasets/commands/create.py | 2 +- superset/datasets/commands/delete.py | 6 +++--- superset/datasets/commands/importers/v0.py | 6 ++++-- superset/datasets/commands/refresh.py | 6 +++--- superset/datasets/commands/update.py | 6 +++--- superset/datasets/metrics/commands/delete.py | 6 +++--- superset/db_engine_specs/bigquery.py | 4 ++-- superset/db_engine_specs/druid.py | 4 ++-- superset/db_engine_specs/postgres.py | 4 ++-- superset/db_engines/hive.py | 4 ++-- superset/jinja_context.py | 8 ++++---- superset/models/tags.py | 4 ++-- .../saved_queries/commands/bulk_delete.py | 2 +- superset/queries/saved_queries/dao.py | 4 ++-- superset/reports/commands/alert.py | 12 +++++------ superset/reports/commands/bulk_delete.py | 6 +++--- superset/reports/commands/create.py | 2 +- superset/reports/commands/delete.py | 6 +++--- superset/reports/commands/execute.py | 16 ++++++++------- superset/reports/commands/update.py | 6 +++--- superset/reports/dao.py | 8 ++++---- superset/reports/notifications/email.py | 2 +- superset/reports/notifications/slack.py | 2 +- superset/sql_lab.py | 10 +++++----- superset/utils/async_query_manager.py | 6 +++--- superset/utils/core.py | 6 +++--- superset/utils/date_parser.py | 6 +++--- superset/utils/pandas_postprocessing.py | 20 +++++++++---------- superset/utils/schema.py | 4 ++-- superset/views/base.py | 4 ++-- superset/views/base_schemas.py | 4 ++-- superset/views/core.py | 10 ++++++---- superset/views/database/mixins.py | 4 ++-- superset/views/database/validators.py | 4 ++-- superset/views/database/views.py | 2 +- superset/views/datasource/views.py | 8 ++++---- superset/views/schedules.py | 4 ++-- superset/views/utils.py | 14 ++++++------- 80 files changed, 216 insertions(+), 211 deletions(-) diff --git a/.pylintrc b/.pylintrc index e921ee5ac..963290417 100644 --- a/.pylintrc +++ b/.pylintrc @@ -84,7 +84,6 @@ confidence= disable= missing-docstring, too-many-lines, - raise-missing-from, duplicate-code, [REPORTS] diff --git a/superset/annotation_layers/annotations/commands/bulk_delete.py b/superset/annotation_layers/annotations/commands/bulk_delete.py index 9d9df6fab..6a164c877 100644 --- a/superset/annotation_layers/annotations/commands/bulk_delete.py +++ b/superset/annotation_layers/annotations/commands/bulk_delete.py @@ -44,7 +44,7 @@ class BulkDeleteAnnotationCommand(BaseCommand): return None except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise AnnotationBulkDeleteFailedError() + raise AnnotationBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists diff --git a/superset/annotation_layers/annotations/commands/create.py b/superset/annotation_layers/annotations/commands/create.py index 398e1b4c5..cbcb09a4c 100644 --- a/superset/annotation_layers/annotations/commands/create.py +++ b/superset/annotation_layers/annotations/commands/create.py @@ -48,7 +48,7 @@ class CreateAnnotationCommand(BaseCommand): annotation = AnnotationDAO.create(self._properties) except DAOCreateFailedError as ex: logger.exception(ex.exception) - raise AnnotationCreateFailedError() + raise AnnotationCreateFailedError() from ex return annotation def validate(self) -> None: diff --git a/superset/annotation_layers/annotations/commands/delete.py b/superset/annotation_layers/annotations/commands/delete.py index bd5c998a5..3d874818d 100644 --- a/superset/annotation_layers/annotations/commands/delete.py +++ b/superset/annotation_layers/annotations/commands/delete.py @@ -44,7 +44,7 @@ class DeleteAnnotationCommand(BaseCommand): annotation = AnnotationDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise AnnotationDeleteFailedError() + raise AnnotationDeleteFailedError() from ex return annotation def validate(self) -> None: diff --git a/superset/annotation_layers/annotations/commands/update.py b/superset/annotation_layers/annotations/commands/update.py index 1942bffa7..eb544344f 100644 --- a/superset/annotation_layers/annotations/commands/update.py +++ b/superset/annotation_layers/annotations/commands/update.py @@ -52,7 +52,7 @@ class UpdateAnnotationCommand(BaseCommand): annotation = AnnotationDAO.update(self._model, self._properties) except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise AnnotationUpdateFailedError() + raise AnnotationUpdateFailedError() from ex return annotation def validate(self) -> None: diff --git a/superset/annotation_layers/annotations/dao.py b/superset/annotation_layers/annotations/dao.py index 50e4bcb29..3b6e5e72e 100644 --- a/superset/annotation_layers/annotations/dao.py +++ b/superset/annotation_layers/annotations/dao.py @@ -39,10 +39,10 @@ class AnnotationDAO(BaseDAO): ) if commit: db.session.commit() - except SQLAlchemyError: + except SQLAlchemyError as ex: if commit: db.session.rollback() - raise DAODeleteFailedError() + raise DAODeleteFailedError() from ex @staticmethod def validate_update_uniqueness( diff --git a/superset/annotation_layers/annotations/schemas.py b/superset/annotation_layers/annotations/schemas.py index 42af48d61..72edcc10d 100644 --- a/superset/annotation_layers/annotations/schemas.py +++ b/superset/annotation_layers/annotations/schemas.py @@ -51,8 +51,8 @@ annotation_json_metadata = "JSON metadata" def validate_json(value: Union[bytes, bytearray, str]) -> None: try: utils.validate_json(value) - except SupersetException: - raise ValidationError("JSON not valid") + except SupersetException as ex: + raise ValidationError("JSON not valid") from ex class AnnotationPostSchema(Schema): diff --git a/superset/annotation_layers/commands/bulk_delete.py b/superset/annotation_layers/commands/bulk_delete.py index 148bdd0bd..a828047fd 100644 --- a/superset/annotation_layers/commands/bulk_delete.py +++ b/superset/annotation_layers/commands/bulk_delete.py @@ -45,7 +45,7 @@ class BulkDeleteAnnotationLayerCommand(BaseCommand): return None except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise AnnotationLayerBulkDeleteFailedError() + raise AnnotationLayerBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists diff --git a/superset/annotation_layers/commands/create.py b/superset/annotation_layers/commands/create.py index c62592194..5e26bc49d 100644 --- a/superset/annotation_layers/commands/create.py +++ b/superset/annotation_layers/commands/create.py @@ -44,7 +44,7 @@ class CreateAnnotationLayerCommand(BaseCommand): annotation_layer = AnnotationLayerDAO.create(self._properties) except DAOCreateFailedError as ex: logger.exception(ex.exception) - raise AnnotationLayerCreateFailedError() + raise AnnotationLayerCreateFailedError() from ex return annotation_layer def validate(self) -> None: diff --git a/superset/annotation_layers/commands/delete.py b/superset/annotation_layers/commands/delete.py index dd9b2c476..c439542b2 100644 --- a/superset/annotation_layers/commands/delete.py +++ b/superset/annotation_layers/commands/delete.py @@ -45,7 +45,7 @@ class DeleteAnnotationLayerCommand(BaseCommand): annotation_layer = AnnotationLayerDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise AnnotationLayerDeleteFailedError() + raise AnnotationLayerDeleteFailedError() from ex return annotation_layer def validate(self) -> None: diff --git a/superset/annotation_layers/commands/update.py b/superset/annotation_layers/commands/update.py index d5625ccb4..7e8f6d5bd 100644 --- a/superset/annotation_layers/commands/update.py +++ b/superset/annotation_layers/commands/update.py @@ -48,7 +48,7 @@ class UpdateAnnotationLayerCommand(BaseCommand): annotation_layer = AnnotationLayerDAO.update(self._model, self._properties) except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise AnnotationLayerUpdateFailedError() + raise AnnotationLayerUpdateFailedError() from ex return annotation_layer def validate(self) -> None: diff --git a/superset/annotation_layers/dao.py b/superset/annotation_layers/dao.py index 9c848e59a..0ca19e270 100644 --- a/superset/annotation_layers/dao.py +++ b/superset/annotation_layers/dao.py @@ -41,10 +41,10 @@ class AnnotationLayerDAO(BaseDAO): ).delete(synchronize_session="fetch") if commit: db.session.commit() - except SQLAlchemyError: + except SQLAlchemyError as ex: if commit: db.session.rollback() - raise DAODeleteFailedError() + raise DAODeleteFailedError() from ex @staticmethod def has_annotations(model_id: Union[int, List[int]]) -> bool: diff --git a/superset/charts/commands/bulk_delete.py b/superset/charts/commands/bulk_delete.py index 463f17bc0..26a3fce9e 100644 --- a/superset/charts/commands/bulk_delete.py +++ b/superset/charts/commands/bulk_delete.py @@ -49,7 +49,7 @@ class BulkDeleteChartCommand(BaseCommand): ChartDAO.bulk_delete(self._models) except DeleteFailedError as ex: logger.exception(ex.exception) - raise ChartBulkDeleteFailedError() + raise ChartBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists @@ -67,5 +67,5 @@ class BulkDeleteChartCommand(BaseCommand): for model in self._models: try: check_ownership(model) - except SupersetSecurityException: - raise ChartForbiddenError() + except SupersetSecurityException as ex: + raise ChartForbiddenError() from ex diff --git a/superset/charts/commands/create.py b/superset/charts/commands/create.py index a393c6811..36dca581a 100644 --- a/superset/charts/commands/create.py +++ b/superset/charts/commands/create.py @@ -49,7 +49,7 @@ class CreateChartCommand(CreateMixin, BaseCommand): chart = ChartDAO.create(self._properties) except DAOCreateFailedError as ex: logger.exception(ex.exception) - raise ChartCreateFailedError() + raise ChartCreateFailedError() from ex return chart def validate(self) -> None: diff --git a/superset/charts/commands/data.py b/superset/charts/commands/data.py index 1a383827c..619244c23 100644 --- a/superset/charts/commands/data.py +++ b/superset/charts/commands/data.py @@ -50,8 +50,8 @@ class ChartDataCommand(BaseCommand): payload = self._query_context.get_payload( cache_query_context=cache_query_context, force_cached=force_cached ) - except CacheLoadError as exc: - raise ChartDataCacheLoadError(exc.message) + except CacheLoadError as ex: + raise ChartDataCacheLoadError(ex.message) from ex # TODO: QueryContext should support SIP-40 style errors for query in payload["queries"]: @@ -77,8 +77,8 @@ class ChartDataCommand(BaseCommand): self._form_data = form_data try: self._query_context = ChartDataQueryContextSchema().load(self._form_data) - except KeyError: - raise ValidationError("Request is incorrect") + except KeyError as ex: + raise ValidationError("Request is incorrect") from ex except ValidationError as error: raise error diff --git a/superset/charts/commands/delete.py b/superset/charts/commands/delete.py index 5b33a5041..faf72c5ef 100644 --- a/superset/charts/commands/delete.py +++ b/superset/charts/commands/delete.py @@ -52,7 +52,7 @@ class DeleteChartCommand(BaseCommand): chart = ChartDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise ChartDeleteFailedError() + raise ChartDeleteFailedError() from ex return chart def validate(self) -> None: @@ -70,5 +70,5 @@ class DeleteChartCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise ChartForbiddenError() + except SupersetSecurityException as ex: + raise ChartForbiddenError() from ex diff --git a/superset/charts/commands/update.py b/superset/charts/commands/update.py index 449c67da2..b09845512 100644 --- a/superset/charts/commands/update.py +++ b/superset/charts/commands/update.py @@ -64,7 +64,7 @@ class UpdateChartCommand(UpdateMixin, BaseCommand): chart = ChartDAO.update(self._model, self._properties) except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise ChartUpdateFailedError() + raise ChartUpdateFailedError() from ex return chart def validate(self) -> None: @@ -89,8 +89,8 @@ class UpdateChartCommand(UpdateMixin, BaseCommand): if not is_query_context_update(self._properties): try: check_ownership(self._model) - except SupersetSecurityException: - raise ChartForbiddenError() + except SupersetSecurityException as ex: + raise ChartForbiddenError() from ex # Validate/Populate datasource if datasource_id is not None: diff --git a/superset/commands/importers/v1/__init__.py b/superset/commands/importers/v1/__init__.py index b9ea24414..0286735de 100644 --- a/superset/commands/importers/v1/__init__.py +++ b/superset/commands/importers/v1/__init__.py @@ -66,9 +66,9 @@ class ImportModelsCommand(BaseCommand): try: self._import(db.session, self._configs, self.overwrite) db.session.commit() - except Exception: + except Exception as ex: db.session.rollback() - raise self.import_error() + raise self.import_error() from ex # pylint: disable=too-many-branches def validate(self) -> None: diff --git a/superset/commands/importers/v1/examples.py b/superset/commands/importers/v1/examples.py index 03ffd2c5d..7091f8841 100644 --- a/superset/commands/importers/v1/examples.py +++ b/superset/commands/importers/v1/examples.py @@ -72,9 +72,9 @@ class ImportExamplesCommand(ImportModelsCommand): try: self._import(db.session, self._configs, self.overwrite, self.force_data) db.session.commit() - except Exception: + except Exception as ex: db.session.rollback() - raise self.import_error() + raise self.import_error() from ex @classmethod def _get_uuids(cls) -> Set[str]: diff --git a/superset/commands/importers/v1/utils.py b/superset/commands/importers/v1/utils.py index b071678a0..15bec8278 100644 --- a/superset/commands/importers/v1/utils.py +++ b/superset/commands/importers/v1/utils.py @@ -47,9 +47,9 @@ def load_yaml(file_name: str, content: str) -> Dict[str, Any]: """Try to load a YAML file""" try: return yaml.safe_load(content) - except yaml.parser.ParserError: + except yaml.parser.ParserError as ex: logger.exception("Invalid YAML in %s", file_name) - raise ValidationError({file_name: "Not a valid YAML file"}) + raise ValidationError({file_name: "Not a valid YAML file"}) from ex def load_metadata(contents: Dict[str, str]) -> Dict[str, str]: @@ -63,15 +63,15 @@ def load_metadata(contents: Dict[str, str]) -> Dict[str, str]: metadata = load_yaml(METADATA_FILE_NAME, contents[METADATA_FILE_NAME]) try: MetadataSchema().load(metadata) - except ValidationError as exc: + except ValidationError as ex: # if the version doesn't match raise an exception so that the # dispatcher can try a different command version - if "version" in exc.messages: - raise IncorrectVersionError(exc.messages["version"][0]) + if "version" in ex.messages: + raise IncorrectVersionError(ex.messages["version"][0]) from ex # otherwise we raise the validation error - exc.messages = {METADATA_FILE_NAME: exc.messages} - raise exc + ex.messages = {METADATA_FILE_NAME: ex.messages} + raise ex return metadata diff --git a/superset/commands/utils.py b/superset/commands/utils.py index 0cecb2e15..c656ce304 100644 --- a/superset/commands/utils.py +++ b/superset/commands/utils.py @@ -76,5 +76,5 @@ def get_datasource_by_id(datasource_id: int, datasource_type: str) -> BaseDataso return ConnectorRegistry.get_datasource( datasource_type, datasource_id, db.session ) - except DatasetNotFoundError: - raise DatasourceNotFoundValidationError() + except DatasetNotFoundError as ex: + raise DatasourceNotFoundValidationError() from ex diff --git a/superset/common/query_context.py b/superset/common/query_context.py index 32f3c5578..566b01c86 100644 --- a/superset/common/query_context.py +++ b/superset/common/query_context.py @@ -138,7 +138,7 @@ class QueryContext: ) query_object_clone.to_dttm = get_past_or_future(offset, outer_to_dttm) except ValueError as ex: - raise QueryObjectValidationError(str(ex)) + raise QueryObjectValidationError(str(ex)) from ex # make sure subquery use main query where clause query_object_clone.inner_from_dttm = outer_from_dttm query_object_clone.inner_to_dttm = outer_to_dttm @@ -417,7 +417,7 @@ class QueryContext: payload = viz_obj.get_payload() return payload["data"] except SupersetException as ex: - raise QueryObjectValidationError(error_msg_from_exception(ex)) + raise QueryObjectValidationError(error_msg_from_exception(ex)) from ex def get_annotation_data(self, query_obj: QueryObject) -> Dict[str, Any]: """ diff --git a/superset/connectors/druid/views.py b/superset/connectors/druid/views.py index 5454a41d3..eca14d481 100644 --- a/superset/connectors/druid/views.py +++ b/superset/connectors/druid/views.py @@ -127,7 +127,7 @@ class DruidColumnInlineView(CompactCRUDMixin, EnsureEnabledMixin, SupersetModelV try: dimension_spec = json.loads(item.dimension_spec_json) except ValueError as ex: - raise ValueError("Invalid Dimension Spec JSON: " + str(ex)) + raise ValueError("Invalid Dimension Spec JSON: " + str(ex)) from ex if not isinstance(dimension_spec, dict): raise ValueError("Dimension Spec must be a JSON object") if "outputName" not in dimension_spec: diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index c28b44ece..fd43010d7 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -719,7 +719,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at "Error in jinja expression in fetch values predicate: %(msg)s", msg=ex.message, ) - ) + ) from ex def values_for_column(self, column_name: str, limit: int = 10000) -> List[Any]: """Runs query against sqla to retrieve some @@ -818,7 +818,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at "Error while rendering virtual dataset query: %(msg)s", msg=ex.message, ) - ) + ) from ex sql = sqlparse.format(sql.strip("\t\r\n; "), strip_comments=True) if not sql: raise QueryObjectValidationError(_("Virtual dataset query cannot be empty")) @@ -929,7 +929,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at except TemplateError as ex: raise QueryObjectValidationError( _("Error in jinja expression in RLS filters: %(msg)s", msg=ex.message,) - ) + ) from ex def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements self, @@ -1252,7 +1252,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at "Error in jinja expression in WHERE clause: %(msg)s", msg=ex.message, ) - ) + ) from ex where_clause_and += [sa.text("({})".format(where))] having = extras.get("having") if having: @@ -1264,7 +1264,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at "Error in jinja expression in HAVING clause: %(msg)s", msg=ex.message, ) - ) + ) from ex having_clause_and += [sa.text("({})".format(having))] if apply_fetch_values_predicate and self.fetch_values_predicate: qry = qry.where(self.get_fetch_values_predicate()) diff --git a/superset/connectors/sqla/utils.py b/superset/connectors/sqla/utils.py index 1ee1fc140..a9b620300 100644 --- a/superset/connectors/sqla/utils.py +++ b/superset/connectors/sqla/utils.py @@ -110,6 +110,6 @@ def get_virtual_table_metadata(dataset: "SqlaTable") -> List[Dict[str, str]]: result = db_engine_spec.fetch_data(cursor, limit=1) result_set = SupersetResultSet(result, cursor.description, db_engine_spec) cols = result_set.columns - except Exception as exc: - raise SupersetGenericDBErrorException(message=str(exc)) + except Exception as ex: + raise SupersetGenericDBErrorException(message=str(ex)) from ex return cols diff --git a/superset/css_templates/commands/bulk_delete.py b/superset/css_templates/commands/bulk_delete.py index 40b2e800c..839dbd26a 100644 --- a/superset/css_templates/commands/bulk_delete.py +++ b/superset/css_templates/commands/bulk_delete.py @@ -44,7 +44,7 @@ class BulkDeleteCssTemplateCommand(BaseCommand): return None except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise CssTemplateBulkDeleteFailedError() + raise CssTemplateBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists diff --git a/superset/css_templates/dao.py b/superset/css_templates/dao.py index 8f9d36be3..1862fb7aa 100644 --- a/superset/css_templates/dao.py +++ b/superset/css_templates/dao.py @@ -39,7 +39,7 @@ class CssTemplateDAO(BaseDAO): ) if commit: db.session.commit() - except SQLAlchemyError: + except SQLAlchemyError as ex: if commit: db.session.rollback() - raise DAODeleteFailedError() + raise DAODeleteFailedError() from ex diff --git a/superset/dao/base.py b/superset/dao/base.py index 0cd0facf7..79ece40c9 100644 --- a/superset/dao/base.py +++ b/superset/dao/base.py @@ -106,7 +106,7 @@ class BaseDAO: db.session.commit() except SQLAlchemyError as ex: # pragma: no cover db.session.rollback() - raise DAOCreateFailedError(exception=ex) + raise DAOCreateFailedError(exception=ex) from ex return model @classmethod @@ -125,7 +125,7 @@ class BaseDAO: db.session.commit() except SQLAlchemyError as ex: # pragma: no cover db.session.rollback() - raise DAOUpdateFailedError(exception=ex) + raise DAOUpdateFailedError(exception=ex) from ex return model @classmethod @@ -140,5 +140,5 @@ class BaseDAO: db.session.commit() except SQLAlchemyError as ex: # pragma: no cover db.session.rollback() - raise DAODeleteFailedError(exception=ex) + raise DAODeleteFailedError(exception=ex) from ex return model diff --git a/superset/dashboards/commands/bulk_delete.py b/superset/dashboards/commands/bulk_delete.py index 27787cc61..958dea27d 100644 --- a/superset/dashboards/commands/bulk_delete.py +++ b/superset/dashboards/commands/bulk_delete.py @@ -50,7 +50,7 @@ class BulkDeleteDashboardCommand(BaseCommand): return None except DeleteFailedError as ex: logger.exception(ex.exception) - raise DashboardBulkDeleteFailedError() + raise DashboardBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists @@ -68,5 +68,5 @@ class BulkDeleteDashboardCommand(BaseCommand): for model in self._models: try: check_ownership(model) - except SupersetSecurityException: - raise DashboardForbiddenError() + except SupersetSecurityException as ex: + raise DashboardForbiddenError() from ex diff --git a/superset/dashboards/commands/create.py b/superset/dashboards/commands/create.py index de136d20e..91f7e90ba 100644 --- a/superset/dashboards/commands/create.py +++ b/superset/dashboards/commands/create.py @@ -46,7 +46,7 @@ class CreateDashboardCommand(CreateMixin, BaseCommand): dashboard = DashboardDAO.update_charts_owners(dashboard, commit=True) except DAOCreateFailedError as ex: logger.exception(ex.exception) - raise DashboardCreateFailedError() + raise DashboardCreateFailedError() from ex return dashboard def validate(self) -> None: diff --git a/superset/dashboards/commands/delete.py b/superset/dashboards/commands/delete.py index 795288a84..67f683a1c 100644 --- a/superset/dashboards/commands/delete.py +++ b/superset/dashboards/commands/delete.py @@ -50,7 +50,7 @@ class DeleteDashboardCommand(BaseCommand): dashboard = DashboardDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise DashboardDeleteFailedError() + raise DashboardDeleteFailedError() from ex return dashboard def validate(self) -> None: @@ -68,5 +68,5 @@ class DeleteDashboardCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DashboardForbiddenError() + except SupersetSecurityException as ex: + raise DashboardForbiddenError() from ex diff --git a/superset/dashboards/commands/update.py b/superset/dashboards/commands/update.py index 877c712fe..c22f4a35f 100644 --- a/superset/dashboards/commands/update.py +++ b/superset/dashboards/commands/update.py @@ -53,7 +53,7 @@ class UpdateDashboardCommand(UpdateMixin, BaseCommand): dashboard = DashboardDAO.update_charts_owners(dashboard, commit=True) except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise DashboardUpdateFailedError() + raise DashboardUpdateFailedError() from ex return dashboard def validate(self) -> None: @@ -69,8 +69,8 @@ class UpdateDashboardCommand(UpdateMixin, BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DashboardForbiddenError() + except SupersetSecurityException as ex: + raise DashboardForbiddenError() from ex # Validate slug uniqueness if not DashboardDAO.validate_update_slug_uniqueness(self._model_id, slug): diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py index 00888b38c..e577e9f19 100644 --- a/superset/dashboards/schemas.py +++ b/superset/dashboards/schemas.py @@ -89,8 +89,8 @@ openapi_spec_methods_override = { def validate_json(value: Union[bytes, bytearray, str]) -> None: try: utils.validate_json(value) - except SupersetException: - raise ValidationError("JSON not valid") + except SupersetException as ex: + raise ValidationError("JSON not valid") from ex def validate_json_metadata(value: Union[bytes, bytearray, str]) -> None: @@ -98,8 +98,8 @@ def validate_json_metadata(value: Union[bytes, bytearray, str]) -> None: return try: value_obj = json.loads(value) - except json.decoder.JSONDecodeError: - raise ValidationError("JSON not valid") + except json.decoder.JSONDecodeError as ex: + raise ValidationError("JSON not valid") from ex errors = DashboardJSONMetadataSchema().validate(value_obj, partial=False) if errors: raise ValidationError(errors) diff --git a/superset/databases/api.py b/superset/databases/api.py index 31be74558..e604c4a4c 100644 --- a/superset/databases/api.py +++ b/superset/databases/api.py @@ -1014,7 +1014,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): try: payload = DatabaseValidateParametersSchema().load(request.json) - except ValidationError as error: + except ValidationError as ex: errors = [ SupersetError( message="\n".join(messages), @@ -1022,9 +1022,9 @@ class DatabaseRestApi(BaseSupersetModelRestApi): level=ErrorLevel.ERROR, extra={"invalid": [attribute]}, ) - for attribute, messages in error.messages.items() + for attribute, messages in ex.messages.items() ] - raise InvalidParametersError(errors) + raise InvalidParametersError(errors) from ex command = ValidateDatabaseParametersCommand(g.user, payload) command.run() diff --git a/superset/databases/commands/create.py b/superset/databases/commands/create.py index e4acf26b5..8e1bb1eed 100644 --- a/superset/databases/commands/create.py +++ b/superset/databases/commands/create.py @@ -53,7 +53,7 @@ class CreateDatabaseCommand(BaseCommand): action=f"db_creation_failed.{ex.__class__.__name__}", engine=self._properties.get("sqlalchemy_uri", "").split(":")[0], ) - raise DatabaseConnectionFailedError() + raise DatabaseConnectionFailedError() from ex try: database = DatabaseDAO.create(self._properties, commit=False) @@ -73,7 +73,7 @@ class CreateDatabaseCommand(BaseCommand): action=f"db_creation_failed.{ex.__class__.__name__}", engine=database.db_engine_spec.__name__, ) - raise DatabaseCreateFailedError() + raise DatabaseCreateFailedError() from ex return database def validate(self) -> None: diff --git a/superset/databases/commands/delete.py b/superset/databases/commands/delete.py index 5f002dbfb..61bd7ad0a 100644 --- a/superset/databases/commands/delete.py +++ b/superset/databases/commands/delete.py @@ -48,7 +48,7 @@ class DeleteDatabaseCommand(BaseCommand): database = DatabaseDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise DatabaseDeleteFailedError() + raise DatabaseDeleteFailedError() from ex return database def validate(self) -> None: diff --git a/superset/databases/commands/test_connection.py b/superset/databases/commands/test_connection.py index 3b3a8e41f..2b5b0b8d2 100644 --- a/superset/databases/commands/test_connection.py +++ b/superset/databases/commands/test_connection.py @@ -95,7 +95,7 @@ class TestConnectionDatabaseCommand(BaseCommand): message=_("Could not load database driver: {}").format( database.db_engine_spec.__name__ ), - ) + ) from ex except DBAPIError as ex: event_logger.log_with_context( action=f"test_connection_error.{ex.__class__.__name__}", @@ -103,20 +103,20 @@ class TestConnectionDatabaseCommand(BaseCommand): ) # check for custom errors (wrong username, wrong password, etc) errors = database.db_engine_spec.extract_errors(ex, context) - raise DatabaseTestConnectionFailedError(errors) + raise DatabaseTestConnectionFailedError(errors) from ex except SupersetSecurityException as ex: event_logger.log_with_context( action=f"test_connection_error.{ex.__class__.__name__}", engine=database.db_engine_spec.__name__, ) - raise DatabaseSecurityUnsafeError(message=str(ex)) + raise DatabaseSecurityUnsafeError(message=str(ex)) from ex except Exception as ex: # pylint: disable=broad-except event_logger.log_with_context( action=f"test_connection_error.{ex.__class__.__name__}", engine=database.db_engine_spec.__name__, ) errors = database.db_engine_spec.extract_errors(ex, context) - raise DatabaseTestConnectionUnexpectedError(errors) + raise DatabaseTestConnectionUnexpectedError(errors) from ex def validate(self) -> None: database_name = self._properties.get("database_name") diff --git a/superset/databases/commands/update.py b/superset/databases/commands/update.py index 7c48e743a..db1741c32 100644 --- a/superset/databases/commands/update.py +++ b/superset/databases/commands/update.py @@ -56,7 +56,7 @@ class UpdateDatabaseCommand(BaseCommand): schemas = database.get_all_schema_names() except Exception as ex: db.session.rollback() - raise DatabaseConnectionFailedError() + raise DatabaseConnectionFailedError() from ex for schema in schemas: security_manager.add_permission_view_menu( "schema_access", security_manager.get_schema_perm(database, schema) @@ -65,7 +65,7 @@ class UpdateDatabaseCommand(BaseCommand): except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise DatabaseUpdateFailedError() + raise DatabaseUpdateFailedError() from ex return database def validate(self) -> None: diff --git a/superset/databases/commands/validate.py b/superset/databases/commands/validate.py index fcbff1fed..5f6e1c772 100644 --- a/superset/databases/commands/validate.py +++ b/superset/databases/commands/validate.py @@ -126,7 +126,7 @@ class ValidateDatabaseParametersCommand(BaseCommand): "database": url.database, } errors = database.db_engine_spec.extract_errors(ex, context) - raise DatabaseTestConnectionFailedError(errors) + raise DatabaseTestConnectionFailedError(errors) from ex if not alive: raise DatabaseOfflineError( diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py index b0dfc2f9a..43ef975d4 100644 --- a/superset/databases/schemas.py +++ b/superset/databases/schemas.py @@ -142,7 +142,7 @@ def sqlalchemy_uri_validator(value: str) -> str: """ try: uri = make_url(value.strip()) - except (ArgumentError, AttributeError, ValueError): + except (ArgumentError, AttributeError, ValueError) as ex: raise ValidationError( [ _( @@ -150,12 +150,12 @@ def sqlalchemy_uri_validator(value: str) -> str: "driver://user:password@database-host/database-name" ) ] - ) + ) from ex if current_app.config.get("PREVENT_UNSAFE_DB_CONNECTIONS", True): try: check_sqlalchemy_uri(uri) except SupersetSecurityException as ex: - raise ValidationError([str(ex)]) + raise ValidationError([str(ex)]) from ex return value @@ -166,8 +166,8 @@ def server_cert_validator(value: str) -> str: if value: try: parse_ssl_cert(value) - except CertificateException: - raise ValidationError([_("Invalid certificate")]) + except CertificateException as ex: + raise ValidationError([_("Invalid certificate")]) from ex return value @@ -181,7 +181,7 @@ def encrypted_extra_validator(value: str) -> str: except json.JSONDecodeError as ex: raise ValidationError( [_("Field cannot be decoded by JSON. %(msg)s", msg=str(ex))] - ) + ) from ex return value @@ -196,7 +196,7 @@ def extra_validator(value: str) -> str: except json.JSONDecodeError as ex: raise ValidationError( [_("Field cannot be decoded by JSON. %(msg)s", msg=str(ex))] - ) + ) from ex else: metadata_signature = inspect.signature(MetaData) for key in extra_.get("metadata_params", {}): diff --git a/superset/datasets/columns/commands/delete.py b/superset/datasets/columns/commands/delete.py index 1076c0090..f5914af52 100644 --- a/superset/datasets/columns/commands/delete.py +++ b/superset/datasets/columns/commands/delete.py @@ -51,7 +51,7 @@ class DeleteDatasetColumnCommand(BaseCommand): return column except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise DatasetColumnDeleteFailedError() + raise DatasetColumnDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists @@ -61,5 +61,5 @@ class DeleteDatasetColumnCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DatasetColumnForbiddenError() + except SupersetSecurityException as ex: + raise DatasetColumnForbiddenError() from ex diff --git a/superset/datasets/commands/bulk_delete.py b/superset/datasets/commands/bulk_delete.py index 0ba6b4e76..13608eda8 100644 --- a/superset/datasets/commands/bulk_delete.py +++ b/superset/datasets/commands/bulk_delete.py @@ -74,7 +74,7 @@ class BulkDeleteDatasetCommand(BaseCommand): return None except DeleteFailedError as ex: logger.exception(ex.exception) - raise DatasetBulkDeleteFailedError() + raise DatasetBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists @@ -85,5 +85,5 @@ class BulkDeleteDatasetCommand(BaseCommand): for model in self._models: try: check_ownership(model) - except SupersetSecurityException: - raise DatasetForbiddenError() + except SupersetSecurityException as ex: + raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/create.py b/superset/datasets/commands/create.py index ca6bf8fae..0bf403ebf 100644 --- a/superset/datasets/commands/create.py +++ b/superset/datasets/commands/create.py @@ -62,7 +62,7 @@ class CreateDatasetCommand(CreateMixin, BaseCommand): except (SQLAlchemyError, DAOCreateFailedError) as ex: logger.warning(ex, exc_info=True) db.session.rollback() - raise DatasetCreateFailedError() + raise DatasetCreateFailedError() from ex return dataset def validate(self) -> None: diff --git a/superset/datasets/commands/delete.py b/superset/datasets/commands/delete.py index 028df423e..a9e5a0ab5 100644 --- a/superset/datasets/commands/delete.py +++ b/superset/datasets/commands/delete.py @@ -75,7 +75,7 @@ class DeleteDatasetCommand(BaseCommand): except (SQLAlchemyError, DAODeleteFailedError) as ex: logger.exception(ex) db.session.rollback() - raise DatasetDeleteFailedError() + raise DatasetDeleteFailedError() from ex return dataset def validate(self) -> None: @@ -86,5 +86,5 @@ class DeleteDatasetCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DatasetForbiddenError() + except SupersetSecurityException as ex: + raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/importers/v0.py b/superset/datasets/commands/importers/v0.py index a19e9ae05..1508298a2 100644 --- a/superset/datasets/commands/importers/v0.py +++ b/superset/datasets/commands/importers/v0.py @@ -322,9 +322,11 @@ class ImportDatasetsCommand(BaseCommand): for file_name, content in self.contents.items(): try: config = yaml.safe_load(content) - except yaml.parser.ParserError: + except yaml.parser.ParserError as ex: logger.exception("Invalid YAML file") - raise IncorrectVersionError(f"{file_name} is not a valid YAML file") + raise IncorrectVersionError( + f"{file_name} is not a valid YAML file" + ) from ex # CLI export if isinstance(config, dict): diff --git a/superset/datasets/commands/refresh.py b/superset/datasets/commands/refresh.py index 22869570b..962ffb410 100644 --- a/superset/datasets/commands/refresh.py +++ b/superset/datasets/commands/refresh.py @@ -48,7 +48,7 @@ class RefreshDatasetCommand(BaseCommand): return self._model except Exception as ex: logger.exception(ex) - raise DatasetRefreshFailedError() + raise DatasetRefreshFailedError() from ex raise DatasetRefreshFailedError() def validate(self) -> None: @@ -59,5 +59,5 @@ class RefreshDatasetCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DatasetForbiddenError() + except SupersetSecurityException as ex: + raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/update.py b/superset/datasets/commands/update.py index 1a8237686..c9bf8500c 100644 --- a/superset/datasets/commands/update.py +++ b/superset/datasets/commands/update.py @@ -72,7 +72,7 @@ class UpdateDatasetCommand(UpdateMixin, BaseCommand): return dataset except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise DatasetUpdateFailedError() + raise DatasetUpdateFailedError() from ex raise DatasetUpdateFailedError() def validate(self) -> None: @@ -85,8 +85,8 @@ class UpdateDatasetCommand(UpdateMixin, BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DatasetForbiddenError() + except SupersetSecurityException as ex: + raise DatasetForbiddenError() from ex database_id = self._properties.get("database", None) table_name = self._properties.get("table_name", None) diff --git a/superset/datasets/metrics/commands/delete.py b/superset/datasets/metrics/commands/delete.py index e6f68dc98..cb3f1e0be 100644 --- a/superset/datasets/metrics/commands/delete.py +++ b/superset/datasets/metrics/commands/delete.py @@ -51,7 +51,7 @@ class DeleteDatasetMetricCommand(BaseCommand): return column except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise DatasetMetricDeleteFailedError() + raise DatasetMetricDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists @@ -61,5 +61,5 @@ class DeleteDatasetMetricCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise DatasetMetricForbiddenError() + except SupersetSecurityException as ex: + raise DatasetMetricForbiddenError() from ex diff --git a/superset/db_engine_specs/bigquery.py b/superset/db_engine_specs/bigquery.py index 99dfdb738..734984499 100644 --- a/superset/db_engine_specs/bigquery.py +++ b/superset/db_engine_specs/bigquery.py @@ -327,12 +327,12 @@ class BigQueryEngineSpec(BaseEngineSpec): # pylint: disable=import-outside-toplevel import pandas_gbq from google.oauth2 import service_account - except ImportError: + except ImportError as ex: raise Exception( "Could not import libraries `pandas_gbq` or `google.oauth2`, which are " "required to be installed in your environment in order " "to upload data to BigQuery" - ) + ) from ex if not table.schema: raise Exception("The table schema must be defined") diff --git a/superset/db_engine_specs/druid.py b/superset/db_engine_specs/druid.py index ef699e43d..faccb0020 100644 --- a/superset/db_engine_specs/druid.py +++ b/superset/db_engine_specs/druid.py @@ -79,8 +79,8 @@ class DruidEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method """ try: extra = json.loads(database.extra or "{}") - except json.JSONDecodeError: - raise SupersetException("Unable to parse database extras") + except json.JSONDecodeError as ex: + raise SupersetException("Unable to parse database extras") from ex if database.server_cert: engine_params = extra.get("engine_params", {}) diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py index 31b2520b2..4d1936310 100644 --- a/superset/db_engine_specs/postgres.py +++ b/superset/db_engine_specs/postgres.py @@ -262,8 +262,8 @@ class PostgresEngineSpec(PostgresBaseEngineSpec, BasicParametersMixin): """ try: extra = json.loads(database.extra or "{}") - except json.JSONDecodeError: - raise SupersetException("Unable to parse database extras") + except json.JSONDecodeError as ex: + raise SupersetException("Unable to parse database extras") from ex if database.server_cert: engine_params = extra.get("engine_params", {}) diff --git a/superset/db_engines/hive.py b/superset/db_engines/hive.py index b5f5cad57..37fe50f5e 100644 --- a/superset/db_engines/hive.py +++ b/superset/db_engines/hive.py @@ -46,9 +46,9 @@ def fetch_logs( logs = self._connection.client.GetLog(req).log return logs # raised if Hive is used - except (ttypes.TApplicationException, Thrift.TApplicationException): + except (ttypes.TApplicationException, Thrift.TApplicationException) as ex: if self._state == self._STATE_NONE: - raise hive.ProgrammingError("No query yet") + raise hive.ProgrammingError("No query yet") from ex logs = [] while True: req = ttypes.TFetchResultsReq( diff --git a/superset/jinja_context.py b/superset/jinja_context.py index ff56fc9b2..907ba99a8 100644 --- a/superset/jinja_context.py +++ b/superset/jinja_context.py @@ -333,10 +333,10 @@ def safe_proxy(func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any: if value_type in COLLECTION_TYPES: try: return_value = json.loads(json.dumps(return_value)) - except TypeError: + except TypeError as ex: raise SupersetTemplateException( _("Unsupported return value for method %(name)s", name=func.__name__,) - ) + ) from ex return return_value @@ -357,10 +357,10 @@ def validate_context_types(context: Dict[str, Any]) -> Dict[str, Any]: if arg_type in COLLECTION_TYPES: try: context[key] = json.loads(json.dumps(context[key])) - except TypeError: + except TypeError as ex: raise SupersetTemplateException( _("Unsupported template value for key %(key)s", key=key) - ) + ) from ex return context diff --git a/superset/models/tags.py b/superset/models/tags.py index 86fc41122..528206e67 100644 --- a/superset/models/tags.py +++ b/superset/models/tags.py @@ -106,8 +106,8 @@ def get_object_type(class_name: str) -> ObjectTypes: } try: return mapping[class_name.lower()] - except KeyError: - raise Exception("No mapping found for {0}".format(class_name)) + except KeyError as ex: + raise Exception("No mapping found for {0}".format(class_name)) from ex class ObjectUpdater: diff --git a/superset/queries/saved_queries/commands/bulk_delete.py b/superset/queries/saved_queries/commands/bulk_delete.py index cf021442f..0d199378c 100644 --- a/superset/queries/saved_queries/commands/bulk_delete.py +++ b/superset/queries/saved_queries/commands/bulk_delete.py @@ -44,7 +44,7 @@ class BulkDeleteSavedQueryCommand(BaseCommand): return None except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise SavedQueryBulkDeleteFailedError() + raise SavedQueryBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists diff --git a/superset/queries/saved_queries/dao.py b/superset/queries/saved_queries/dao.py index cd20fe60d..48dc67d06 100644 --- a/superset/queries/saved_queries/dao.py +++ b/superset/queries/saved_queries/dao.py @@ -41,7 +41,7 @@ class SavedQueryDAO(BaseDAO): ) if commit: db.session.commit() - except SQLAlchemyError: + except SQLAlchemyError as ex: if commit: db.session.rollback() - raise DAODeleteFailedError() + raise DAODeleteFailedError() from ex diff --git a/superset/reports/commands/alert.py b/superset/reports/commands/alert.py index 5dd979705..a13916f59 100644 --- a/superset/reports/commands/alert.py +++ b/superset/reports/commands/alert.py @@ -79,8 +79,8 @@ class AlertCommand(BaseCommand): ] return OPERATOR_FUNCTIONS[operator](self._result, threshold) - except (KeyError, json.JSONDecodeError): - raise AlertValidatorConfigError() + except (KeyError, json.JSONDecodeError) as ex: + raise AlertValidatorConfigError() from ex def _validate_not_null(self, rows: np.recarray) -> None: self._validate_result(rows) @@ -115,8 +115,8 @@ class AlertCommand(BaseCommand): # Check if it's float or if we can convert it self._result = float(rows[0][1]) return - except (AssertionError, TypeError, ValueError): - raise AlertQueryInvalidTypeError() + except (AssertionError, TypeError, ValueError) as ex: + raise AlertQueryInvalidTypeError() from ex @property def _is_validator_not_null(self) -> bool: @@ -157,9 +157,9 @@ class AlertCommand(BaseCommand): return df except SoftTimeLimitExceeded as ex: logger.warning("A timeout occurred while executing the alert query: %s", ex) - raise AlertQueryTimeout() + raise AlertQueryTimeout() from ex except Exception as ex: - raise AlertQueryError(message=str(ex)) + raise AlertQueryError(message=str(ex)) from ex def validate(self) -> None: """ diff --git a/superset/reports/commands/bulk_delete.py b/superset/reports/commands/bulk_delete.py index aa4898e9e..4bff600d2 100644 --- a/superset/reports/commands/bulk_delete.py +++ b/superset/reports/commands/bulk_delete.py @@ -47,7 +47,7 @@ class BulkDeleteReportScheduleCommand(BaseCommand): return None except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise ReportScheduleBulkDeleteFailedError() + raise ReportScheduleBulkDeleteFailedError() from ex def validate(self) -> None: # Validate/populate model exists @@ -59,5 +59,5 @@ class BulkDeleteReportScheduleCommand(BaseCommand): for model in self._models: try: check_ownership(model) - except SupersetSecurityException: - raise ReportScheduleForbiddenError() + except SupersetSecurityException as ex: + raise ReportScheduleForbiddenError() from ex diff --git a/superset/reports/commands/create.py b/superset/reports/commands/create.py index 518a95e10..23ed27e89 100644 --- a/superset/reports/commands/create.py +++ b/superset/reports/commands/create.py @@ -51,7 +51,7 @@ class CreateReportScheduleCommand(CreateMixin, BaseReportScheduleCommand): report_schedule = ReportScheduleDAO.create(self._properties) except DAOCreateFailedError as ex: logger.exception(ex.exception) - raise ReportScheduleCreateFailedError() + raise ReportScheduleCreateFailedError() from ex return report_schedule def validate(self) -> None: diff --git a/superset/reports/commands/delete.py b/superset/reports/commands/delete.py index 8375f52c3..eef7a56af 100644 --- a/superset/reports/commands/delete.py +++ b/superset/reports/commands/delete.py @@ -47,7 +47,7 @@ class DeleteReportScheduleCommand(BaseCommand): report_schedule = ReportScheduleDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) - raise ReportScheduleDeleteFailedError() + raise ReportScheduleDeleteFailedError() from ex return report_schedule def validate(self) -> None: @@ -59,5 +59,5 @@ class DeleteReportScheduleCommand(BaseCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise ReportScheduleForbiddenError() + except SupersetSecurityException as ex: + raise ReportScheduleForbiddenError() from ex diff --git a/superset/reports/commands/execute.py b/superset/reports/commands/execute.py index aea2ff41c..065e38bc7 100644 --- a/superset/reports/commands/execute.py +++ b/superset/reports/commands/execute.py @@ -201,13 +201,13 @@ class BaseReportState: user = self._get_user() try: image_data = screenshot.get_screenshot(user=user) - except SoftTimeLimitExceeded: + except SoftTimeLimitExceeded as ex: logger.warning("A timeout occurred while taking a screenshot.") - raise ReportScheduleScreenshotTimeout() + raise ReportScheduleScreenshotTimeout() from ex except Exception as ex: raise ReportScheduleScreenshotFailedError( f"Failed taking a screenshot {str(ex)}" - ) + ) from ex if not image_data: raise ReportScheduleScreenshotFailedError() return image_data @@ -239,10 +239,12 @@ class BaseReportState: try: logger.info("Getting chart from %s", url) csv_data = get_chart_csv_data(url, auth_cookies) - except SoftTimeLimitExceeded: - raise ReportScheduleCsvTimeout() + except SoftTimeLimitExceeded as ex: + raise ReportScheduleCsvTimeout() from ex except Exception as ex: - raise ReportScheduleCsvFailedError(f"Failed generating csv {str(ex)}") + raise ReportScheduleCsvFailedError( + f"Failed generating csv {str(ex)}" + ) from ex if not csv_data: raise ReportScheduleCsvFailedError() return csv_data @@ -581,7 +583,7 @@ class AsyncExecuteReportScheduleCommand(BaseCommand): except CommandException as ex: raise ex except Exception as ex: - raise ReportScheduleUnexpectedError(str(ex)) + raise ReportScheduleUnexpectedError(str(ex)) from ex def validate( # pylint: disable=arguments-differ self, session: Session = None diff --git a/superset/reports/commands/update.py b/superset/reports/commands/update.py index 09809807f..c1dd41679 100644 --- a/superset/reports/commands/update.py +++ b/superset/reports/commands/update.py @@ -55,7 +55,7 @@ class UpdateReportScheduleCommand(UpdateMixin, BaseReportScheduleCommand): report_schedule = ReportScheduleDAO.update(self._model, self._properties) except DAOUpdateFailedError as ex: logger.exception(ex.exception) - raise ReportScheduleUpdateFailedError() + raise ReportScheduleUpdateFailedError() from ex return report_schedule def validate(self) -> None: @@ -110,8 +110,8 @@ class UpdateReportScheduleCommand(UpdateMixin, BaseReportScheduleCommand): # Check ownership try: check_ownership(self._model) - except SupersetSecurityException: - raise ReportScheduleForbiddenError() + except SupersetSecurityException as ex: + raise ReportScheduleForbiddenError() from ex # Validate/Populate owner if owner_ids is None: diff --git a/superset/reports/dao.py b/superset/reports/dao.py index 697b08c1f..ce69ba004 100644 --- a/superset/reports/dao.py +++ b/superset/reports/dao.py @@ -111,7 +111,7 @@ class ReportScheduleDAO(BaseDAO): except SQLAlchemyError as ex: if commit: db.session.rollback() - raise DAODeleteFailedError(str(ex)) + raise DAODeleteFailedError(str(ex)) from ex @staticmethod def validate_update_uniqueness( @@ -161,7 +161,7 @@ class ReportScheduleDAO(BaseDAO): return model except SQLAlchemyError as ex: db.session.rollback() - raise DAOCreateFailedError(str(ex)) + raise DAOCreateFailedError(str(ex)) from ex @classmethod def update( @@ -194,7 +194,7 @@ class ReportScheduleDAO(BaseDAO): return model except SQLAlchemyError as ex: db.session.rollback() - raise DAOCreateFailedError(str(ex)) + raise DAOCreateFailedError(str(ex)) from ex @staticmethod def find_active(session: Optional[Session] = None) -> List[ReportSchedule]: @@ -302,4 +302,4 @@ class ReportScheduleDAO(BaseDAO): except SQLAlchemyError as ex: if commit: session.rollback() - raise DAODeleteFailedError(str(ex)) + raise DAODeleteFailedError(str(ex)) from ex diff --git a/superset/reports/notifications/email.py b/superset/reports/notifications/email.py index 9a5ab29ae..a55824d4f 100644 --- a/superset/reports/notifications/email.py +++ b/superset/reports/notifications/email.py @@ -133,4 +133,4 @@ class EmailNotification(BaseNotification): # pylint: disable=too-few-public-met ) logger.info("Report sent to email") except Exception as ex: - raise NotificationError(ex) + raise NotificationError(ex) from ex diff --git a/superset/reports/notifications/slack.py b/superset/reports/notifications/slack.py index 6d04b0991..8d4078c92 100644 --- a/superset/reports/notifications/slack.py +++ b/superset/reports/notifications/slack.py @@ -152,4 +152,4 @@ Error: %(text)s client.chat_postMessage(channel=channel, text=body) logger.info("Report sent to slack") except SlackClientError as ex: - raise NotificationError(ex) + raise NotificationError(ex) from ex diff --git a/superset/sql_lab.py b/superset/sql_lab.py index d58124d73..d392e6c25 100644 --- a/superset/sql_lab.py +++ b/superset/sql_lab.py @@ -149,8 +149,8 @@ def get_query(query_id: int, session: Session) -> Query: """attempts to get the query and retry if it cannot""" try: return session.query(Query).filter_by(id=query_id).one() - except Exception: - raise SqlLabException("Failed at getting query") + except Exception as ex: + raise SqlLabException("Failed at getting query") from ex @celery_app.task( @@ -291,17 +291,17 @@ def execute_sql_statement( error_type=SupersetErrorType.SQLLAB_TIMEOUT_ERROR, level=ErrorLevel.ERROR, ) - ) + ) from ex except Exception as ex: # query is stopped in another thread/worker # stopping raises expected exceptions which we should skip session.refresh(query) if query.status == QueryStatus.STOPPED: - raise SqlLabQueryStoppedException() + raise SqlLabQueryStoppedException() from ex logger.error("Query %d: %s", query.id, type(ex), exc_info=True) logger.debug("Query %d: %s", query.id, ex) - raise SqlLabException(db_engine_spec.extract_error_message(ex)) + raise SqlLabException(db_engine_spec.extract_error_message(ex)) from ex logger.debug("Query %d: Fetching cursor description", query.id) cursor_description = cursor.description diff --git a/superset/utils/async_query_manager.py b/superset/utils/async_query_manager.py index 258024f7f..011564e82 100644 --- a/superset/utils/async_query_manager.py +++ b/superset/utils/async_query_manager.py @@ -165,9 +165,9 @@ class AsyncQueryManager: try: return self.parse_jwt(token) - except Exception as exc: - logger.warning(exc) - raise AsyncQueryTokenException("Failed to parse token") + except Exception as ex: + logger.warning(ex) + raise AsyncQueryTokenException("Failed to parse token") from ex def init_job(self, channel_id: str, user_id: Optional[str]) -> Dict[str, Any]: job_id = str(uuid.uuid4()) diff --git a/superset/utils/core.py b/superset/utils/core.py index 8e51afb9c..270d74094 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -765,7 +765,7 @@ def validate_json(obj: Union[bytes, bytearray, str]) -> None: json.loads(obj) except Exception as ex: logger.error("JSON is not valid %s", str(ex), exc_info=True) - raise SupersetException("JSON is not valid") + raise SupersetException("JSON is not valid") from ex class SigalrmTimeout: @@ -1424,8 +1424,8 @@ def parse_ssl_cert(certificate: str) -> _Certificate: return x509.load_pem_x509_certificate( certificate.encode("utf-8"), default_backend() ) - except ValueError: - raise CertificateException("Invalid certificate") + except ValueError as ex: + raise CertificateException("Invalid certificate") from ex def create_ssl_cert_file(certificate: str) -> str: diff --git a/superset/utils/date_parser.py b/superset/utils/date_parser.py index eaa7f7f98..3e742d56d 100644 --- a/superset/utils/date_parser.py +++ b/superset/utils/date_parser.py @@ -66,7 +66,7 @@ def parse_human_datetime(human_readable: str) -> datetime: # 0 == not parsed at all if parsed_flags == 0: logger.debug(ex) - raise TimeRangeParseFailError(human_readable) + raise TimeRangeParseFailError(human_readable) from ex # when time is not extracted, we 'reset to midnight' if parsed_flags & 2 == 0: parsed_dttm = parsed_dttm.replace(hour=0, minute=0, second=0) @@ -476,8 +476,8 @@ def datetime_eval(datetime_expression: Optional[str] = None) -> Optional[datetim if datetime_expression: try: return datetime_parser().parseString(datetime_expression)[0].eval() - except ParseException as error: - raise ValueError(error) + except ParseException as ex: + raise ValueError(ex) from ex return None diff --git a/superset/utils/pandas_postprocessing.py b/superset/utils/pandas_postprocessing.py index 1c27cf9c3..ad6c6afed 100644 --- a/superset/utils/pandas_postprocessing.py +++ b/superset/utils/pandas_postprocessing.py @@ -397,14 +397,14 @@ def rolling( # pylint: disable=too-many-arguments ) try: df_rolling = getattr(df_rolling, rolling_type)(**rolling_type_options) - except TypeError: + except TypeError as ex: raise QueryObjectValidationError( _( "Invalid options for %(rolling_type)s: %(options)s", rolling_type=rolling_type, options=rolling_type_options, ) - ) + ) from ex df = _append_columns(df, df_rolling, columns) if min_periods: df = df[min_periods:] @@ -569,8 +569,8 @@ def geohash_decode( return _append_columns( df, lonlat_df, {"latitude": latitude, "longitude": longitude} ) - except ValueError: - raise QueryObjectValidationError(_("Invalid geohash string")) + except ValueError as ex: + raise QueryObjectValidationError(_("Invalid geohash string")) from ex def geohash_encode( @@ -592,8 +592,8 @@ def geohash_encode( lambda row: geohash_lib.encode(row["latitude"], row["longitude"]), axis=1, ) return _append_columns(df, encode_df, {"geohash": geohash}) - except ValueError: - raise QueryObjectValidationError(_("Invalid longitude/latitude")) + except ValueError as ex: + raise QueryObjectValidationError(_("Invalid longitude/latitude")) from ex def geodetic_parse( @@ -634,8 +634,8 @@ def geodetic_parse( if altitude: columns["altitude"] = altitude return _append_columns(df, geodetic_df, columns) - except ValueError: - raise QueryObjectValidationError(_("Invalid geodetic string")) + except ValueError as ex: + raise QueryObjectValidationError(_("Invalid geodetic string")) from ex @validate_column_args("columns") @@ -720,8 +720,8 @@ def _prophet_fit_and_predict( # pylint: disable=too-many-arguments prophet_logger = logging.getLogger("prophet.plot") prophet_logger.setLevel(logging.CRITICAL) prophet_logger.setLevel(logging.NOTSET) - except ModuleNotFoundError: - raise QueryObjectValidationError(_("`prophet` package not installed")) + except ModuleNotFoundError as ex: + raise QueryObjectValidationError(_("`prophet` package not installed")) from ex model = Prophet( interval_width=confidence_interval, yearly_seasonality=yearly_seasonality, diff --git a/superset/utils/schema.py b/superset/utils/schema.py index 2384e2851..c082ae017 100644 --- a/superset/utils/schema.py +++ b/superset/utils/schema.py @@ -50,5 +50,5 @@ def validate_json(value: Union[bytes, bytearray, str]) -> None: """ try: utils.validate_json(value) - except SupersetException: - raise ValidationError("JSON not valid") + except SupersetException as ex: + raise ValidationError("JSON not valid") from ex diff --git a/superset/views/base.py b/superset/views/base.py index a636762c6..2de98b5e6 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -254,7 +254,7 @@ def validate_sqlatable(table: models.SqlaTable) -> None: "database connection, schema, and " "table name, error: {}" ).format(table.name, str(ex)) - ) + ) from ex def create_table_permissions(table: models.SqlaTable) -> None: @@ -501,7 +501,7 @@ def validate_json(form: Form, field: Field) -> None: # pylint: disable=unused-a json.loads(field.data) except Exception as ex: logger.exception(ex) - raise Exception(_("json isn't valid")) + raise Exception(_("json isn't valid")) from ex class YamlExportMixin: # pylint: disable=too-few-public-methods diff --git a/superset/views/base_schemas.py b/superset/views/base_schemas.py index 65c9a3567..de39e7102 100644 --- a/superset/views/base_schemas.py +++ b/superset/views/base_schemas.py @@ -31,8 +31,8 @@ def validate_owner(value: int) -> None: .filter_by(id=value) .one() ) - except NoResultFound: - raise ValidationError(f"User {value} does not exist") + except NoResultFound as ex: + raise ValidationError(f"User {value} does not exist") from ex class BaseSupersetSchema(Schema): diff --git a/superset/views/core.py b/superset/views/core.py index b46fa969a..cc03e8e92 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -2040,14 +2040,14 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods try: table_name = data["datasourceName"] database_id = data["dbId"] - except KeyError: + except KeyError as ex: raise SupersetGenericErrorException( __( "One or more required fields are missing in the request. Please try " "again, and if the problem persists conctact your administrator." ), status=400, - ) + ) from ex database = db.session.query(Database).get(database_id) if not database: raise SupersetErrorException( @@ -2480,7 +2480,7 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods query.error_message = message session.commit() - raise SupersetErrorException(error) + raise SupersetErrorException(error) from ex # Update saved query with execution info from the query execution QueryDAO.update_saved_query_exec_info(query_id) @@ -2549,7 +2549,9 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods raise ex except Exception as ex: # pylint: disable=broad-except logger.exception("Query %i failed unexpectedly", query.id) - raise SupersetGenericDBErrorException(utils.error_msg_from_exception(ex)) + raise SupersetGenericDBErrorException( + utils.error_msg_from_exception(ex) + ) from ex if data.get("status") == QueryStatus.FAILED: # new error payload with rich context diff --git a/superset/views/database/mixins.py b/superset/views/database/mixins.py index c415d68f3..2c1fb26df 100644 --- a/superset/views/database/mixins.py +++ b/superset/views/database/mixins.py @@ -242,7 +242,7 @@ class DatabaseMixin: except Exception as ex: raise Exception( _("Extra field cannot be decoded by JSON. %(msg)s", msg=str(ex)) - ) + ) from ex # this will check whether 'metadata_params' is configured correctly metadata_signature = inspect.signature(MetaData) @@ -266,4 +266,4 @@ class DatabaseMixin: except Exception as ex: raise Exception( _("Extra field cannot be decoded by JSON. %(msg)s", msg=str(ex)) - ) + ) from ex diff --git a/superset/views/database/validators.py b/superset/views/database/validators.py index a54b853b4..bd3b3335c 100644 --- a/superset/views/database/validators.py +++ b/superset/views/database/validators.py @@ -34,7 +34,7 @@ def sqlalchemy_uri_validator( """ try: make_url(uri.strip()) - except (ArgumentError, AttributeError): + except (ArgumentError, AttributeError) as ex: raise exception( [ _( @@ -45,7 +45,7 @@ def sqlalchemy_uri_validator( "

" ) ] - ) + ) from ex def schema_allows_csv_upload(database: Database, schema: Optional[str]) -> bool: diff --git a/superset/views/database/views.py b/superset/views/database/views.py index 0a0a50d81..d999853c1 100644 --- a/superset/views/database/views.py +++ b/superset/views/database/views.py @@ -65,7 +65,7 @@ def certificate_form_validator(_: _, field: StringField) -> None: try: utils.parse_ssl_cert(field.data) except CertificateException as ex: - raise ValidationError(ex.message) + raise ValidationError(ex.message) from ex def upload_stream_write(form_file_field: "FileStorage", path: str) -> None: diff --git a/superset/views/datasource/views.py b/superset/views/datasource/views.py index 448a68228..cc3d6d202 100644 --- a/superset/views/datasource/views.py +++ b/superset/views/datasource/views.py @@ -81,8 +81,8 @@ class Datasource(BaseSupersetView): if app.config["OLD_API_CHECK_DATASET_OWNERSHIP"]: try: check_ownership(orm_datasource) - except SupersetSecurityException: - raise DatasetForbiddenError() + except SupersetSecurityException as ex: + raise DatasetForbiddenError() from ex datasource_dict["owners"] = ( db.session.query(orm_datasource.owner_class) @@ -175,6 +175,6 @@ class Datasource(BaseSupersetView): table_name=params["table_name"], schema_name=params["schema_name"], ) - except (NoResultFound, NoSuchTableError): - raise DatasetNotFoundError + except (NoResultFound, NoSuchTableError) as ex: + raise DatasetNotFoundError() from ex return self.json_response(external_metadata) diff --git a/superset/views/schedules.py b/superset/views/schedules.py index 792414395..679973b8d 100644 --- a/superset/views/schedules.py +++ b/superset/views/schedules.py @@ -134,8 +134,8 @@ class EmailScheduleView( try: recipients = get_email_address_list(item.recipients) item.recipients = ", ".join(recipients) - except Exception: - raise SupersetException("Invalid email list") + except Exception as ex: + raise SupersetException("Invalid email list") from ex item.user = item.user or g.user if not croniter.is_valid(item.crontab): diff --git a/superset/views/utils.py b/superset/views/utils.py index 4d4bc17ab..6a61f66b0 100644 --- a/superset/views/utils.py +++ b/superset/views/utils.py @@ -521,7 +521,7 @@ def check_datasource_perms( level=ErrorLevel.ERROR, message=str(ex), ) - ) + ) from ex if datasource_type is None: raise SupersetSecurityException( @@ -539,14 +539,14 @@ def check_datasource_perms( form_data=form_data, force=False, ) - except NoResultFound: + except NoResultFound as ex: raise SupersetSecurityException( SupersetError( error_type=SupersetErrorType.UNKNOWN_DATASOURCE_TYPE_ERROR, level=ErrorLevel.ERROR, message=_("Could not find viz object"), ) - ) + ) from ex viz_obj.raise_for_access() @@ -572,14 +572,14 @@ def check_slice_perms(_self: Any, slice_id: int) -> None: form_data=form_data, force=False, ) - except NoResultFound: + except NoResultFound as ex: raise SupersetSecurityException( SupersetError( error_type=SupersetErrorType.UNKNOWN_DATASOURCE_TYPE_ERROR, level=ErrorLevel.ERROR, message="Could not find viz object", ) - ) + ) from ex viz_obj.raise_for_access() @@ -597,8 +597,8 @@ def _deserialize_results_payload( with stats_timing("sqllab.query.results_backend_pa_deserialize", stats_logger): try: pa_table = pa.deserialize(ds_payload["data"]) - except pa.ArrowSerializationError: - raise SerializationError("Unable to deserialize table") + except pa.ArrowSerializationError as ex: + raise SerializationError("Unable to deserialize table") from ex df = result_set.SupersetResultSet.convert_table_to_df(pa_table) ds_payload["data"] = dataframe.df_to_records(df) or []