mirror of
https://github.com/apache/superset.git
synced 2026-06-09 17:49:26 +00:00
Compare commits
2 Commits
fix/helm-r
...
feat/viz-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10bcc8bab5 | ||
|
|
fb484cc932 |
@@ -168,6 +168,12 @@ NATIVE_FILTER_DEFAULT_ROW_LIMIT = 1000
|
||||
# max rows retrieved by filter select auto complete
|
||||
FILTER_SELECT_ROW_LIMIT = 10000
|
||||
|
||||
# Upper bound on the number of entries in user-supplied list fields that each
|
||||
# fan out into one or more additional database queries within a single chart
|
||||
# request, to limit query amplification. Set to 0 to disable a bound.
|
||||
VIZ_TIME_COMPARE_MAX_LIST_SIZE = 10
|
||||
VIZ_DECK_SLICES_MAX_LIST_SIZE = 10
|
||||
|
||||
# SupersetClient HTTP retry configuration
|
||||
# Controls retry behavior for all HTTP requests made through SupersetClient
|
||||
# This helps handle transient server errors (like 502 Bad Gateway) automatically
|
||||
|
||||
@@ -1082,6 +1082,15 @@ class NVD3TimeSeriesViz(NVD3Viz):
|
||||
if not isinstance(time_compare, list):
|
||||
time_compare = [time_compare]
|
||||
|
||||
max_time_compare = current_app.config["VIZ_TIME_COMPARE_MAX_LIST_SIZE"]
|
||||
if max_time_compare and len(time_compare) > max_time_compare:
|
||||
raise QueryObjectValidationError(
|
||||
_(
|
||||
"Too many time comparisons requested; the maximum is %(limit)s.",
|
||||
limit=max_time_compare,
|
||||
)
|
||||
)
|
||||
|
||||
for option in time_compare:
|
||||
query_object = self.query_obj()
|
||||
try:
|
||||
@@ -1664,7 +1673,17 @@ class DeckGLMultiLayer(BaseViz):
|
||||
from superset import db
|
||||
from superset.models.slice import Slice
|
||||
|
||||
slice_ids = self.form_data.get("deck_slices")
|
||||
slice_ids = self.form_data.get("deck_slices") or []
|
||||
if not isinstance(slice_ids, list):
|
||||
slice_ids = []
|
||||
max_deck_slices = current_app.config["VIZ_DECK_SLICES_MAX_LIST_SIZE"]
|
||||
if max_deck_slices and len(slice_ids) > max_deck_slices:
|
||||
raise QueryObjectValidationError(
|
||||
_(
|
||||
"Too many layers requested; the maximum is %(limit)s.",
|
||||
limit=max_deck_slices,
|
||||
)
|
||||
)
|
||||
slices = db.session.query(Slice).filter(Slice.id.in_(slice_ids)).all()
|
||||
|
||||
features: dict[str, list[Any]] = {}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -91,6 +92,56 @@ def test_get_df_payload_captures_generic_exception_as_viz_get_df_error() -> None
|
||||
assert obj.errors[0]["message"] == "boom"
|
||||
|
||||
|
||||
def _datasource() -> SqlaTable:
|
||||
database = Database(database_name="d", sqlalchemy_uri="sqlite://")
|
||||
return SqlaTable(
|
||||
table_name="t",
|
||||
columns=[],
|
||||
metrics=[],
|
||||
main_dttm_col=None,
|
||||
database=database,
|
||||
)
|
||||
|
||||
|
||||
def test_run_extra_queries_rejects_too_many_time_compares() -> None:
|
||||
obj = viz.NVD3TimeSeriesViz(
|
||||
datasource=_datasource(),
|
||||
form_data={
|
||||
"viz_type": "line",
|
||||
"time_compare": [f"{i} days ago" for i in range(11)],
|
||||
},
|
||||
force=True,
|
||||
)
|
||||
with pytest.raises(QueryObjectValidationError, match="Too many time comparisons"):
|
||||
obj.run_extra_queries()
|
||||
|
||||
|
||||
def test_run_extra_queries_allows_time_compare_within_limit() -> None:
|
||||
obj = viz.NVD3TimeSeriesViz(
|
||||
datasource=_datasource(),
|
||||
form_data={"viz_type": "line", "time_compare": ["1 day ago"]},
|
||||
force=True,
|
||||
)
|
||||
query_obj = {"from_dttm": datetime(2021, 1, 2), "to_dttm": datetime(2021, 1, 3)}
|
||||
with (
|
||||
patch.object(viz.NVD3TimeSeriesViz, "query_obj", return_value=query_obj),
|
||||
patch.object(
|
||||
viz.NVD3TimeSeriesViz, "get_df_payload", return_value={"df": None}
|
||||
),
|
||||
):
|
||||
obj.run_extra_queries() # must not raise the limit error
|
||||
|
||||
|
||||
def test_deck_multi_rejects_too_many_slices() -> None:
|
||||
obj = viz.DeckGLMultiLayer(
|
||||
datasource=_datasource(),
|
||||
form_data={"viz_type": "deck_multi", "deck_slices": list(range(11))},
|
||||
force=True,
|
||||
)
|
||||
with pytest.raises(QueryObjectValidationError, match="Too many layers"):
|
||||
obj.get_data(None)
|
||||
|
||||
|
||||
def test_get_df_payload_captures_query_object_validation_error() -> None:
|
||||
"""
|
||||
``QueryObjectValidationError`` is reported as ``VIZ_GET_DF_ERROR``.
|
||||
|
||||
Reference in New Issue
Block a user