Skip to content

Commit bb62216

Browse files
committed
fix: validate plan enums before membership checks
1 parent a07c6b4 commit bb62216

1 file changed

Lines changed: 6 additions & 6 deletions

File tree

‎src/openstatspec/transform/plan.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def __post_init__(self) -> None:
183183
_invalid("Recode source and target names must be non-empty.")
184184
if self.op != "recode":
185185
_invalid("Recode operation discriminator is invalid.")
186-
if self.target_mode not in {"create", "replace"}:
186+
if not isinstance(self.target_mode, str) or self.target_mode not in {"create", "replace"}:
187187
_invalid("Recode target_mode must be create or replace.")
188188
if not isinstance(self.rules, tuple) or not self.rules:
189189
_invalid("Recode requires at least one non-ELSE rule.")
@@ -304,7 +304,7 @@ def __post_init__(self) -> None:
304304
_invalid("Comparison expression discriminator is invalid.")
305305
if not isinstance(self.left, Operand) or not isinstance(self.right, Operand):
306306
_invalid("A comparison requires two typed operands.")
307-
if self.operator not in {"=", "<", "<=", ">", ">="}:
307+
if not isinstance(self.operator, str) or self.operator not in {"=", "<", "<=", ">", ">="}:
308308
_invalid("Comparison operator is outside the bounded expression profile.")
309309

310310
def as_dict(self) -> dict[str, Any]:
@@ -323,7 +323,7 @@ class BooleanExpression:
323323
def __post_init__(self) -> None:
324324
if self.expression != "boolean":
325325
_invalid("Boolean expression discriminator is invalid.")
326-
if self.operator not in {"and", "or"}:
326+
if not isinstance(self.operator, str) or self.operator not in {"and", "or"}:
327327
_invalid("Boolean operator must be and or or.")
328328
if not isinstance(self.operands, tuple) or len(self.operands) < 2:
329329
_invalid("A boolean expression requires at least two operands.")
@@ -352,7 +352,7 @@ def __post_init__(self) -> None:
352352
_invalid("Assign operation discriminator is invalid.")
353353
if not isinstance(self.target, str) or not self.target:
354354
_invalid("Assign target must be non-empty text.")
355-
if self.target_mode not in {"create", "replace"}:
355+
if not isinstance(self.target_mode, str) or self.target_mode not in {"create", "replace"}:
356356
_invalid("Assign target_mode must be create or replace.")
357357
if not isinstance(self.value, Operand):
358358
_invalid("Assign value must be a typed operand.")
@@ -435,7 +435,7 @@ def __post_init__(self) -> None:
435435
_invalid("Measurement-level operation discriminator is invalid.")
436436
if not isinstance(self.variable, str) or not self.variable:
437437
_invalid("Measurement-level operation requires a variable.")
438-
if self.level not in {"nominal", "ordinal", "scale"}:
438+
if not isinstance(self.level, str) or self.level not in {"nominal", "ordinal", "scale"}:
439439
_invalid("Measurement level must be nominal, ordinal, or scale.")
440440

441441
def as_dict(self) -> dict[str, Any]:
@@ -470,7 +470,7 @@ class TransformationPlan:
470470
input_alias: str = "parent"
471471

472472
def __post_init__(self) -> None:
473-
if self.contract not in _TRANSFORMATION_PLAN_CONTRACTS:
473+
if not isinstance(self.contract, str) or self.contract not in _TRANSFORMATION_PLAN_CONTRACTS:
474474
_invalid("Plan contract is not a supported transformation-plan contract.")
475475
if self.contract == TRANSFORMATION_PLAN_V1_CONTRACT and any(
476476
isinstance(operation, (

0 commit comments

Comments
 (0)