Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acad2b142e | ||
|
|
cb62570e69 | ||
|
|
33645ecd3c |
@@ -1,3 +1,14 @@
|
||||
## 2.1.2 - 2022-09-15
|
||||
|
||||
Changes:
|
||||
|
||||
1. Fixes issues with date comparison.
|
||||
## 2.1.1 - 2022-09-14
|
||||
|
||||
Changes:
|
||||
|
||||
1. Feature flags local evaluation now supports date property filters as well. Accepts both strings and datetime objects.
|
||||
|
||||
## 2.1.0 - 2022-08-11
|
||||
|
||||
Changes:
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import datetime
|
||||
import hashlib
|
||||
import re
|
||||
|
||||
from posthog.utils import is_valid_regex
|
||||
from dateutil import parser
|
||||
|
||||
from posthog.utils import convert_to_datetime_aware, is_valid_regex
|
||||
|
||||
__LONG_SCALE__ = float(0xFFFFFFFFFFFFFFF)
|
||||
|
||||
@@ -126,4 +129,35 @@ 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)
|
||||
parsed_date = convert_to_datetime_aware(parsed_date)
|
||||
except Exception:
|
||||
raise InconclusiveMatchError("The date set on the flag is not a valid format")
|
||||
|
||||
if isinstance(override_value, datetime.datetime):
|
||||
override_date = convert_to_datetime_aware(override_value)
|
||||
if operator == "is_date_before":
|
||||
return override_date < parsed_date
|
||||
else:
|
||||
return override_date > parsed_date
|
||||
elif isinstance(override_value, datetime.date):
|
||||
if operator == "is_date_before":
|
||||
return override_value < parsed_date.date()
|
||||
else:
|
||||
return override_value > parsed_date.date()
|
||||
elif isinstance(override_value, str):
|
||||
try:
|
||||
override_date = parser.parse(override_value)
|
||||
override_date = convert_to_datetime_aware(override_date)
|
||||
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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
from dateutil import parser, tz
|
||||
from freezegun import freeze_time
|
||||
|
||||
from posthog.client import Client
|
||||
@@ -1118,6 +1120,58 @@ class TestMatchProperties(unittest.TestCase):
|
||||
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.date(2022, 4, 30)}))
|
||||
self.assertTrue(match_property(property_a, {"key": datetime.datetime(2022, 4, 30, 1, 2, 3)}))
|
||||
self.assertTrue(
|
||||
match_property(
|
||||
property_a, {"key": datetime.datetime(2022, 4, 30, 1, 2, 3, tzinfo=tz.gettz("Europe/Madrid"))}
|
||||
)
|
||||
)
|
||||
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.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})
|
||||
|
||||
# Timezone aware property
|
||||
property_d = self.property(key="key", value="2022-04-05 12:34:12 +01:00", operator="is_date_before")
|
||||
self.assertFalse(match_property(property_d, {"key": "2022-05-30"}))
|
||||
|
||||
self.assertTrue(match_property(property_d, {"key": "2022-03-30"}))
|
||||
self.assertTrue(match_property(property_d, {"key": "2022-04-05 12:34:11 +01:00"}))
|
||||
self.assertTrue(match_property(property_d, {"key": "2022-04-05 12:34:11 +01:00"}))
|
||||
|
||||
self.assertFalse(match_property(property_d, {"key": "2022-04-05 12:34:13 +01:00"}))
|
||||
|
||||
self.assertTrue(match_property(property_d, {"key": "2022-04-05 11:34:11 +00:00"}))
|
||||
self.assertFalse(match_property(property_d, {"key": "2022-04-05 11:34:13 +00:00"}))
|
||||
|
||||
|
||||
class TestCaptureCalls(unittest.TestCase):
|
||||
@mock.patch.object(Client, "capture")
|
||||
|
||||
+7
-1
@@ -2,7 +2,7 @@ import logging
|
||||
import numbers
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from datetime import date, datetime
|
||||
from datetime import date, datetime, timezone
|
||||
from decimal import Decimal
|
||||
from uuid import UUID
|
||||
|
||||
@@ -109,3 +109,9 @@ class SizeLimitedDict(defaultdict):
|
||||
self.clear()
|
||||
|
||||
super().__setitem__(key, value)
|
||||
|
||||
|
||||
def convert_to_datetime_aware(date_obj):
|
||||
if date_obj.tzinfo is None:
|
||||
date_obj = date_obj.replace(tzinfo=timezone.utc)
|
||||
return date_obj
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
VERSION = "2.1.0"
|
||||
VERSION = "2.1.2"
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(VERSION, end="")
|
||||
|
||||
Reference in New Issue
Block a user