2222 IterationResult ,
2323 Status ,
2424)
25- from eligibility_signposting_api .services .calculators .rule_calculator import RuleCalculator
25+ from eligibility_signposting_api .services .calculators .rule_calculator import (
26+ RuleCalculator ,
27+ )
2628
2729Row = Collection [Mapping [str , Any ]]
2830
2931
3032@service
3133class EligibilityCalculatorFactory :
3234 @staticmethod
33- def get (person_data : Row , campaign_configs : Collection [rules .CampaignConfig ]) -> EligibilityCalculator :
34- return EligibilityCalculator (person_data = person_data , campaign_configs = campaign_configs )
35+ def get (
36+ person_data : Row , campaign_configs : Collection [rules .CampaignConfig ]
37+ ) -> EligibilityCalculator :
38+ return EligibilityCalculator (
39+ person_data = person_data , campaign_configs = campaign_configs
40+ )
3541
3642
3743@dataclass
@@ -51,34 +57,51 @@ def campaigns_grouped_by_condition_name(
5157 ) -> Iterator [tuple [eligibility .ConditionName , list [rules .CampaignConfig ]]]:
5258 """Generator function to iterate over campaign groups by condition name."""
5359 for condition_name , campaign_group in groupby (
54- sorted (self .active_campaigns , key = attrgetter ("target" )), key = attrgetter ("target" )
60+ sorted (self .active_campaigns , key = attrgetter ("target" )),
61+ key = attrgetter ("target" ),
5562 ):
5663 yield condition_name , list (campaign_group )
5764
5865 @property
5966 def person_cohorts (self ) -> set [str ]:
6067 cohorts_row : Mapping [str , dict [str , dict [str , dict [str , Any ]]]] = next (
61- (row for row in self .person_data if row .get ("ATTRIBUTE_TYPE" ) == "COHORTS" ), {}
68+ (row for row in self .person_data if row .get ("ATTRIBUTE_TYPE" ) == "COHORTS" ),
69+ {},
70+ )
71+ return set (
72+ cohorts_row .get ("COHORT_MAP" , {}).get ("cohorts" , {}).get ("M" , {}).keys ()
6273 )
63- return set (cohorts_row .get ("COHORT_MAP" , {}).get ("cohorts" , {}).get ("M" , {}).keys ())
6474
6575 @staticmethod
66- def get_the_best_cohort_memberships (cohort_results : dict [str , CohortResult ]) -> tuple [Status , list [CohortResult ]]:
76+ def get_the_best_cohort_memberships (
77+ cohort_results : dict [str , CohortResult ],
78+ ) -> tuple [Status , list [CohortResult ]]:
6779 """
6880 1. Get all the cohorts with the best status
6981 2. Case 1: Ignore magic cohort if other cohorts have better status
70- Case 2: If no cohorts have the better status than magic cohort,
71- then response excludes cohort memberships but will have actions/suitability rules
72- also, excludes the cohorts with no positive or negative description
82+ Case 2: If no cohorts have the better status than magic cohort, then response excludes cohort memberships but
83+ will have actions/suitability rules also excludes the cohorts with no positive or negative description
7384 """
7485 if not cohort_results :
7586 return eligibility .Status .not_eligible , []
76- best_status = eligibility .Status .best (* [result .status for result in cohort_results .values ()])
77- best_cohorts = [result for result in cohort_results .values () if result .status == best_status ]
78- if all (cc .cohort_code and str (cc .cohort_code .upper ()) == MAGIC_COHORT_LABEL .upper () for cc in best_cohorts ):
87+ best_status = eligibility .Status .best (
88+ * [result .status for result in cohort_results .values ()]
89+ )
90+ best_cohorts = [
91+ result for result in cohort_results .values () if result .status == best_status
92+ ]
93+ if all (
94+ cc .cohort_code and str (cc .cohort_code .upper ()) == MAGIC_COHORT_LABEL .upper ()
95+ for cc in best_cohorts
96+ ):
7997 # Update the magic cohort to have no cohort membership information
8098 best_cohorts = [
81- CohortResult (cohort_code = "" , status = best_status , reasons = best_cohorts [0 ].reasons , description = "" )
99+ CohortResult (
100+ cohort_code = "" ,
101+ status = best_status ,
102+ reasons = best_cohorts [0 ].reasons ,
103+ description = "" ,
104+ )
82105 ]
83106 else :
84107 best_cohorts = [
@@ -99,15 +122,22 @@ def get_exclusion_rules(
99122 for ir in filter_rules
100123 if ir .cohort_label is None
101124 or cohort .cohort_label == ir .cohort_label
102- or (isinstance (ir .cohort_label , (list , set , tuple )) and cohort .cohort_label in ir .cohort_label )
125+ or (
126+ isinstance (ir .cohort_label , (list , set , tuple ))
127+ and cohort .cohort_label in ir .cohort_label
128+ )
103129 )
104130
105131 @staticmethod
106132 def get_rules_by_type (
107133 active_iteration : Iteration ,
108134 ) -> tuple [tuple [rules .IterationRule , ...], tuple [rules .IterationRule , ...]]:
109135 filter_rules , suppression_rules = (
110- tuple (rule for rule in active_iteration .iteration_rules if attrgetter ("type" )(rule ) == rule_type )
136+ tuple (
137+ rule
138+ for rule in active_iteration .iteration_rules
139+ if attrgetter ("type" )(rule ) == rule_type
140+ )
111141 for rule_type in (rules .RuleType .filter , rules .RuleType .suppression )
112142 )
113143 return filter_rules , suppression_rules
@@ -122,33 +152,54 @@ def evaluate_eligibility(self) -> eligibility.EligibilityStatus:
122152 for active_iteration in [cc .current_iteration for cc in campaign_group ]:
123153 cohort_results : dict [str , CohortResult ] = {}
124154
125- filter_rules , suppression_rules = self .get_rules_by_type (active_iteration )
155+ filter_rules , suppression_rules = self .get_rules_by_type (
156+ active_iteration
157+ )
126158
127- for cohort in sorted (active_iteration .iteration_cohorts , key = attrgetter ("priority" )):
159+ for cohort in sorted (
160+ active_iteration .iteration_cohorts , key = attrgetter ("priority" )
161+ ):
128162 # Base Eligibility - check
129- if cohort .cohort_label in self .person_cohorts or active_iteration .has_magic_cohort :
163+ if (
164+ cohort .cohort_label in self .person_cohorts
165+ or active_iteration .has_magic_cohort
166+ ):
130167 # Eligibility - check
131- if self .is_eligible_by_filter_rules (cohort , cohort_results , filter_rules ):
168+ if self .is_eligible_by_filter_rules (
169+ cohort , cohort_results , filter_rules
170+ ):
132171 # Actionability - evaluation
133- self .evaluate_suppression_rules (cohort , cohort_results , suppression_rules )
172+ self .evaluate_suppression_rules (
173+ cohort , cohort_results , suppression_rules
174+ )
134175
135176 # Not base eligible
136177 elif cohort .cohort_label is not None :
137178 cohort_results [cohort .cohort_label ] = CohortResult (
138- cohort .cohort_group if cohort .cohort_group else cohort .cohort_label ,
179+ (
180+ cohort .cohort_group
181+ if cohort .cohort_group
182+ else cohort .cohort_label
183+ ),
139184 Status .not_eligible ,
140185 [],
141186 str (cohort .negative_description ),
142187 )
143188
144189 # Determine Result between cohorts - get the best
145- status , best_cohorts = self .get_the_best_cohort_memberships (cohort_results )
190+ status , best_cohorts = self .get_the_best_cohort_memberships (
191+ cohort_results
192+ )
146193
147- iteration_results [active_iteration .name ] = IterationResult (status , best_cohorts )
194+ iteration_results [active_iteration .name ] = IterationResult (
195+ status , best_cohorts
196+ )
148197
149198 # Determine results between iterations - get the best
150199 if iteration_results :
151- best_candidate = max (iteration_results .values (), key = lambda r : r .status .value )
200+ best_candidate = max (
201+ iteration_results .values (), key = lambda r : r .status .value
202+ )
152203 else :
153204 best_candidate = IterationResult (eligibility .Status .not_eligible , [])
154205 condition_results [condition_name ] = best_candidate
@@ -158,19 +209,25 @@ def evaluate_eligibility(self) -> eligibility.EligibilityStatus:
158209 return eligibility .EligibilityStatus (conditions = final_result )
159210
160211 @staticmethod
161- def build_condition_results (condition_results : dict [ConditionName , IterationResult ]) -> list [Condition ]:
212+ def build_condition_results (
213+ condition_results : dict [ConditionName , IterationResult ],
214+ ) -> list [Condition ]:
162215 conditions : list [Condition ] = []
163216 # iterate over conditions
164217 for condition_name , active_iteration_result in condition_results .items ():
165218 grouped_cohort_results = defaultdict (list )
166219 # iterate over cohorts and group them by status and cohort_group
167220 for cohort_result in active_iteration_result .cohort_results :
168221 if active_iteration_result .status == cohort_result .status :
169- grouped_cohort_results [cohort_result .cohort_code ].append (cohort_result )
222+ grouped_cohort_results [cohort_result .cohort_code ].append (
223+ cohort_result
224+ )
170225
171226 # deduplicate grouped cohort results by cohort_code
172227 deduplicated_cohort_results = {
173- cohort_code : results [0 ] for cohort_code , results in grouped_cohort_results .items () if results
228+ cohort_code : results [0 ]
229+ for cohort_code , results in grouped_cohort_results .items ()
230+ if results
174231 }
175232
176233 # return condition with cohort results
@@ -191,16 +248,22 @@ def is_eligible_by_filter_rules(
191248 ) -> bool :
192249 is_eligible = True
193250 priority_getter = attrgetter ("priority" )
194- sorted_rules_by_priority = sorted (self .get_exclusion_rules (cohort , filter_rules ), key = priority_getter )
251+ sorted_rules_by_priority = sorted (
252+ self .get_exclusion_rules (cohort , filter_rules ), key = priority_getter
253+ )
195254
196255 for _ , rule_group in groupby (sorted_rules_by_priority , key = priority_getter ):
197- status , group_inclusion_reasons , group_exclusion_reasons , rule_stop = self . evaluate_rules_priority_group (
198- rule_group
256+ status , group_inclusion_reasons , group_exclusion_reasons , rule_stop = (
257+ self . evaluate_rules_priority_group ( rule_group )
199258 )
200259 if status .is_exclusion :
201260 if cohort .cohort_label is not None :
202261 cohort_results [str (cohort .cohort_label )] = CohortResult (
203- cohort .cohort_group if cohort .cohort_group else cohort .cohort_label ,
262+ (
263+ cohort .cohort_group
264+ if cohort .cohort_group
265+ else cohort .cohort_label
266+ ),
204267 Status .not_eligible ,
205268 [],
206269 str (cohort .negative_description ),
@@ -219,11 +282,13 @@ def evaluate_suppression_rules(
219282 priority_getter = attrgetter ("priority" )
220283 suppression_reasons = []
221284
222- sorted_rules_by_priority = sorted (self .get_exclusion_rules (cohort , suppression_rules ), key = priority_getter )
285+ sorted_rules_by_priority = sorted (
286+ self .get_exclusion_rules (cohort , suppression_rules ), key = priority_getter
287+ )
223288
224289 for _ , rule_group in groupby (sorted_rules_by_priority , key = priority_getter ):
225- status , group_inclusion_reasons , group_exclusion_reasons , rule_stop = self . evaluate_rules_priority_group (
226- rule_group
290+ status , group_inclusion_reasons , group_exclusion_reasons , rule_stop = (
291+ self . evaluate_rules_priority_group ( rule_group )
227292 )
228293 if status .is_exclusion :
229294 is_actionable = False
@@ -250,7 +315,9 @@ def evaluate_suppression_rules(
250315
251316 def evaluate_rules_priority_group (
252317 self , rules_group : Iterator [rules .IterationRule ]
253- ) -> tuple [eligibility .Status , list [eligibility .Reason ], list [eligibility .Reason ], bool ]:
318+ ) -> tuple [
319+ eligibility .Status , list [eligibility .Reason ], list [eligibility .Reason ], bool
320+ ]:
254321 is_rule_stop = False
255322 inclusion_reasons , exclusion_reasons = [], []
256323 best_status = eligibility .Status .not_eligible
0 commit comments