Skip to content

Commit 2b22d8c

Browse files
authored
Introduce a dedicated validate_properties() method in plugin API (#107)
* Introduce a dedicated `validate_properties()` method in plugin API * Merge the obsolete `BasePluginLoader._get_configs()` helper * Change the API to a single-property `validate_property()` Given that the benefit (if any) from validating all properties at once is minimal, change the protocol to much simpler `validate_property()` method. This avoids problems with custom property types that aren't suitable as `dict` keys, as well as the more general problem of "what if dict contains different keys than the properties we've given it".
1 parent 9f49349 commit 2b22d8c

File tree

12 files changed

+164
-303
lines changed

12 files changed

+164
-303
lines changed

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ show = "variantlib.commands.config.show:show"
7676

7777
[project.entry-points."variantlib.actions.plugins"]
7878
list = "variantlib.commands.plugins.list_plugins:list_plugins"
79-
get-all-configs = "variantlib.commands.plugins.get_all_configs:get_all_configs"
8079
get-supported-configs = "variantlib.commands.plugins.get_supported_configs:get_supported_configs"
8180

8281
[tool.pytest.ini_options]
Binary file not shown.

tests/artifacts/test-plugin-package/test_plugin_package.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@ class FeatConfig:
1717
dynamic = False
1818

1919

20-
def get_all_configs(known_properties: frozenset[VariantPropertyType] | None) -> list[FeatConfig]:
21-
assert known_properties is None
22-
return [
23-
FeatConfig("feat1", ["val1a", "val1b", "val1c"]),
24-
FeatConfig("feat2", ["val2a", "val2b"]),
25-
]
26-
27-
28-
def get_supported_configs(known_properties: frozenset[VariantPropertyType] | None) -> list[FeatConfig]:
20+
def validate_property(
21+
variant_property: VariantPropertyType,
22+
) -> bool:
23+
assert variant_property.namespace == namespace
24+
return (
25+
(variant_property.feature == "feat1" and variant_property.value in ["val1a", "val1b", "val1c"])
26+
or (variant_property.feature == "feat2" and variant_property.value in ["val2a", "val2b"])
27+
)
28+
29+
30+
def get_supported_configs(
31+
known_properties: frozenset[VariantPropertyType] | None,
32+
) -> list[FeatConfig]:
2933
assert known_properties is None
3034
return [
3135
FeatConfig("feat1", ["val1c", "val1b"]),

tests/commands/test_plugins.py

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,62 +23,6 @@ def test_plugins_list(
2323
)
2424

2525

26-
def test_plugins_get_all_configs(
27-
capsys: pytest.CaptureFixture[str],
28-
mocked_entry_points: None,
29-
) -> None:
30-
main(["plugins", "get-all-configs"])
31-
assert (
32-
capsys.readouterr().out
33-
== """\
34-
incompatible_namespace :: flag1 :: on
35-
incompatible_namespace :: flag2 :: on
36-
incompatible_namespace :: flag3 :: on
37-
incompatible_namespace :: flag4 :: on
38-
second_namespace :: name3 :: val3a
39-
second_namespace :: name3 :: val3b
40-
second_namespace :: name3 :: val3c
41-
test_namespace :: name1 :: val1a
42-
test_namespace :: name1 :: val1b
43-
test_namespace :: name1 :: val1c
44-
test_namespace :: name1 :: val1d
45-
test_namespace :: name2 :: val2a
46-
test_namespace :: name2 :: val2b
47-
test_namespace :: name2 :: val2c
48-
"""
49-
)
50-
51-
52-
def test_plugins_get_all_configs_filter_namespace(
53-
capsys: pytest.CaptureFixture[str],
54-
mocked_entry_points: None,
55-
) -> None:
56-
main(["plugins", "get-all-configs", "-n", "second_namespace"])
57-
assert (
58-
capsys.readouterr().out
59-
== """\
60-
second_namespace :: name3 :: val3a
61-
second_namespace :: name3 :: val3b
62-
second_namespace :: name3 :: val3c
63-
"""
64-
)
65-
66-
67-
def test_plugins_get_all_configs_filter_feature(
68-
capsys: pytest.CaptureFixture[str],
69-
mocked_entry_points: None,
70-
) -> None:
71-
main(["plugins", "get-all-configs", "-f", "name2"])
72-
assert (
73-
capsys.readouterr().out
74-
== """\
75-
test_namespace :: name2 :: val2a
76-
test_namespace :: name2 :: val2b
77-
test_namespace :: name2 :: val2c
78-
"""
79-
)
80-
81-
8226
def test_plugins_get_supported_configs(
8327
capsys: pytest.CaptureFixture[str],
8428
mocked_entry_points: None,

tests/mocked_plugin_as_module.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
from argparse import Namespace
43
from typing import TYPE_CHECKING
54

65
if TYPE_CHECKING:
@@ -12,11 +11,14 @@
1211
dynamic = False
1312

1413

15-
def get_all_configs(
16-
known_properties: frozenset[VariantPropertyType] | None,
17-
) -> list[VariantFeatureConfigType]:
18-
assert known_properties is None
19-
return [Namespace(name="feature", values=["a", "b"])]
14+
def validate_property(
15+
variant_property: VariantPropertyType,
16+
) -> bool:
17+
assert variant_property.namespace == namespace
18+
return variant_property.feature == "feature" and variant_property.value in [
19+
"a",
20+
"b",
21+
]
2022

2123

2224
def get_supported_configs(

tests/mocked_plugins.py

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ class MockedPluginA(PluginType):
2020
namespace = "test_namespace" # pyright: ignore[reportAssignmentType,reportIncompatibleMethodOverride]
2121
dynamic = False # pyright: ignore[reportAssignmentType,reportIncompatibleMethodOverride]
2222

23-
def get_all_configs(
24-
self, known_properties: frozenset[VariantPropertyType] | None
25-
) -> list[VariantFeatureConfigType]:
26-
assert known_properties is None
27-
return [
28-
VariantFeatureConfig("name1", ["val1a", "val1b", "val1c", "val1d"]),
29-
VariantFeatureConfig("name2", ["val2a", "val2b", "val2c"]),
30-
]
23+
def validate_property(self, variant_property: VariantPropertyType) -> bool:
24+
assert variant_property.namespace == self.namespace
25+
return (
26+
variant_property.feature == "name1"
27+
and variant_property.value in ["val1a", "val1b", "val1c", "val1d"]
28+
) or (
29+
variant_property.feature == "name2"
30+
and variant_property.value in ["val2a", "val2b", "val2c"]
31+
)
3132

3233
def get_supported_configs(
3334
self, known_properties: frozenset[VariantPropertyType] | None
@@ -61,20 +62,9 @@ class MockedPluginB:
6162
namespace = "second_namespace"
6263
dynamic = True
6364

64-
def get_all_configs(
65-
self, known_properties: frozenset[VariantPropertyType] | None
66-
) -> list[MyVariantFeatureConfig]:
67-
assert known_properties is not None
68-
assert all(prop.namespace == self.namespace for prop in known_properties)
69-
vals3 = ["val3a", "val3b", "val3c"]
70-
vals3.extend(
71-
x.value
72-
for x in known_properties
73-
if x.feature == "name3" and x.value not in vals3
74-
)
75-
return [
76-
MyVariantFeatureConfig("name3", vals3),
77-
]
65+
def validate_property(self, variant_property: VariantPropertyType) -> bool:
66+
assert variant_property.namespace == self.namespace
67+
return variant_property.feature == "name3"
7868

7969
def get_supported_configs(
8070
self, known_properties: frozenset[VariantPropertyType] | None
@@ -105,16 +95,12 @@ class MockedPluginC(PluginType):
10595
namespace = "incompatible_namespace"
10696
dynamic = False
10797

108-
def get_all_configs(
109-
self, known_properties: frozenset[VariantPropertyType] | None
110-
) -> list[VariantFeatureConfigType]:
111-
assert known_properties is None
112-
return [
113-
MyFlag("flag1"),
114-
MyFlag("flag2"),
115-
MyFlag("flag3"),
116-
MyFlag("flag4"),
117-
]
98+
def validate_property(self, variant_property: VariantPropertyType) -> bool:
99+
assert variant_property.namespace == self.namespace
100+
return (
101+
variant_property.feature in ("flag1", "flag2", "flag3", "flag4")
102+
and variant_property.value == "on"
103+
)
118104

119105
def get_supported_configs(
120106
self, known_properties: frozenset[VariantPropertyType] | None

0 commit comments

Comments
 (0)