Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions CHANGELOG.md

This file was deleted.

2 changes: 1 addition & 1 deletion eppo_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from eppo_client.http_client import HttpClient, SdkParams
from eppo_client.read_write_lock import ReadWriteLock

__version__ = "1.3.0"
__version__ = "1.3.1"

__client: Optional[EppoClient] = None
__lock = ReadWriteLock()
Expand Down
38 changes: 35 additions & 3 deletions eppo_client/rules.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numbers
import re
import semver
from enum import Enum
from typing import Any, List

Expand Down Expand Up @@ -55,9 +56,13 @@ def evaluate_condition(subject_attributes: dict, condition: Condition) -> bool:
value.lower() for value in condition.value
]
else:
return isinstance(
subject_value, numbers.Number
) and evaluate_numeric_condition(subject_value, condition)
# Numeric operator: value could be numeric or semver.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the comments 🙌

if isinstance(subject_value, numbers.Number):
return evaluate_numeric_condition(subject_value, condition)
elif is_valid_semver(subject_value):
return compare_semver(
subject_value, condition.value, condition.operator
)
return False


Expand All @@ -70,4 +75,31 @@ def evaluate_numeric_condition(subject_value: numbers.Number, condition: Conditi
return subject_value < condition.value
elif condition.operator == OperatorType.LTE:
return subject_value <= condition.value

return False


def is_valid_semver(value: str):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 Clean 🧼

try:
# Parse the string. If it's a valid semver, it will return without errors.
semver.VersionInfo.parse(value)
return True
except ValueError:
# If a ValueError is raised, the string is not a valid semver.
return False


def compare_semver(attribute_value: Any, condition_value: Any, operator: OperatorType):
if not is_valid_semver(attribute_value) or not is_valid_semver(condition_value):
return False

if operator == OperatorType.GT:
return semver.compare(attribute_value, condition_value) > 0
elif operator == OperatorType.GTE:
return semver.compare(attribute_value, condition_value) >= 0
elif operator == OperatorType.LT:
return semver.compare(attribute_value, condition_value) < 0
elif operator == OperatorType.LTE:
return semver.compare(attribute_value, condition_value) <= 0

return False
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ requests==2.31.*
cachetools==5.3.*
types-cachetools==5.3.*
types-requests==2.31.*
semver==3.0.*
17 changes: 17 additions & 0 deletions test/rules_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ def test_find_matching_rule_with_numeric_value_and_regex():
assert find_matching_rule({"age": 99}, [rule]) == rule


def test_find_matching_rule_with_semver():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

semver_greater_than_condition = Condition(
operator=OperatorType.GTE, value="1.0.0", attribute="version"
)
semver_less_than_condition = Condition(
operator=OperatorType.LTE, value="2.0.0", attribute="version"
)
semver_rule = Rule(
allocation_key="allocation",
conditions=[semver_less_than_condition, semver_greater_than_condition],
)

assert find_matching_rule({"version": "1.1.0"}, [semver_rule]) is semver_rule
assert find_matching_rule({"version": "2.0.0"}, [semver_rule]) is semver_rule
assert find_matching_rule({"version": "2.1.0"}, [semver_rule]) is None
Comment on lines +73 to +75
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for shits, to make sure more than just a string comparison is at play, consider having test data so that we do something like making sure "1.12.3" is greater than "1.2.0"



def test_one_of_operator_with_boolean():
oneOfRule = Rule(
allocation_key="allocation",
Expand Down