From 07b2449bd777cf04a266f1de3d72af6874b9c305 Mon Sep 17 00:00:00 2001 From: Eyal Ezer Date: Tue, 28 May 2024 16:17:41 -0500 Subject: [PATCH] refactor: Unify all json.(loads|dumps) usage to utils.json (#28702) Co-authored-by: Eyal Ezer --- .pylintrc | 2 +- .../annotation_layers/annotations/schemas.py | 7 +- superset/async_events/async_query_manager.py | 2 +- superset/charts/api.py | 2 +- superset/charts/data/api.py | 11 ++- superset/commands/chart/export.py | 4 +- superset/commands/chart/importers/v1/utils.py | 4 +- superset/commands/chart/warm_up_cache.py | 2 +- superset/commands/dashboard/export.py | 6 +- superset/commands/dashboard/importers/v0.py | 2 +- .../commands/dashboard/importers/v1/utils.py | 2 +- superset/commands/dashboard/update.py | 2 +- superset/commands/database/export.py | 4 +- .../commands/database/importers/v1/utils.py | 2 +- superset/commands/database/validate.py | 4 +- superset/commands/dataset/export.py | 8 +- superset/commands/dataset/importers/v0.py | 2 +- .../commands/dataset/importers/v1/utils.py | 2 +- superset/commands/explore/get.py | 3 +- superset/commands/query/export.py | 4 +- superset/commands/report/alert.py | 2 +- superset/commands/report/create.py | 2 +- superset/commands/report/execute.py | 2 +- superset/commands/report/update.py | 2 +- superset/common/query_object.py | 3 +- superset/connectors/sqla/models.py | 6 +- superset/daos/dashboard.py | 2 +- superset/daos/report.py | 2 +- superset/dashboards/api.py | 2 +- superset/dashboards/schemas.py | 10 +-- superset/databases/api.py | 2 +- superset/databases/schemas.py | 4 +- superset/datasets/api.py | 2 +- superset/datasets/schemas.py | 2 +- superset/db_engine_specs/base.py | 3 +- superset/db_engine_specs/bigquery.py | 3 +- superset/db_engine_specs/databricks.py | 2 +- superset/db_engine_specs/druid.py | 3 +- superset/db_engine_specs/gsheets.py | 2 +- superset/db_engine_specs/postgres.py | 3 +- superset/db_engine_specs/presto.py | 3 +- superset/db_engine_specs/snowflake.py | 2 +- superset/db_engine_specs/trino.py | 3 +- superset/embedded/view.py | 6 +- superset/examples/bart_lines.py | 2 +- superset/examples/birth_names.py | 2 +- superset/examples/deck.py | 2 +- superset/examples/helpers.py | 2 +- superset/examples/misc_dashboard.py | 2 +- superset/examples/paris.py | 2 +- superset/examples/sf_population_polygons.py | 2 +- .../examples/supported_charts_dashboard.py | 2 +- superset/examples/tabbed_dashboard.py | 2 +- superset/examples/world_bank.py | 3 +- superset/extensions/pylint.py | 60 +++++++++++++ superset/forms.py | 3 +- superset/importexport/api.py | 2 +- superset/jinja_context.py | 2 +- .../migrations/shared/migrate_viz/base.py | 2 +- superset/migrations/shared/native_filters.py | 2 +- superset/migrations/shared/utils.py | 5 +- ...31_db0c65b146bd_update_slice_model_json.py | 3 +- ...a_rewriting_url_from_shortner_with_new_.py | 2 +- ...8-19_67a6ac9b727b_update_spatial_params.py | 3 +- ...11-06_21e88bc06c02_annotation_migration.py | 3 +- ...8-02-13_08-07_e866bd2d4976_smaller_grid.py | 3 +- ...06ae5eb46_cal_heatmap_metric_to_metrics.py | 3 +- ...6-04_11-12_c5756bec8b47_time_grain_sqla.py | 3 +- ...09-52_afb7730f6a9c_remove_empty_filters.py | 3 +- ...-20_4451805bbaa1_remove_double_percents.py | 3 +- ...-06-13_14-54_bddc498dd179_adhoc_filters.py | 3 +- ...31_80a67c5192fa_single_pie_chart_metric.py | 3 +- ..._migrate_num_period_compare_and_period_.py | 2 +- ...f3fed1fe_convert_dashboard_v1_positions.py | 2 +- .../2018-08-01_11-47_7fcdcde0761c_.py | 2 +- ..._migrate_time_range_for_default_filters.py | 3 +- ...12-11_22-03_fb13d49b72f9_better_filters.py | 2 +- ...bc82_add_parent_ids_in_dashboard_layout.py | 2 +- .../2019-06-28_13-17_ab8c66efdd01_resample.py | 2 +- ...019-10-10_13-52_1495eb914ad3_time_range.py | 2 +- ...d1d_reconvert_legacy_filters_into_adhoc.py | 2 +- ...3_3325d4caccc8_dashboard_scoped_filters.py | 2 +- ..._f9a30386bd74_cleanup_time_grainularity.py | 3 +- ...-24_620241d1153f_update_time_grain_sqla.py | 3 +- ...5563a02_migrate_iframe_to_dash_markdown.py | 2 +- ...0de1855_add_uuid_column_to_import_mixin.py | 6 +- ...649a77_migrate_x_dateunit_in_time_range.py | 2 +- ...add_granularity_to_charts_where_missing.py | 3 +- ...2-32_41ce8799acc3_rename_pie_label_type.py | 3 +- ...c1e5a7b_legacy_force_directed_to_echart.py | 3 +- ...e479899_rename_filter_configuration_in_.py | 3 +- ...5e7_remove_dataset_health_check_message.py | 2 +- ..._country_map_use_lowercase_country_name.py | 3 +- ...ff221_migrate_filter_sets_to_new_format.py | 2 +- ...95_migrate_native_filters_to_new_schema.py | 2 +- ...370a_fix_schemas_allowed_for_csv_upload.py | 4 +- ...migrate_pivot_table_v2_heatmaps_to_new_.py | 3 +- ...add_type_to_native_filter_configuration.py | 2 +- ...e2e_migrate_timeseries_limit_metric_to_.py | 3 +- ...-15_32646df09c64_update_time_grain_sqla.py | 3 +- ...acd_rename_to_schemas_allowed_for_file_.py | 6 +- ...1_rename_big_viz_total_form_data_fields.py | 2 +- ...move_pivot_table_v2_legacy_order_by_to_.py | 2 +- ...944_change_adhoc_filter_b_from_none_to_.py | 3 +- ..._a9422eeaae74_new_dataset_models_take_2.py | 6 +- ...074e4_deprecate_time_range_endpoints_v2.py | 3 +- ...dbaba_rm_time_range_endpoints_from_qc_3.py | 5 +- ...fix_table_chart_conditional_formatting_.py | 3 +- ...1d9b25135_remove_filter_bar_orientation.py | 3 +- ...c0a3ea245b61_remove_show_native_filters.py | 3 +- ...b5b83_invert_horizontal_bar_chart_order.py | 3 +- ...24_b5ea9d343307_bar_chart_stack_options.py | 3 +- ..._12-30_7e67aecbf3f1_chart_ds_constraint.py | 2 +- ...1ddfd_convert_key_value_entries_to_json.py | 2 +- ...ea966691069_cross_filter_global_scoping.py | 2 +- ...e_obsolete_druid_nosql_slice_parameters.py | 2 +- ...280_cleanup_erroneous_parent_filter_ids.py | 2 +- ...54_ee179a490af9_deckgl_path_width_units.py | 2 +- ...e8_add_percent_calculation_type_funnel_.py | 3 +- ...1b217cd8cd_big_number_kpi_single_metric.py | 3 +- ..._update_charts_with_old_time_comparison.py | 2 +- superset/models/core.py | 7 +- superset/models/dashboard.py | 5 +- superset/models/helpers.py | 6 +- superset/models/slice.py | 5 +- superset/models/sql_lab.py | 2 +- superset/queries/saved_queries/api.py | 2 +- superset/reports/notifications/email.py | 2 +- superset/reports/notifications/slack.py | 2 +- superset/result_set.py | 5 +- superset/security/manager.py | 2 +- superset/sql_lab.py | 10 +-- superset/sqllab/api.py | 10 +-- .../sqllab/execution_context_convertor.py | 10 +-- superset/sqllab/sqllab_execution_context.py | 3 +- superset/tasks/cache.py | 2 +- superset/utils/csv.py | 4 +- .../dashboard_filter_scopes_converter.py | 2 +- superset/utils/hashing.py | 2 +- superset/utils/json.py | 65 +++++++++++--- superset/utils/lock.py | 2 +- superset/utils/log.py | 2 +- superset/utils/mock_data.py | 2 +- superset/utils/schema.py | 7 +- superset/views/api.py | 7 +- superset/views/base.py | 26 +++--- superset/views/chart/views.py | 6 +- superset/views/core.py | 19 ++-- superset/views/dashboard/views.py | 6 +- superset/views/datasource/views.py | 2 +- superset/views/key_value.py | 3 +- superset/views/sql_lab/views.py | 5 +- superset/views/sqllab.py | 2 +- superset/views/tags.py | 6 +- superset/views/utils.py | 2 +- superset/viz.py | 11 ++- .../advanced_data_type/api_tests.py | 2 +- .../annotation_layers/api_tests.py | 3 +- .../async_events/api_tests.py | 2 +- .../available_domains/api_tests.py | 3 +- tests/integration_tests/base_api_tests.py | 2 +- tests/integration_tests/base_tests.py | 2 +- tests/integration_tests/cache_tests.py | 3 +- tests/integration_tests/charts/api_tests.py | 2 +- .../charts/commands_tests.py | 2 +- .../charts/data/api_tests.py | 2 +- tests/integration_tests/commands_test.py | 2 +- tests/integration_tests/core_tests.py | 7 +- .../css_templates/api_tests.py | 2 +- tests/integration_tests/dashboard_utils.py | 2 +- .../integration_tests/dashboards/api_tests.py | 2 +- .../dashboards/commands_tests.py | 2 +- .../integration_tests/dashboards/dao_tests.py | 2 +- .../dashboards/filter_state/api_tests.py | 2 +- .../security/security_dataset_tests.py | 3 +- .../security/security_rbac_tests.py | 2 +- .../integration_tests/databases/api_tests.py | 10 +-- .../databases/commands/upload_test.py | 3 +- tests/integration_tests/datasets/api_tests.py | 2 +- .../integration_tests/datasource/api_tests.py | 2 +- tests/integration_tests/datasource_tests.py | 2 +- .../dict_import_export_tests.py | 2 +- tests/integration_tests/explore/api_tests.py | 2 +- .../explore/form_data/api_tests.py | 2 +- .../explore/form_data/commands_tests.py | 2 +- .../explore/permalink/api_tests.py | 2 +- .../fixtures/tabbed_dashboard.py | 2 +- .../fixtures/world_bank_dashboard.py | 2 +- .../integration_tests/import_export_tests.py | 2 +- .../key_value/commands/create_test.py | 2 +- .../key_value/commands/delete_test.py | 2 +- .../key_value/commands/fixtures.py | 2 +- .../key_value/commands/get_test.py | 2 +- .../key_value/commands/update_test.py | 2 +- .../key_value/commands/upsert_test.py | 2 +- tests/integration_tests/log_api_tests.py | 2 +- ...7e67aecbf3f1_chart_ds_constraint__tests.py | 3 +- ...rm_time_range_endpoints_from_qc_3__test.py | 3 +- ...78868b6_migrating_legacy_treemap__tests.py | 2 +- .../fb13d49b72f9_better_filters__tests.py | 3 +- tests/integration_tests/model_tests.py | 2 +- tests/integration_tests/queries/api_tests.py | 2 +- .../queries/saved_queries/api_tests.py | 2 +- tests/integration_tests/reports/api_tests.py | 2 +- .../reports/commands_tests.py | 2 +- tests/integration_tests/reports/utils.py | 2 +- tests/integration_tests/security/api_tests.py | 3 +- .../security/guest_token_security_tests.py | 2 +- .../security/row_level_security_tests.py | 2 +- tests/integration_tests/security_tests.py | 2 +- tests/integration_tests/sql_lab/api_tests.py | 3 +- tests/integration_tests/sqllab_tests.py | 2 +- tests/integration_tests/tags/api_tests.py | 2 +- tests/integration_tests/thumbnails_tests.py | 2 +- tests/integration_tests/users/api_tests.py | 3 +- tests/integration_tests/utils/__init__.py | 3 +- tests/integration_tests/utils_tests.py | 79 ++++++++--------- .../commands/importers/v1/utils_test.py | 3 +- tests/unit_tests/databases/api_test.py | 2 +- .../commands/importers/v1/import_test.py | 2 +- .../datasets/commands/export_test.py | 3 +- .../commands/importers/v1/import_test.py | 2 +- .../db_engine_specs/test_bigquery.py | 2 +- .../db_engine_specs/test_databricks.py | 2 +- .../unit_tests/db_engine_specs/test_duckdb.py | 2 +- .../db_engine_specs/test_gsheets.py | 2 +- .../db_engine_specs/test_snowflake.py | 2 +- .../unit_tests/db_engine_specs/test_trino.py | 2 +- tests/unit_tests/importexport/api_test.py | 2 +- tests/unit_tests/jinja_context_test.py | 2 +- tests/unit_tests/migrations/viz/utils.py | 2 +- tests/unit_tests/models/core_test.py | 2 +- tests/unit_tests/queries/dao_test.py | 2 +- tests/unit_tests/utils/json_tests.py | 86 +++++++++++++------ 234 files changed, 530 insertions(+), 480 deletions(-) create mode 100644 superset/extensions/pylint.py diff --git a/.pylintrc b/.pylintrc index 5f51e9fcff..e11376fc10 100644 --- a/.pylintrc +++ b/.pylintrc @@ -36,7 +36,7 @@ persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins= +load-plugins=superset.extensions.pylint # Use multiple processes to speed up Pylint. jobs=2 diff --git a/superset/annotation_layers/annotations/schemas.py b/superset/annotation_layers/annotations/schemas.py index 516241b9e3..6ca96a4a74 100644 --- a/superset/annotation_layers/annotations/schemas.py +++ b/superset/annotation_layers/annotations/schemas.py @@ -19,8 +19,7 @@ from typing import Union from marshmallow import fields, Schema, ValidationError from marshmallow.validate import Length -from superset.exceptions import SupersetException -from superset.utils import json as json_utils +from superset.utils import json openapi_spec_methods_override = { "get": {"get": {"summary": "Get an annotation layer"}}, @@ -51,8 +50,8 @@ annotation_json_metadata = "JSON metadata" def validate_json(value: Union[bytes, bytearray, str]) -> None: try: - json_utils.validate_json(value) - except SupersetException as ex: + json.validate_json(value) + except json.JSONDecodeError as ex: raise ValidationError("JSON not valid") from ex diff --git a/superset/async_events/async_query_manager.py b/superset/async_events/async_query_manager.py index 1007176e81..84b20d753c 100644 --- a/superset/async_events/async_query_manager.py +++ b/superset/async_events/async_query_manager.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging import uuid from typing import Any, Literal, Optional @@ -23,6 +22,7 @@ import jwt import redis from flask import Flask, Request, request, Response, session +from superset.utils import json from superset.utils.core import get_user_id logger = logging.getLogger(__name__) diff --git a/superset/charts/api.py b/superset/charts/api.py index 4034c8ef27..d32f1f665a 100644 --- a/superset/charts/api.py +++ b/superset/charts/api.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=too-many-lines -import json import logging from datetime import datetime from io import BytesIO @@ -81,6 +80,7 @@ from superset.extensions import event_logger from superset.models.slice import Slice from superset.tasks.thumbnails import cache_chart_thumbnail from superset.tasks.utils import get_current_user +from superset.utils import json from superset.utils.screenshots import ChartScreenshot, DEFAULT_CHART_WINDOW_SIZE from superset.utils.urls import get_url_path from superset.views.base_api import ( diff --git a/superset/charts/data/api.py b/superset/charts/data/api.py index e902d5738a..932a666738 100644 --- a/superset/charts/data/api.py +++ b/superset/charts/data/api.py @@ -17,7 +17,6 @@ from __future__ import annotations import contextlib -import json import logging from typing import Any, TYPE_CHECKING @@ -46,7 +45,7 @@ from superset.daos.exceptions import DatasourceNotFound from superset.exceptions import QueryObjectValidationError from superset.extensions import event_logger from superset.models.sql_lab import Query -from superset.utils import json as json_utils +from superset.utils import json from superset.utils.core import ( create_zip, DatasourceType, @@ -129,7 +128,7 @@ class ChartDataRestApi(ChartRestApi): try: json_body = json.loads(chart.query_context) - except (TypeError, json.decoder.JSONDecodeError): + except (TypeError, json.JSONDecodeError): json_body = None if json_body is None: @@ -171,7 +170,7 @@ class ChartDataRestApi(ChartRestApi): try: form_data = json.loads(chart.params) - except (TypeError, json.decoder.JSONDecodeError): + except (TypeError, json.JSONDecodeError): form_data = {} return self._get_data_response( @@ -395,9 +394,9 @@ class ChartDataRestApi(ChartRestApi): ) if result_format == ChartDataResultFormat.JSON: - response_data = json_utils.dumps( + response_data = json.dumps( {"result": result["queries"]}, - default=json_utils.json_int_dttm_ser, + default=json.json_int_dttm_ser, ignore_nan=True, ) resp = make_response(response_data, 200) diff --git a/superset/commands/chart/export.py b/superset/commands/chart/export.py index dc24a14540..a84dfcca14 100644 --- a/superset/commands/chart/export.py +++ b/superset/commands/chart/export.py @@ -16,7 +16,6 @@ # under the License. # isort:skip_file -import json import logging from collections.abc import Iterator from typing import Callable @@ -30,6 +29,7 @@ from superset.commands.export.models import ExportModelsCommand from superset.models.slice import Slice from superset.utils.dict_import_export import EXPORT_VERSION from superset.utils.file import get_filename +from superset.utils import json logger = logging.getLogger(__name__) @@ -64,7 +64,7 @@ class ExportChartsCommand(ExportModelsCommand): if payload.get("params"): try: payload["params"] = json.loads(payload["params"]) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: logger.info("Unable to decode `params` field: %s", payload["params"]) payload["version"] = EXPORT_VERSION diff --git a/superset/commands/chart/importers/v1/utils.py b/superset/commands/chart/importers/v1/utils.py index f1b38e7ddc..39ca49a5d5 100644 --- a/superset/commands/chart/importers/v1/utils.py +++ b/superset/commands/chart/importers/v1/utils.py @@ -16,7 +16,6 @@ # under the License. import copy -import json from inspect import isclass from typing import Any @@ -25,6 +24,7 @@ from superset.commands.exceptions import ImportFailedError from superset.migrations.shared.migrate_viz import processors from superset.migrations.shared.migrate_viz.base import MigrateViz from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import AnnotationType, get_user @@ -117,7 +117,7 @@ def migrate_chart(config: dict[str, Any]) -> dict[str, Any]: # also update `query_context` try: query_context = json.loads(output.get("query_context") or "{}") - except (json.decoder.JSONDecodeError, TypeError): + except (json.JSONDecodeError, TypeError): query_context = {} if "form_data" in query_context: query_context["form_data"] = output["params"] diff --git a/superset/commands/chart/warm_up_cache.py b/superset/commands/chart/warm_up_cache.py index 2e5c0ac3a3..ea794c2842 100644 --- a/superset/commands/chart/warm_up_cache.py +++ b/superset/commands/chart/warm_up_cache.py @@ -18,7 +18,6 @@ from typing import Any, Optional, Union -import simplejson as json from flask import g from superset.commands.base import BaseCommand @@ -29,6 +28,7 @@ from superset.commands.chart.exceptions import ( ) from superset.extensions import db from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import error_msg_from_exception from superset.views.utils import get_dashboard_extra_filters, get_form_data, get_viz from superset.viz import viz_types diff --git a/superset/commands/dashboard/export.py b/superset/commands/dashboard/export.py index d6f7369643..fe3a6b8eab 100644 --- a/superset/commands/dashboard/export.py +++ b/superset/commands/dashboard/export.py @@ -16,7 +16,6 @@ # under the License. # isort:skip_file -import json import logging import random import string @@ -36,6 +35,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.utils.dict_import_export import EXPORT_VERSION from superset.utils.file import get_filename +from superset.utils import json logger = logging.getLogger(__name__) @@ -126,7 +126,7 @@ class ExportDashboardsCommand(ExportModelsCommand): if value: try: payload[new_name] = json.loads(value) - except (TypeError, json.decoder.JSONDecodeError): + except (TypeError, json.JSONDecodeError): logger.info("Unable to decode `%s` field: %s", key, value) payload[new_name] = {} @@ -176,7 +176,7 @@ class ExportDashboardsCommand(ExportModelsCommand): if value: try: payload[new_name] = json.loads(value) - except (TypeError, json.decoder.JSONDecodeError): + except (TypeError, json.JSONDecodeError): logger.info("Unable to decode `%s` field: %s", key, value) payload[new_name] = {} diff --git a/superset/commands/dashboard/importers/v0.py b/superset/commands/dashboard/importers/v0.py index 48dcb230ef..a9ee3e484e 100644 --- a/superset/commands/dashboard/importers/v0.py +++ b/superset/commands/dashboard/importers/v0.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging import time from copy import copy @@ -32,6 +31,7 @@ from superset.exceptions import DashboardImportException from superset.migrations.shared.native_filters import migrate_dashboard from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from superset.utils.dashboard_filter_scopes_converter import ( convert_filter_scopes, copy_filter_scopes, diff --git a/superset/commands/dashboard/importers/v1/utils.py b/superset/commands/dashboard/importers/v1/utils.py index 09be75a6ea..f10afd12bc 100644 --- a/superset/commands/dashboard/importers/v1/utils.py +++ b/superset/commands/dashboard/importers/v1/utils.py @@ -15,13 +15,13 @@ # specific language governing permissions and limitations # under the License. -import json import logging from typing import Any from superset import db, security_manager from superset.commands.exceptions import ImportFailedError from superset.models.dashboard import Dashboard +from superset.utils import json from superset.utils.core import get_user logger = logging.getLogger(__name__) diff --git a/superset/commands/dashboard/update.py b/superset/commands/dashboard/update.py index d35fb6b28e..890422602d 100644 --- a/superset/commands/dashboard/update.py +++ b/superset/commands/dashboard/update.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from typing import Any, Optional @@ -37,6 +36,7 @@ from superset.exceptions import SupersetSecurityException from superset.extensions import db from superset.models.dashboard import Dashboard from superset.tags.models import ObjectType +from superset.utils import json logger = logging.getLogger(__name__) diff --git a/superset/commands/database/export.py b/superset/commands/database/export.py index fefe86adce..97333a80aa 100644 --- a/superset/commands/database/export.py +++ b/superset/commands/database/export.py @@ -16,7 +16,6 @@ # under the License. # isort:skip_file import functools -import json import logging from typing import Any, Callable from collections.abc import Iterator @@ -30,6 +29,7 @@ from superset.models.core import Database from superset.utils.dict_import_export import EXPORT_VERSION from superset.utils.file import get_filename from superset.utils.ssh_tunnel import mask_password_info +from superset.utils import json logger = logging.getLogger(__name__) @@ -37,7 +37,7 @@ logger = logging.getLogger(__name__) def parse_extra(extra_payload: str) -> dict[str, Any]: try: extra = json.loads(extra_payload) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: logger.info("Unable to decode `extra` field: %s", extra_payload) return {} diff --git a/superset/commands/database/importers/v1/utils.py b/superset/commands/database/importers/v1/utils.py index 17b8488b44..56d31b03e1 100644 --- a/superset/commands/database/importers/v1/utils.py +++ b/superset/commands/database/importers/v1/utils.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. -import json from typing import Any from superset import app, db, security_manager @@ -25,6 +24,7 @@ from superset.databases.utils import make_url_safe from superset.exceptions import SupersetSecurityException from superset.models.core import Database from superset.security.analytics_db_safety import check_sqlalchemy_uri +from superset.utils import json def import_database( diff --git a/superset/commands/database/validate.py b/superset/commands/database/validate.py index e550f51d70..65df1ed1e1 100644 --- a/superset/commands/database/validate.py +++ b/superset/commands/database/validate.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from contextlib import closing from typing import Any, Optional @@ -33,6 +32,7 @@ from superset.db_engine_specs import get_engine_spec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.extensions import event_logger from superset.models.core import Database +from superset.utils import json BYPASS_VALIDATION_ENGINES = {"bigquery"} @@ -82,7 +82,7 @@ class ValidateDatabaseParametersCommand(BaseCommand): ) try: encrypted_extra = json.loads(serialized_encrypted_extra) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: encrypted_extra = {} # try to connect diff --git a/superset/commands/dataset/export.py b/superset/commands/dataset/export.py index 9646bffc67..70cce0291a 100644 --- a/superset/commands/dataset/export.py +++ b/superset/commands/dataset/export.py @@ -16,7 +16,6 @@ # under the License. # isort:skip_file -import json import logging from collections.abc import Iterator from typing import Callable @@ -31,6 +30,7 @@ from superset.daos.dataset import DatasetDAO from superset.utils.dict_import_export import EXPORT_VERSION from superset.utils.file import get_filename from superset.utils.ssh_tunnel import mask_password_info +from superset.utils import json logger = logging.getLogger(__name__) @@ -63,14 +63,14 @@ class ExportDatasetsCommand(ExportModelsCommand): if payload.get(key): try: payload[key] = json.loads(payload[key]) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: logger.info("Unable to decode `%s` field: %s", key, payload[key]) for key in ("metrics", "columns"): for attributes in payload.get(key, []): if attributes.get("extra"): try: attributes["extra"] = json.loads(attributes["extra"]) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: logger.info( "Unable to decode `extra` field: %s", attributes["extra"] ) @@ -108,7 +108,7 @@ class ExportDatasetsCommand(ExportModelsCommand): if payload.get("extra"): try: payload["extra"] = json.loads(payload["extra"]) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: logger.info("Unable to decode `extra` field: %s", payload["extra"]) if ssh_tunnel := DatabaseDAO.get_ssh_tunnel(model.database.id): diff --git a/superset/commands/dataset/importers/v0.py b/superset/commands/dataset/importers/v0.py index 6c1d79779e..14be54174a 100644 --- a/superset/commands/dataset/importers/v0.py +++ b/superset/commands/dataset/importers/v0.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from typing import Any, Callable, Optional @@ -34,6 +33,7 @@ from superset.connectors.sqla.models import ( TableColumn, ) from superset.models.core import Database +from superset.utils import json from superset.utils.dict_import_export import DATABASES_KEY logger = logging.getLogger(__name__) diff --git a/superset/commands/dataset/importers/v1/utils.py b/superset/commands/dataset/importers/v1/utils.py index 0d2226f724..da39be4721 100644 --- a/superset/commands/dataset/importers/v1/utils.py +++ b/superset/commands/dataset/importers/v1/utils.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. import gzip -import json import logging import re from typing import Any @@ -33,6 +32,7 @@ from superset.commands.exceptions import ImportFailedError from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.sql_parse import Table +from superset.utils import json from superset.utils.core import get_user logger = logging.getLogger(__name__) diff --git a/superset/commands/explore/get.py b/superset/commands/explore/get.py index d0d71c1eec..535ed8ee32 100644 --- a/superset/commands/explore/get.py +++ b/superset/commands/explore/get.py @@ -19,7 +19,6 @@ import logging from abc import ABC from typing import Any, cast, Optional -import simplejson as json from flask import request from flask_babel import lazy_gettext as _ from sqlalchemy.exc import SQLAlchemyError @@ -38,7 +37,7 @@ from superset.exceptions import SupersetException from superset.explore.exceptions import WrongEndpointError from superset.explore.permalink.exceptions import ExplorePermalinkGetFailedError from superset.extensions import security_manager -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.views.utils import ( get_datasource_info, get_form_data, diff --git a/superset/commands/query/export.py b/superset/commands/query/export.py index db3379ab81..e63cde5f28 100644 --- a/superset/commands/query/export.py +++ b/superset/commands/query/export.py @@ -16,7 +16,6 @@ # under the License. # isort:skip_file -import json import logging from collections.abc import Iterator from typing import Callable @@ -29,6 +28,7 @@ from superset.models.sql_lab import SavedQuery from superset.commands.query.exceptions import SavedQueryNotFoundError from superset.daos.query import SavedQueryDAO from superset.utils.dict_import_export import EXPORT_VERSION +from superset.utils import json logger = logging.getLogger(__name__) @@ -90,7 +90,7 @@ class ExportSavedQueriesCommand(ExportModelsCommand): if "extra" in payload: try: payload["extra"] = json.loads(payload["extra"]) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: logger.info("Unable to decode `extra` field: %s", payload["extra"]) payload["version"] = EXPORT_VERSION diff --git a/superset/commands/report/alert.py b/superset/commands/report/alert.py index 0e5d5401f7..30861bddaa 100644 --- a/superset/commands/report/alert.py +++ b/superset/commands/report/alert.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import logging from operator import eq, ge, gt, le, lt, ne from timeit import default_timer @@ -39,6 +38,7 @@ from superset.commands.report.exceptions import ( ) from superset.reports.models import ReportSchedule, ReportScheduleValidatorType from superset.tasks.utils import get_executor +from superset.utils import json from superset.utils.core import override_user from superset.utils.retries import retry_call diff --git a/superset/commands/report/create.py b/superset/commands/report/create.py index e73da467d1..ed1889e8b3 100644 --- a/superset/commands/report/create.py +++ b/superset/commands/report/create.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from typing import Any, Optional @@ -40,6 +39,7 @@ from superset.reports.models import ( ReportScheduleType, ) from superset.reports.types import ReportScheduleExtra +from superset.utils import json logger = logging.getLogger(__name__) diff --git a/superset/commands/report/execute.py b/superset/commands/report/execute.py index d521ac161f..1540fa70d8 100644 --- a/superset/commands/report/execute.py +++ b/superset/commands/report/execute.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from datetime import datetime, timedelta from typing import Any, Optional, Union @@ -67,6 +66,7 @@ from superset.reports.notifications import create_notification from superset.reports.notifications.base import NotificationContent from superset.reports.notifications.exceptions import NotificationError from superset.tasks.utils import get_executor +from superset.utils import json from superset.utils.core import HeaderDataType, override_user from superset.utils.csv import get_chart_csv_data, get_chart_dataframe from superset.utils.decorators import logs_context diff --git a/superset/commands/report/update.py b/superset/commands/report/update.py index f5ff0ca158..ad54f44f06 100644 --- a/superset/commands/report/update.py +++ b/superset/commands/report/update.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from typing import Any, Optional @@ -37,6 +36,7 @@ from superset.daos.exceptions import DAOUpdateFailedError from superset.daos.report import ReportScheduleDAO from superset.exceptions import SupersetSecurityException from superset.reports.models import ReportSchedule, ReportScheduleType, ReportState +from superset.utils import json logger = logging.getLogger(__name__) diff --git a/superset/common/query_object.py b/superset/common/query_object.py index 35b1d2974f..209e6f0029 100644 --- a/superset/common/query_object.py +++ b/superset/common/query_object.py @@ -17,7 +17,6 @@ # pylint: disable=invalid-name from __future__ import annotations -import json import logging from datetime import datetime from pprint import pformat @@ -36,7 +35,7 @@ from superset.exceptions import ( ) from superset.sql_parse import sanitize_clause from superset.superset_typing import Column, Metric, OrderBy -from superset.utils import pandas_postprocessing +from superset.utils import json, pandas_postprocessing from superset.utils.core import ( DTTM_ALIAS, find_duplicates, diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 8c74dfd589..a566079b0f 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -19,14 +19,12 @@ from __future__ import annotations import builtins import dataclasses -import json import logging import re from collections import defaultdict from collections.abc import Hashable from dataclasses import dataclass, field from datetime import datetime, timedelta -from json.decoder import JSONDecodeError from typing import Any, Callable, cast import dateutil.parser @@ -118,7 +116,7 @@ from superset.superset_typing import ( QueryObjectDict, ResultSetColumnType, ) -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.backports import StrEnum from superset.utils.core import GenericDataType, MediumText @@ -1051,7 +1049,7 @@ class SqlMetric(AuditMixinNullable, ImportExportMixin, CertificationMixin, Model def currency_json(self) -> dict[str, str | None] | None: try: return json.loads(self.currency or "{}") or None - except (TypeError, JSONDecodeError) as exc: + except (TypeError, json.JSONDecodeError) as exc: logger.error( "Unable to load currency json: %r. Leaving empty.", exc, exc_info=True ) diff --git a/superset/daos/dashboard.py b/superset/daos/dashboard.py index eef46362e2..55288a11a8 100644 --- a/superset/daos/dashboard.py +++ b/superset/daos/dashboard.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import logging from datetime import datetime from typing import Any @@ -38,6 +37,7 @@ from superset.models.core import FavStar, FavStarClassName from superset.models.dashboard import Dashboard, id_or_slug_filter from superset.models.embedded_dashboard import EmbeddedDashboard from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import get_user_id from superset.utils.dashboard_filter_scopes_converter import copy_filter_scopes diff --git a/superset/daos/report.py b/superset/daos/report.py index b5db391ec4..4662f32587 100644 --- a/superset/daos/report.py +++ b/superset/daos/report.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import logging from datetime import datetime from typing import Any @@ -34,6 +33,7 @@ from superset.reports.models import ( ReportScheduleType, ReportState, ) +from superset.utils import json from superset.utils.core import get_user_id logger = logging.getLogger(__name__) diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index ff6f5f5f48..5d3616361f 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -16,7 +16,6 @@ # under the License. # pylint: disable=too-many-lines import functools -import json import logging from datetime import datetime from io import BytesIO @@ -84,6 +83,7 @@ from superset.models.dashboard import Dashboard from superset.models.embedded_dashboard import EmbeddedDashboard from superset.tasks.thumbnails import cache_dashboard_thumbnail from superset.tasks.utils import get_current_user +from superset.utils import json from superset.utils.screenshots import DashboardScreenshot from superset.utils.urls import get_url_path from superset.views.base_api import ( diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py index 60eb50918e..33fafcb1d5 100644 --- a/superset/dashboards/schemas.py +++ b/superset/dashboards/schemas.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import re from typing import Any, Union @@ -22,9 +21,8 @@ from marshmallow import fields, post_dump, post_load, pre_load, Schema from marshmallow.validate import Length, ValidationError from superset import security_manager -from superset.exceptions import SupersetException from superset.tags.models import TagType -from superset.utils import json as json_utils +from superset.utils import json get_delete_ids_schema = {"type": "array", "items": {"type": "integer"}} get_export_ids_schema = {"type": "array", "items": {"type": "integer"}} @@ -89,8 +87,8 @@ openapi_spec_methods_override = { def validate_json(value: Union[bytes, bytearray, str]) -> None: try: - json_utils.validate_json(value) - except SupersetException as ex: + json.validate_json(value) + except json.JSONDecodeError as ex: raise ValidationError("JSON not valid") from ex @@ -99,7 +97,7 @@ def validate_json_metadata(value: Union[bytes, bytearray, str]) -> None: return try: value_obj = json.loads(value) - except json.decoder.JSONDecodeError as ex: + except json.JSONDecodeError as ex: raise ValidationError("JSON not valid") from ex errors = DashboardJSONMetadataSchema().validate(value_obj, partial=False) if errors: diff --git a/superset/databases/api.py b/superset/databases/api.py index 31db3ceacc..2c0aff8da0 100644 --- a/superset/databases/api.py +++ b/superset/databases/api.py @@ -18,7 +18,6 @@ from __future__ import annotations -import json import logging from datetime import datetime, timedelta from io import BytesIO @@ -120,6 +119,7 @@ from superset.extensions import security_manager from superset.models.core import Database from superset.sql_parse import Table from superset.superset_typing import FlaskResponse +from superset.utils import json from superset.utils.core import error_msg_from_exception, parse_js_uri_path_item from superset.utils.oauth2 import decode_oauth2_state from superset.utils.ssh_tunnel import mask_password_info diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py index e6f6eaa12e..7dbaf0243a 100644 --- a/superset/databases/schemas.py +++ b/superset/databases/schemas.py @@ -20,7 +20,6 @@ from __future__ import annotations import inspect -import json import os from pathlib import Path from typing import Any, TypedDict @@ -53,6 +52,7 @@ from superset.db_engine_specs import get_engine_spec from superset.exceptions import CertificateException, SupersetSecurityException from superset.models.core import ConfigurationMethod, Database from superset.security.analytics_db_safety import check_sqlalchemy_uri +from superset.utils import json from superset.utils.core import markdown, parse_ssl_cert database_schemas_query_schema = { @@ -349,7 +349,7 @@ class DatabaseParametersSchemaMixin: # pylint: disable=too-few-public-methods serialized_encrypted_extra = data.get("masked_encrypted_extra") or "{}" try: encrypted_extra = json.loads(serialized_encrypted_extra) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: encrypted_extra = {} data["sqlalchemy_uri"] = engine_spec.build_sqlalchemy_uri( diff --git a/superset/datasets/api.py b/superset/datasets/api.py index 0b793392d7..0f14be1a6d 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=too-many-lines -import json import logging from datetime import datetime from io import BytesIO @@ -66,6 +65,7 @@ from superset.datasets.schemas import ( GetOrCreateDatasetSchema, openapi_spec_methods_override, ) +from superset.utils import json from superset.utils.core import parse_boolean_string from superset.views.base import DatasourceFilter from superset.views.base_api import ( diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py index 5ce0621675..54b433d377 100644 --- a/superset/datasets/schemas.py +++ b/superset/datasets/schemas.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from datetime import datetime from typing import Any @@ -26,6 +25,7 @@ from marshmallow_sqlalchemy import SQLAlchemyAutoSchema from superset.datasets.models import Dataset from superset.exceptions import SupersetMarshmallowValidationError +from superset.utils import json get_delete_ids_schema = {"type": "array", "items": {"type": "integer"}} get_export_ids_schema = {"type": "array", "items": {"type": "integer"}} diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index fafea897f1..6df0dc61aa 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -18,7 +18,6 @@ from __future__ import annotations -import json import logging import re import warnings @@ -72,7 +71,7 @@ from superset.superset_typing import ( ResultSetColumnType, SQLAColumnType, ) -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.core import ColumnSpec, GenericDataType from superset.utils.hashing import md5_sha_from_str from superset.utils.network import is_hostname_valid, is_port_open diff --git a/superset/db_engine_specs/bigquery.py b/superset/db_engine_specs/bigquery.py index 4fff5ab3d7..7693e48da2 100644 --- a/superset/db_engine_specs/bigquery.py +++ b/superset/db_engine_specs/bigquery.py @@ -18,7 +18,6 @@ from __future__ import annotations import contextlib -import json import re import urllib from datetime import datetime @@ -48,7 +47,7 @@ from superset.errors import SupersetError, SupersetErrorType from superset.exceptions import SupersetException from superset.sql_parse import Table from superset.superset_typing import ResultSetColumnType -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.hashing import md5_sha_from_str try: diff --git a/superset/db_engine_specs/databricks.py b/superset/db_engine_specs/databricks.py index 3f72931626..d487f682ae 100644 --- a/superset/db_engine_specs/databricks.py +++ b/superset/db_engine_specs/databricks.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json from datetime import datetime from typing import Any, TYPE_CHECKING, TypedDict, Union @@ -33,6 +32,7 @@ from superset.databases.utils import make_url_safe from superset.db_engine_specs.base import BaseEngineSpec, BasicParametersMixin from superset.db_engine_specs.hive import HiveEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.utils import json from superset.utils.network import is_hostname_valid, is_port_open if TYPE_CHECKING: diff --git a/superset/db_engine_specs/druid.py b/superset/db_engine_specs/druid.py index 7cd85ec924..9dc366aa5b 100644 --- a/superset/db_engine_specs/druid.py +++ b/superset/db_engine_specs/druid.py @@ -17,7 +17,6 @@ from __future__ import annotations -import json import logging from datetime import datetime from typing import Any, TYPE_CHECKING @@ -29,7 +28,7 @@ from superset.constants import TimeGrain from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.exceptions import SupersetDBAPIConnectionError from superset.exceptions import SupersetException -from superset.utils import core as utils +from superset.utils import core as utils, json if TYPE_CHECKING: from superset.connectors.sqla.models import TableColumn diff --git a/superset/db_engine_specs/gsheets.py b/superset/db_engine_specs/gsheets.py index 7606e93b50..e876aca8de 100644 --- a/superset/db_engine_specs/gsheets.py +++ b/superset/db_engine_specs/gsheets.py @@ -18,7 +18,6 @@ from __future__ import annotations import contextlib -import json import logging import re from re import Pattern @@ -43,6 +42,7 @@ from superset.databases.schemas import encrypted_field_properties, EncryptedStri from superset.db_engine_specs.shillelagh import ShillelaghEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetException +from superset.utils import json if TYPE_CHECKING: from superset.models.core import Database diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py index bba2157e0a..015d5c52f2 100644 --- a/superset/db_engine_specs/postgres.py +++ b/superset/db_engine_specs/postgres.py @@ -17,7 +17,6 @@ from __future__ import annotations -import json import logging import re from datetime import datetime @@ -37,7 +36,7 @@ from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetException, SupersetSecurityException from superset.models.sql_lab import Query from superset.sql_parse import SQLScript -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.core import GenericDataType if TYPE_CHECKING: diff --git a/superset/db_engine_specs/presto.py b/superset/db_engine_specs/presto.py index 4f3b82af60..5e0b433e1e 100644 --- a/superset/db_engine_specs/presto.py +++ b/superset/db_engine_specs/presto.py @@ -30,7 +30,6 @@ from typing import Any, cast, Optional, TYPE_CHECKING from urllib import parse import pandas as pd -import simplejson as json from flask import current_app from flask_babel import gettext as __, lazy_gettext as _ from packaging.version import Version @@ -60,7 +59,7 @@ from superset.models.sql_types.presto_sql_types import ( ) from superset.result_set import destringify from superset.superset_typing import ResultSetColumnType -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.core import GenericDataType if TYPE_CHECKING: diff --git a/superset/db_engine_specs/snowflake.py b/superset/db_engine_specs/snowflake.py index 137cc4e00e..3d394385ee 100644 --- a/superset/db_engine_specs/snowflake.py +++ b/superset/db_engine_specs/snowflake.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging import re from datetime import datetime @@ -39,6 +38,7 @@ from superset.db_engine_specs.base import BaseEngineSpec, BasicPropertiesType from superset.db_engine_specs.postgres import PostgresBaseEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.models.sql_lab import Query +from superset.utils import json if TYPE_CHECKING: from superset.models.core import Database diff --git a/superset/db_engine_specs/trino.py b/superset/db_engine_specs/trino.py index 08a38894e6..eea00877d9 100644 --- a/superset/db_engine_specs/trino.py +++ b/superset/db_engine_specs/trino.py @@ -22,7 +22,6 @@ import threading import time from typing import Any, TYPE_CHECKING -import simplejson as json from flask import current_app from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.url import URL @@ -42,7 +41,7 @@ from superset.db_engine_specs.presto import PrestoBaseEngineSpec from superset.models.sql_lab import Query from superset.sql_parse import Table from superset.superset_typing import ResultSetColumnType -from superset.utils import core as utils +from superset.utils import core as utils, json if TYPE_CHECKING: from superset.models.core import Database diff --git a/superset/embedded/view.py b/superset/embedded/view.py index a260e33b5e..05490726f3 100644 --- a/superset/embedded/view.py +++ b/superset/embedded/view.py @@ -24,7 +24,7 @@ from flask_wtf.csrf import same_origin from superset import event_logger, is_feature_enabled from superset.daos.dashboard import EmbeddedDashboardDAO from superset.superset_typing import FlaskResponse -from superset.utils import json as json_utils +from superset.utils import json from superset.views.base import BaseSupersetView, common_bootstrap_payload @@ -86,7 +86,7 @@ class EmbeddedView(BaseSupersetView): return self.render_template( "superset/spa.html", entry="embedded", - bootstrap_data=json_utils.dumps( - bootstrap_data, default=json_utils.pessimistic_json_iso_dttm_ser + bootstrap_data=json.dumps( + bootstrap_data, default=json.pessimistic_json_iso_dttm_ser ), ) diff --git a/superset/examples/bart_lines.py b/superset/examples/bart_lines.py index efbb830201..8b3b315226 100644 --- a/superset/examples/bart_lines.py +++ b/superset/examples/bart_lines.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import pandas as pd import polyline @@ -22,6 +21,7 @@ from sqlalchemy import inspect, String, Text from superset import db from superset.sql_parse import Table +from superset.utils import json from ..utils.database import get_example_database from .helpers import get_example_url, get_table_connector_registry diff --git a/superset/examples/birth_names.py b/superset/examples/birth_names.py index 7b7928c532..229734057c 100644 --- a/superset/examples/birth_names.py +++ b/superset/examples/birth_names.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import textwrap from typing import Union @@ -28,6 +27,7 @@ from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.sql_parse import Table +from superset.utils import json from superset.utils.core import DatasourceType from ..utils.database import get_example_database diff --git a/superset/examples/deck.py b/superset/examples/deck.py index 326977054e..b0cb65b03f 100644 --- a/superset/examples/deck.py +++ b/superset/examples/deck.py @@ -14,11 +14,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from superset import db from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import DatasourceType from .helpers import ( diff --git a/superset/examples/helpers.py b/superset/examples/helpers.py index 76310b4046..b865e2dfca 100644 --- a/superset/examples/helpers.py +++ b/superset/examples/helpers.py @@ -16,13 +16,13 @@ # under the License. """Loads datasets, dashboards and slices in a new superset instance""" -import json import os from typing import Any from superset import app, db from superset.connectors.sqla.models import SqlaTable from superset.models.slice import Slice +from superset.utils import json BASE_URL = "https://github.com/apache-superset/examples-data/blob/master/" diff --git a/superset/examples/misc_dashboard.py b/superset/examples/misc_dashboard.py index aa8d037495..825dc6352c 100644 --- a/superset/examples/misc_dashboard.py +++ b/superset/examples/misc_dashboard.py @@ -14,11 +14,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import textwrap from superset import db from superset.models.dashboard import Dashboard +from superset.utils import json from .helpers import update_slice_ids diff --git a/superset/examples/paris.py b/superset/examples/paris.py index 1cd6c84d92..990aa01ca6 100644 --- a/superset/examples/paris.py +++ b/superset/examples/paris.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import pandas as pd from sqlalchemy import inspect, String, Text @@ -22,6 +21,7 @@ from sqlalchemy import inspect, String, Text import superset.utils.database as database_utils from superset import db from superset.sql_parse import Table +from superset.utils import json from .helpers import get_example_url, get_table_connector_registry diff --git a/superset/examples/sf_population_polygons.py b/superset/examples/sf_population_polygons.py index d4754887c7..4fa59db721 100644 --- a/superset/examples/sf_population_polygons.py +++ b/superset/examples/sf_population_polygons.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import pandas as pd from sqlalchemy import BigInteger, Float, inspect, Text @@ -22,6 +21,7 @@ from sqlalchemy import BigInteger, Float, inspect, Text import superset.utils.database as database_utils from superset import db from superset.sql_parse import Table +from superset.utils import json from .helpers import get_example_url, get_table_connector_registry diff --git a/superset/examples/supported_charts_dashboard.py b/superset/examples/supported_charts_dashboard.py index ae0962fc17..49141eb73c 100644 --- a/superset/examples/supported_charts_dashboard.py +++ b/superset/examples/supported_charts_dashboard.py @@ -17,7 +17,6 @@ # pylint: disable=too-many-lines -import json import textwrap from sqlalchemy import inspect @@ -27,6 +26,7 @@ from superset.connectors.sqla.models import SqlaTable from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.sql_parse import Table +from superset.utils import json from superset.utils.core import DatasourceType from ..utils.database import get_example_database diff --git a/superset/examples/tabbed_dashboard.py b/superset/examples/tabbed_dashboard.py index cc735ec4ec..bbc11e7730 100644 --- a/superset/examples/tabbed_dashboard.py +++ b/superset/examples/tabbed_dashboard.py @@ -16,11 +16,11 @@ # under the License. """Loads datasets, dashboards and slices in a new superset instance""" -import json import textwrap from superset import db from superset.models.dashboard import Dashboard +from superset.utils import json from .helpers import update_slice_ids diff --git a/superset/examples/world_bank.py b/superset/examples/world_bank.py index 7b6b374921..afbb6a994a 100644 --- a/superset/examples/world_bank.py +++ b/superset/examples/world_bank.py @@ -16,7 +16,6 @@ # under the License. """Loads datasets, dashboards and slices in a new superset instance""" -import json import os import pandas as pd @@ -38,7 +37,7 @@ from superset.examples.helpers import ( from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.sql_parse import Table -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.core import DatasourceType diff --git a/superset/extensions/pylint.py b/superset/extensions/pylint.py new file mode 100644 index 0000000000..1cf9821f44 --- /dev/null +++ b/superset/extensions/pylint.py @@ -0,0 +1,60 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import os + +from astroid import nodes +from pylint.checkers import BaseChecker +from pylint.lint import PyLinter + + +class JSONLibraryImportChecker(BaseChecker): + name = "json-library-import-checker" + priority = -1 + msgs = { + "C9999": ( + "Disallowed json import used, use superset.utils.json instead", + "disallowed-import", + "Used when a disallowed import is used in a specific file.", + ), + } + exclude_files = [ + "setup.py", + "superset/utils/json.py", + "superset/config.py", + "superset/cli/update.py", + "superset/key_value/types.py", + "superset/translations/utils.py", + "superset/extensions/__init__.py", + ] + path_strip_prefix = os.getcwd() + os.sep + + def visit_import(self, node: nodes.Import) -> None: + file = (node.root().file).replace(self.path_strip_prefix, "", 1) + if file not in self.exclude_files: + for module_name, _ in node.names: + if module_name in ["json", "simplejson"]: + self.add_message("disallowed-import", node=node) + + def visit_importfrom(self, node: nodes.ImportFrom) -> None: + file = (node.root().file).replace(self.path_strip_prefix, "", 1) + if file not in self.exclude_files: + if node.modname in ["json", "simplejson"]: + self.add_message("disallowed-import", node=node) + + +def register(linter: PyLinter) -> None: + linter.register_checker(JSONLibraryImportChecker(linter)) diff --git a/superset/forms.py b/superset/forms.py index a808da74b2..59f2826953 100644 --- a/superset/forms.py +++ b/superset/forms.py @@ -16,12 +16,13 @@ # under the License. """Contains the logic to create cohesive forms on the explore view""" -import json from typing import Any, Optional from flask_appbuilder.fieldwidgets import BS3TextFieldWidget from wtforms import Field +from superset.utils import json + class JsonListField(Field): widget = BS3TextFieldWidget() diff --git a/superset/importexport/api.py b/superset/importexport/api.py index fe170d2593..0d3906b1a1 100644 --- a/superset/importexport/api.py +++ b/superset/importexport/api.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from datetime import datetime from io import BytesIO from zipfile import is_zipfile, ZipFile @@ -30,6 +29,7 @@ from superset.commands.importers.exceptions import ( from superset.commands.importers.v1.assets import ImportAssetsCommand from superset.commands.importers.v1.utils import get_contents_from_bundle from superset.extensions import event_logger +from superset.utils import json from superset.views.base_api import BaseSupersetApi, requires_form_data, statsd_metrics diff --git a/superset/jinja_context.py b/superset/jinja_context.py index 4a036d7696..8d59eade15 100644 --- a/superset/jinja_context.py +++ b/superset/jinja_context.py @@ -16,7 +16,6 @@ # under the License. """Defines the templating context for SQL Lab""" -import json import re from datetime import datetime from functools import lru_cache, partial @@ -35,6 +34,7 @@ from superset.commands.dataset.exceptions import DatasetNotFoundError from superset.constants import LRU_CACHE_MAX_SIZE from superset.exceptions import SupersetTemplateException from superset.extensions import feature_flag_manager +from superset.utils import json from superset.utils.core import ( convert_legacy_filters_into_adhoc, get_user_email, diff --git a/superset/migrations/shared/migrate_viz/base.py b/superset/migrations/shared/migrate_viz/base.py index 83d27cdd4b..1be0391659 100644 --- a/superset/migrations/shared/migrate_viz/base.py +++ b/superset/migrations/shared/migrate_viz/base.py @@ -17,7 +17,6 @@ from __future__ import annotations import copy -import json from typing import Any from sqlalchemy import and_, Column, Integer, String, Text @@ -27,6 +26,7 @@ from sqlalchemy.orm import Session from superset import conf from superset.constants import TimeGrain from superset.migrations.shared.utils import paginated_update, try_load_json +from superset.utils import json Base = declarative_base() diff --git a/superset/migrations/shared/native_filters.py b/superset/migrations/shared/native_filters.py index 05b9f4033f..6e04928fab 100644 --- a/superset/migrations/shared/native_filters.py +++ b/superset/migrations/shared/native_filters.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from collections import defaultdict from textwrap import dedent from typing import Any @@ -23,6 +22,7 @@ from shortid import ShortId from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from superset.utils.dashboard_filter_scopes_converter import convert_filter_scopes diff --git a/superset/migrations/shared/utils.py b/superset/migrations/shared/utils.py index 208d839bc1..17e5b4128e 100644 --- a/superset/migrations/shared/utils.py +++ b/superset/migrations/shared/utils.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging import os import time @@ -29,6 +28,8 @@ from sqlalchemy.dialects.postgresql.base import PGDialect from sqlalchemy.exc import NoSuchTableError from sqlalchemy.orm import Query, Session +from superset.utils import json + logger = logging.getLogger(__name__) DEFAULT_BATCH_SIZE = int(os.environ.get("BATCH_SIZE", 1000)) @@ -164,6 +165,6 @@ def paginated_update( def try_load_json(data: Optional[str]) -> dict[str, Any]: try: return data and json.loads(data) or {} - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: print(f"Failed to parse: {data}") return {} diff --git a/superset/migrations/versions/2017-01-24_12-31_db0c65b146bd_update_slice_model_json.py b/superset/migrations/versions/2017-01-24_12-31_db0c65b146bd_update_slice_model_json.py index 4eff93991c..6de97648fa 100644 --- a/superset/migrations/versions/2017-01-24_12-31_db0c65b146bd_update_slice_model_json.py +++ b/superset/migrations/versions/2017-01-24_12-31_db0c65b146bd_update_slice_model_json.py @@ -26,13 +26,12 @@ Create Date: 2017-01-24 12:31:06.541746 revision = "db0c65b146bd" down_revision = "f18570e03440" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py b/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py index 5df9a62739..00182f5eeb 100644 --- a/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py +++ b/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py @@ -26,7 +26,6 @@ Create Date: 2017-02-08 14:16:34.948793 revision = "a99f2f7c195a" down_revision = "db0c65b146bd" -import json # noqa: E402 from urllib import parse # noqa: E402 import sqlalchemy as sa # noqa: E402 @@ -34,6 +33,7 @@ from alembic import op # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2017-12-08_08-19_67a6ac9b727b_update_spatial_params.py b/superset/migrations/versions/2017-12-08_08-19_67a6ac9b727b_update_spatial_params.py index df5c115372..ec2fc2009e 100644 --- a/superset/migrations/versions/2017-12-08_08-19_67a6ac9b727b_update_spatial_params.py +++ b/superset/migrations/versions/2017-12-08_08-19_67a6ac9b727b_update_spatial_params.py @@ -22,13 +22,12 @@ Create Date: 2017-12-08 08:19:21.148775 """ -import json - from alembic import op from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "67a6ac9b727b" diff --git a/superset/migrations/versions/2017-12-17_11-06_21e88bc06c02_annotation_migration.py b/superset/migrations/versions/2017-12-17_11-06_21e88bc06c02_annotation_migration.py index 9c28d6cc23..7cf379c468 100644 --- a/superset/migrations/versions/2017-12-17_11-06_21e88bc06c02_annotation_migration.py +++ b/superset/migrations/versions/2017-12-17_11-06_21e88bc06c02_annotation_migration.py @@ -22,13 +22,12 @@ Create Date: 2017-12-17 11:06:30.180267 """ -import json - from alembic import op from sqlalchemy import Column, Integer, or_, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "21e88bc06c02" diff --git a/superset/migrations/versions/2018-02-13_08-07_e866bd2d4976_smaller_grid.py b/superset/migrations/versions/2018-02-13_08-07_e866bd2d4976_smaller_grid.py index 3a4a7634eb..e97bfea639 100644 --- a/superset/migrations/versions/2018-02-13_08-07_e866bd2d4976_smaller_grid.py +++ b/superset/migrations/versions/2018-02-13_08-07_e866bd2d4976_smaller_grid.py @@ -21,13 +21,12 @@ Revises: 21e88bc06c02 Create Date: 2018-02-13 08:07:40.766277 """ -import json - import sqlalchemy as sa from alembic import op from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json revision = "e866bd2d4976" down_revision = "21e88bc06c02" diff --git a/superset/migrations/versions/2018-04-10_11-19_bf706ae5eb46_cal_heatmap_metric_to_metrics.py b/superset/migrations/versions/2018-04-10_11-19_bf706ae5eb46_cal_heatmap_metric_to_metrics.py index 9c660b651a..30cb7e4bb2 100644 --- a/superset/migrations/versions/2018-04-10_11-19_bf706ae5eb46_cal_heatmap_metric_to_metrics.py +++ b/superset/migrations/versions/2018-04-10_11-19_bf706ae5eb46_cal_heatmap_metric_to_metrics.py @@ -22,13 +22,12 @@ Create Date: 2018-04-10 11:19:47.621878 """ -import json - from alembic import op from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json Base = declarative_base() diff --git a/superset/migrations/versions/2018-06-04_11-12_c5756bec8b47_time_grain_sqla.py b/superset/migrations/versions/2018-06-04_11-12_c5756bec8b47_time_grain_sqla.py index b0f00e219a..36ad22526d 100644 --- a/superset/migrations/versions/2018-06-04_11-12_c5756bec8b47_time_grain_sqla.py +++ b/superset/migrations/versions/2018-06-04_11-12_c5756bec8b47_time_grain_sqla.py @@ -26,13 +26,12 @@ Create Date: 2018-06-04 11:12:59.878742 revision = "c5756bec8b47" down_revision = "e502db2af7be" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2018-06-07_09-52_afb7730f6a9c_remove_empty_filters.py b/superset/migrations/versions/2018-06-07_09-52_afb7730f6a9c_remove_empty_filters.py index ab11a2cf6c..c9ea7b9b34 100644 --- a/superset/migrations/versions/2018-06-07_09-52_afb7730f6a9c_remove_empty_filters.py +++ b/superset/migrations/versions/2018-06-07_09-52_afb7730f6a9c_remove_empty_filters.py @@ -26,13 +26,12 @@ Create Date: 2018-06-07 09:52:54.535961 revision = "afb7730f6a9c" down_revision = "c5756bec8b47" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2018-06-13_10-20_4451805bbaa1_remove_double_percents.py b/superset/migrations/versions/2018-06-13_10-20_4451805bbaa1_remove_double_percents.py index 7f51ac06a5..1786ae37e6 100644 --- a/superset/migrations/versions/2018-06-13_10-20_4451805bbaa1_remove_double_percents.py +++ b/superset/migrations/versions/2018-06-13_10-20_4451805bbaa1_remove_double_percents.py @@ -27,8 +27,6 @@ revision = "4451805bbaa1" down_revision = "bddc498dd179" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import ( # noqa: E402 Column, @@ -41,6 +39,7 @@ from sqlalchemy import ( # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2018-06-13_14-54_bddc498dd179_adhoc_filters.py b/superset/migrations/versions/2018-06-13_14-54_bddc498dd179_adhoc_filters.py index e3b891d29c..8ebcc104e8 100644 --- a/superset/migrations/versions/2018-06-13_14-54_bddc498dd179_adhoc_filters.py +++ b/superset/migrations/versions/2018-06-13_14-54_bddc498dd179_adhoc_filters.py @@ -27,13 +27,12 @@ revision = "bddc498dd179" down_revision = "80a67c5192fa" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 from superset.utils.core import ( # noqa: E402 convert_legacy_filters_into_adhoc, split_adhoc_filters_into_base_filters, diff --git a/superset/migrations/versions/2018-06-14_14-31_80a67c5192fa_single_pie_chart_metric.py b/superset/migrations/versions/2018-06-14_14-31_80a67c5192fa_single_pie_chart_metric.py index d25a37cbac..302dda2a51 100644 --- a/superset/migrations/versions/2018-06-14_14-31_80a67c5192fa_single_pie_chart_metric.py +++ b/superset/migrations/versions/2018-06-14_14-31_80a67c5192fa_single_pie_chart_metric.py @@ -27,13 +27,12 @@ revision = "80a67c5192fa" down_revision = "afb7730f6a9c" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py b/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py index 79fbce331f..685c45c631 100644 --- a/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py +++ b/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py @@ -25,7 +25,6 @@ Create Date: 2018-07-05 15:19:14.609299 # revision identifiers, used by Alembic. import datetime -import json import isodate from alembic import op @@ -33,6 +32,7 @@ from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json from superset.utils.date_parser import parse_human_timedelta revision = "3dda56f1c4c6" diff --git a/superset/migrations/versions/2018-07-22_11-59_bebcf3fed1fe_convert_dashboard_v1_positions.py b/superset/migrations/versions/2018-07-22_11-59_bebcf3fed1fe_convert_dashboard_v1_positions.py index f5af630a89..b57f4f3e9f 100644 --- a/superset/migrations/versions/2018-07-22_11-59_bebcf3fed1fe_convert_dashboard_v1_positions.py +++ b/superset/migrations/versions/2018-07-22_11-59_bebcf3fed1fe_convert_dashboard_v1_positions.py @@ -24,7 +24,6 @@ Create Date: 2018-07-22 11:59:07.025119 # revision identifiers, used by Alembic. import collections -import json import sys import uuid from functools import reduce @@ -35,6 +34,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from superset import db +from superset.utils import json revision = "bebcf3fed1fe" down_revision = "fc480c87706c" diff --git a/superset/migrations/versions/2018-08-01_11-47_7fcdcde0761c_.py b/superset/migrations/versions/2018-08-01_11-47_7fcdcde0761c_.py index 111cea4506..6f5220197d 100644 --- a/superset/migrations/versions/2018-08-01_11-47_7fcdcde0761c_.py +++ b/superset/migrations/versions/2018-08-01_11-47_7fcdcde0761c_.py @@ -23,7 +23,6 @@ Create Date: 2018-08-01 11:47:02.233971 """ # revision identifiers, used by Alembic. -import json import re import sqlalchemy as sa @@ -31,6 +30,7 @@ from alembic import op from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json revision = "7fcdcde0761c" down_revision = "c18bd4186f15" diff --git a/superset/migrations/versions/2018-11-12_13-31_4ce8df208545_migrate_time_range_for_default_filters.py b/superset/migrations/versions/2018-11-12_13-31_4ce8df208545_migrate_time_range_for_default_filters.py index 74b276e276..d1f68979cc 100644 --- a/superset/migrations/versions/2018-11-12_13-31_4ce8df208545_migrate_time_range_for_default_filters.py +++ b/superset/migrations/versions/2018-11-12_13-31_4ce8df208545_migrate_time_range_for_default_filters.py @@ -23,13 +23,12 @@ Create Date: 2018-11-12 13:31:07.578090 """ # revision identifiers, used by Alembic. -import json - from alembic import op from sqlalchemy import Column, Integer, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json revision = "4ce8df208545" down_revision = "55e910a74826" diff --git a/superset/migrations/versions/2018-12-11_22-03_fb13d49b72f9_better_filters.py b/superset/migrations/versions/2018-12-11_22-03_fb13d49b72f9_better_filters.py index 7b6676d553..c2af161f73 100644 --- a/superset/migrations/versions/2018-12-11_22-03_fb13d49b72f9_better_filters.py +++ b/superset/migrations/versions/2018-12-11_22-03_fb13d49b72f9_better_filters.py @@ -22,7 +22,6 @@ Create Date: 2018-12-11 22:03:21.612516 """ -import json import logging from alembic import op @@ -30,6 +29,7 @@ from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "fb13d49b72f9" diff --git a/superset/migrations/versions/2019-04-09_16-27_80aa3f04bc82_add_parent_ids_in_dashboard_layout.py b/superset/migrations/versions/2019-04-09_16-27_80aa3f04bc82_add_parent_ids_in_dashboard_layout.py index 61cb3c62ff..b78af79e34 100644 --- a/superset/migrations/versions/2019-04-09_16-27_80aa3f04bc82_add_parent_ids_in_dashboard_layout.py +++ b/superset/migrations/versions/2019-04-09_16-27_80aa3f04bc82_add_parent_ids_in_dashboard_layout.py @@ -22,7 +22,6 @@ Create Date: 2019-04-09 16:27:03.392872 """ -import json import logging from alembic import op @@ -30,6 +29,7 @@ from sqlalchemy import Column, Integer, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "80aa3f04bc82" diff --git a/superset/migrations/versions/2019-06-28_13-17_ab8c66efdd01_resample.py b/superset/migrations/versions/2019-06-28_13-17_ab8c66efdd01_resample.py index ea45104ee7..7ca0d5eacb 100644 --- a/superset/migrations/versions/2019-06-28_13-17_ab8c66efdd01_resample.py +++ b/superset/migrations/versions/2019-06-28_13-17_ab8c66efdd01_resample.py @@ -26,7 +26,6 @@ Create Date: 2019-06-28 13:17:59.517089 revision = "ab8c66efdd01" down_revision = "d7c1a0d6f2da" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -34,6 +33,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2019-10-10_13-52_1495eb914ad3_time_range.py b/superset/migrations/versions/2019-10-10_13-52_1495eb914ad3_time_range.py index 40f7bf8f3b..a1b0fca3df 100644 --- a/superset/migrations/versions/2019-10-10_13-52_1495eb914ad3_time_range.py +++ b/superset/migrations/versions/2019-10-10_13-52_1495eb914ad3_time_range.py @@ -22,7 +22,6 @@ Create Date: 2019-10-10 13:52:54.544475 """ -import json import logging from alembic import op @@ -31,6 +30,7 @@ from sqlalchemy.ext.declarative import declarative_base from superset import db from superset.legacy import update_time_range +from superset.utils import json # revision identifiers, used by Alembic. revision = "1495eb914ad3" diff --git a/superset/migrations/versions/2019-11-06_15-23_78ee127d0d1d_reconvert_legacy_filters_into_adhoc.py b/superset/migrations/versions/2019-11-06_15-23_78ee127d0d1d_reconvert_legacy_filters_into_adhoc.py index a9f013f408..a969bc9ba1 100644 --- a/superset/migrations/versions/2019-11-06_15-23_78ee127d0d1d_reconvert_legacy_filters_into_adhoc.py +++ b/superset/migrations/versions/2019-11-06_15-23_78ee127d0d1d_reconvert_legacy_filters_into_adhoc.py @@ -27,7 +27,6 @@ revision = "78ee127d0d1d" down_revision = "c2acd2cf3df2" import copy # noqa: E402 -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -35,6 +34,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 from superset.utils.core import ( # noqa: E402 convert_legacy_filters_into_adhoc, ) diff --git a/superset/migrations/versions/2020-02-07_14-13_3325d4caccc8_dashboard_scoped_filters.py b/superset/migrations/versions/2020-02-07_14-13_3325d4caccc8_dashboard_scoped_filters.py index f925b54b26..f37aa3e872 100644 --- a/superset/migrations/versions/2020-02-07_14-13_3325d4caccc8_dashboard_scoped_filters.py +++ b/superset/migrations/versions/2020-02-07_14-13_3325d4caccc8_dashboard_scoped_filters.py @@ -23,7 +23,6 @@ Create Date: 2020-02-07 14:13:51.714678 """ # revision identifiers, used by Alembic. -import json import logging from alembic import op @@ -32,6 +31,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from superset import db +from superset.utils import json from superset.utils.dashboard_filter_scopes_converter import convert_filter_scopes revision = "3325d4caccc8" diff --git a/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py b/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py index fd1469a6df..f85cf5db9c 100644 --- a/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py +++ b/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py @@ -26,13 +26,12 @@ Create Date: 2020-03-25 10:42:11.047328 revision = "f9a30386bd74" down_revision = "b5998378c225" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2020-04-29_09-24_620241d1153f_update_time_grain_sqla.py b/superset/migrations/versions/2020-04-29_09-24_620241d1153f_update_time_grain_sqla.py index 3492d77dd1..2f9e7cc566 100644 --- a/superset/migrations/versions/2020-04-29_09-24_620241d1153f_update_time_grain_sqla.py +++ b/superset/migrations/versions/2020-04-29_09-24_620241d1153f_update_time_grain_sqla.py @@ -26,14 +26,13 @@ Create Date: 2020-04-29 09:24:04.952368 revision = "620241d1153f" down_revision = "f9a30386bd74" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, ForeignKey, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db, db_engine_specs # noqa: E402 from superset.databases.utils import make_url_safe # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2020-08-12_00-24_978245563a02_migrate_iframe_to_dash_markdown.py b/superset/migrations/versions/2020-08-12_00-24_978245563a02_migrate_iframe_to_dash_markdown.py index c59abc8d46..404d8b3511 100644 --- a/superset/migrations/versions/2020-08-12_00-24_978245563a02_migrate_iframe_to_dash_markdown.py +++ b/superset/migrations/versions/2020-08-12_00-24_978245563a02_migrate_iframe_to_dash_markdown.py @@ -22,7 +22,6 @@ Create Date: 2020-08-12 00:24:39.617899 """ -import json import logging import uuid from collections import defaultdict @@ -33,6 +32,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "978245563a02" diff --git a/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py b/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py index e92c1f0650..57c9917ce4 100644 --- a/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py +++ b/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py @@ -22,9 +22,7 @@ Create Date: 2020-09-28 17:57:23.128142 """ -import json import os -from json.decoder import JSONDecodeError from uuid import uuid4 import sqlalchemy as sa @@ -35,7 +33,7 @@ from sqlalchemy_utils import UUIDType from superset import db from superset.migrations.shared.utils import assign_uuids -from superset.utils import core as utils +from superset.utils import core as utils, json # revision identifiers, used by Alembic. revision = "b56500de1855" @@ -81,7 +79,7 @@ default_batch_size = int(os.environ.get("BATCH_SIZE", 200)) def update_position_json(dashboard, session, uuid_map): try: layout = json.loads(dashboard.position_json or "{}") - except JSONDecodeError: + except json.JSONDecodeError: layout = {} for object_ in layout.values(): diff --git a/superset/migrations/versions/2021-01-23_16-25_260bf0649a77_migrate_x_dateunit_in_time_range.py b/superset/migrations/versions/2021-01-23_16-25_260bf0649a77_migrate_x_dateunit_in_time_range.py index f56007fd0d..5718458fc7 100644 --- a/superset/migrations/versions/2021-01-23_16-25_260bf0649a77_migrate_x_dateunit_in_time_range.py +++ b/superset/migrations/versions/2021-01-23_16-25_260bf0649a77_migrate_x_dateunit_in_time_range.py @@ -26,7 +26,6 @@ Create Date: 2021-01-23 16:25:14.496774 revision = "260bf0649a77" down_revision = "c878781977c6" -import json # noqa: E402 import re # noqa: E402 import sqlalchemy as sa # noqa: E402 @@ -38,6 +37,7 @@ from sqlalchemy.exc import OperationalError # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 from superset.utils.date_parser import DateRangeMigration # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-02-04_09-34_070c043f2fdb_add_granularity_to_charts_where_missing.py b/superset/migrations/versions/2021-02-04_09-34_070c043f2fdb_add_granularity_to_charts_where_missing.py index 133db66497..cda2a9b411 100644 --- a/superset/migrations/versions/2021-02-04_09-34_070c043f2fdb_add_granularity_to_charts_where_missing.py +++ b/superset/migrations/versions/2021-02-04_09-34_070c043f2fdb_add_granularity_to_charts_where_missing.py @@ -26,13 +26,12 @@ Create Date: 2021-02-04 09:34:13.608891 revision = "070c043f2fdb" down_revision = "41ce8799acc3" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import and_, Boolean, Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-02-10_12-32_41ce8799acc3_rename_pie_label_type.py b/superset/migrations/versions/2021-02-10_12-32_41ce8799acc3_rename_pie_label_type.py index 7e84392b11..f5bdaf9725 100644 --- a/superset/migrations/versions/2021-02-10_12-32_41ce8799acc3_rename_pie_label_type.py +++ b/superset/migrations/versions/2021-02-10_12-32_41ce8799acc3_rename_pie_label_type.py @@ -26,13 +26,12 @@ Create Date: 2021-02-10 12:32:27.385579 revision = "41ce8799acc3" down_revision = "e11ccdd12658" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import and_, Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-02-14_11-46_1412ec1e5a7b_legacy_force_directed_to_echart.py b/superset/migrations/versions/2021-02-14_11-46_1412ec1e5a7b_legacy_force_directed_to_echart.py index 862a629c16..5a8dbb934e 100644 --- a/superset/migrations/versions/2021-02-14_11-46_1412ec1e5a7b_legacy_force_directed_to_echart.py +++ b/superset/migrations/versions/2021-02-14_11-46_1412ec1e5a7b_legacy_force_directed_to_echart.py @@ -22,13 +22,12 @@ Create Date: 2021-02-14 11:46:02.379832 """ -import json - from alembic import op from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "1412ec1e5a7b" diff --git a/superset/migrations/versions/2021-03-24_09-47_989bbe479899_rename_filter_configuration_in_.py b/superset/migrations/versions/2021-03-24_09-47_989bbe479899_rename_filter_configuration_in_.py index d738b0e6d2..4610545458 100644 --- a/superset/migrations/versions/2021-03-24_09-47_989bbe479899_rename_filter_configuration_in_.py +++ b/superset/migrations/versions/2021-03-24_09-47_989bbe479899_rename_filter_configuration_in_.py @@ -26,13 +26,12 @@ Create Date: 2021-03-24 09:47:21.569508 revision = "989bbe479899" down_revision = "67da9ef1ef9c" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-04-07_07-21_134cea61c5e7_remove_dataset_health_check_message.py b/superset/migrations/versions/2021-04-07_07-21_134cea61c5e7_remove_dataset_health_check_message.py index adcc04fdaa..ceb7c49408 100644 --- a/superset/migrations/versions/2021-04-07_07-21_134cea61c5e7_remove_dataset_health_check_message.py +++ b/superset/migrations/versions/2021-04-07_07-21_134cea61c5e7_remove_dataset_health_check_message.py @@ -26,7 +26,6 @@ Create Date: 2021-04-07 07:21:27.324983 revision = "134cea61c5e7" down_revision = "301362411006" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -34,6 +33,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-04-09_16-14_085f06488938_country_map_use_lowercase_country_name.py b/superset/migrations/versions/2021-04-09_16-14_085f06488938_country_map_use_lowercase_country_name.py index a303d12c86..a16caedeb9 100644 --- a/superset/migrations/versions/2021-04-09_16-14_085f06488938_country_map_use_lowercase_country_name.py +++ b/superset/migrations/versions/2021-04-09_16-14_085f06488938_country_map_use_lowercase_country_name.py @@ -22,13 +22,12 @@ Create Date: 2021-04-09 16:14:19.040884 """ -import json - from alembic import op from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "085f06488938" diff --git a/superset/migrations/versions/2021-04-12_12-38_fc3a3a8ff221_migrate_filter_sets_to_new_format.py b/superset/migrations/versions/2021-04-12_12-38_fc3a3a8ff221_migrate_filter_sets_to_new_format.py index 13cfab0a43..a7f85e5106 100644 --- a/superset/migrations/versions/2021-04-12_12-38_fc3a3a8ff221_migrate_filter_sets_to_new_format.py +++ b/superset/migrations/versions/2021-04-12_12-38_fc3a3a8ff221_migrate_filter_sets_to_new_format.py @@ -26,7 +26,6 @@ Create Date: 2021-04-12 12:38:03.913514 revision = "fc3a3a8ff221" down_revision = "085f06488938" -import json # noqa: E402 from collections.abc import Iterable # noqa: E402 from typing import Any # noqa: E402 @@ -35,6 +34,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-04-29_15-32_f1410ed7ec95_migrate_native_filters_to_new_schema.py b/superset/migrations/versions/2021-04-29_15-32_f1410ed7ec95_migrate_native_filters_to_new_schema.py index 44bbc0c964..ab60f9d00c 100644 --- a/superset/migrations/versions/2021-04-29_15-32_f1410ed7ec95_migrate_native_filters_to_new_schema.py +++ b/superset/migrations/versions/2021-04-29_15-32_f1410ed7ec95_migrate_native_filters_to_new_schema.py @@ -26,7 +26,6 @@ Create Date: 2021-04-29 15:32:21.939018 revision = "f1410ed7ec95" down_revision = "d416d0d715cc" -import json # noqa: E402 from collections.abc import Iterable # noqa: E402 from typing import Any # noqa: E402 @@ -35,6 +34,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-08-02_16-39_e323605f370a_fix_schemas_allowed_for_csv_upload.py b/superset/migrations/versions/2021-08-02_16-39_e323605f370a_fix_schemas_allowed_for_csv_upload.py index 6d8c1a4a1b..92f63d2f8e 100644 --- a/superset/migrations/versions/2021-08-02_16-39_e323605f370a_fix_schemas_allowed_for_csv_upload.py +++ b/superset/migrations/versions/2021-08-02_16-39_e323605f370a_fix_schemas_allowed_for_csv_upload.py @@ -22,7 +22,6 @@ Create Date: 2021-08-02 16:39:45.329151 """ -import json import logging from alembic import op @@ -30,6 +29,7 @@ from sqlalchemy import Column, Integer, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "e323605f370a" @@ -55,7 +55,7 @@ def upgrade(): for database in session.query(Database).all(): try: extra = json.loads(database.extra) - except json.decoder.JSONDecodeError as ex: + except json.JSONDecodeError as ex: logging.warning(str(ex)) continue diff --git a/superset/migrations/versions/2021-08-03_15-36_143b6f2815da_migrate_pivot_table_v2_heatmaps_to_new_.py b/superset/migrations/versions/2021-08-03_15-36_143b6f2815da_migrate_pivot_table_v2_heatmaps_to_new_.py index 861f163c3c..f49a37a105 100644 --- a/superset/migrations/versions/2021-08-03_15-36_143b6f2815da_migrate_pivot_table_v2_heatmaps_to_new_.py +++ b/superset/migrations/versions/2021-08-03_15-36_143b6f2815da_migrate_pivot_table_v2_heatmaps_to_new_.py @@ -26,13 +26,12 @@ Create Date: 2021-08-03 15:36:35.925420 revision = "143b6f2815da" down_revision = "e323605f370a" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import and_, Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py b/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py index 32b5b1ade5..9237148284 100644 --- a/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py +++ b/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py @@ -26,7 +26,6 @@ Create Date: 2021-08-31 11:37:40.604081 revision = "021b81fe4fbb" down_revision = "07071313dd52" -import json # noqa: E402 import logging # noqa: E402 import sqlalchemy as sa # noqa: E402 @@ -34,6 +33,7 @@ from alembic import op # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-09-27_11-31_60dc453f4e2e_migrate_timeseries_limit_metric_to_.py b/superset/migrations/versions/2021-09-27_11-31_60dc453f4e2e_migrate_timeseries_limit_metric_to_.py index 449cf72734..537d73c858 100644 --- a/superset/migrations/versions/2021-09-27_11-31_60dc453f4e2e_migrate_timeseries_limit_metric_to_.py +++ b/superset/migrations/versions/2021-09-27_11-31_60dc453f4e2e_migrate_timeseries_limit_metric_to_.py @@ -26,13 +26,12 @@ Create Date: 2021-09-27 11:31:53.453164 revision = "60dc453f4e2e" down_revision = "3ebe0993c770" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import and_, Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-10-12_11-15_32646df09c64_update_time_grain_sqla.py b/superset/migrations/versions/2021-10-12_11-15_32646df09c64_update_time_grain_sqla.py index f3cd97ccaa..aa87f30369 100644 --- a/superset/migrations/versions/2021-10-12_11-15_32646df09c64_update_time_grain_sqla.py +++ b/superset/migrations/versions/2021-10-12_11-15_32646df09c64_update_time_grain_sqla.py @@ -26,13 +26,12 @@ Create Date: 2021-10-12 11:15:25.559532 revision = "32646df09c64" down_revision = "60dc453f4e2e" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-11-11_04-18_0ca9e5f1dacd_rename_to_schemas_allowed_for_file_.py b/superset/migrations/versions/2021-11-11_04-18_0ca9e5f1dacd_rename_to_schemas_allowed_for_file_.py index 370cf508c4..d017fac539 100644 --- a/superset/migrations/versions/2021-11-11_04-18_0ca9e5f1dacd_rename_to_schemas_allowed_for_file_.py +++ b/superset/migrations/versions/2021-11-11_04-18_0ca9e5f1dacd_rename_to_schemas_allowed_for_file_.py @@ -26,7 +26,6 @@ Create Date: 2021-11-11 04:18:26.171851 revision = "0ca9e5f1dacd" down_revision = "b92d69a6643c" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -34,6 +33,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() @@ -51,7 +51,7 @@ def upgrade(): for database in session.query(Database).all(): try: extra = json.loads(database.extra) - except json.decoder.JSONDecodeError as ex: + except json.JSONDecodeError as ex: logging.warning(str(ex)) continue @@ -73,7 +73,7 @@ def downgrade(): for database in session.query(Database).all(): try: extra = json.loads(database.extra) - except json.decoder.JSONDecodeError as ex: + except json.JSONDecodeError as ex: logging.warning(str(ex)) continue diff --git a/superset/migrations/versions/2021-12-13_14-06_fe23025b9441_rename_big_viz_total_form_data_fields.py b/superset/migrations/versions/2021-12-13_14-06_fe23025b9441_rename_big_viz_total_form_data_fields.py index 11a46a919e..f2e8407add 100644 --- a/superset/migrations/versions/2021-12-13_14-06_fe23025b9441_rename_big_viz_total_form_data_fields.py +++ b/superset/migrations/versions/2021-12-13_14-06_fe23025b9441_rename_big_viz_total_form_data_fields.py @@ -26,7 +26,6 @@ Create Date: 2021-12-13 14:06:24.426970 revision = "fe23025b9441" down_revision = "3ba29ecbaac5" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -34,6 +33,7 @@ from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2021-12-17_16-56_31bb738bd1d2_move_pivot_table_v2_legacy_order_by_to_.py b/superset/migrations/versions/2021-12-17_16-56_31bb738bd1d2_move_pivot_table_v2_legacy_order_by_to_.py index 7740e23da4..f9ee00b705 100644 --- a/superset/migrations/versions/2021-12-17_16-56_31bb738bd1d2_move_pivot_table_v2_legacy_order_by_to_.py +++ b/superset/migrations/versions/2021-12-17_16-56_31bb738bd1d2_move_pivot_table_v2_legacy_order_by_to_.py @@ -27,7 +27,6 @@ revision = "31bb738bd1d2" down_revision = "fe23025b9441" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -35,6 +34,7 @@ from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2022-03-02_16-41_7293b0ca7944_change_adhoc_filter_b_from_none_to_.py b/superset/migrations/versions/2022-03-02_16-41_7293b0ca7944_change_adhoc_filter_b_from_none_to_.py index 3c0eb78448..9085ea05d3 100644 --- a/superset/migrations/versions/2022-03-02_16-41_7293b0ca7944_change_adhoc_filter_b_from_none_to_.py +++ b/superset/migrations/versions/2022-03-02_16-41_7293b0ca7944_change_adhoc_filter_b_from_none_to_.py @@ -27,13 +27,12 @@ revision = "7293b0ca7944" down_revision = "ab9a9d86e695" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py b/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py index 1b3c95dc32..9618dd98ff 100644 --- a/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py +++ b/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py @@ -26,7 +26,6 @@ Create Date: 2022-04-01 14:38:09.499483 revision = "a9422eeaae74" down_revision = "ad07e4fdbaba" -import json # noqa: E402 import os # noqa: E402 from datetime import datetime # noqa: E402 from typing import Optional, Union # noqa: E402 @@ -50,6 +49,7 @@ from superset.connectors.sqla.utils import ( # noqa: E402 from superset.extensions import encrypted_field_factory # noqa: E402 from superset.migrations.shared.utils import assign_uuids # noqa: E402 from superset.sql_parse import extract_table_references, Table # noqa: E402 +from superset.utils import json # noqa: E402 from superset.utils.core import MediumText # noqa: E402 Base = declarative_base() @@ -579,7 +579,7 @@ def postprocess_datasets(session: Session) -> None: if schema: try: extra_json = json.loads(extra) if extra else {} - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: extra_json = {} extra_json["schema"] = schema updates["extra_json"] = json.dumps(extra_json) @@ -771,7 +771,7 @@ def postprocess_columns(session: Session) -> None: ) in session.execute(query): try: extra = json.loads(extra_json) if extra_json else {} - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: extra = {} updated_extra = {**extra} updates = {} diff --git a/superset/migrations/versions/2022-04-04_15-04_b0d0249074e4_deprecate_time_range_endpoints_v2.py b/superset/migrations/versions/2022-04-04_15-04_b0d0249074e4_deprecate_time_range_endpoints_v2.py index 2d0f01477f..9b9a67f3fe 100644 --- a/superset/migrations/versions/2022-04-04_15-04_b0d0249074e4_deprecate_time_range_endpoints_v2.py +++ b/superset/migrations/versions/2022-04-04_15-04_b0d0249074e4_deprecate_time_range_endpoints_v2.py @@ -22,13 +22,12 @@ Create Date: 2022-04-04 15:04:05.606340 """ -import json - from alembic import op from sqlalchemy import Column, Integer, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "b0d0249074e4" diff --git a/superset/migrations/versions/2022-04-18_11-20_ad07e4fdbaba_rm_time_range_endpoints_from_qc_3.py b/superset/migrations/versions/2022-04-18_11-20_ad07e4fdbaba_rm_time_range_endpoints_from_qc_3.py index 2087bc3e0f..7b87098384 100644 --- a/superset/migrations/versions/2022-04-18_11-20_ad07e4fdbaba_rm_time_range_endpoints_from_qc_3.py +++ b/superset/migrations/versions/2022-04-18_11-20_ad07e4fdbaba_rm_time_range_endpoints_from_qc_3.py @@ -26,13 +26,12 @@ Create Date: 2022-04-18 11:20:47.390901 revision = "ad07e4fdbaba" down_revision = "cecc6bf46990" -import json # noqa: E402 - import sqlalchemy as sa # noqa: E402 from alembic import op # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() @@ -47,7 +46,7 @@ class Slice(Base): def upgrade_slice(slc: Slice): try: query_context = json.loads(slc.query_context) - except json.decoder.JSONDecodeError: + except json.JSONDecodeError: return query_context.get("form_data", {}).pop("time_range_endpoints", None) diff --git a/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py b/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py index 37b28c0aca..dc86babffb 100644 --- a/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py +++ b/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py @@ -22,13 +22,12 @@ Create Date: 2022-08-16 15:23:42.860038 """ -import json - from alembic import op from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "6d3c6f9d665d" diff --git a/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py b/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py index 86ee15350f..6b4dc27b85 100644 --- a/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py +++ b/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py @@ -26,13 +26,12 @@ Create Date: 2022-11-28 17:51:08.954439 revision = "4ce1d9b25135" down_revision = "deb4c9d4a4ef" -import json # noqa: E402 - import sqlalchemy as sa # noqa: E402 from alembic import op # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-02-28_14-46_c0a3ea245b61_remove_show_native_filters.py b/superset/migrations/versions/2023-02-28_14-46_c0a3ea245b61_remove_show_native_filters.py index 3954a7cb9a..7be7162d29 100644 --- a/superset/migrations/versions/2023-02-28_14-46_c0a3ea245b61_remove_show_native_filters.py +++ b/superset/migrations/versions/2023-02-28_14-46_c0a3ea245b61_remove_show_native_filters.py @@ -26,13 +26,12 @@ Create Date: 2023-02-28 14:46:59.597847 revision = "c0a3ea245b61" down_revision = "9c2a5681ddfd" -import json # noqa: E402 - import sqlalchemy as sa # noqa: E402 from alembic import op # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-03-05_10-06_d0ac08bb5b83_invert_horizontal_bar_chart_order.py b/superset/migrations/versions/2023-03-05_10-06_d0ac08bb5b83_invert_horizontal_bar_chart_order.py index df97cdb210..f060a596dc 100644 --- a/superset/migrations/versions/2023-03-05_10-06_d0ac08bb5b83_invert_horizontal_bar_chart_order.py +++ b/superset/migrations/versions/2023-03-05_10-06_d0ac08bb5b83_invert_horizontal_bar_chart_order.py @@ -26,13 +26,12 @@ Create Date: 2023-03-05 10:06:23.250310 revision = "d0ac08bb5b83" down_revision = "c0a3ea245b61" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import and_, Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-03-17_13-24_b5ea9d343307_bar_chart_stack_options.py b/superset/migrations/versions/2023-03-17_13-24_b5ea9d343307_bar_chart_stack_options.py index 983384b3ff..c5bce59ce6 100644 --- a/superset/migrations/versions/2023-03-17_13-24_b5ea9d343307_bar_chart_stack_options.py +++ b/superset/migrations/versions/2023-03-17_13-24_b5ea9d343307_bar_chart_stack_options.py @@ -26,13 +26,12 @@ Create Date: 2023-03-17 13:24:54.662754 revision = "b5ea9d343307" down_revision = "d0ac08bb5b83" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-03-27_12-30_7e67aecbf3f1_chart_ds_constraint.py b/superset/migrations/versions/2023-03-27_12-30_7e67aecbf3f1_chart_ds_constraint.py index 7b877d17e2..4507ea7368 100644 --- a/superset/migrations/versions/2023-03-27_12-30_7e67aecbf3f1_chart_ds_constraint.py +++ b/superset/migrations/versions/2023-03-27_12-30_7e67aecbf3f1_chart_ds_constraint.py @@ -26,7 +26,6 @@ Create Date: 2023-03-27 12:30:01.164594 revision = "7e67aecbf3f1" down_revision = "07f9a902af1b" -import json # noqa: E402 import logging # noqa: E402 import sqlalchemy as sa # noqa: E402 @@ -34,6 +33,7 @@ from alembic import op # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-05-01_12-03_9c2a5681ddfd_convert_key_value_entries_to_json.py b/superset/migrations/versions/2023-05-01_12-03_9c2a5681ddfd_convert_key_value_entries_to_json.py index fd1d728f0d..ccc199df5e 100644 --- a/superset/migrations/versions/2023-05-01_12-03_9c2a5681ddfd_convert_key_value_entries_to_json.py +++ b/superset/migrations/versions/2023-05-01_12-03_9c2a5681ddfd_convert_key_value_entries_to_json.py @@ -27,7 +27,6 @@ revision = "9c2a5681ddfd" down_revision = "f3c2d8ec8595" import io # noqa: E402 -import json # noqa: E402 import pickle # noqa: E402 from alembic import op # noqa: E402 @@ -37,6 +36,7 @@ from sqlalchemy.orm import Session # noqa: E402 from superset import db # noqa: E402 from superset.migrations.shared.utils import paginated_update # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() VALUE_MAX_SIZE = 2**24 - 1 diff --git a/superset/migrations/versions/2023-05-11_12-41_4ea966691069_cross_filter_global_scoping.py b/superset/migrations/versions/2023-05-11_12-41_4ea966691069_cross_filter_global_scoping.py index 52128f8fda..3eb7af7bb9 100644 --- a/superset/migrations/versions/2023-05-11_12-41_4ea966691069_cross_filter_global_scoping.py +++ b/superset/migrations/versions/2023-05-11_12-41_4ea966691069_cross_filter_global_scoping.py @@ -27,7 +27,6 @@ revision = "4ea966691069" down_revision = "7e67aecbf3f1" import copy # noqa: E402 -import json # noqa: E402 import logging # noqa: E402 import sqlalchemy as sa # noqa: E402 @@ -36,6 +35,7 @@ from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 from superset.migrations.shared.utils import paginated_update # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() logger = logging.getLogger(__name__) diff --git a/superset/migrations/versions/2023-07-18_15-30_863adcf72773_delete_obsolete_druid_nosql_slice_parameters.py b/superset/migrations/versions/2023-07-18_15-30_863adcf72773_delete_obsolete_druid_nosql_slice_parameters.py index 4104c2a593..1c6e9c2419 100644 --- a/superset/migrations/versions/2023-07-18_15-30_863adcf72773_delete_obsolete_druid_nosql_slice_parameters.py +++ b/superset/migrations/versions/2023-07-18_15-30_863adcf72773_delete_obsolete_druid_nosql_slice_parameters.py @@ -26,7 +26,6 @@ Create Date: 2023-07-18 15:30:43.695135 revision = "863adcf72773" down_revision = "6d05b0a70c89" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -34,6 +33,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-07-19_16-48_a23c6f8b1280_cleanup_erroneous_parent_filter_ids.py b/superset/migrations/versions/2023-07-19_16-48_a23c6f8b1280_cleanup_erroneous_parent_filter_ids.py index a41dea4976..f728e20679 100644 --- a/superset/migrations/versions/2023-07-19_16-48_a23c6f8b1280_cleanup_erroneous_parent_filter_ids.py +++ b/superset/migrations/versions/2023-07-19_16-48_a23c6f8b1280_cleanup_erroneous_parent_filter_ids.py @@ -27,7 +27,6 @@ revision = "a23c6f8b1280" down_revision = "863adcf72773" -import json # noqa: E402 import logging # noqa: E402 from alembic import op # noqa: E402 @@ -35,6 +34,7 @@ from sqlalchemy import Column, Integer, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2023-07-19_17-54_ee179a490af9_deckgl_path_width_units.py b/superset/migrations/versions/2023-07-19_17-54_ee179a490af9_deckgl_path_width_units.py index 8110c42dc7..25042dd682 100644 --- a/superset/migrations/versions/2023-07-19_17-54_ee179a490af9_deckgl_path_width_units.py +++ b/superset/migrations/versions/2023-07-19_17-54_ee179a490af9_deckgl_path_width_units.py @@ -22,7 +22,6 @@ Create Date: 2023-07-19 17:54:06.752360 """ -import json import logging from alembic import op @@ -30,6 +29,7 @@ from sqlalchemy import Column, Integer, or_, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db +from superset.utils import json # revision identifiers, used by Alembic. revision = "ee179a490af9" diff --git a/superset/migrations/versions/2023-12-15_17-58_06dd9ff00fe8_add_percent_calculation_type_funnel_.py b/superset/migrations/versions/2023-12-15_17-58_06dd9ff00fe8_add_percent_calculation_type_funnel_.py index 5811cb4b3d..7f89235cf2 100644 --- a/superset/migrations/versions/2023-12-15_17-58_06dd9ff00fe8_add_percent_calculation_type_funnel_.py +++ b/superset/migrations/versions/2023-12-15_17-58_06dd9ff00fe8_add_percent_calculation_type_funnel_.py @@ -22,14 +22,13 @@ Create Date: 2023-12-15 17:58:18.277951 """ -import json - from alembic import op from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base from superset import db from superset.migrations.shared.utils import paginated_update +from superset.utils import json # revision identifiers, used by Alembic. revision = "06dd9ff00fe8" diff --git a/superset/migrations/versions/2024-03-01_10-47_be1b217cd8cd_big_number_kpi_single_metric.py b/superset/migrations/versions/2024-03-01_10-47_be1b217cd8cd_big_number_kpi_single_metric.py index 84466b5480..e09e6fa647 100644 --- a/superset/migrations/versions/2024-03-01_10-47_be1b217cd8cd_big_number_kpi_single_metric.py +++ b/superset/migrations/versions/2024-03-01_10-47_be1b217cd8cd_big_number_kpi_single_metric.py @@ -27,14 +27,13 @@ revision = "be1b217cd8cd" down_revision = "17fcea065655" -import json # noqa: E402 - from alembic import op # noqa: E402 from sqlalchemy import Column, Integer, String, Text # noqa: E402 from sqlalchemy.ext.declarative import declarative_base # noqa: E402 from superset import db # noqa: E402 from superset.migrations.shared.utils import paginated_update # noqa: E402 +from superset.utils import json # noqa: E402 Base = declarative_base() diff --git a/superset/migrations/versions/2024-05-10_18-02_f84fde59123a_update_charts_with_old_time_comparison.py b/superset/migrations/versions/2024-05-10_18-02_f84fde59123a_update_charts_with_old_time_comparison.py index c349344f56..dcdc3f0b44 100644 --- a/superset/migrations/versions/2024-05-10_18-02_f84fde59123a_update_charts_with_old_time_comparison.py +++ b/superset/migrations/versions/2024-05-10_18-02_f84fde59123a_update_charts_with_old_time_comparison.py @@ -22,7 +22,6 @@ Create Date: 2024-05-10 18:02:38.891060 """ -import json import logging from copy import deepcopy from datetime import datetime, timedelta @@ -35,6 +34,7 @@ from sqlalchemy.ext.declarative import declarative_base from superset import db from superset.migrations.shared.utils import paginated_update +from superset.utils import json from superset.utils.date_parser import get_since_until # revision identifiers, used by Alembic. diff --git a/superset/models/core.py b/superset/models/core.py index 2d7e579295..b933c1694f 100755 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -22,7 +22,6 @@ from __future__ import annotations import builtins -import json import logging import textwrap from ast import literal_eval @@ -76,7 +75,7 @@ from superset.models.helpers import AuditMixinNullable, ImportExportMixin from superset.result_set import SupersetResultSet from superset.sql_parse import Table from superset.superset_typing import OAuth2ClientConfig, ResultSetColumnType -from superset.utils import cache as cache_util, core as utils, json as json_utils +from superset.utils import cache as cache_util, core as utils, json from superset.utils.backports import StrEnum from superset.utils.core import DatasourceName, get_username from superset.utils.oauth2 import get_oauth2_access_token @@ -601,7 +600,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin): # pylint: disable for col, coltype in df.dtypes.to_dict().items(): if coltype == numpy.object_ and column_needs_conversion(df[col]): - df[col] = df[col].apply(json_utils.json_dumps_w_dates) + df[col] = df[col].apply(json.json_dumps_w_dates) return df @property @@ -957,7 +956,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin): # pylint: disable def _convert(value: Any) -> Any: try: - return json_utils.base_json_conv(value) + return json.base_json_conv(value) except TypeError: return None diff --git a/superset/models/dashboard.py b/superset/models/dashboard.py index f478583246..6e6989bf9e 100644 --- a/superset/models/dashboard.py +++ b/superset/models/dashboard.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import logging import uuid from collections import defaultdict @@ -51,7 +50,7 @@ from superset.models.user_attributes import UserAttribute from superset.tasks.thumbnails import cache_dashboard_thumbnail from superset.tasks.utils import get_current_user from superset.thumbnails.digest import get_dashboard_digest -from superset.utils import core as utils, json as json_utils +from superset.utils import core as utils, json metadata = Model.metadata # pylint: disable=no-member config = app.config @@ -372,7 +371,7 @@ class Dashboard(AuditMixinNullable, ImportExportMixin, Model): return json.dumps( {"dashboards": copied_dashboards, "datasources": eager_datasources}, - cls=json_utils.DashboardEncoder, + cls=json.DashboardEncoder, indent=4, ) diff --git a/superset/models/helpers.py b/superset/models/helpers.py index 100391086c..dffb285663 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -19,14 +19,12 @@ import builtins import dataclasses -import json import logging import re import uuid from collections import defaultdict from collections.abc import Hashable from datetime import datetime, timedelta -from json.decoder import JSONDecodeError from typing import Any, cast, NamedTuple, Optional, TYPE_CHECKING, Union import dateutil.parser @@ -88,7 +86,7 @@ from superset.superset_typing import ( OrderBy, QueryObjectDict, ) -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.core import ( GenericDataType, get_column_name, @@ -597,7 +595,7 @@ class ExtraJSONMixin: def extra(self) -> dict[str, Any]: try: return json.loads(self.extra_json or "{}") or {} - except (TypeError, JSONDecodeError) as exc: + except (TypeError, json.JSONDecodeError) as exc: logger.error( "Unable to load an extra json: %r. Leaving empty.", exc, exc_info=True ) diff --git a/superset/models/slice.py b/superset/models/slice.py index 2a0734b107..bc89b5b7c4 100644 --- a/superset/models/slice.py +++ b/superset/models/slice.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import logging from typing import Any, TYPE_CHECKING from urllib import parse @@ -45,7 +44,7 @@ from superset.models.helpers import AuditMixinNullable, ImportExportMixin from superset.tasks.thumbnails import cache_chart_thumbnail from superset.tasks.utils import get_current_user from superset.thumbnails.digest import get_chart_digest -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.viz import BaseViz, viz_types if TYPE_CHECKING: @@ -289,7 +288,7 @@ class Slice( # pylint: disable=too-many-public-methods return self.get_query_context_factory().create( **json.loads(self.query_context) ) - except json.decoder.JSONDecodeError as ex: + except json.JSONDecodeError as ex: logger.error("Malformed json in slice's query context", exc_info=True) logger.exception(ex) return None diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py index 4e948b58e9..3c26c6c12f 100644 --- a/superset/models/sql_lab.py +++ b/superset/models/sql_lab.py @@ -24,7 +24,6 @@ from collections.abc import Hashable from datetime import datetime from typing import Any, Optional, TYPE_CHECKING -import simplejson as json import sqlalchemy as sqla from flask import current_app from flask_appbuilder import Model @@ -59,6 +58,7 @@ from superset.models.helpers import ( ) from superset.sql_parse import CtasMethod, extract_tables_from_jinja_sql, Table from superset.sqllab.limiting_factor import LimitingFactor +from superset.utils import json from superset.utils.core import ( get_column_name, LongText, diff --git a/superset/queries/saved_queries/api.py b/superset/queries/saved_queries/api.py index 57ef2dab14..cd7b04193f 100644 --- a/superset/queries/saved_queries/api.py +++ b/superset/queries/saved_queries/api.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from datetime import datetime from io import BytesIO @@ -54,6 +53,7 @@ from superset.queries.saved_queries.schemas import ( get_export_ids_schema, openapi_spec_methods_override, ) +from superset.utils import json from superset.views.base_api import ( BaseSupersetModelRestApi, requires_form_data, diff --git a/superset/reports/notifications/email.py b/superset/reports/notifications/email.py index b8da60b909..d9ac6dca22 100644 --- a/superset/reports/notifications/email.py +++ b/superset/reports/notifications/email.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging import textwrap from dataclasses import dataclass @@ -29,6 +28,7 @@ from superset.exceptions import SupersetErrorsException from superset.reports.models import ReportRecipientType from superset.reports.notifications.base import BaseNotification from superset.reports.notifications.exceptions import NotificationError +from superset.utils import json from superset.utils.core import HeaderDataType, send_email_smtp from superset.utils.decorators import statsd_gauge diff --git a/superset/reports/notifications/slack.py b/superset/reports/notifications/slack.py index a7072ca20c..b70cab4435 100644 --- a/superset/reports/notifications/slack.py +++ b/superset/reports/notifications/slack.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from collections.abc import Sequence from io import IOBase @@ -43,6 +42,7 @@ from superset.reports.notifications.exceptions import ( NotificationParamException, NotificationUnprocessableException, ) +from superset.utils import json from superset.utils.core import get_email_address_list from superset.utils.decorators import statsd_gauge from superset.utils.slack import get_slack_client diff --git a/superset/result_set.py b/superset/result_set.py index 38ca9453a5..f4303a7f80 100644 --- a/superset/result_set.py +++ b/superset/result_set.py @@ -17,7 +17,6 @@ """Superset wrapper around pyarrow.Table.""" import datetime -import json import logging from typing import Any, Optional @@ -28,7 +27,7 @@ from numpy.typing import NDArray from superset.db_engine_specs import BaseEngineSpec from superset.superset_typing import DbapiDescription, DbapiResult, ResultSetColumnType -from superset.utils import core as utils, json as json_utils +from superset.utils import core as utils, json from superset.utils.core import GenericDataType logger = logging.getLogger(__name__) @@ -61,7 +60,7 @@ def dedup(l: list[str], suffix: str = "__", case_sensitive: bool = True) -> list def stringify(obj: Any) -> str: - return json_utils.dumps(obj, default=json_utils.json_iso_dttm_ser) + return json.dumps(obj, default=json.json_iso_dttm_ser) def stringify_values(array: NDArray[Any]) -> NDArray[Any]: diff --git a/superset/security/manager.py b/superset/security/manager.py index 009fd662fd..722ac363a0 100644 --- a/superset/security/manager.py +++ b/superset/security/manager.py @@ -17,7 +17,6 @@ # pylint: disable=too-many-lines """A set of constants and methods to manage permissions and security""" -import json import logging import re import time @@ -69,6 +68,7 @@ from superset.security.guest_token import ( ) from superset.sql_parse import extract_tables_from_jinja_sql, Table from superset.superset_typing import Metric +from superset.utils import json from superset.utils.core import ( DatasourceName, DatasourceType, diff --git a/superset/sql_lab.py b/superset/sql_lab.py index d2e6680fbb..0e77c5a902 100644 --- a/superset/sql_lab.py +++ b/superset/sql_lab.py @@ -58,7 +58,7 @@ from superset.sql_parse import ( ) from superset.sqllab.limiting_factor import LimitingFactor from superset.sqllab.utils import write_ipc_buffer -from superset.utils import json as json_utils +from superset.utils import json from superset.utils.core import ( override_user, QuerySource, @@ -348,13 +348,9 @@ def _serialize_payload( ) -> Union[bytes, str]: logger.debug("Serializing to msgpack: %r", use_msgpack) if use_msgpack: - return msgpack.dumps( - payload, default=json_utils.json_iso_dttm_ser, use_bin_type=True - ) + return msgpack.dumps(payload, default=json.json_iso_dttm_ser, use_bin_type=True) - return json_utils.dumps( - payload, default=json_utils.json_iso_dttm_ser, ignore_nan=True - ) + return json.dumps(payload, default=json.json_iso_dttm_ser, ignore_nan=True) def _serialize_and_expand_data( diff --git a/superset/sqllab/api.py b/superset/sqllab/api.py index df6506a5d2..cdb331c19b 100644 --- a/superset/sqllab/api.py +++ b/superset/sqllab/api.py @@ -61,7 +61,7 @@ from superset.sqllab.sqllab_execution_context import SqlJsonExecutionContext from superset.sqllab.utils import bootstrap_sqllab_data from superset.sqllab.validators import CanAccessQueryValidatorImpl from superset.superset_typing import FlaskResponse -from superset.utils import core as utils, json as json_utils +from superset.utils import core as utils, json from superset.views.base import CsvResponse, generate_download_headers, json_success from superset.views.base_api import BaseSupersetApi, requires_json, statsd_metrics @@ -131,9 +131,9 @@ class SqlLabRestApi(BaseSupersetApi): result = bootstrap_sqllab_data(user_id) return json_success( - json_utils.dumps( + json.dumps( {"result": result}, - default=json_utils.json_iso_dttm_ser, + default=json.json_iso_dttm_ser, ignore_nan=True, ), 200, @@ -342,9 +342,9 @@ class SqlLabRestApi(BaseSupersetApi): # Using pessimistic json serialization since some database drivers can return # unserializeable types at times - payload = json_utils.dumps( + payload = json.dumps( result, - default=json_utils.pessimistic_json_iso_dttm_ser, + default=json.pessimistic_json_iso_dttm_ser, ignore_nan=True, ) return json_success(payload, 200) diff --git a/superset/sqllab/execution_context_convertor.py b/superset/sqllab/execution_context_convertor.py index 9453faa152..670f4ed2d5 100644 --- a/superset/sqllab/execution_context_convertor.py +++ b/superset/sqllab/execution_context_convertor.py @@ -21,7 +21,7 @@ from typing import Any, TYPE_CHECKING from superset.sqllab.command_status import SqlJsonExecutionStatus from superset.sqllab.utils import apply_display_max_row_configuration_if_require -from superset.utils import json as json_utils +from superset.utils import json logger = logging.getLogger(__name__) @@ -50,16 +50,16 @@ class ExecutionContextConvertor: def serialize_payload(self) -> str: if self._exc_status == SqlJsonExecutionStatus.HAS_RESULTS: - return json_utils.dumps( + return json.dumps( apply_display_max_row_configuration_if_require( self.payload, self._max_row_in_display_configuration ), - default=json_utils.pessimistic_json_iso_dttm_ser, + default=json.pessimistic_json_iso_dttm_ser, ignore_nan=True, ) - return json_utils.dumps( + return json.dumps( {"query": self.payload}, - default=json_utils.json_int_dttm_ser, + default=json.json_int_dttm_ser, ignore_nan=True, ) diff --git a/superset/sqllab/sqllab_execution_context.py b/superset/sqllab/sqllab_execution_context.py index 7ab4459be3..f67e2bf5a9 100644 --- a/superset/sqllab/sqllab_execution_context.py +++ b/superset/sqllab/sqllab_execution_context.py @@ -17,7 +17,6 @@ from __future__ import annotations import contextlib -import json import logging from dataclasses import dataclass from typing import Any, cast, TYPE_CHECKING @@ -28,7 +27,7 @@ from sqlalchemy.orm.exc import DetachedInstanceError from superset import is_feature_enabled from superset.models.sql_lab import Query from superset.sql_parse import CtasMethod -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.utils.core import apply_max_row_limit, get_user_id from superset.utils.dates import now_as_float from superset.views.utils import get_cta_schema_name diff --git a/superset/tasks/cache.py b/superset/tasks/cache.py index d2757aa22c..d1051c8fcb 100644 --- a/superset/tasks/cache.py +++ b/superset/tasks/cache.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from typing import Any, Optional, Union from urllib import request @@ -30,6 +29,7 @@ from superset.models.core import Log from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.tags.models import Tag, TaggedObject +from superset.utils import json from superset.utils.date_parser import parse_human_datetime from superset.utils.machine_auth import MachineAuthProvider from superset.utils.urls import get_url_path diff --git a/superset/utils/csv.py b/superset/utils/csv.py index 74a33187a5..08848adde5 100644 --- a/superset/utils/csv.py +++ b/superset/utils/csv.py @@ -22,8 +22,8 @@ from urllib.error import URLError import numpy as np import pandas as pd -import simplejson +from superset.utils import json from superset.utils.core import GenericDataType logger = logging.getLogger(__name__) @@ -107,7 +107,7 @@ def get_chart_dataframe( if content is None: return None - result = simplejson.loads(content.decode("utf-8")) + result = json.loads(content.decode("utf-8")) # need to convert float value to string to show full long number pd.set_option("display.float_format", lambda x: str(x)) df = pd.DataFrame.from_dict(result["result"][0]["data"]) diff --git a/superset/utils/dashboard_filter_scopes_converter.py b/superset/utils/dashboard_filter_scopes_converter.py index 6a3ead7c14..f3c09bc83a 100644 --- a/superset/utils/dashboard_filter_scopes_converter.py +++ b/superset/utils/dashboard_filter_scopes_converter.py @@ -14,12 +14,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import logging from collections import defaultdict from typing import Any from superset.models.slice import Slice +from superset.utils import json logger = logging.getLogger(__name__) diff --git a/superset/utils/hashing.py b/superset/utils/hashing.py index 86ed736b08..86c04657c5 100644 --- a/superset/utils/hashing.py +++ b/superset/utils/hashing.py @@ -17,7 +17,7 @@ import hashlib from typing import Any, Callable, Optional -import simplejson as json +from superset.utils import json def md5_sha_from_str(val: str) -> str: diff --git a/superset/utils/json.py b/superset/utils/json.py index 9068a84bb3..e3a530525b 100644 --- a/superset/utils/json.py +++ b/superset/utils/json.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. import decimal -import json import logging import uuid from datetime import date, datetime, time, timedelta @@ -25,20 +24,20 @@ import numpy as np import pandas as pd import simplejson from flask_babel.speaklater import LazyString +from simplejson import JSONDecodeError # noqa: F401 # pylint: disable=unused-import -from superset.exceptions import SupersetException from superset.utils.dates import datetime_to_epoch, EPOCH logging.getLogger("MARKDOWN").setLevel(logging.INFO) logger = logging.getLogger(__name__) -class DashboardEncoder(json.JSONEncoder): +class DashboardEncoder(simplejson.JSONEncoder): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.sort_keys = True - def default(self, o: Any) -> Union[dict[Any, Any], str]: + def default(self, o: Any) -> Union[dict[Any, Any], str]: # type: ignore if isinstance(o, uuid.UUID): return str(o) try: @@ -47,7 +46,7 @@ class DashboardEncoder(json.JSONEncoder): except Exception: # pylint: disable=broad-except if isinstance(o, datetime): return {"__datetime__": o.replace(microsecond=0).isoformat()} - return json.JSONEncoder(sort_keys=True).default(o) + return simplejson.JSONEncoder(sort_keys=True).default(o) def format_timedelta(time_delta: timedelta) -> str: @@ -172,40 +171,82 @@ def validate_json(obj: Union[bytes, bytearray, str]) -> None: :param obj: an object that should be parseable to JSON """ if obj: - try: - 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") from ex + loads(obj) -def dumps( +def dumps( # pylint: disable=too-many-arguments obj: Any, default: Optional[Callable[[Any], Any]] = json_iso_dttm_ser, + allow_nan: bool = False, ignore_nan: bool = True, sort_keys: bool = False, + indent: Union[str, int, None] = None, + separators: Union[tuple[str, str], None] = None, + cls: Union[type[simplejson.JSONEncoder], None] = None, ) -> str: """ Dumps object to compatible JSON format :param obj: The serializable object :param default: function that should return a serializable version of obj + :param allow_nan: when set to True NaN values will be serialized :param ignore_nan: when set to True nan values will be ignored :param sort_keys: when set to True keys will be sorted + :param indent: when set elements and object members will be pretty-printed + :param separators: when specified dumps will use (item_separator, key_separator) + :param cls: custom `JSONEncoder` subclass :returns: String object in the JSON compatible form """ results_string = "" try: results_string = simplejson.dumps( - obj, default=default, ignore_nan=ignore_nan, sort_keys=sort_keys + obj, + default=default, + allow_nan=allow_nan, + ignore_nan=ignore_nan, + sort_keys=sort_keys, + indent=indent, + separators=separators, + cls=cls, ) except UnicodeDecodeError: results_string = simplejson.dumps( # type: ignore[call-overload] obj, default=default, + allow_nan=allow_nan, ignore_nan=ignore_nan, sort_keys=sort_keys, + indent=indent, + separators=separators, + cls=cls, encoding=None, ) return results_string + + +def loads( + obj: Union[bytes, bytearray, str], + encoding: Union[str, None] = None, + allow_nan: bool = False, + object_hook: Union[Callable[[dict[Any, Any]], Any], None] = None, +) -> Any: + """ + deserializable instance to a Python object. + + :param obj: The deserializable object + :param encoding: determines the encoding used to interpret the obj + :param allow_nan: if True it will allow the parser to accept nan values + :param object_hook: function that will be called to decode objects values + :returns: A Python object deserialized from string + """ + try: + return simplejson.loads( + obj, + encoding=encoding, + allow_nan=allow_nan, + object_hook=object_hook, + ) + except JSONDecodeError as ex: + logger.error("JSON is not valid %s", str(ex), exc_info=True) + raise ex diff --git a/superset/utils/lock.py b/superset/utils/lock.py index 7a84278f09..50bfb6d955 100644 --- a/superset/utils/lock.py +++ b/superset/utils/lock.py @@ -17,7 +17,6 @@ from __future__ import annotations -import json import logging import uuid from collections.abc import Iterator @@ -28,6 +27,7 @@ from typing import Any, cast, TypeVar, Union from superset.exceptions import CreateKeyValueDistributedLockFailedException from superset.key_value.exceptions import KeyValueCreateFailedError from superset.key_value.types import KeyValueResource, PickleKeyValueCodec +from superset.utils import json LOCK_EXPIRATION = timedelta(seconds=30) logger = logging.getLogger(__name__) diff --git a/superset/utils/log.py b/superset/utils/log.py index cdf68437e9..4b9ebb50b9 100644 --- a/superset/utils/log.py +++ b/superset/utils/log.py @@ -18,7 +18,6 @@ from __future__ import annotations import functools import inspect -import json import logging import textwrap from abc import ABC, abstractmethod @@ -32,6 +31,7 @@ from flask_appbuilder.const import API_URI_RIS_KEY from sqlalchemy.exc import SQLAlchemyError from superset.extensions import stats_logger_manager +from superset.utils import json from superset.utils.core import get_user_id, LoggerLevel, to_int if TYPE_CHECKING: diff --git a/superset/utils/mock_data.py b/superset/utils/mock_data.py index 5013d0954c..cffa89719d 100644 --- a/superset/utils/mock_data.py +++ b/superset/utils/mock_data.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. import decimal -import json import logging import os import random @@ -36,6 +35,7 @@ from sqlalchemy.sql.visitors import VisitableType from superset import db from superset.sql_parse import Table +from superset.utils import json logger = logging.getLogger(__name__) diff --git a/superset/utils/schema.py b/superset/utils/schema.py index 7fd83d715b..8994b87c1d 100644 --- a/superset/utils/schema.py +++ b/superset/utils/schema.py @@ -18,8 +18,7 @@ from typing import Any, Union from marshmallow import validate, ValidationError -from superset.exceptions import SupersetException -from superset.utils import json as json_utils +from superset.utils import json class OneOfCaseInsensitive(validate.OneOf): @@ -49,6 +48,6 @@ def validate_json(value: Union[bytes, bytearray, str]) -> None: :param value: an object that should be parseable to JSON """ try: - json_utils.validate_json(value) - except SupersetException as ex: + json.validate_json(value) + except json.JSONDecodeError as ex: raise ValidationError("JSON not valid") from ex diff --git a/superset/views/api.py b/superset/views/api.py index eef2b72bc7..8ef59cb482 100644 --- a/superset/views/api.py +++ b/superset/views/api.py @@ -18,7 +18,6 @@ from __future__ import annotations from typing import Any, TYPE_CHECKING -import simplejson as json from flask import request from flask_appbuilder import expose from flask_appbuilder.api import rison @@ -33,7 +32,7 @@ from superset.commands.chart.exceptions import ( from superset.legacy import update_time_range from superset.models.slice import Slice from superset.superset_typing import FlaskResponse -from superset.utils import json as json_utils +from superset.utils import json from superset.utils.date_parser import get_since_until from superset.views.base import api, BaseSupersetView, handle_api_exception @@ -73,9 +72,7 @@ class Api(BaseSupersetView): query_context.raise_for_access() result = query_context.get_payload() payload_json = result["queries"] - return json_utils.dumps( - payload_json, default=json_utils.json_int_dttm_ser, ignore_nan=True - ) + return json.dumps(payload_json, default=json.json_int_dttm_ser, ignore_nan=True) @event_logger.log_this @api diff --git a/superset/views/base.py b/superset/views/base.py index 04583387bd..be3af99147 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -83,7 +83,7 @@ from superset.models.helpers import ImportExportMixin from superset.reports.models import ReportRecipientType from superset.superset_typing import FlaskResponse from superset.translations.utils import get_language_pack -from superset.utils import core as utils, json as json_utils +from superset.utils import core as utils, json from superset.utils.filters import get_dataset_access_filters from .utils import bootstrap_user_data @@ -153,9 +153,7 @@ def json_error_response( payload = payload or {"error": f"{msg}"} return Response( - json_utils.dumps( - payload, default=json_utils.json_iso_dttm_ser, ignore_nan=True - ), + json.dumps(payload, default=json.json_iso_dttm_ser, ignore_nan=True), status=status, mimetype="application/json", ) @@ -170,9 +168,7 @@ def json_errors_response( payload["errors"] = [dataclasses.asdict(error) for error in errors] return Response( - json_utils.dumps( - payload, default=json_utils.json_iso_dttm_ser, ignore_nan=True - ), + json.dumps(payload, default=json.json_iso_dttm_ser, ignore_nan=True), status=status, mimetype="application/json; charset=utf-8", ) @@ -294,9 +290,7 @@ class BaseSupersetView(BaseView): @staticmethod def json_response(obj: Any, status: int = 200) -> FlaskResponse: return Response( - json_utils.dumps( - obj, default=json_utils.json_int_dttm_ser, ignore_nan=True - ), + json.dumps(obj, default=json.json_int_dttm_ser, ignore_nan=True), status=status, mimetype="application/json", ) @@ -312,8 +306,8 @@ class BaseSupersetView(BaseView): return self.render_template( "superset/spa.html", entry="spa", - bootstrap_data=json_utils.dumps( - payload, default=json_utils.pessimistic_json_iso_dttm_ser + bootstrap_data=json.dumps( + payload, default=json.pessimistic_json_iso_dttm_ser ), ) @@ -547,9 +541,9 @@ def show_unexpected_exception(ex: Exception) -> FlaskResponse: @superset_app.context_processor def get_common_bootstrap_data() -> dict[str, Any]: def serialize_bootstrap_data() -> str: - return json_utils.dumps( + return json.dumps( {"common": common_bootstrap_payload()}, - default=json_utils.pessimistic_json_iso_dttm_ser, + default=json.pessimistic_json_iso_dttm_ser, ) return {"bootstrap_data": serialize_bootstrap_data} @@ -630,8 +624,8 @@ class SupersetModelView(ModelView): return self.render_template( "superset/spa.html", entry="spa", - bootstrap_data=json_utils.dumps( - payload, default=json_utils.pessimistic_json_iso_dttm_ser + bootstrap_data=json.dumps( + payload, default=json.pessimistic_json_iso_dttm_ser ), ) diff --git a/superset/views/chart/views.py b/superset/views/chart/views.py index e8ea621902..340ded9b0d 100644 --- a/superset/views/chart/views.py +++ b/superset/views/chart/views.py @@ -22,7 +22,7 @@ from superset import security_manager from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod from superset.models.slice import Slice from superset.superset_typing import FlaskResponse -from superset.utils import json as json_utils +from superset.utils import json from superset.views.base import DeleteMixin, DeprecateModelViewMixin, SupersetModelView from superset.views.chart.mixin import SliceMixin @@ -41,10 +41,10 @@ class SliceModelView( method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP def pre_add(self, item: "SliceModelView") -> None: - json_utils.validate_json(item.params) + json.validate_json(item.params) def pre_update(self, item: "SliceModelView") -> None: - json_utils.validate_json(item.params) + json.validate_json(item.params) security_manager.raise_for_ownership(item) def pre_delete(self, item: "SliceModelView") -> None: diff --git a/superset/views/core.py b/superset/views/core.py index 83dcbf0a0d..5f76b05a78 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -23,7 +23,6 @@ from datetime import datetime from typing import Any, Callable, cast from urllib import parse -import simplejson as json from flask import abort, flash, g, redirect, render_template, request, Response from flask_appbuilder import expose from flask_appbuilder.security.decorators import ( @@ -71,7 +70,7 @@ from superset.models.slice import Slice from superset.models.sql_lab import Query from superset.models.user_attributes import UserAttribute from superset.superset_typing import FlaskResponse -from superset.utils import core as utils, json as json_utils +from superset.utils import core as utils, json from superset.utils.cache import etag_cache from superset.utils.core import ( DatasourceType, @@ -575,8 +574,8 @@ class Superset(BaseSupersetView): return self.render_template( "superset/basic.html", - bootstrap_data=json_utils.dumps( - bootstrap_data, default=json_utils.pessimistic_json_iso_dttm_ser + bootstrap_data=json.dumps( + bootstrap_data, default=json.pessimistic_json_iso_dttm_ser ), entry="explore", title=title, @@ -752,7 +751,7 @@ class Superset(BaseSupersetView): ) return json_success( - json_utils.dumps( + json.dumps( [ { "slice_id" if key == "chart_id" else key: value @@ -764,7 +763,7 @@ class Superset(BaseSupersetView): } for slc in slices ], - default=json_utils.base_json_conv, + default=json.base_json_conv, ), ) @@ -813,12 +812,12 @@ class Superset(BaseSupersetView): "superset/spa.html", entry="spa", title=dashboard.dashboard_title, # dashboard title is always visible - bootstrap_data=json_utils.dumps( + bootstrap_data=json.dumps( { "user": bootstrap_user_data(g.user, include_perms=True), "common": common_bootstrap_payload(), }, - default=json_utils.pessimistic_json_iso_dttm_ser, + default=json.pessimistic_json_iso_dttm_ser, ), standalone_mode=ReservedUrlParameters.is_standalone_mode(), ) @@ -918,8 +917,8 @@ class Superset(BaseSupersetView): return self.render_template( "superset/spa.html", entry="spa", - bootstrap_data=json_utils.dumps( - payload, default=json_utils.pessimistic_json_iso_dttm_ser + bootstrap_data=json.dumps( + payload, default=json.pessimistic_json_iso_dttm_ser ), ) diff --git a/superset/views/dashboard/views.py b/superset/views/dashboard/views.py index 97735b9081..2e88b4acd0 100644 --- a/superset/views/dashboard/views.py +++ b/superset/views/dashboard/views.py @@ -34,7 +34,7 @@ from superset import db, event_logger, is_feature_enabled from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod from superset.models.dashboard import Dashboard as DashboardModel from superset.superset_typing import FlaskResponse -from superset.utils import json as json_utils +from superset.utils import json from superset.views.base import ( BaseSupersetView, common_bootstrap_payload, @@ -159,8 +159,8 @@ class Dashboard(BaseSupersetView): return self.render_template( "superset/spa.html", entry="embedded", - bootstrap_data=json_utils.dumps( - bootstrap_data, default=json_utils.pessimistic_json_iso_dttm_ser + bootstrap_data=json.dumps( + bootstrap_data, default=json.pessimistic_json_iso_dttm_ser ), ) diff --git a/superset/views/datasource/views.py b/superset/views/datasource/views.py index 27371a5d2e..89907df000 100644 --- a/superset/views/datasource/views.py +++ b/superset/views/datasource/views.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from collections import Counter from typing import Any @@ -39,6 +38,7 @@ from superset.exceptions import SupersetException, SupersetSecurityException from superset.models.core import Database from superset.sql_parse import Table from superset.superset_typing import FlaskResponse +from superset.utils import json from superset.utils.core import DatasourceType from superset.views.base import ( api, diff --git a/superset/views/key_value.py b/superset/views/key_value.py index e4d41cb2eb..3ba53073c7 100644 --- a/superset/views/key_value.py +++ b/superset/views/key_value.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import simplejson as json from flask import request, Response from flask_appbuilder import expose from flask_appbuilder.hooks import before_request @@ -24,7 +23,7 @@ from werkzeug.exceptions import NotFound from superset import db, event_logger, is_feature_enabled from superset.models import core as models from superset.superset_typing import FlaskResponse -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.views.base import BaseSupersetView, deprecated, json_error_response diff --git a/superset/views/sql_lab/views.py b/superset/views/sql_lab/views.py index b2c0509591..693299118d 100644 --- a/superset/views/sql_lab/views.py +++ b/superset/views/sql_lab/views.py @@ -16,7 +16,6 @@ # under the License. import logging -import simplejson as json from flask import request, Response from flask_appbuilder import expose from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -28,7 +27,7 @@ from superset import db from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod from superset.models.sql_lab import Query, SavedQuery, TableSchema, TabState from superset.superset_typing import FlaskResponse -from superset.utils import json as json_utils +from superset.utils import json from superset.utils.core import get_user_id from superset.views.base import ( BaseSupersetView, @@ -140,7 +139,7 @@ class TabStateView(BaseSupersetView): if tab_state is None: return Response(status=404) return json_success( - json.dumps(tab_state.to_dict(), default=json_utils.json_iso_dttm_ser) + json.dumps(tab_state.to_dict(), default=json.json_iso_dttm_ser) ) @has_access_api diff --git a/superset/views/sqllab.py b/superset/views/sqllab.py index b4bfa5194f..5677237c48 100644 --- a/superset/views/sqllab.py +++ b/superset/views/sqllab.py @@ -16,7 +16,6 @@ # under the License. import contextlib -import simplejson as json from flask import request from flask_appbuilder import permission_name from flask_appbuilder.api import expose @@ -25,6 +24,7 @@ from flask_appbuilder.security.decorators import has_access from superset import event_logger from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP from superset.superset_typing import FlaskResponse +from superset.utils import json from .base import BaseSupersetView diff --git a/superset/views/tags.py b/superset/views/tags.py index f78b2b5ede..0a161e823f 100644 --- a/superset/views/tags.py +++ b/superset/views/tags.py @@ -26,7 +26,7 @@ from werkzeug.exceptions import NotFound from superset import db, is_feature_enabled from superset.superset_typing import FlaskResponse from superset.tags.models import Tag -from superset.utils import json as json_utils +from superset.utils import json from superset.views.base import SupersetModelView from .base import BaseSupersetView, json_success @@ -74,6 +74,4 @@ class TagView(BaseSupersetView): } for obj in query ] - return json_success( - json_utils.dumps(results, default=json_utils.json_int_dttm_ser) - ) + return json_success(json.dumps(results, default=json.json_int_dttm_ser)) diff --git a/superset/views/utils.py b/superset/views/utils.py index 2d8fcd68da..8c45b774aa 100644 --- a/superset/views/utils.py +++ b/superset/views/utils.py @@ -22,7 +22,6 @@ from typing import Any, Callable, DefaultDict, Optional, Union import msgpack import pyarrow as pa -import simplejson as json from flask import flash, g, has_request_context, redirect, request from flask_appbuilder.security.sqla import models as ab_models from flask_appbuilder.security.sqla.models import User @@ -47,6 +46,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.models.sql_lab import Query from superset.superset_typing import FormData +from superset.utils import json from superset.utils.core import DatasourceType from superset.utils.decorators import stats_timing from superset.viz import BaseViz diff --git a/superset/viz.py b/superset/viz.py index b06bb42186..43b85a29f2 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -37,7 +37,6 @@ import geohash import numpy as np import pandas as pd import polyline -import simplejson as json from dateutil import relativedelta as rdelta from deprecation import deprecated from flask import request @@ -66,7 +65,7 @@ from superset.superset_typing import ( VizData, VizPayload, ) -from superset.utils import core as utils, csv, json as json_utils +from superset.utils import core as utils, csv, json from superset.utils.cache import set_and_log_cache from superset.utils.core import ( apply_max_row_limit, @@ -440,8 +439,8 @@ class BaseViz: # pylint: disable=too-many-public-methods @deprecated(deprecated_in="3.0") def get_json(self) -> str: - return json_utils.dumps( - self.get_payload(), default=json_utils.json_int_dttm_ser, ignore_nan=True + return json.dumps( + self.get_payload(), default=json.json_int_dttm_ser, ignore_nan=True ) @deprecated(deprecated_in="3.0") @@ -641,9 +640,9 @@ class BaseViz: # pylint: disable=too-many-public-methods @staticmethod @deprecated(deprecated_in="3.0") def json_dumps(query_obj: Any, sort_keys: bool = False) -> str: - return json_utils.dumps( + return json.dumps( query_obj, - default=json_utils.json_int_dttm_ser, + default=json.json_int_dttm_ser, ignore_nan=True, sort_keys=sort_keys, ) diff --git a/tests/integration_tests/advanced_data_type/api_tests.py b/tests/integration_tests/advanced_data_type/api_tests.py index 5080617f07..4e0ad45d89 100644 --- a/tests/integration_tests/advanced_data_type/api_tests.py +++ b/tests/integration_tests/advanced_data_type/api_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json import prison from superset.utils.core import get_example_default_schema # noqa: F401 @@ -32,6 +31,7 @@ from superset.advanced_data_type.types import ( AdvancedDataTypeResponse, ) from superset.utils.core import FilterOperator, FilterStringOperators +from superset.utils import json target_resp: AdvancedDataTypeResponse = { diff --git a/tests/integration_tests/annotation_layers/api_tests.py b/tests/integration_tests/annotation_layers/api_tests.py index 20ca2da0f7..49c88ae292 100644 --- a/tests/integration_tests/annotation_layers/api_tests.py +++ b/tests/integration_tests/annotation_layers/api_tests.py @@ -17,14 +17,13 @@ # isort:skip_file """Unit tests for Superset""" -import json - import pytest import prison from sqlalchemy.sql import func import tests.integration_tests.test_app # noqa: F401 from superset import db +from superset.utils import json from superset.models.annotations import Annotation, AnnotationLayer from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/async_events/api_tests.py b/tests/integration_tests/async_events/api_tests.py index e7d40456a1..66aef25c2e 100644 --- a/tests/integration_tests/async_events/api_tests.py +++ b/tests/integration_tests/async_events/api_tests.py @@ -14,11 +14,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from typing import Optional from unittest import mock from superset.extensions import async_query_manager +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME from tests.integration_tests.test_app import app diff --git a/tests/integration_tests/available_domains/api_tests.py b/tests/integration_tests/available_domains/api_tests.py index 8838207d29..8d7ea9ea92 100644 --- a/tests/integration_tests/available_domains/api_tests.py +++ b/tests/integration_tests/available_domains/api_tests.py @@ -14,8 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json - +from superset.utils import json from tests.integration_tests.test_app import app diff --git a/tests/integration_tests/base_api_tests.py b/tests/integration_tests/base_api_tests.py index 1a65ce1668..de003ff945 100644 --- a/tests/integration_tests/base_api_tests.py +++ b/tests/integration_tests/base_api_tests.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. # isort:skip_file -import json from unittest.mock import patch from tests.integration_tests.fixtures.world_bank_dashboard import ( @@ -32,6 +31,7 @@ from superset import db, security_manager from superset.extensions import appbuilder from superset.models.dashboard import Dashboard from superset.views.base_api import BaseSupersetModelRestApi, requires_json # noqa: F401 +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.conftest import with_config diff --git a/tests/integration_tests/base_tests.py b/tests/integration_tests/base_tests.py index b7b3199917..77633d6564 100644 --- a/tests/integration_tests/base_tests.py +++ b/tests/integration_tests/base_tests.py @@ -19,7 +19,6 @@ from datetime import datetime import imp -import json from contextlib import contextmanager from typing import Any, Union, Optional from unittest.mock import Mock, patch, MagicMock @@ -43,6 +42,7 @@ from superset.models.slice import Slice from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.utils.core import get_example_default_schema, shortid +from superset.utils import json from superset.utils.database import get_example_database from superset.views.base_api import BaseSupersetModelRestApi diff --git a/tests/integration_tests/cache_tests.py b/tests/integration_tests/cache_tests.py index b1bf2822f4..88b20282f4 100644 --- a/tests/integration_tests/cache_tests.py +++ b/tests/integration_tests/cache_tests.py @@ -16,13 +16,12 @@ # under the License. """Unit tests for Superset with caching""" -import json - import pytest from superset import app, db # noqa: F401 from superset.common.db_query_status import QueryStatus from superset.extensions import cache_manager +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME from tests.integration_tests.fixtures.birth_names_dashboard import ( diff --git a/tests/integration_tests/charts/api_tests.py b/tests/integration_tests/charts/api_tests.py index 3b28cfbcaa..42df108de9 100644 --- a/tests/integration_tests/charts/api_tests.py +++ b/tests/integration_tests/charts/api_tests.py @@ -16,7 +16,6 @@ # under the License. """Unit tests for Superset""" -import json from io import BytesIO from unittest import mock from zipfile import is_zipfile, ZipFile @@ -38,6 +37,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.reports.models import ReportSchedule, ReportScheduleType from superset.tags.models import ObjectType, Tag, TaggedObject, TagType +from superset.utils import json from superset.utils.core import get_example_default_schema from superset.utils.database import get_example_database # noqa: F401 from superset.viz import viz_types # noqa: F401 diff --git a/tests/integration_tests/charts/commands_tests.py b/tests/integration_tests/charts/commands_tests.py index 3601056fb7..1ee4658b88 100644 --- a/tests/integration_tests/charts/commands_tests.py +++ b/tests/integration_tests/charts/commands_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from unittest.mock import patch import pytest @@ -36,6 +35,7 @@ from superset.commands.importers.exceptions import IncorrectVersionError from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.slice import Slice +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, # noqa: F401 diff --git a/tests/integration_tests/charts/data/api_tests.py b/tests/integration_tests/charts/data/api_tests.py index 6d70a1cd75..58cfd9d494 100644 --- a/tests/integration_tests/charts/data/api_tests.py +++ b/tests/integration_tests/charts/data/api_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json import unittest import copy from datetime import datetime @@ -64,6 +63,7 @@ from superset.utils.core import ( AdhocMetricExpressionType, ExtraFiltersReasonType, ) +from superset.utils import json from superset.utils.database import get_example_database, get_main_database from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType diff --git a/tests/integration_tests/commands_test.py b/tests/integration_tests/commands_test.py index 3215364e80..83409fd022 100644 --- a/tests/integration_tests/commands_test.py +++ b/tests/integration_tests/commands_test.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. import copy -import json import yaml from flask import g @@ -26,6 +25,7 @@ from superset.commands.importers.v1.assets import ImportAssetsCommand from superset.commands.importers.v1.utils import is_valid_config from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.fixtures.importexport import ( chart_config, diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py index ed683c95c5..923fe4a6b9 100644 --- a/tests/integration_tests/core_tests.py +++ b/tests/integration_tests/core_tests.py @@ -19,7 +19,6 @@ import datetime import doctest import html -import json import logging import random import unittest @@ -51,7 +50,7 @@ from superset.models.slice import Slice from superset.models.sql_lab import Query from superset.result_set import SupersetResultSet from superset.sql_parse import Table -from superset.utils import core as utils, json as json_utils +from superset.utils import core as utils, json from superset.utils.core import backend from superset.utils.database import get_example_database from superset.views.database.views import DatabaseView @@ -502,7 +501,7 @@ class TestCore(SupersetTestCase): results = SupersetResultSet(list(data), [["data"]], BaseEngineSpec) df = results.to_pandas_df() data = dataframe.df_to_records(df) - json_str = json.dumps(data, default=json_utils.pessimistic_json_iso_dttm_ser) + json_str = json.dumps(data, default=json.pessimistic_json_iso_dttm_ser) self.assertDictEqual( data[0], {"data": pd.Timestamp("2017-11-18 21:53:00.219225+0100", tz=tz)} ) @@ -943,7 +942,7 @@ class TestCore(SupersetTestCase): encoded = json.dumps( {"FOO": lambda x: 1, "super": "set"}, - default=json_utils.pessimistic_json_iso_dttm_ser, + default=json.pessimistic_json_iso_dttm_ser, ) html_string = ( html.escape(encoded, quote=False) diff --git a/tests/integration_tests/css_templates/api_tests.py b/tests/integration_tests/css_templates/api_tests.py index dfb6f6e90f..27754afd30 100644 --- a/tests/integration_tests/css_templates/api_tests.py +++ b/tests/integration_tests/css_templates/api_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json import pytest import prison from datetime import datetime @@ -28,6 +27,7 @@ import tests.integration_tests.test_app # noqa: F401 from superset import db from superset.models.core import CssTemplate from superset.utils.database import get_example_database # noqa: F401 +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME diff --git a/tests/integration_tests/dashboard_utils.py b/tests/integration_tests/dashboard_utils.py index 98498cac04..1b900ecbcc 100644 --- a/tests/integration_tests/dashboard_utils.py +++ b/tests/integration_tests/dashboard_utils.py @@ -16,7 +16,6 @@ # under the License. """Utils to provide dashboards for tests""" -import json from typing import Optional from pandas import DataFrame # noqa: F401 @@ -26,6 +25,7 @@ from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import DatasourceType, get_example_default_schema diff --git a/tests/integration_tests/dashboards/api_tests.py b/tests/integration_tests/dashboards/api_tests.py index 614524cb2d..bd7e230dbe 100644 --- a/tests/integration_tests/dashboards/api_tests.py +++ b/tests/integration_tests/dashboards/api_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json from io import BytesIO from time import sleep from unittest.mock import ANY, patch @@ -38,6 +37,7 @@ from superset.reports.models import ReportSchedule, ReportScheduleType from superset.models.slice import Slice from superset.tags.models import Tag, TaggedObject, TagType, ObjectType from superset.utils.core import backend, override_user +from superset.utils import json from tests.integration_tests.base_api_tests import ApiOwnersTestCaseMixin from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/dashboards/commands_tests.py b/tests/integration_tests/dashboards/commands_tests.py index 4c199372f9..06edd6c6d0 100644 --- a/tests/integration_tests/dashboards/commands_tests.py +++ b/tests/integration_tests/dashboards/commands_tests.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. import itertools -import json from unittest.mock import MagicMock, patch # noqa: F401 import pytest @@ -36,6 +35,7 @@ from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.fixtures.importexport import ( chart_config, diff --git a/tests/integration_tests/dashboards/dao_tests.py b/tests/integration_tests/dashboards/dao_tests.py index e030a49e2e..83ef02730b 100644 --- a/tests/integration_tests/dashboards/dao_tests.py +++ b/tests/integration_tests/dashboards/dao_tests.py @@ -16,13 +16,13 @@ # under the License. # isort:skip_file import copy -import json import time from unittest.mock import patch import pytest import tests.integration_tests.test_app # pylint: disable=unused-import # noqa: F401 from superset import db, security_manager +from superset.utils import json from superset.daos.dashboard import DashboardDAO from superset.models.dashboard import Dashboard from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/dashboards/filter_state/api_tests.py b/tests/integration_tests/dashboards/filter_state/api_tests.py index e1b622dd17..b050a326d5 100644 --- a/tests/integration_tests/dashboards/filter_state/api_tests.py +++ b/tests/integration_tests/dashboards/filter_state/api_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from unittest.mock import patch # noqa: F401 import pytest @@ -30,6 +29,7 @@ from superset.commands.temporary_cache.entry import Entry from superset.extensions import cache_manager from superset.models.dashboard import Dashboard from superset.temporary_cache.utils import cache_key +from superset.utils import json from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, # noqa: F401 load_world_bank_data, # noqa: F401 diff --git a/tests/integration_tests/dashboards/security/security_dataset_tests.py b/tests/integration_tests/dashboards/security/security_dataset_tests.py index 998c3db417..17a5c477e6 100644 --- a/tests/integration_tests/dashboards/security/security_dataset_tests.py +++ b/tests/integration_tests/dashboards/security/security_dataset_tests.py @@ -16,14 +16,13 @@ # under the License. """Unit tests for Superset""" -import json - import prison import pytest from flask import escape # noqa: F401 from superset import app from superset.daos.dashboard import DashboardDAO +from superset.utils import json from tests.integration_tests.constants import ADMIN_USERNAME, GAMMA_USERNAME from tests.integration_tests.dashboards.base_case import DashboardTestCase from tests.integration_tests.dashboards.consts import * # noqa: F403 diff --git a/tests/integration_tests/dashboards/security/security_rbac_tests.py b/tests/integration_tests/dashboards/security/security_rbac_tests.py index 0718d821b1..797212d516 100644 --- a/tests/integration_tests/dashboards/security/security_rbac_tests.py +++ b/tests/integration_tests/dashboards/security/security_rbac_tests.py @@ -16,7 +16,6 @@ # under the License. """Unit tests for Superset""" -import json from unittest import mock from unittest.mock import patch # noqa: F401 @@ -24,6 +23,7 @@ import pytest from superset.commands.dashboard.exceptions import DashboardForbiddenError from superset.daos.dashboard import DashboardDAO +from superset.utils import json from superset.utils.core import backend, override_user from tests.integration_tests.conftest import with_feature_flags from tests.integration_tests.constants import ( diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py index a6deb942a2..9f9882c99b 100644 --- a/tests/integration_tests/databases/api_tests.py +++ b/tests/integration_tests/databases/api_tests.py @@ -18,7 +18,6 @@ """Unit tests for Superset""" import dataclasses -import json from collections import defaultdict from io import BytesIO from unittest import mock @@ -49,6 +48,7 @@ from superset.errors import SupersetError from superset.models.core import Database, ConfigurationMethod from superset.reports.models import ReportSchedule, ReportScheduleType from superset.utils.database import get_example_database, get_main_database +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME, GAMMA_USERNAME from tests.integration_tests.fixtures.birth_names_dashboard import ( @@ -1013,14 +1013,14 @@ class TestDatabaseApi(SupersetTestCase): response = json.loads(rv.data.decode("utf-8")) expected_response = { "message": { + "extra": [ + "Field cannot be decoded by JSON. Expecting ',' " + "delimiter or ']': line 1 column 5 (char 4)" + ], "masked_encrypted_extra": [ "Field cannot be decoded by JSON. Expecting ':' " "delimiter: line 1 column 15 (char 14)" ], - "extra": [ - "Field cannot be decoded by JSON. Expecting ','" - " delimiter: line 1 column 5 (char 4)" - ], } } self.assertEqual(rv.status_code, 400) diff --git a/tests/integration_tests/databases/commands/upload_test.py b/tests/integration_tests/databases/commands/upload_test.py index 3093782d76..3e0eb55b77 100644 --- a/tests/integration_tests/databases/commands/upload_test.py +++ b/tests/integration_tests/databases/commands/upload_test.py @@ -17,8 +17,6 @@ from __future__ import annotations -import json - import pytest from flask.ctx import AppContext @@ -32,6 +30,7 @@ from superset.commands.database.uploaders.base import UploadCommand from superset.commands.database.uploaders.csv_reader import CSVReader from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database +from superset.utils import json from superset.utils.core import override_user from superset.utils.database import get_or_create_db from tests.integration_tests.conftest import only_postgresql diff --git a/tests/integration_tests/datasets/api_tests.py b/tests/integration_tests/datasets/api_tests.py index 6cc3cc8828..6a879e6995 100644 --- a/tests/integration_tests/datasets/api_tests.py +++ b/tests/integration_tests/datasets/api_tests.py @@ -16,7 +16,6 @@ # under the License. """Unit tests for Superset""" -import json import unittest from io import BytesIO from typing import Optional @@ -43,6 +42,7 @@ from superset.extensions import db, security_manager from superset.models.core import Database from superset.models.slice import Slice from superset.sql_parse import Table +from superset.utils import json from superset.utils.core import backend, get_example_default_schema from superset.utils.database import get_example_database, get_main_database from superset.utils.dict_import_export import export_to_dict diff --git a/tests/integration_tests/datasource/api_tests.py b/tests/integration_tests/datasource/api_tests.py index 044aead80a..5cf29d5755 100644 --- a/tests/integration_tests/datasource/api_tests.py +++ b/tests/integration_tests/datasource/api_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from unittest.mock import ANY, Mock, patch import pytest @@ -22,6 +21,7 @@ import pytest from superset import db, security_manager from superset.connectors.sqla.models import SqlaTable from superset.daos.exceptions import DatasourceTypeNotSupportedError +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME, GAMMA_USERNAME diff --git a/tests/integration_tests/datasource_tests.py b/tests/integration_tests/datasource_tests.py index 716e031e0c..1b7fcb733b 100644 --- a/tests/integration_tests/datasource_tests.py +++ b/tests/integration_tests/datasource_tests.py @@ -16,7 +16,6 @@ # under the License. """Unit tests for Superset""" -import json from contextlib import contextmanager from datetime import datetime, timedelta from unittest import mock @@ -36,6 +35,7 @@ from superset.constants import CacheRegion from superset.daos.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError from superset.exceptions import SupersetGenericDBErrorException from superset.models.core import Database +from superset.utils import json from superset.utils.core import backend, get_example_default_schema # noqa: F401 from superset.utils.database import ( # noqa: F401 get_example_database, diff --git a/tests/integration_tests/dict_import_export_tests.py b/tests/integration_tests/dict_import_export_tests.py index ff25d1b402..2db17a77b5 100644 --- a/tests/integration_tests/dict_import_export_tests.py +++ b/tests/integration_tests/dict_import_export_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json import unittest from uuid import uuid4 @@ -29,6 +28,7 @@ from superset import db from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn from superset.utils.database import get_example_database from superset.utils.dict_import_export import export_to_dict +from superset.utils import json from .base_tests import SupersetTestCase diff --git a/tests/integration_tests/explore/api_tests.py b/tests/integration_tests/explore/api_tests.py index dc410b23f1..730e013f82 100644 --- a/tests/integration_tests/explore/api_tests.py +++ b/tests/integration_tests/explore/api_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from unittest.mock import patch import pytest @@ -27,6 +26,7 @@ from superset.connectors.sqla.models import SqlaTable from superset.explore.exceptions import DatasetAccessDeniedError from superset.extensions import cache_manager from superset.models.slice import Slice +from superset.utils import json from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, # noqa: F401 load_world_bank_data, # noqa: F401 diff --git a/tests/integration_tests/explore/form_data/api_tests.py b/tests/integration_tests/explore/form_data/api_tests.py index 82bd7854bc..6057bb271f 100644 --- a/tests/integration_tests/explore/form_data/api_tests.py +++ b/tests/integration_tests/explore/form_data/api_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from unittest.mock import patch import pytest @@ -27,6 +26,7 @@ from superset.commands.explore.form_data.state import TemporaryExploreState from superset.connectors.sqla.models import SqlaTable from superset.extensions import cache_manager from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import DatasourceType from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, # noqa: F401 diff --git a/tests/integration_tests/explore/form_data/commands_tests.py b/tests/integration_tests/explore/form_data/commands_tests.py index b9ad733014..979d0f2cf0 100644 --- a/tests/integration_tests/explore/form_data/commands_tests.py +++ b/tests/integration_tests/explore/form_data/commands_tests.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. -import json from unittest.mock import patch import pytest @@ -30,6 +29,7 @@ from superset.commands.explore.form_data.update import UpdateFormDataCommand from superset.connectors.sqla.models import SqlaTable from superset.models.slice import Slice from superset.models.sql_lab import Query +from superset.utils import json from superset.utils.core import DatasourceType, get_example_default_schema from superset.utils.database import get_example_database from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/explore/permalink/api_tests.py b/tests/integration_tests/explore/permalink/api_tests.py index 0040619896..a241030612 100644 --- a/tests/integration_tests/explore/permalink/api_tests.py +++ b/tests/integration_tests/explore/permalink/api_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from collections.abc import Iterator from typing import Any from uuid import uuid3 @@ -28,6 +27,7 @@ from superset.key_value.models import KeyValueEntry from superset.key_value.types import KeyValueResource, MarshmallowKeyValueCodec from superset.key_value.utils import decode_permalink_id, encode_permalink_key from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import DatasourceType from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, # noqa: F401 diff --git a/tests/integration_tests/fixtures/tabbed_dashboard.py b/tests/integration_tests/fixtures/tabbed_dashboard.py index 15a871c7ae..d4ddff5796 100644 --- a/tests/integration_tests/fixtures/tabbed_dashboard.py +++ b/tests/integration_tests/fixtures/tabbed_dashboard.py @@ -14,12 +14,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import pytest from superset import db from superset.models.dashboard import Dashboard +from superset.utils import json from superset.utils.core import shortid from tests.integration_tests.dashboards.superset_factory_util import create_dashboard diff --git a/tests/integration_tests/fixtures/world_bank_dashboard.py b/tests/integration_tests/fixtures/world_bank_dashboard.py index 56531d7781..34c718c200 100644 --- a/tests/integration_tests/fixtures/world_bank_dashboard.py +++ b/tests/integration_tests/fixtures/world_bank_dashboard.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json import string from random import choice, randint, random, uniform from typing import Any @@ -29,6 +28,7 @@ from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.utils import json from superset.utils.core import get_example_default_schema from superset.utils.database import get_example_database from tests.integration_tests.dashboard_utils import ( diff --git a/tests/integration_tests/import_export_tests.py b/tests/integration_tests/import_export_tests.py index 8f7352facf..e4c9bff51e 100644 --- a/tests/integration_tests/import_export_tests.py +++ b/tests/integration_tests/import_export_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json import unittest from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, # noqa: F401 @@ -43,6 +42,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.utils.core import DatasourceType, get_example_default_schema from superset.utils.database import get_example_database +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME diff --git a/tests/integration_tests/key_value/commands/create_test.py b/tests/integration_tests/key_value/commands/create_test.py index c16a9da474..b18b9886d6 100644 --- a/tests/integration_tests/key_value/commands/create_test.py +++ b/tests/integration_tests/key_value/commands/create_test.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import pickle import pytest @@ -25,6 +24,7 @@ from flask_appbuilder.security.sqla.models import User from superset.extensions import db from superset.key_value.exceptions import KeyValueCreateFailedError +from superset.utils import json from superset.utils.core import override_user from tests.integration_tests.key_value.commands.fixtures import ( admin, # noqa: F401 diff --git a/tests/integration_tests/key_value/commands/delete_test.py b/tests/integration_tests/key_value/commands/delete_test.py index 141547e56b..ac51fa640b 100644 --- a/tests/integration_tests/key_value/commands/delete_test.py +++ b/tests/integration_tests/key_value/commands/delete_test.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json from typing import TYPE_CHECKING from uuid import UUID @@ -25,6 +24,7 @@ from flask.ctx import AppContext from flask_appbuilder.security.sqla.models import User from superset.extensions import db +from superset.utils import json from tests.integration_tests.key_value.commands.fixtures import ( admin, # noqa: F401 JSON_VALUE, diff --git a/tests/integration_tests/key_value/commands/fixtures.py b/tests/integration_tests/key_value/commands/fixtures.py index 31bcaadea5..c0262124b6 100644 --- a/tests/integration_tests/key_value/commands/fixtures.py +++ b/tests/integration_tests/key_value/commands/fixtures.py @@ -17,7 +17,6 @@ from __future__ import annotations -import json from collections.abc import Generator from typing import TYPE_CHECKING from uuid import UUID @@ -31,6 +30,7 @@ from superset.key_value.types import ( KeyValueResource, PickleKeyValueCodec, ) +from superset.utils import json from tests.integration_tests.test_app import app if TYPE_CHECKING: diff --git a/tests/integration_tests/key_value/commands/get_test.py b/tests/integration_tests/key_value/commands/get_test.py index bf5859dbb7..8ea4ccd87d 100644 --- a/tests/integration_tests/key_value/commands/get_test.py +++ b/tests/integration_tests/key_value/commands/get_test.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import json import uuid from datetime import datetime, timedelta from typing import TYPE_CHECKING @@ -24,6 +23,7 @@ from typing import TYPE_CHECKING from flask.ctx import AppContext from superset.extensions import db +from superset.utils import json from tests.integration_tests.key_value.commands.fixtures import ( ID_KEY, JSON_CODEC, diff --git a/tests/integration_tests/key_value/commands/update_test.py b/tests/integration_tests/key_value/commands/update_test.py index d8922ab2e9..bb434ec3b9 100644 --- a/tests/integration_tests/key_value/commands/update_test.py +++ b/tests/integration_tests/key_value/commands/update_test.py @@ -16,13 +16,13 @@ # under the License. from __future__ import annotations -import json from typing import TYPE_CHECKING from flask.ctx import AppContext from flask_appbuilder.security.sqla.models import User from superset.extensions import db +from superset.utils import json from superset.utils.core import override_user from tests.integration_tests.key_value.commands.fixtures import ( admin, # noqa: F401 diff --git a/tests/integration_tests/key_value/commands/upsert_test.py b/tests/integration_tests/key_value/commands/upsert_test.py index a652c2ce7a..6ff61423f1 100644 --- a/tests/integration_tests/key_value/commands/upsert_test.py +++ b/tests/integration_tests/key_value/commands/upsert_test.py @@ -16,13 +16,13 @@ # under the License. from __future__ import annotations -import json from typing import TYPE_CHECKING from flask.ctx import AppContext from flask_appbuilder.security.sqla.models import User from superset.extensions import db +from superset.utils import json from superset.utils.core import override_user from tests.integration_tests.key_value.commands.fixtures import ( admin, # noqa: F401 diff --git a/tests/integration_tests/log_api_tests.py b/tests/integration_tests/log_api_tests.py index cd55b6270e..fae09754aa 100644 --- a/tests/integration_tests/log_api_tests.py +++ b/tests/integration_tests/log_api_tests.py @@ -18,7 +18,6 @@ """Unit tests for Superset""" from datetime import datetime, timedelta -import json from typing import Optional from unittest.mock import ANY @@ -29,6 +28,7 @@ from unittest.mock import patch from superset import db from superset.models.core import Log from superset.views.log.api import LogRestApi +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.conftest import with_feature_flags # noqa: F401 from tests.integration_tests.constants import ( diff --git a/tests/integration_tests/migrations/7e67aecbf3f1_chart_ds_constraint__tests.py b/tests/integration_tests/migrations/7e67aecbf3f1_chart_ds_constraint__tests.py index 320c3bc210..f1772404dc 100644 --- a/tests/integration_tests/migrations/7e67aecbf3f1_chart_ds_constraint__tests.py +++ b/tests/integration_tests/migrations/7e67aecbf3f1_chart_ds_constraint__tests.py @@ -15,9 +15,10 @@ # specific language governing permissions and limitations # under the License. -import json from importlib import import_module +from superset.utils import json + chart_ds_constraint = import_module( "superset.migrations.versions." "2023-03-27_12-30_7e67aecbf3f1_chart_ds_constraint", ) diff --git a/tests/integration_tests/migrations/ad07e4fdbaba_rm_time_range_endpoints_from_qc_3__test.py b/tests/integration_tests/migrations/ad07e4fdbaba_rm_time_range_endpoints_from_qc_3__test.py index 7d95b65dea..d8db954379 100644 --- a/tests/integration_tests/migrations/ad07e4fdbaba_rm_time_range_endpoints_from_qc_3__test.py +++ b/tests/integration_tests/migrations/ad07e4fdbaba_rm_time_range_endpoints_from_qc_3__test.py @@ -14,9 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from importlib import import_module +from superset.utils import json + rm_time_range_endpoints_from_qc_3 = import_module( "superset.migrations.versions." "2022-04-18_11-20_ad07e4fdbaba_rm_time_range_endpoints_from_qc_3", diff --git a/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py b/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py index e67d87fa13..0fd9276121 100644 --- a/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py +++ b/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py @@ -14,10 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from superset.app import SupersetApp from superset.migrations.shared.migrate_viz import MigrateTreeMap +from superset.utils import json treemap_form_data = """{ "adhoc_filters": [ diff --git a/tests/integration_tests/migrations/fb13d49b72f9_better_filters__tests.py b/tests/integration_tests/migrations/fb13d49b72f9_better_filters__tests.py index 60a6c5e819..28cfd5a7b6 100644 --- a/tests/integration_tests/migrations/fb13d49b72f9_better_filters__tests.py +++ b/tests/integration_tests/migrations/fb13d49b72f9_better_filters__tests.py @@ -14,9 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from importlib import import_module +from superset.utils import json + better_filters = import_module( "superset.migrations.versions." "2018-12-11_22-03_fb13d49b72f9_better_filters", ) diff --git a/tests/integration_tests/model_tests.py b/tests/integration_tests/model_tests.py index df806b04b5..458168009b 100644 --- a/tests/integration_tests/model_tests.py +++ b/tests/integration_tests/model_tests.py @@ -15,8 +15,8 @@ # specific language governing permissions and limitations # under the License. # isort:skip_file -import json from superset.utils.core import DatasourceType +from superset.utils import json import unittest from unittest import mock diff --git a/tests/integration_tests/queries/api_tests.py b/tests/integration_tests/queries/api_tests.py index e38c489436..2819c23b41 100644 --- a/tests/integration_tests/queries/api_tests.py +++ b/tests/integration_tests/queries/api_tests.py @@ -19,7 +19,6 @@ from datetime import datetime, timedelta from unittest import mock -import json import random import string @@ -32,6 +31,7 @@ from superset import db, security_manager from superset.common.db_query_status import QueryStatus from superset.models.core import Database from superset.utils.database import get_example_database, get_main_database +from superset.utils import json from superset.models.sql_lab import Query from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/queries/saved_queries/api_tests.py b/tests/integration_tests/queries/saved_queries/api_tests.py index 7c51bb8b4a..da203a7139 100644 --- a/tests/integration_tests/queries/saved_queries/api_tests.py +++ b/tests/integration_tests/queries/saved_queries/api_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json from datetime import datetime from io import BytesIO from typing import Optional @@ -34,6 +33,7 @@ from superset.models.core import Database from superset.models.core import FavStar from superset.models.sql_lab import SavedQuery from superset.utils.database import get_example_database +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME, GAMMA_SQLLAB_USERNAME diff --git a/tests/integration_tests/reports/api_tests.py b/tests/integration_tests/reports/api_tests.py index 4f63a5ab7e..180ac81e2a 100644 --- a/tests/integration_tests/reports/api_tests.py +++ b/tests/integration_tests/reports/api_tests.py @@ -19,7 +19,6 @@ from datetime import datetime, timedelta from unittest.mock import patch -import json import pytz @@ -42,6 +41,7 @@ from superset.reports.models import ( ReportState, ) from superset.utils.database import get_example_database +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.conftest import with_feature_flags from tests.integration_tests.constants import ADMIN_USERNAME, GAMMA_USERNAME diff --git a/tests/integration_tests/reports/commands_tests.py b/tests/integration_tests/reports/commands_tests.py index fd271b84d6..30d1834852 100644 --- a/tests/integration_tests/reports/commands_tests.py +++ b/tests/integration_tests/reports/commands_tests.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from contextlib import contextmanager from datetime import datetime, timedelta, timezone from typing import Optional @@ -77,6 +76,7 @@ from superset.reports.notifications.exceptions import ( NotificationParamException, ) from superset.tasks.types import ExecutorType +from superset.utils import json from superset.utils.database import get_example_database from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, # noqa: F401 diff --git a/tests/integration_tests/reports/utils.py b/tests/integration_tests/reports/utils.py index 8a7f1db4a6..c963efc840 100644 --- a/tests/integration_tests/reports/utils.py +++ b/tests/integration_tests/reports/utils.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. -import json from contextlib import contextmanager from typing import Any, Optional from uuid import uuid4 @@ -35,6 +34,7 @@ from superset.reports.models import ( ReportScheduleType, ReportState, ) +from superset.utils import json from superset.utils.core import override_user from tests.integration_tests.test_app import app # noqa: F401 from tests.integration_tests.utils import read_fixture diff --git a/tests/integration_tests/security/api_tests.py b/tests/integration_tests/security/api_tests.py index 09e4477c96..1fff519bd4 100644 --- a/tests/integration_tests/security/api_tests.py +++ b/tests/integration_tests/security/api_tests.py @@ -17,8 +17,6 @@ # isort:skip_file """Tests for security api methods""" -import json - import jwt import pytest @@ -27,6 +25,7 @@ from superset import db from superset.daos.dashboard import EmbeddedDashboardDAO from superset.models.dashboard import Dashboard from superset.utils.urls import get_url_host +from superset.utils import json from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.constants import ADMIN_USERNAME, GAMMA_USERNAME from tests.integration_tests.fixtures.birth_names_dashboard import ( diff --git a/tests/integration_tests/security/guest_token_security_tests.py b/tests/integration_tests/security/guest_token_security_tests.py index 1ccd6ed59a..f4a515bb75 100644 --- a/tests/integration_tests/security/guest_token_security_tests.py +++ b/tests/integration_tests/security/guest_token_security_tests.py @@ -16,7 +16,6 @@ # under the License. """Unit tests for Superset""" -import json from unittest.mock import Mock, patch import pytest @@ -29,6 +28,7 @@ from superset.exceptions import SupersetSecurityException from superset.models.dashboard import Dashboard from superset.security.guest_token import GuestTokenResourceType # noqa: F401 from superset.sql_parse import Table # noqa: F401 +from superset.utils import json from superset.utils.core import get_example_default_schema from superset.utils.database import get_example_database from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/security/row_level_security_tests.py b/tests/integration_tests/security/row_level_security_tests.py index 48a95c54dd..2c8a13a71f 100644 --- a/tests/integration_tests/security/row_level_security_tests.py +++ b/tests/integration_tests/security/row_level_security_tests.py @@ -21,7 +21,6 @@ from unittest import mock import pytest from flask import g -import json import prison from superset import db, security_manager, app # noqa: F401 @@ -30,6 +29,7 @@ from superset.security.guest_token import ( GuestTokenResourceType, GuestUser, ) +from superset.utils import json from flask_babel import lazy_gettext as _ # noqa: F401 from flask_appbuilder.models.sqla import filters from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/security_tests.py b/tests/integration_tests/security_tests.py index 5eca7b4a67..5b8e4f2ae0 100644 --- a/tests/integration_tests/security_tests.py +++ b/tests/integration_tests/security_tests.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. # isort:skip_file -import json import inspect import time import unittest @@ -45,6 +44,7 @@ from superset.utils.core import ( get_example_default_schema, override_user, ) +from superset.utils import json from superset.utils.database import get_example_database from superset.utils.urls import get_url_host diff --git a/tests/integration_tests/sql_lab/api_tests.py b/tests/integration_tests/sql_lab/api_tests.py index 0c55dc3329..282a0c993e 100644 --- a/tests/integration_tests/sql_lab/api_tests.py +++ b/tests/integration_tests/sql_lab/api_tests.py @@ -18,7 +18,6 @@ """Unit tests for Superset""" import datetime -import json import random import csv import pandas as pd @@ -35,7 +34,7 @@ from superset import db, sql_lab from superset.common.db_query_status import QueryStatus from superset.models.core import Database # noqa: F401 from superset.utils.database import get_example_database, get_main_database # noqa: F401 -from superset.utils import core as utils +from superset.utils import core as utils, json from superset.models.sql_lab import Query from tests.integration_tests.base_tests import SupersetTestCase diff --git a/tests/integration_tests/sqllab_tests.py b/tests/integration_tests/sqllab_tests.py index 8bbf7023a4..3602097b20 100644 --- a/tests/integration_tests/sqllab_tests.py +++ b/tests/integration_tests/sqllab_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Sql Lab""" -import json from datetime import datetime from textwrap import dedent @@ -45,6 +44,7 @@ from superset.sql_lab import ( ) from superset.sql_parse import CtasMethod from superset.utils.core import backend +from superset.utils import json from superset.utils.json import datetime_to_epoch # noqa: F401 from superset.utils.database import get_example_database, get_main_database diff --git a/tests/integration_tests/tags/api_tests.py b/tests/integration_tests/tags/api_tests.py index b62ee11a2b..3f6e499449 100644 --- a/tests/integration_tests/tags/api_tests.py +++ b/tests/integration_tests/tags/api_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset""" -import json import prison from datetime import datetime @@ -40,6 +39,7 @@ from superset import db, security_manager # noqa: F401 from superset.common.db_query_status import QueryStatus # noqa: F401 from superset.models.core import Database # noqa: F401 from superset.utils.database import get_example_database, get_main_database # noqa: F401 +from superset.utils import json from superset.tags.models import ObjectType, Tag, TagType, TaggedObject from tests.integration_tests.constants import ADMIN_USERNAME, ALPHA_USERNAME from tests.integration_tests.fixtures.birth_names_dashboard import ( diff --git a/tests/integration_tests/thumbnails_tests.py b/tests/integration_tests/thumbnails_tests.py index 623f69d88f..cbab3f84f9 100644 --- a/tests/integration_tests/thumbnails_tests.py +++ b/tests/integration_tests/thumbnails_tests.py @@ -17,7 +17,6 @@ # from superset import db # from superset.models.dashboard import Dashboard -import json import urllib.request from io import BytesIO from unittest import skipUnless @@ -32,6 +31,7 @@ from superset.extensions import machine_auth_provider_factory from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.tasks.types import ExecutorType +from superset.utils import json from superset.utils.screenshots import ChartScreenshot, DashboardScreenshot from superset.utils.urls import get_url_path from superset.utils.webdriver import WebDriverSelenium diff --git a/tests/integration_tests/users/api_tests.py b/tests/integration_tests/users/api_tests.py index e4fc7ddd77..4153a5bd08 100644 --- a/tests/integration_tests/users/api_tests.py +++ b/tests/integration_tests/users/api_tests.py @@ -17,11 +17,10 @@ # type: ignore """Unit tests for Superset""" -import json from unittest.mock import patch from superset import security_manager -from superset.utils import slack # noqa: F401 +from superset.utils import json, slack # noqa: F401 from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.conftest import with_config from tests.integration_tests.constants import ADMIN_USERNAME diff --git a/tests/integration_tests/utils/__init__.py b/tests/integration_tests/utils/__init__.py index d493d5b634..c00f4379ae 100644 --- a/tests/integration_tests/utils/__init__.py +++ b/tests/integration_tests/utils/__init__.py @@ -14,9 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from os import path +from superset.utils import json + FIXTURES_DIR = "tests/integration_tests/fixtures" diff --git a/tests/integration_tests/utils_tests.py b/tests/integration_tests/utils_tests.py index 8916d30631..cbdea3f60b 100644 --- a/tests/integration_tests/utils_tests.py +++ b/tests/integration_tests/utils_tests.py @@ -18,7 +18,6 @@ import uuid from datetime import date, datetime, time, timedelta from decimal import Decimal -import json import os import re from typing import Any, Optional @@ -66,13 +65,7 @@ from superset.utils.core import ( zlib_decompress, DateColumn, ) -from superset.utils.json import ( - base_json_conv, - format_timedelta, - json_int_dttm_ser, - json_iso_dttm_ser, - validate_json, -) +from superset.utils import json from superset.utils.database import get_or_create_db from superset.utils import schema from superset.utils.hashing import md5_sha_from_str @@ -91,49 +84,49 @@ class TestUtils(SupersetTestCase): def test_json_int_dttm_ser(self): dttm = datetime(2020, 1, 1) ts = 1577836800000.0 - assert json_int_dttm_ser(dttm) == ts - assert json_int_dttm_ser(date(2020, 1, 1)) == ts - assert json_int_dttm_ser(datetime(1970, 1, 1)) == 0 - assert json_int_dttm_ser(date(1970, 1, 1)) == 0 - assert json_int_dttm_ser(dttm + timedelta(milliseconds=1)) == (ts + 1) - assert json_int_dttm_ser(np.int64(1)) == 1 + assert json.json_int_dttm_ser(dttm) == ts + assert json.json_int_dttm_ser(date(2020, 1, 1)) == ts + assert json.json_int_dttm_ser(datetime(1970, 1, 1)) == 0 + assert json.json_int_dttm_ser(date(1970, 1, 1)) == 0 + assert json.json_int_dttm_ser(dttm + timedelta(milliseconds=1)) == (ts + 1) + assert json.json_int_dttm_ser(np.int64(1)) == 1 with self.assertRaises(TypeError): - json_int_dttm_ser(np.datetime64()) + json.json_int_dttm_ser(np.datetime64()) def test_json_iso_dttm_ser(self): dttm = datetime(2020, 1, 1) dt = date(2020, 1, 1) t = time() - assert json_iso_dttm_ser(dttm) == dttm.isoformat() - assert json_iso_dttm_ser(dt) == dt.isoformat() - assert json_iso_dttm_ser(t) == t.isoformat() - assert json_iso_dttm_ser(np.int64(1)) == 1 + assert json.json_iso_dttm_ser(dttm) == dttm.isoformat() + assert json.json_iso_dttm_ser(dt) == dt.isoformat() + assert json.json_iso_dttm_ser(t) == t.isoformat() + assert json.json_iso_dttm_ser(np.int64(1)) == 1 assert ( - json_iso_dttm_ser(np.datetime64(), pessimistic=True) + json.json_iso_dttm_ser(np.datetime64(), pessimistic=True) == "Unserializable []" ) with self.assertRaises(TypeError): - json_iso_dttm_ser(np.datetime64()) + json.json_iso_dttm_ser(np.datetime64()) def test_base_json_conv(self): - assert isinstance(base_json_conv(np.bool_(1)), bool) - assert isinstance(base_json_conv(np.int64(1)), int) - assert isinstance(base_json_conv(np.array([1, 2, 3])), list) - assert base_json_conv(np.array(None)) is None - assert isinstance(base_json_conv({1}), list) - assert isinstance(base_json_conv(Decimal("1.0")), float) - assert isinstance(base_json_conv(uuid.uuid4()), str) - assert isinstance(base_json_conv(time()), str) - assert isinstance(base_json_conv(timedelta(0)), str) - assert isinstance(base_json_conv(b""), str) - assert isinstance(base_json_conv(b"\xff\xfe"), str) - assert base_json_conv(b"\xff") == "[bytes]" + assert isinstance(json.base_json_conv(np.bool_(1)), bool) + assert isinstance(json.base_json_conv(np.int64(1)), int) + assert isinstance(json.base_json_conv(np.array([1, 2, 3])), list) + assert json.base_json_conv(np.array(None)) is None + assert isinstance(json.base_json_conv({1}), list) + assert isinstance(json.base_json_conv(Decimal("1.0")), float) + assert isinstance(json.base_json_conv(uuid.uuid4()), str) + assert isinstance(json.base_json_conv(time()), str) + assert isinstance(json.base_json_conv(timedelta(0)), str) + assert isinstance(json.base_json_conv(b""), str) + assert isinstance(json.base_json_conv(b"\xff\xfe"), str) + assert json.base_json_conv(b"\xff") == "[bytes]" with pytest.raises(TypeError): - base_json_conv(np.datetime64()) + json.base_json_conv(np.datetime64()) def test_zlib_compression(self): json_str = '{"test": 1}' @@ -574,24 +567,26 @@ class TestUtils(SupersetTestCase): ) def test_format_timedelta(self): - self.assertEqual(format_timedelta(timedelta(0)), "0:00:00") - self.assertEqual(format_timedelta(timedelta(days=1)), "1 day, 0:00:00") - self.assertEqual(format_timedelta(timedelta(minutes=-6)), "-0:06:00") + self.assertEqual(json.format_timedelta(timedelta(0)), "0:00:00") + self.assertEqual(json.format_timedelta(timedelta(days=1)), "1 day, 0:00:00") + self.assertEqual(json.format_timedelta(timedelta(minutes=-6)), "-0:06:00") self.assertEqual( - format_timedelta(timedelta(0) - timedelta(days=1, hours=5, minutes=6)), + json.format_timedelta(timedelta(0) - timedelta(days=1, hours=5, minutes=6)), "-1 day, 5:06:00", ) self.assertEqual( - format_timedelta(timedelta(0) - timedelta(days=16, hours=4, minutes=3)), + json.format_timedelta( + timedelta(0) - timedelta(days=16, hours=4, minutes=3) + ), "-16 days, 4:03:00", ) def test_validate_json(self): valid = '{"a": 5, "b": [1, 5, ["g", "h"]]}' - self.assertIsNone(validate_json(valid)) + self.assertIsNone(json.validate_json(valid)) invalid = '{"a": 5, "b": [1, 5, ["g", "h]]}' - with self.assertRaises(SupersetException): - validate_json(invalid) + with self.assertRaises(json.JSONDecodeError): + json.validate_json(invalid) def test_convert_legacy_filters_into_adhoc_where(self): form_data = {"where": "a = 1"} diff --git a/tests/unit_tests/charts/commands/importers/v1/utils_test.py b/tests/unit_tests/charts/commands/importers/v1/utils_test.py index de3f805d8b..754742e0dc 100644 --- a/tests/unit_tests/charts/commands/importers/v1/utils_test.py +++ b/tests/unit_tests/charts/commands/importers/v1/utils_test.py @@ -15,9 +15,8 @@ # specific language governing permissions and limitations # under the License. -import json - from superset.commands.chart.importers.v1.utils import migrate_chart +from superset.utils import json def test_migrate_chart_area() -> None: diff --git a/tests/unit_tests/databases/api_test.py b/tests/unit_tests/databases/api_test.py index 86c20935d7..43bc085405 100644 --- a/tests/unit_tests/databases/api_test.py +++ b/tests/unit_tests/databases/api_test.py @@ -19,7 +19,6 @@ from __future__ import annotations -import json from datetime import datetime from io import BytesIO from typing import Any @@ -41,6 +40,7 @@ from superset.db_engine_specs.sqlite import SqliteEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetSecurityException from superset.sql_parse import Table +from superset.utils import json from tests.unit_tests.fixtures.common import ( create_columnar_file, create_csv_file, diff --git a/tests/unit_tests/databases/commands/importers/v1/import_test.py b/tests/unit_tests/databases/commands/importers/v1/import_test.py index ad18f0157c..bf1237cd9e 100644 --- a/tests/unit_tests/databases/commands/importers/v1/import_test.py +++ b/tests/unit_tests/databases/commands/importers/v1/import_test.py @@ -17,7 +17,6 @@ # pylint: disable=unused-argument, import-outside-toplevel, invalid-name import copy -import json import pytest from pytest_mock import MockFixture @@ -25,6 +24,7 @@ from sqlalchemy.orm.session import Session from superset import db from superset.commands.exceptions import ImportFailedError +from superset.utils import json def test_import_database(mocker: MockFixture, session: Session) -> None: diff --git a/tests/unit_tests/datasets/commands/export_test.py b/tests/unit_tests/datasets/commands/export_test.py index 9104e5b76e..0dc01ed3e9 100644 --- a/tests/unit_tests/datasets/commands/export_test.py +++ b/tests/unit_tests/datasets/commands/export_test.py @@ -16,11 +16,10 @@ # under the License. # pylint: disable=import-outside-toplevel, unused-argument, unused-import -import json - from sqlalchemy.orm.session import Session from superset import db +from superset.utils import json def test_export(session: Session) -> None: diff --git a/tests/unit_tests/datasets/commands/importers/v1/import_test.py b/tests/unit_tests/datasets/commands/importers/v1/import_test.py index 6c306007d3..97fef4866f 100644 --- a/tests/unit_tests/datasets/commands/importers/v1/import_test.py +++ b/tests/unit_tests/datasets/commands/importers/v1/import_test.py @@ -17,7 +17,6 @@ # pylint: disable=import-outside-toplevel, unused-argument, unused-import, invalid-name import copy -import json import re import uuid from typing import Any @@ -33,6 +32,7 @@ from superset.commands.dataset.exceptions import ( DatasetForbiddenDataURI, ) from superset.commands.dataset.importers.v1.utils import validate_data_uri +from superset.utils import json def test_import_dataset(mocker: MockFixture, session: Session) -> None: diff --git a/tests/unit_tests/db_engine_specs/test_bigquery.py b/tests/unit_tests/db_engine_specs/test_bigquery.py index 13eecda09c..b96c92f328 100644 --- a/tests/unit_tests/db_engine_specs/test_bigquery.py +++ b/tests/unit_tests/db_engine_specs/test_bigquery.py @@ -17,7 +17,6 @@ # pylint: disable=line-too-long, import-outside-toplevel, protected-access, invalid-name -import json from datetime import datetime from typing import Optional @@ -30,6 +29,7 @@ from sqlalchemy_bigquery import BigQueryDialect from superset.sql_parse import Table from superset.superset_typing import ResultSetColumnType +from superset.utils import json from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm # noqa: F401 diff --git a/tests/unit_tests/db_engine_specs/test_databricks.py b/tests/unit_tests/db_engine_specs/test_databricks.py index 204faed445..77d7313dc7 100644 --- a/tests/unit_tests/db_engine_specs/test_databricks.py +++ b/tests/unit_tests/db_engine_specs/test_databricks.py @@ -16,7 +16,6 @@ # under the License. # pylint: disable=unused-argument, import-outside-toplevel, protected-access -import json from datetime import datetime from typing import Optional @@ -25,6 +24,7 @@ from pytest_mock import MockerFixture from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.utils import json from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm # noqa: F401 diff --git a/tests/unit_tests/db_engine_specs/test_duckdb.py b/tests/unit_tests/db_engine_specs/test_duckdb.py index 37b8dd0074..7fc3416c81 100644 --- a/tests/unit_tests/db_engine_specs/test_duckdb.py +++ b/tests/unit_tests/db_engine_specs/test_duckdb.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. -import json from datetime import datetime from typing import Optional @@ -23,6 +22,7 @@ import pytest from pytest_mock import MockerFixture from superset.config import VERSION_STRING +from superset.utils import json from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm # noqa: F401 diff --git a/tests/unit_tests/db_engine_specs/test_gsheets.py b/tests/unit_tests/db_engine_specs/test_gsheets.py index b3d754a24e..caa5414f9c 100644 --- a/tests/unit_tests/db_engine_specs/test_gsheets.py +++ b/tests/unit_tests/db_engine_specs/test_gsheets.py @@ -17,7 +17,6 @@ # pylint: disable=import-outside-toplevel, invalid-name, line-too-long -import json from typing import TYPE_CHECKING from urllib.parse import parse_qs, urlparse @@ -30,6 +29,7 @@ from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetException from superset.sql_parse import Table from superset.superset_typing import OAuth2ClientConfig +from superset.utils import json from superset.utils.oauth2 import decode_oauth2_state if TYPE_CHECKING: diff --git a/tests/unit_tests/db_engine_specs/test_snowflake.py b/tests/unit_tests/db_engine_specs/test_snowflake.py index dbbd58f000..67ac88f695 100644 --- a/tests/unit_tests/db_engine_specs/test_snowflake.py +++ b/tests/unit_tests/db_engine_specs/test_snowflake.py @@ -17,7 +17,6 @@ # pylint: disable=import-outside-toplevel -import json from datetime import datetime from typing import Optional from unittest import mock @@ -27,6 +26,7 @@ from pytest_mock import MockerFixture from sqlalchemy.engine.url import make_url from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.utils import json from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm # noqa: F401 diff --git a/tests/unit_tests/db_engine_specs/test_trino.py b/tests/unit_tests/db_engine_specs/test_trino.py index c783780a45..88608f1e38 100644 --- a/tests/unit_tests/db_engine_specs/test_trino.py +++ b/tests/unit_tests/db_engine_specs/test_trino.py @@ -16,7 +16,6 @@ # under the License. # pylint: disable=unused-argument, import-outside-toplevel, protected-access import copy -import json from datetime import datetime from typing import Any, Optional from unittest.mock import MagicMock, Mock, patch @@ -41,6 +40,7 @@ from superset.db_engine_specs.exceptions import ( ) from superset.sql_parse import Table from superset.superset_typing import ResultSetColumnType, SQLAColumnType, SQLType +from superset.utils import json from superset.utils.core import GenericDataType from tests.unit_tests.db_engine_specs.utils import ( assert_column_spec, diff --git a/tests/unit_tests/importexport/api_test.py b/tests/unit_tests/importexport/api_test.py index ddbe8e2851..f5443450ff 100644 --- a/tests/unit_tests/importexport/api_test.py +++ b/tests/unit_tests/importexport/api_test.py @@ -17,7 +17,6 @@ # pylint: disable=invalid-name, import-outside-toplevel, unused-argument -import json from io import BytesIO from pathlib import Path from typing import Any @@ -26,6 +25,7 @@ from zipfile import is_zipfile, ZipFile from pytest_mock import MockFixture from superset import security_manager +from superset.utils import json def test_export_assets( diff --git a/tests/unit_tests/jinja_context_test.py b/tests/unit_tests/jinja_context_test.py index 441104c424..b53b3537ea 100644 --- a/tests/unit_tests/jinja_context_test.py +++ b/tests/unit_tests/jinja_context_test.py @@ -16,7 +16,6 @@ # under the License. # pylint: disable=invalid-name, unused-argument -import json from typing import Any import pytest @@ -37,6 +36,7 @@ from superset.jinja_context import ( ) from superset.models.core import Database from superset.models.slice import Slice +from superset.utils import json def test_filter_values_adhoc_filters() -> None: diff --git a/tests/unit_tests/migrations/viz/utils.py b/tests/unit_tests/migrations/viz/utils.py index 9da90c853f..d8eeb833e5 100644 --- a/tests/unit_tests/migrations/viz/utils.py +++ b/tests/unit_tests/migrations/viz/utils.py @@ -14,10 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json from typing import Any from superset.migrations.shared.migrate_viz import MigrateViz +from superset.utils import json TIMESERIES_SOURCE_FORM_DATA: dict[str, Any] = { "bottom_margin": 20, diff --git a/tests/unit_tests/models/core_test.py b/tests/unit_tests/models/core_test.py index 5ee521fc0a..e653eee716 100644 --- a/tests/unit_tests/models/core_test.py +++ b/tests/unit_tests/models/core_test.py @@ -16,7 +16,6 @@ # under the License. # pylint: disable=import-outside-toplevel -import json from datetime import datetime import pytest @@ -26,6 +25,7 @@ from sqlalchemy.engine.reflection import Inspector from superset.connectors.sqla.models import SqlaTable, TableColumn from superset.models.core import Database from superset.sql_parse import Table +from superset.utils import json def test_get_metrics(mocker: MockFixture) -> None: diff --git a/tests/unit_tests/queries/dao_test.py b/tests/unit_tests/queries/dao_test.py index dbca78a9d3..3d882cefbf 100644 --- a/tests/unit_tests/queries/dao_test.py +++ b/tests/unit_tests/queries/dao_test.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json +from superset.utils import json def test_column_attributes_on_query(): diff --git a/tests/unit_tests/utils/json_tests.py b/tests/unit_tests/utils/json_tests.py index a3d0a6d9d9..2eb7f7c2a8 100644 --- a/tests/unit_tests/utils/json_tests.py +++ b/tests/unit_tests/utils/json_tests.py @@ -15,30 +15,64 @@ # specific language governing permissions and limitations # under the License. import datetime -import json +import math from unittest.mock import MagicMock import pytest -from superset.exceptions import SupersetException -from superset.utils.json import ( - dumps, - json_iso_dttm_ser, - pessimistic_json_iso_dttm_ser, - validate_json, -) +from superset.utils import json + + +def test_json_loads(): + serialized_data = ( + '{"str": "Hello World", "int": 123456789, "float": 0.12345, "bool": true}' + ) + data = json.loads(serialized_data) + assert data["str"] == "Hello World" + assert data["int"] == 123456789 + assert data["float"] == 0.12345 + assert data["bool"] is True + + +def test_json_loads_exception(): + invalid = '{"a": 5, "b": [1, 5, ["g", "h]]}' + with pytest.raises(json.JSONDecodeError) as excinfo: + json.loads(invalid) + assert ( + str(excinfo.value) + == "Unterminated string starting at: line 1 column 28 (char 27)" + ) + + +def test_json_loads_encoding(): + unicode_data = b'{"a": "\u0073\u0074\u0072"}' + data = json.loads(unicode_data) + assert data["a"] == "str" + utf16_data = b'\xff\xfe{\x00"\x00a\x00"\x00:\x00 \x00"\x00s\x00t\x00r\x00"\x00}\x00' + data = json.loads(utf16_data, encoding="utf-16") + assert data["a"] == "str" + + +def test_json_loads_allow_nan(): + serialized_data = '{"float": NaN}' + with pytest.raises(json.JSONDecodeError) as excinfo: + json.loads(serialized_data) + assert str(excinfo.value) == "Expecting value: line 1 column 11 (char 10)" + data = json.loads(serialized_data, allow_nan=True) + assert isinstance(data, object) + assert math.isnan(data["float"]) is True def test_json_dumps(): data = { - "str": "some string", + "str": "Hello World", "int": 123456789, "float": 0.12345, "bool": True, } - json_str = dumps(data, default=pessimistic_json_iso_dttm_ser) + json_str = json.dumps(data, default=json.pessimistic_json_iso_dttm_ser) reloaded_data = json.loads(json_str) - assert reloaded_data["str"] == "some string" + assert reloaded_data["str"] == "Hello World" assert reloaded_data["int"] == 123456789 assert reloaded_data["float"] == 0.12345 assert reloaded_data["bool"] is True @@ -50,7 +84,7 @@ def test_json_dumps_encoding(): "utf16": b"\xff\xfeH\x00e\x00l\x00l\x00o\x00 \x00W\x00o\x00r\x00l\x00d\x00", "bytes": b"\xff", } - json_str = dumps(data, default=pessimistic_json_iso_dttm_ser) + json_str = json.dumps(data, default=json.pessimistic_json_iso_dttm_ser) reloaded_data = json.loads(json_str) assert reloaded_data["utf8"] == "Hello World" assert reloaded_data["utf16"] == "Hello World" @@ -62,7 +96,7 @@ def test_json_iso_dttm_ser(): "datetime": datetime.datetime(2021, 1, 1, 0, 0, 0), "date": datetime.date(2021, 1, 1), } - json_str = json.dumps(data, default=json_iso_dttm_ser) + json_str = json.dumps(data, default=json.json_iso_dttm_ser) reloaded_data = json.loads(json_str) assert reloaded_data["datetime"] == "2021-01-01T00:00:00" assert reloaded_data["date"] == "2021-01-01" @@ -72,16 +106,14 @@ def test_pessimistic_json_iso_dttm_ser(): data = { "datetime": datetime.datetime(2021, 1, 1, 0, 0, 0), "date": datetime.date(2021, 1, 1), - "UNSERIALIZABLE": MagicMock(), } - json_str = json.dumps(data, default=pessimistic_json_iso_dttm_ser) + json_str = json.dumps(data, default=json.pessimistic_json_iso_dttm_ser) reloaded_data = json.loads(json_str) assert reloaded_data["datetime"] == "2021-01-01T00:00:00" assert reloaded_data["date"] == "2021-01-01" - assert ( - reloaded_data["UNSERIALIZABLE"] - == "Unserializable []" - ) + with pytest.raises(TypeError) as excinfo: + json.dumps({"UNSERIALIZABLE": MagicMock()}) + assert str(excinfo.value) == "_asdict() must return a dict, not MagicMock" def test_pessimistic_json_iso_dttm_ser_nonutf8(): @@ -89,7 +121,7 @@ def test_pessimistic_json_iso_dttm_ser_nonutf8(): "INVALID_UTF8_BYTES": b"\xff", } assert isinstance(data["INVALID_UTF8_BYTES"], bytes) - json_str = json.dumps(data, default=pessimistic_json_iso_dttm_ser) + json_str = json.dumps(data, default=json.pessimistic_json_iso_dttm_ser) reloaded_data = json.loads(json_str) assert reloaded_data["INVALID_UTF8_BYTES"] == "[bytes]" @@ -99,16 +131,18 @@ def test_pessimistic_json_iso_dttm_ser_utf16(): "VALID_UTF16_BYTES": b"\xff\xfeS0\x930k0a0o0\x16NLu", } assert isinstance(data["VALID_UTF16_BYTES"], bytes) - json_str = json.dumps(data, default=pessimistic_json_iso_dttm_ser) + json_str = json.dumps(data, default=json.pessimistic_json_iso_dttm_ser) reloaded_data = json.loads(json_str) assert reloaded_data["VALID_UTF16_BYTES"] == "こんにちは世界" def test_validate_json(): valid = '{"a": 5, "b": [1, 5, ["g", "h"]]}' - assert validate_json(valid) is None - + assert json.validate_json(valid) is None invalid = '{"a": 5, "b": [1, 5, ["g", "h]]}' - with pytest.raises(SupersetException) as excinfo: - validate_json(invalid) - assert str(excinfo.value) == "JSON is not valid" + with pytest.raises(json.JSONDecodeError) as excinfo: + json.validate_json(invalid) + assert ( + str(excinfo.value) + == "Unterminated string starting at: line 1 column 28 (char 27)" + )