From ba5d66cb0a8485aaaace56d7c47bc799f77f640e Mon Sep 17 00:00:00 2001 From: Beto Dealmeida Date: Fri, 14 May 2021 14:07:34 -0700 Subject: [PATCH] fix: DB parameter validation (#14636) --- superset/databases/schemas.py | 2 +- superset/exceptions.py | 6 ++++++ tests/databases/api_tests.py | 19 +++++++++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py index 13fdc4309..8251289df 100644 --- a/superset/databases/schemas.py +++ b/superset/databases/schemas.py @@ -278,7 +278,7 @@ class DatabaseValidateParametersSchema(Schema): engine = fields.String(required=True, description="SQLAlchemy engine to use") parameters = fields.Dict( keys=fields.String(), - values=fields.Raw(), + values=fields.Raw(allow_none=True), description="DB-specific parameters for configuration", ) database_name = fields.String( diff --git a/superset/exceptions.py b/superset/exceptions.py index 292681706..cde7c3f44 100644 --- a/superset/exceptions.py +++ b/superset/exceptions.py @@ -14,6 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from collections import defaultdict from typing import Any, Dict, List, Optional from flask_babel import gettext as _ @@ -175,6 +176,11 @@ class InvalidPayloadSchemaError(SupersetErrorException): status = 422 def __init__(self, error: ValidationError): + # dataclasses.asdict does not work with defaultdict, convert to dict + # https://bugs.python.org/issue35540 + for k, v in error.messages.items(): + if isinstance(v, defaultdict): + error.messages[k] = dict(v) error = SupersetError( message="An error happened when validating the request", error_type=SupersetErrorType.INVALID_PAYLOAD_SCHEMA_ERROR, diff --git a/tests/databases/api_tests.py b/tests/databases/api_tests.py index d14f790f9..70234bb5b 100644 --- a/tests/databases/api_tests.py +++ b/tests/databases/api_tests.py @@ -19,6 +19,7 @@ """Unit tests for Superset""" import dataclasses import json +from collections import defaultdict from io import BytesIO from unittest import mock from zipfile import is_zipfile, ZipFile @@ -1369,15 +1370,18 @@ class TestDatabaseApi(SupersetTestCase): url = "api/v1/database/validate_parameters" payload = { "engine": "postgresql", - "parameters": { + "parameters": defaultdict(dict), + } + payload["parameters"].update( + { "host": "", "port": 5432, "username": "", "password": "", "database": "", "query": {}, - }, - } + } + ) rv = self.client.post(url, json=payload) response = json.loads(rv.data.decode("utf-8")) @@ -1409,15 +1413,18 @@ class TestDatabaseApi(SupersetTestCase): url = "api/v1/database/validate_parameters" payload = { "engine": "postgresql", - "parameters": { + "parameters": defaultdict(dict), + } + payload["parameters"].update( + { "host": "localhost", "port": 5432, "username": "", "password": "", "database": "", "query": {}, - }, - } + } + ) rv = self.client.post(url, json=payload) response = json.loads(rv.data.decode("utf-8"))