Description
Expected Behaviour
Rule Conditions allow users to evaluate context attributes against values and actions defined in Rule Conditions.
The condition can easily be pivoted on a certain value in the context evaluating to falsy values. Consider the following example -
Context-
{
"is_paid": 0,
}
Feature Flag -
{
"sales_offer": {
"default": false,
"rules": {
"unpaid_users": {
"when_match": true,
"conditions": [ {"action": "EQUALS", "key": "is_paid", "value": 0} ]
}
}
}
The values
attribute should be able to accept any value except null
The condition should also honor any value for context key variable.
Current Behaviour
Definition - Falsy Values
In python, the following values evaluate to False in boolean context - these are known as falsy values.
empty_list = []
empty_string = ""
zero = 0
false_boolean = False
Falsy Values in Condition value
The values
attribute in conditions cannot accept any of the falsy values, some of which are essential to framing conditions in practical use-cases.
If any of the falsy values are present in the condition - the utility throws the error below
File ~/venv/lib/python3.8/site-packages/aws_lambda_powertools/utilities/feature_flags/schema.py:330, in ConditionsValidator.validate_condition_value(condition, rule_name)
328 value = condition.get(CONDITION_VALUE, "")
329 if not value:
--> 330 raise SchemaValidationError(f"'value' key must not be empty, rule={rule_name}")
331 action = condition.get(CONDITION_ACTION, "")
333 # time actions need to be parsed to make sure date and time format is valid and timezone is recognized
SchemaValidationError: 'value' key must not be empty, rule=unpaid_users
Falsy Values in context value
The conditions simply return evaluate to false if the value for the key passed in context is falsy. These are also extremely essential to framing conditions in practical use-cases.
Example -
🚨 The condition below will evaluate to False even if the context value (0) is NOT EQUAL to condition value (1) 🚨
{
"sales_offer": {
"default": false,
"rules": {
"unpaid_users": {
"when_match": true,
"conditions": [ {"action": "NOT_EQUALS", "key": "is_paid", "value": 1} ]
}
}
}
Code snippet
Falsy Values in Condition value
// context.json
{
"is_paid": 0
}
// features.json
{
"sales_offer": {
"default": false,
"rules": {
"unpaid_users": {
"when_match": true,
"conditions": [ {"action": "EQUALS", "key": "is_paid", "value": 0} ]
}
}
}
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
app_config = AppConfigStore(
environment="dev",
application="product-catalogue",
name="features"
)
feature_flags = FeatureFlags(store=app_config)
def lambda_handler(event, context):
# Get customer's tier from incoming request
ctx = { "is_paid": 2 } # 1: Standard Plan | 2: Advanced Plan
is_unpaid: bool = feature_flags.evaluate(name="sales_offer", context=ctx, default=True)
Falsy Values in Context key value
// context.json
{
"is_paid": 0
}
// features.json
{
"sales_offer": {
"default": false,
"rules": {
"unpaid_users": {
"when_match": true,
"conditions": [ {"action": "NOT_EQUALS", "key": "is_paid", "value": 1} ]
}
}
}
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
app_config = AppConfigStore(
environment="dev",
application="product-catalogue",
name="features"
)
feature_flags = FeatureFlags(store=app_config)
def lambda_handler(event, context):
# Get customer's tier from incoming request
ctx = { "is_paid": 2 } # 1: Standard Plan | 2: Advanced Plan
is_unpaid: bool = feature_flags.evaluate(name="sales_offer", context=ctx, default=True)
Possible Solution
Falsy Values in condition value
suggest
value = condition.get(CONDITION_VALUE, None)
if value is None:
raise SchemaValidationError(f"'value' key must not be null, rule={rule_name}")
Falsy Values in context key value
suggest
def _match_by_action(self, action: str, condition_value: Any, context_value: Any) -> bool:
if context_value is None:
return False
Steps to Reproduce
Shared code snippet should reproduce the issue
AWS Lambda Powertools for Python version
latest
AWS Lambda function runtime
3.6
Packaging format used
PyPi
Debugging logs
No response