diff --git a/CHANGELOG.md b/CHANGELOG.md index b33b414c..331b84c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.1.1 - 2022-09-14 + +Changes: + +1. Feature flags local evaluation now supports date property filters as well. ## 2.1.0 - 2022-08-11 Changes: diff --git a/posthog/feature_flags.py b/posthog/feature_flags.py index 11a44e4e..c7e9de6a 100644 --- a/posthog/feature_flags.py +++ b/posthog/feature_flags.py @@ -1,6 +1,9 @@ +import datetime import hashlib import re +from dateutil import parser + from posthog.utils import is_valid_regex __LONG_SCALE__ = float(0xFFFFFFFFFFFFFFF) @@ -126,4 +129,27 @@ def match_property(property, property_values) -> bool: if operator == "lte": return type(override_value) == type(value) and override_value <= value + if operator in ["is_date_before", "is_date_after"]: + try: + parsed_date = parser.parse(value) + except Exception: + raise InconclusiveMatchError("The date set on the flag is not a valid format") + + if isinstance(override_value, datetime.date): + if operator == "is_date_before": + return override_value < parsed_date + else: + return override_value > parsed_date + elif isinstance(override_value, str): + try: + override_date = parser.parse(override_value) + if operator == "is_date_before": + return override_date < parsed_date + else: + return override_date > parsed_date + except Exception: + raise InconclusiveMatchError("The date provided is not a valid format") + else: + raise InconclusiveMatchError("The date provided must be a string or date object") + return False diff --git a/posthog/test/test_feature_flags.py b/posthog/test/test_feature_flags.py index 2f07c521..3168c636 100644 --- a/posthog/test/test_feature_flags.py +++ b/posthog/test/test_feature_flags.py @@ -1,6 +1,8 @@ import unittest +from datetime import datetime import mock +from dateutil import parser from freezegun import freeze_time from posthog.client import Client @@ -1118,6 +1120,39 @@ def test_match_properties_math_operators(self): self.assertFalse(match_property(property_d, {"key": "44"})) self.assertFalse(match_property(property_d, {"key": 44})) + def test_match_property_date_operators(self): + property_a = self.property(key="key", value="2022-05-01", operator="is_date_before") + self.assertTrue(match_property(property_a, {"key": "2022-03-01"})) + self.assertTrue(match_property(property_a, {"key": "2022-04-30"})) + self.assertTrue(match_property(property_a, {"key": datetime(2022, 4, 30)})) + self.assertTrue(match_property(property_a, {"key": parser.parse("2022-04-30")})) + self.assertFalse(match_property(property_a, {"key": "2022-05-30"})) + + # Can't be a number + with self.assertRaises(InconclusiveMatchError): + match_property(property_a, {"key": 1}) + + # can't be invalid string + with self.assertRaises(InconclusiveMatchError): + match_property(property_a, {"key": "abcdef"}) + + property_b = self.property(key="key", value="2022-05-01", operator="is_date_after") + self.assertTrue(match_property(property_b, {"key": "2022-05-02"})) + self.assertTrue(match_property(property_b, {"key": "2022-05-30"})) + self.assertTrue(match_property(property_b, {"key": datetime(2022, 5, 30)})) + self.assertTrue(match_property(property_b, {"key": parser.parse("2022-05-30")})) + self.assertFalse(match_property(property_b, {"key": "2022-04-30"})) + + # can't be invalid string + with self.assertRaises(InconclusiveMatchError): + match_property(property_b, {"key": "abcdef"}) + + # Invalid flag property + property_c = self.property(key="key", value=1234, operator="is_date_before") + + with self.assertRaises(InconclusiveMatchError): + match_property(property_c, {"key": 1}) + class TestCaptureCalls(unittest.TestCase): @mock.patch.object(Client, "capture") diff --git a/posthog/version.py b/posthog/version.py index 8b5a2a80..9c9ab081 100644 --- a/posthog/version.py +++ b/posthog/version.py @@ -1,4 +1,4 @@ -VERSION = "2.1.0" +VERSION = "2.1.1" if __name__ == "__main__": print(VERSION, end="")