Expected Behaviour
A condition whose key is absent from the evaluation context should not match, regardless of action. A rule written as "tier is not premium" should not fire for a request that carries no tier at all.
Current Behaviour
context.get(key) returns None for an absent key, and None is then compared as an ordinary value. None != "premium" is True, None not in [...] is True, so negative actions (NOT_EQUALS, NOT_IN, KEY_NOT_IN_VALUE, VALUE_NOT_IN_KEY) match missing keys. Rules intended to target one segment fire for anonymous or partially-populated traffic. The behaviour is not documented and no test asserts it.
Code snippet
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, RuleAction
class InMemoryStore:
def __init__(self, d): self.d = d
def get_configuration(self): return self.d
@property
def get_raw_configuration(self): return self.d
features = {
"discount_banner": {
"default": False,
"rules": {
"non premium users": {
"when_match": True,
"conditions": [{
"action": RuleAction.NOT_EQUALS.value,
"key": "tier",
"value": "premium",
}],
}
},
}
}
flags = FeatureFlags(store=InMemoryStore(features))
print(flags.evaluate(name="discount_banner", context={}, default=False)) # True (unexpected)
print(flags.evaluate(name="discount_banner", context={"tier": "free"}, default=False)) # True
Possible Solution
In _evaluate_conditions, if condition["key"] is not in context, treat the condition as not matched before calling the comparator. Time-based keys are already special-cased and would be unaffected.
This changes results for documents that, knowingly or not, rely on the current behaviour. We think it qualifies as a defect fix in the same spirit as #2051 (falsy values), where the old result was wrong rather than a designed behaviour, but we'd understand if maintainers prefer to hold it for a major. Context: the TypeScript port (aws-powertools/powertools-lambda-typescript#5614) is adopting "missing key never matches" and we'd like the two runtimes to agree.
Steps to Reproduce
Run the snippet; first print is True.
Powertools for AWS Lambda (Python) version
latest
AWS Lambda function runtime
3.13
Packaging format used
PyPi
Debugging logs
Expected Behaviour
A condition whose
keyis absent from the evaluation context should not match, regardless of action. A rule written as "tier is not premium" should not fire for a request that carries notierat all.Current Behaviour
context.get(key)returnsNonefor an absent key, andNoneis then compared as an ordinary value.None != "premium"isTrue,None not in [...]isTrue, so negative actions (NOT_EQUALS,NOT_IN,KEY_NOT_IN_VALUE,VALUE_NOT_IN_KEY) match missing keys. Rules intended to target one segment fire for anonymous or partially-populated traffic. The behaviour is not documented and no test asserts it.Code snippet
Possible Solution
In
_evaluate_conditions, ifcondition["key"]is not incontext, treat the condition as not matched before calling the comparator. Time-based keys are already special-cased and would be unaffected.This changes results for documents that, knowingly or not, rely on the current behaviour. We think it qualifies as a defect fix in the same spirit as #2051 (falsy values), where the old result was wrong rather than a designed behaviour, but we'd understand if maintainers prefer to hold it for a major. Context: the TypeScript port (aws-powertools/powertools-lambda-typescript#5614) is adopting "missing key never matches" and we'd like the two runtimes to agree.
Steps to Reproduce
Run the snippet; first print is
True.Powertools for AWS Lambda (Python) version
latest
AWS Lambda function runtime
3.13
Packaging format used
PyPi
Debugging logs