question 339 Functional & Dynamic Python · hard
A rule engine for product labels
Label rules are kept as data so the nutrition team can edit them without touching code: ["nutriments.sugars_100g", ">", 22.5, "high sugar"]. Write apply_rules(products, rules): return {code: [labels]} with, for each product, the labels of the rules that hold, in rule order. A field is a dotted path into the product; a rule whose field is missing doesn't apply. Operators are >, >=, <, <=, ==, !=, looked up in a dictionary (the operator module has the functions); an unknown operator raises ValueError before any product is checked.
Function
apply_rules(products, rules)rule
[field_path, op, value, label]Returnsa new dictionary from each product's
code to its list of labels (possibly empty)Raises
ValueError for an unknown operatorExamples
callapply_rules([{'code': '5010029219494', 'nutriscore_grade': 'a', 'nutriments': {'sugars_100g': 1, 'salt_100g': 0.03}}, {'code': '7613032192570', 'nutriscore_grade': 'd', 'nutriments': {'sugars_100g': 25, 'salt_100g': 0.49}}], [['nutriments.sugars_100g', '>', 22.5, 'high sugar'], ['nutriments.salt_100g', '>', 1.5, 'high salt'], ['nutriscore_grade', '==', 'a', 'best grade']])returns{'5010029219494': ['best grade'], '7613032192570': ['high sugar']}
callapply_rules([{'code': '0038000001109', 'nutriscore_grade': 'c', 'nutriments': {'sugars_100g': 10.71, 'salt_100g': 1.785, 'fiber_100g': 3.6}}], [['nutriments.fiber_100g', '>=', 6, 'high fibre'], ['nutriments.salt_100g', '>', 1.5, 'high salt']])returns{'0038000001109': ['high salt']}
callapply_rules([], [['nutriments.sugars_100g', '>', 22.5, 'high sugar']])returns{}