Files
superset2/tests/unit_tests/widgets/test_composites.py
T
Enzo MartellucciandClaude Sonnet 5 11935099ff feat(dashboard-v2): add composite control registry with MetricControl
New superset_core.widgets.composites module: a @composite_control
decorator registers a reusable Pydantic BaseModel mixin (with its
title/description) into a read-only, discoverable registry
(list_composite_controls()), mirroring the existing @widget /
superset/widgets/registry.py pattern. Composing a composite control into
a widget's controls_class is plain single inheritance -- the registry is
for docs/MCP discovery, not for composition.

MetricControl is the first composite: a metrics: list[Any] field with
today's DataBinding.metrics description and x-control: metric-multi
extras, moved here verbatim so it can be reused outside DataBinding.
Re-exported from superset_core.widgets via the codebase's existing
redundant-alias idiom.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 22:02:47 +02:00

76 lines
2.5 KiB
Python

# 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.
from __future__ import annotations
from types import MappingProxyType
import pytest
from pydantic import BaseModel
from superset_core.widgets import (
composite_control,
list_composite_controls,
MetricControl,
)
from superset_core.widgets.composites import _registry
def test_metric_control_is_registered() -> None:
info = list_composite_controls()["metric"]
assert info.name == "metric"
assert info.model is MetricControl
def test_metric_control_declares_metric_multi_field() -> None:
schema = MetricControl.model_json_schema()
assert schema["properties"]["metrics"]["x-control"] == "metric-multi"
def test_list_composite_controls_is_read_only() -> None:
result = list_composite_controls()
assert isinstance(result, MappingProxyType)
with pytest.raises(TypeError):
result["metric"] = None # type: ignore[index]
def test_composite_control_registers_new_entry() -> None:
@composite_control(name="test-only", title="Test Only", description="...")
class _TestOnly(BaseModel):
value: int = 0
try:
info = list_composite_controls()["test-only"]
assert info.title == "Test Only"
assert info.model is _TestOnly
finally:
_registry.pop("test-only", None)
def test_composite_control_duplicate_name_raises() -> None:
@composite_control(name="dup-test", title="Dup", description="...")
class _First(BaseModel):
value: int = 0
try:
with pytest.raises(ValueError, match="already registered"):
@composite_control(name="dup-test", title="Dup2", description="...")
class _Second(BaseModel):
value: int = 0
finally:
_registry.pop("dup-test", None)