1414
1515@dataclass (kw_only = True )
1616class ValueEquals :
17+ """Condition that matches when an attribute equals a specific value."""
18+
1719 attribute : str
1820 value : Any
1921 kind : Literal ['value-equals' ] = 'value-equals'
2022
2123 def matches (self , attributes : Mapping [str , Any ]) -> bool :
24+ """Check if the attribute equals the expected value."""
2225 return attributes .get (self .attribute , object ()) == self .value
2326
2427
2528@dataclass (kw_only = True )
2629class ValueDoesNotEqual :
30+ """Condition that matches when an attribute does not equal a specific value."""
31+
2732 attribute : str
2833 value : Any
2934 kind : Literal ['value-does-not-equal' ] = 'value-does-not-equal'
3035
3136 def matches (self , attributes : Mapping [str , Any ]) -> bool :
37+ """Check if the attribute does not equal the specified value."""
3238 return attributes .get (self .attribute , object ()) != self .value
3339
3440
3541@dataclass (kw_only = True )
3642class ValueIsIn :
43+ """Condition that matches when an attribute value is in a set of values."""
44+
3745 attribute : str
3846 values : Sequence [Any ]
3947 kind : Literal ['value-is-in' ] = 'value-is-in'
4048
4149 def matches (self , attributes : Mapping [str , Any ]) -> bool :
50+ """Check if the attribute value is in the allowed set."""
4251 value = attributes .get (self .attribute , object ())
4352 return value in self .values
4453
4554
4655@dataclass (kw_only = True )
4756class ValueIsNotIn :
57+ """Condition that matches when an attribute value is not in a set of values."""
58+
4859 attribute : str
4960 values : Sequence [Any ]
5061 kind : Literal ['value-is-not-in' ] = 'value-is-not-in'
5162
5263 def matches (self , attributes : Mapping [str , Any ]) -> bool :
64+ """Check if the attribute value is not in the excluded set."""
5365 value = attributes .get (self .attribute , object ())
5466 return value not in self .values
5567
5668
5769@dataclass (kw_only = True )
5870class ValueMatchesRegex :
71+ """Condition that matches when an attribute value matches a regex pattern."""
72+
5973 attribute : str
6074 pattern : str | re .Pattern [str ]
6175 kind : Literal ['value-matches-regex' ] = 'value-matches-regex'
6276
6377 def matches (self , attributes : Mapping [str , Any ]) -> bool :
78+ """Check if the attribute value matches the regex pattern."""
6479 value = attributes .get (self .attribute )
6580 if not isinstance (value , str ):
6681 return False
@@ -69,11 +84,14 @@ def matches(self, attributes: Mapping[str, Any]) -> bool:
6984
7085@dataclass (kw_only = True )
7186class ValueDoesNotMatchRegex :
87+ """Condition that matches when an attribute value does not match a regex pattern."""
88+
7289 attribute : str
7390 pattern : str | re .Pattern [str ]
7491 kind : Literal ['value-does-not-match-regex' ] = 'value-does-not-match-regex'
7592
7693 def matches (self , attributes : Mapping [str , Any ]) -> bool :
94+ """Check if the attribute value does not match the regex pattern."""
7795 value = attributes .get (self .attribute )
7896 if not isinstance (value , str ):
7997 return False
@@ -82,19 +100,25 @@ def matches(self, attributes: Mapping[str, Any]) -> bool:
82100
83101@dataclass (kw_only = True )
84102class KeyIsPresent :
103+ """Condition that matches when an attribute key is present."""
104+
85105 attribute : str
86106 kind : Literal ['key-is-present' ] = 'key-is-present'
87107
88108 def matches (self , attributes : Mapping [str , Any ]) -> bool :
109+ """Check if the attribute key exists in the attributes."""
89110 return self .attribute in attributes
90111
91112
92113@dataclass (kw_only = True )
93114class KeyIsNotPresent :
115+ """Condition that matches when an attribute key is not present."""
116+
94117 attribute : str
95118 kind : Literal ['key-is-not-present' ] = 'key-is-not-present'
96119
97120 def matches (self , attributes : Mapping [str , Any ]) -> bool :
121+ """Check if the attribute key does not exist in the attributes."""
98122 return self .attribute not in attributes
99123
100124
@@ -123,6 +147,8 @@ def matches(self, attributes: Mapping[str, Any]) -> bool:
123147
124148@dataclass (kw_only = True )
125149class Rollout :
150+ """Configuration for variant selection with weighted probabilities."""
151+
126152 variants : dict [VariantKey , float ]
127153
128154 @field_validator ('variants' )
@@ -135,6 +161,7 @@ def _validate_variant_proportions(cls, v: dict[VariantKey, float]):
135161 return v
136162
137163 def select_variant (self , seed : str | None ) -> VariantKey | None :
164+ """Select a variant based on configured weights using optional seeded randomness."""
138165 rand = random .Random (seed )
139166
140167 population : list [VariantKey | None ] = []
@@ -153,6 +180,8 @@ def select_variant(self, seed: str | None) -> VariantKey | None:
153180
154181@dataclass (kw_only = True )
155182class Variant :
183+ """A specific variant of a managed variable with its serialized value."""
184+
156185 key : VariantKey
157186 serialized_value : str
158187 # format: Literal['json', 'yaml'] # TODO: Consider supporting yaml, and not just JSON; allows comments and better formatting
@@ -162,12 +191,16 @@ class Variant:
162191
163192@dataclass (kw_only = True )
164193class RolloutOverride :
194+ """An override of the default rollout when specific conditions are met."""
195+
165196 conditions : list [Condition ]
166197 rollout : Rollout
167198
168199
169200@dataclass (kw_only = True )
170201class VariableConfig :
202+ """Configuration for a single managed variable including variants and rollout rules."""
203+
171204 name : VariableName
172205 variants : dict [VariantKey , Variant ]
173206 rollout : Rollout
@@ -228,6 +261,8 @@ def resolve_variant(
228261
229262@dataclass (kw_only = True )
230263class VariablesConfig :
264+ """Container for all managed variable configurations."""
265+
231266 variables : dict [VariableName , VariableConfig ]
232267
233268 @model_validator (mode = 'after' )
@@ -239,6 +274,7 @@ def _validate_variables(self):
239274 return self
240275
241276 def get_validation_errors (self , variables : list [Variable [Any ]]) -> dict [str , dict [str | None , Exception ]]:
277+ """Validate that all variable variants can be deserialized to their expected types."""
242278 errors : dict [str , dict [str | None , Exception ]] = {}
243279 for variable in variables :
244280 try :
@@ -256,6 +292,7 @@ def get_validation_errors(self, variables: list[Variable[Any]]) -> dict[str, dic
256292
257293 @staticmethod
258294 def validate_python (data : Any ) -> VariablesConfig :
295+ """Parse and validate a VariablesConfig from a Python object."""
259296 return _VariablesConfigAdapter .validate_python (data )
260297
261298
0 commit comments