Skip to content

Commit 5920e33

Browse files
CopilotAtR1an
authored andcommitted
Replace visible_choices with hidden_choices for clearer semantics
Co-authored-by: AtR1an <12174376+AtR1an@users.noreply.github.com>
1 parent f7d643c commit 5920e33

File tree

2 files changed

+163
-123
lines changed

2 files changed

+163
-123
lines changed

org.knime.python3.nodes.tests/src/test/python/unittest/test_knime_parameter.py

Lines changed: 101 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,64 +1602,64 @@ def test_invalid_assignment_static(self):
16021602

16031603

16041604
class TestModelOptions(kp.EnumParameterOptions):
1605-
"""Test enum for visible_choices testing"""
1605+
"""Test enum for hidden_choices testing"""
16061606

16071607
LINEAR = ("Linear Regression", "Fits a linear model")
16081608
RANDOM_FOREST = ("Random Forest", "Ensemble tree model")
16091609
NEURAL_NET = ("Neural Network", "Deep learning model")
16101610
SVM = ("Support Vector Machine", "SVM model")
16111611

16121612

1613-
class ParameterizedWithVisibleChoices:
1614-
"""Test class for EnumParameter with visible_choices callable"""
1613+
class ParameterizedWithHiddenChoices:
1614+
"""Test class for EnumParameter with hidden_choices callable"""
16151615

16161616
@staticmethod
1617-
def _filter_to_two(ctx):
1618-
"""Filter to only LINEAR and RANDOM_FOREST"""
1619-
return [TestModelOptions.LINEAR, TestModelOptions.RANDOM_FOREST]
1617+
def _hide_two(ctx):
1618+
"""Hide NEURAL_NET and SVM"""
1619+
return [TestModelOptions.NEURAL_NET, TestModelOptions.SVM]
16201620

16211621
@staticmethod
1622-
def _filter_by_specs(ctx):
1623-
"""Filter based on context specs"""
1622+
def _hide_by_specs(ctx):
1623+
"""Hide based on context specs"""
16241624
if ctx is None:
1625-
# No context - return subset (subsetting use-case)
1626-
return [TestModelOptions.LINEAR, TestModelOptions.SVM]
1625+
# No context - hide advanced option (hiding use-case)
1626+
return [TestModelOptions.NEURAL_NET, TestModelOptions.RANDOM_FOREST]
16271627

16281628
specs = ctx.get_input_specs()
16291629
if not specs or len(specs) == 0:
1630-
return list(TestModelOptions)
1630+
return [] # Hide nothing
16311631

16321632
# Simulate filtering based on spec (e.g., spec has 'supported_models' attribute)
16331633
# For testing, we'll use spec count as a proxy
16341634
if len(specs) == 1:
1635-
return [TestModelOptions.LINEAR, TestModelOptions.RANDOM_FOREST]
1636-
else:
16371635
return [TestModelOptions.NEURAL_NET, TestModelOptions.SVM]
1636+
else:
1637+
return [TestModelOptions.LINEAR, TestModelOptions.RANDOM_FOREST]
16381638

16391639
@staticmethod
1640-
def _filter_invalid():
1640+
def _hide_invalid():
16411641
"""Returns invalid members for testing warnings"""
16421642
return ["INVALID_OPTION", TestModelOptions.LINEAR]
16431643

16441644
@staticmethod
1645-
def _filter_empty(ctx):
1646-
"""Returns empty list"""
1645+
def _hide_empty(ctx):
1646+
"""Returns empty list - hide nothing"""
16471647
return []
16481648

16491649
param_filtered = kp.EnumParameter(
16501650
label="Filtered Model",
16511651
description="Model with filtered choices",
16521652
default_value=TestModelOptions.LINEAR.name,
16531653
enum=TestModelOptions,
1654-
visible_choices=_filter_to_two.__func__,
1654+
hidden_choices=_hide_two.__func__,
16551655
)
16561656

16571657
param_context_dependent = kp.EnumParameter(
16581658
label="Context Dependent",
16591659
description="Choices depend on context",
16601660
default_value=TestModelOptions.LINEAR, # Using enum member as default
16611661
enum=TestModelOptions,
1662-
visible_choices=_filter_by_specs.__func__,
1662+
hidden_choices=_hide_by_specs.__func__,
16631663
)
16641664

16651665
param_no_filter = kp.EnumParameter(
@@ -1670,27 +1670,27 @@ def _filter_empty(ctx):
16701670
)
16711671

16721672

1673-
class TestEnumParameterVisibleChoices(unittest.TestCase):
1674-
"""Test EnumParameter visible_choices functionality"""
1673+
class TestEnumParameterHiddenChoices(unittest.TestCase):
1674+
"""Test EnumParameter hidden_choices functionality"""
16751675

16761676
def test_filtered_schema_contains_subset(self):
16771677
"""Test that filtered options appear in schema oneOf"""
1678-
obj = ParameterizedWithVisibleChoices()
1678+
obj = ParameterizedWithHiddenChoices()
16791679
schema = kp.extract_schema(
16801680
obj, dialog_creation_context=DummyDialogCreationContext()
16811681
)
16821682
s = schema["properties"]["model"]["properties"]["param_filtered"]
16831683

16841684
self.assertIn("oneOf", s)
16851685
values = {entry["const"] for entry in s["oneOf"]}
1686-
# Should only contain LINEAR and RANDOM_FOREST
1686+
# Should only contain LINEAR and RANDOM_FOREST (NEURAL_NET and SVM are hidden)
16871687
self.assertEqual(values, {"LINEAR", "RANDOM_FOREST"})
16881688
self.assertNotIn("NEURAL_NET", values)
16891689
self.assertNotIn("SVM", values)
16901690

16911691
def test_no_filter_shows_all_options(self):
1692-
"""Test that parameter without visible_choices shows all options"""
1693-
obj = ParameterizedWithVisibleChoices()
1692+
"""Test that parameter without hidden_choices shows all options"""
1693+
obj = ParameterizedWithHiddenChoices()
16941694
schema = kp.extract_schema(
16951695
obj, dialog_creation_context=DummyDialogCreationContext()
16961696
)
@@ -1702,74 +1702,74 @@ def test_no_filter_shows_all_options(self):
17021702

17031703
def test_context_dependent_filtering(self):
17041704
"""Test that filtering works based on context"""
1705-
obj = ParameterizedWithVisibleChoices()
1705+
obj = ParameterizedWithHiddenChoices()
17061706

1707-
# With one spec
1707+
# With one spec - hide NEURAL_NET and SVM
17081708
ctx_one = DummyDialogCreationContext(specs=[test_schema])
17091709
schema = kp.extract_schema(obj, dialog_creation_context=ctx_one)
17101710
s = schema["properties"]["model"]["properties"]["param_context_dependent"]
17111711
values = {entry["const"] for entry in s["oneOf"]}
17121712
self.assertEqual(values, {"LINEAR", "RANDOM_FOREST"})
17131713

1714-
# With two specs
1714+
# With two specs - hide LINEAR and RANDOM_FOREST
17151715
ctx_two = DummyDialogCreationContext(specs=[test_schema, test_schema])
17161716
schema = kp.extract_schema(obj, dialog_creation_context=ctx_two)
17171717
s = schema["properties"]["model"]["properties"]["param_context_dependent"]
17181718
values = {entry["const"] for entry in s["oneOf"]}
17191719
self.assertEqual(values, {"NEURAL_NET", "SVM"})
17201720

1721-
def test_none_context_subsetting(self):
1722-
"""Test that None context enables subsetting use-case"""
1723-
obj = ParameterizedWithVisibleChoices()
1721+
def test_none_context_hiding(self):
1722+
"""Test that None context enables hiding use-case"""
1723+
obj = ParameterizedWithHiddenChoices()
17241724

17251725
# Extract schema without context
17261726
schema = kp.extract_schema(obj, dialog_creation_context=None)
17271727
s = schema["properties"]["model"]["properties"]["param_context_dependent"]
17281728

17291729
self.assertIn("oneOf", s)
17301730
values = {entry["const"] for entry in s["oneOf"]}
1731-
# Should return subset defined for None case
1731+
# Should hide NEURAL_NET and RANDOM_FOREST (defined for None case)
17321732
self.assertEqual(values, {"LINEAR", "SVM"})
17331733

1734-
def test_description_respects_visible_choices(self):
1735-
"""Test that description respects visible_choices based on None context"""
1734+
def test_description_respects_hidden_choices(self):
1735+
"""Test that description respects hidden_choices based on None context"""
17361736

1737-
# param_filtered uses _filter_to_two which doesn't check context
1737+
# param_filtered uses _hide_two which doesn't check context
17381738
# So description should show only LINEAR and RANDOM_FOREST
1739-
desc_dict = ParameterizedWithVisibleChoices.param_filtered._extract_description(
1739+
desc_dict = ParameterizedWithHiddenChoices.param_filtered._extract_description(
17401740
"param_filtered", None
17411741
)
17421742
description = desc_dict["description"]
17431743

1744-
# Description should contain only filtered options
1744+
# Description should contain only non-hidden options
17451745
self.assertIn("Linear Regression", description)
17461746
self.assertIn("Random Forest", description)
1747-
# Should NOT contain filtered-out options
1747+
# Should NOT contain hidden options
17481748
self.assertNotIn("Neural Network", description)
17491749
self.assertNotIn("Support Vector Machine", description)
17501750

17511751
def test_description_with_context_dependent_filter(self):
17521752
"""Test description with context-dependent filter (None case)"""
17531753

1754-
# param_context_dependent returns subset for None context
1755-
desc_dict = ParameterizedWithVisibleChoices.param_context_dependent._extract_description(
1754+
# param_context_dependent hides NEURAL_NET and RANDOM_FOREST for None context
1755+
desc_dict = ParameterizedWithHiddenChoices.param_context_dependent._extract_description(
17561756
"param_context_dependent", None
17571757
)
17581758
description = desc_dict["description"]
17591759

1760-
# Description should show subset returned for None
1760+
# Description should show non-hidden options
17611761
self.assertIn("Linear Regression", description)
17621762
self.assertIn("Support Vector Machine", description)
1763-
# Should NOT contain other options
1763+
# Should NOT contain hidden options
17641764
self.assertNotIn("Random Forest", description)
17651765
self.assertNotIn("Neural Network", description)
17661766

17671767
def test_description_without_filter_shows_all(self):
17681768
"""Test that description without filter shows all options"""
17691769

1770-
# param_no_filter has no visible_choices
1770+
# param_no_filter has no hidden_choices
17711771
desc_dict = (
1772-
ParameterizedWithVisibleChoices.param_no_filter._extract_description(
1772+
ParameterizedWithHiddenChoices.param_no_filter._extract_description(
17731773
"param_no_filter", None
17741774
)
17751775
)
@@ -1783,12 +1783,12 @@ def test_description_without_filter_shows_all(self):
17831783

17841784
def test_validation_accepts_filtered_out_values(self):
17851785
"""Test that validation accepts any enum member, even if filtered out"""
1786-
obj = ParameterizedWithVisibleChoices()
1786+
obj = ParameterizedWithHiddenChoices()
17871787

17881788
# Extract schema with filtering active
17891789
kp.extract_schema(obj, dialog_creation_context=DummyDialogCreationContext())
17901790

1791-
# NEURAL_NET is filtered out but should still be valid
1791+
# NEURAL_NET is hidden but should still be valid
17921792
obj.param_filtered = "NEURAL_NET"
17931793
self.assertEqual(obj.param_filtered, "NEURAL_NET")
17941794

@@ -1798,46 +1798,39 @@ def test_validation_accepts_filtered_out_values(self):
17981798

17991799
def test_default_as_enum_member(self):
18001800
"""Test that default_value accepts enum member directly"""
1801-
obj = ParameterizedWithVisibleChoices()
1801+
obj = ParameterizedWithHiddenChoices()
18021802

18031803
# param_context_dependent uses enum member as default
18041804
self.assertEqual(obj.param_context_dependent, "LINEAR")
18051805

1806-
def test_empty_filter_result_shows_empty(self):
1807-
"""Test that empty filter result shows no options with warning"""
1806+
def test_empty_filter_result_shows_all(self):
1807+
"""Test that empty filter result shows all options (hide nothing)"""
18081808

18091809
def empty_filter(ctx):
18101810
return []
18111811

18121812
param = kp.EnumParameter(
18131813
label="Empty Filter",
1814-
description="Should be empty",
1814+
description="Should show all",
18151815
default_value=TestModelOptions.LINEAR.name,
18161816
enum=TestModelOptions,
1817-
visible_choices=empty_filter,
1817+
hidden_choices=empty_filter,
18181818
)
18191819

18201820
class TestObj:
18211821
empty_param = param
18221822

18231823
obj = TestObj()
18241824

1825-
# Should log warning and return empty
1826-
with self.assertLogs("Python backend", level="WARNING") as log:
1827-
schema = kp.extract_schema(
1828-
obj, dialog_creation_context=DummyDialogCreationContext()
1829-
)
1830-
1831-
# Check warning was logged
1832-
self.assertTrue(
1833-
any(
1834-
"returned an empty list" in msg or "empty options" in msg
1835-
for msg in log.output
1836-
)
1825+
# Should show all options (no warning expected for empty hide list)
1826+
schema = kp.extract_schema(
1827+
obj, dialog_creation_context=DummyDialogCreationContext()
18371828
)
18381829

18391830
s = schema["properties"]["model"]["properties"]["empty_param"]
1840-
self.assertEqual(s["oneOf"], [])
1831+
values = {entry["const"] for entry in s["oneOf"]}
1832+
# Should show all options
1833+
self.assertEqual(values, {"LINEAR", "RANDOM_FOREST", "NEURAL_NET", "SVM"})
18411834

18421835
def test_invalid_members_filtered_with_warning(self):
18431836
"""Test that invalid members are filtered out with warning"""
@@ -1854,7 +1847,7 @@ class FakeMember:
18541847
description="Has invalid members",
18551848
default_value=TestModelOptions.LINEAR.name,
18561849
enum=TestModelOptions,
1857-
visible_choices=invalid_filter,
1850+
hidden_choices=invalid_filter,
18581851
)
18591852

18601853
class TestObj:
@@ -1873,23 +1866,25 @@ class TestObj:
18731866
self.assertIn("invalid members", warning_msg.lower())
18741867
self.assertIn("Valid options", warning_msg)
18751868

1876-
# Schema should only contain valid member
1869+
# Schema should hide only the valid member (LINEAR)
18771870
s = schema["properties"]["model"]["properties"]["invalid_param"]
18781871
values = {entry["const"] for entry in s["oneOf"]}
1879-
self.assertEqual(values, {"LINEAR"})
1872+
# LINEAR is hidden, others remain visible
1873+
self.assertEqual(values, {"RANDOM_FOREST", "NEURAL_NET", "SVM"})
18801874

18811875
def test_default_not_in_visible_options_warns(self):
18821876
"""Test that warning is logged when default is not in visible options"""
18831877

1884-
def filter_without_default(ctx):
1885-
return [TestModelOptions.RANDOM_FOREST, TestModelOptions.SVM]
1878+
def hide_including_default(ctx):
1879+
# Hide LINEAR (which is the default) and NEURAL_NET
1880+
return [TestModelOptions.LINEAR, TestModelOptions.NEURAL_NET]
18861881

18871882
param = kp.EnumParameter(
18881883
label="Default Not Visible",
1889-
description="Default filtered out",
1890-
default_value=TestModelOptions.LINEAR.name, # Not in visible choices
1884+
description="Default hidden",
1885+
default_value=TestModelOptions.LINEAR.name, # Will be hidden
18911886
enum=TestModelOptions,
1892-
visible_choices=filter_without_default,
1887+
hidden_choices=hide_including_default,
18931888
)
18941889

18951890
class TestObj:
@@ -1906,19 +1901,19 @@ class TestObj:
19061901
self.assertIn("not in the currently visible options", warning_msg)
19071902

19081903
def test_caching_works(self):
1909-
"""Test that visible_choices callable is cached per context"""
1904+
"""Test that hidden_choices callable is cached per context"""
19101905
call_count = [0]
19111906

19121907
def counting_filter(ctx):
19131908
call_count[0] += 1
1914-
return [TestModelOptions.LINEAR, TestModelOptions.SVM]
1909+
return [TestModelOptions.NEURAL_NET, TestModelOptions.SVM]
19151910

19161911
param = kp.EnumParameter(
19171912
label="Cached",
19181913
description="Should cache",
19191914
default_value=TestModelOptions.LINEAR.name,
19201915
enum=TestModelOptions,
1921-
visible_choices=counting_filter,
1916+
hidden_choices=counting_filter,
19221917
)
19231918

19241919
class TestObj:
@@ -1936,6 +1931,38 @@ class TestObj:
19361931
# generation, and the result is cached after the first call
19371932
self.assertEqual(call_count[0], 1)
19381933

1934+
def test_hiding_all_options_shows_empty(self):
1935+
"""Test that hiding all options results in empty list with warning"""
1936+
1937+
def hide_all(ctx):
1938+
return list(TestModelOptions)
1939+
1940+
param = kp.EnumParameter(
1941+
label="Hide All",
1942+
description="All hidden",
1943+
default_value=TestModelOptions.LINEAR.name,
1944+
enum=TestModelOptions,
1945+
hidden_choices=hide_all,
1946+
)
1947+
1948+
class TestObj:
1949+
hide_all_param = param
1950+
1951+
obj = TestObj()
1952+
1953+
# Should log warning about hiding all options
1954+
with self.assertLogs("Python backend", level="WARNING") as log:
1955+
schema = kp.extract_schema(
1956+
obj, dialog_creation_context=DummyDialogCreationContext()
1957+
)
1958+
1959+
# Check warning was logged
1960+
warning_msg = " ".join(log.output)
1961+
self.assertIn("would hide all options", warning_msg.lower())
1962+
1963+
s = schema["properties"]["model"]["properties"]["hide_all_param"]
1964+
self.assertEqual(s["oneOf"], [])
1965+
19391966

19401967
class DummyDialogCreationContext:
19411968
def __init__(self, specs: List = None) -> None:

0 commit comments

Comments
 (0)