Skip to content

Commit 6d61ec8

Browse files
refactored
1 parent 9153de0 commit 6d61ec8

File tree

3 files changed

+88
-28
lines changed

3 files changed

+88
-28
lines changed

src/eligibility_signposting_api/model/campaign_config.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -163,27 +163,6 @@ def parse_yn_to_bool(cls, v: str | bool) -> bool: # noqa: N805
163163
return v.upper() == "Y"
164164
return v
165165

166-
@model_validator( mode="after")
167-
def validate_attribute_name_is_optional_only_for_cohort_attribute_level(self) -> typing.Self: # noqa: N805
168-
if self.attribute_name:
169-
return self
170-
else:
171-
if self.attribute_level == RuleAttributeLevel.COHORT:
172-
return self
173-
else:
174-
raise ValueError(f"AttributeName must be set where AttributeLevel is {self.attribute_level} .")
175-
176-
@model_validator(mode="after")
177-
def validate_attribute_target_is_mandatory_for_target_attribute_level(self) -> typing.Self: # noqa: N805
178-
if self.attribute_target:
179-
return self
180-
else:
181-
if self.attribute_level != RuleAttributeLevel.TARGET:
182-
return self
183-
else:
184-
raise ValueError(f"AttributeTarget is mandatory where AttributeLevel is {self.attribute_level}.")
185-
186-
187166
_parent: Iteration | None = PrivateAttr(default=None)
188167

189168
def set_parent(self, parent: Iteration) -> None:

src/rules_validation_api/validators/iteration_rules_validator.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Self
1+
import typing
22

33
from pydantic import model_validator
44

@@ -12,7 +12,7 @@
1212

1313
class IterationRuleValidation(IterationRule):
1414
@model_validator(mode="after")
15-
def check_cohort_attribute_name(self) -> Self:
15+
def check_cohort_attribute_name(self) -> typing.Self:
1616
if (
1717
self.attribute_level == RuleAttributeLevel.COHORT
1818
and self.attribute_name
@@ -23,7 +23,7 @@ def check_cohort_attribute_name(self) -> Self:
2323
return self
2424

2525
@model_validator(mode="after")
26-
def check_cohort_label_for_non_f_and_s_types(self) -> Self:
26+
def check_cohort_label_for_non_f_and_s_types(self) -> typing.Self:
2727
allowed_types = {RuleType("F"), RuleType("S")}
2828
if self.cohort_label is not None and self.type not in allowed_types:
2929
msg = (
@@ -32,3 +32,19 @@ def check_cohort_label_for_non_f_and_s_types(self) -> Self:
3232
)
3333
raise ValueError(msg)
3434
return self
35+
36+
@model_validator(mode="after")
37+
def validate_attribute_name_is_optional_only_for_cohort_attribute_level(self) -> typing.Self:
38+
if self.attribute_name:
39+
return self
40+
if self.attribute_level == RuleAttributeLevel.COHORT:
41+
return self
42+
raise ValueError(f"AttributeName must be set where AttributeLevel is {self.attribute_level} .")
43+
44+
@model_validator(mode="after")
45+
def validate_attribute_target_is_mandatory_for_target_attribute_level(self) -> typing.Self:
46+
if self.attribute_target:
47+
return self
48+
if self.attribute_level != RuleAttributeLevel.TARGET:
49+
return self
50+
raise ValueError(f"AttributeTarget is mandatory where AttributeLevel is {self.attribute_level}.")

tests/unit/validation/test_iteration_rules_validator.py

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22
from pydantic import ValidationError
33

4+
from eligibility_signposting_api.model.campaign_config import RuleAttributeLevel
45
from rules_validation_api.validators.iteration_validator import IterationRuleValidation
56

67

@@ -80,8 +81,18 @@ def test_invalid_priority(self, priority_value, valid_iteration_rule_with_only_m
8081
with pytest.raises(ValidationError):
8182
IterationRuleValidation(**data)
8283

83-
@pytest.mark.parametrize("attribute_level", ["PERSON", "TARGET", "COHORT"])
84-
def test_valid_attribute_level(self, attribute_level, valid_iteration_rule_with_only_mandatory_fields):
84+
@pytest.mark.parametrize("attribute_level", ["PERSON", "TARGET"])
85+
def test_valid_attribute_level_person_and_targer(
86+
self, attribute_level, valid_iteration_rule_with_only_mandatory_fields
87+
):
88+
data = valid_iteration_rule_with_only_mandatory_fields.copy()
89+
data["AttributeLevel"] = attribute_level
90+
data["AttributeName"] = "Something" # Ignoring the validation constraint btw AttributeLevel and AttributeName
91+
result = IterationRuleValidation(**data)
92+
assert result.attribute_level == attribute_level
93+
94+
@pytest.mark.parametrize("attribute_level", ["COHORT"])
95+
def test_valid_attribute_level_cohort(self, attribute_level, valid_iteration_rule_with_only_mandatory_fields):
8596
data = valid_iteration_rule_with_only_mandatory_fields.copy()
8697
data["AttributeLevel"] = attribute_level
8798
data["AttributeName"] = None # Ignoring the validation constraint btw AttributeLevel and AttributeName
@@ -148,7 +159,7 @@ def test_rule_stop_boolean_resolution(
148159

149160
class TestOptionalFieldsSchemaValidations:
150161
# AttributeName
151-
@pytest.mark.parametrize("attr_name", ["status", "user_type", None])
162+
@pytest.mark.parametrize("attr_name", ["status", "user_type"])
152163
def test_valid_attribute_name(self, attr_name, valid_iteration_rule_with_only_mandatory_fields):
153164
data = valid_iteration_rule_with_only_mandatory_fields.copy()
154165
data["AttributeName"] = attr_name
@@ -192,7 +203,7 @@ def test_invalid_cohort_label(self, label, valid_iteration_rule_with_only_mandat
192203
IterationRuleValidation(**data)
193204

194205
# AttributeTarget
195-
@pytest.mark.parametrize("target", ["target_value", None])
206+
@pytest.mark.parametrize("target", ["target_value"])
196207
def test_valid_attribute_target(self, target, valid_iteration_rule_with_only_mandatory_fields):
197208
data = valid_iteration_rule_with_only_mandatory_fields.copy()
198209
data["AttributeTarget"] = target
@@ -291,3 +302,57 @@ def test_valid_when_cohort_label_absent_for_non_f_s_types(
291302
data.pop("CohortLabel", None)
292303
result = IterationRuleValidation(**data)
293304
assert result.cohort_label is None
305+
306+
@pytest.mark.parametrize(
307+
("attribute_level", "attribute_name", "is_valid"),
308+
[
309+
(RuleAttributeLevel.COHORT, None, True), # Allowed: name optional for cohort
310+
(RuleAttributeLevel.COHORT, "COHORT_LABEL", True), # Allowed: name provided
311+
(RuleAttributeLevel.TARGET, "RSV", True), # Allowed: name provided for target
312+
(RuleAttributeLevel.TARGET, None, False), # NOT allowed: missing for non-cohort
313+
],
314+
)
315+
def test_attribute_name_optional_only_for_cohort(
316+
self, attribute_level, attribute_name, is_valid, valid_iteration_rule_with_only_mandatory_fields
317+
):
318+
data = valid_iteration_rule_with_only_mandatory_fields.copy()
319+
data["AttributeLevel"] = attribute_level
320+
data["AttributeName"] = attribute_name
321+
322+
if is_valid:
323+
# Should validate with no exceptions
324+
IterationRuleValidation(**data)
325+
else:
326+
with pytest.raises(ValidationError) as exc:
327+
IterationRuleValidation(**data)
328+
329+
assert "AttributeName must be set" in str(exc.value)
330+
331+
@pytest.mark.parametrize(
332+
("attribute_level", "attribute_target", "attribute_name", "is_valid"),
333+
[
334+
(RuleAttributeLevel.TARGET, "RSV", "BOOKED_APPOINTMENT_DATE", True), # Valid: required for TARGET
335+
(RuleAttributeLevel.TARGET, None, "BOOKED_APPOINTMENT_DATE", False), # Invalid: missing
336+
(RuleAttributeLevel.COHORT, None, "COHORT_LABEL", True), # Valid: not required
337+
],
338+
)
339+
def test_attribute_target_mandatory_for_target_level(
340+
self,
341+
attribute_level,
342+
attribute_target,
343+
attribute_name,
344+
is_valid,
345+
valid_iteration_rule_with_only_mandatory_fields,
346+
):
347+
data = valid_iteration_rule_with_only_mandatory_fields.copy()
348+
data["AttributeLevel"] = attribute_level
349+
data["AttributeTarget"] = attribute_target
350+
data["AttributeName"] = attribute_name
351+
352+
if is_valid:
353+
IterationRuleValidation(**data)
354+
else:
355+
with pytest.raises(ValidationError) as exc:
356+
IterationRuleValidation(**data)
357+
358+
assert "AttributeTarget is mandatory" in str(exc.value)

0 commit comments

Comments
 (0)