Skip to content
5 changes: 5 additions & 0 deletions .sampo/changesets/resolute-guardian-ilmarinen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
pypi/posthog: patch
---

add PROPERTY_OPERATORS constant for match_property
51 changes: 31 additions & 20 deletions posthog/feature_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@

NONE_VALUES_ALLOWED_OPERATORS = ["is_not"]

# All operators supported by match_property, grouped by category.
EQUALITY_OPERATORS = ("exact", "is_not", "is_set", "is_not_set")
STRING_OPERATORS = ("icontains", "not_icontains", "regex", "not_regex")
NUMERIC_OPERATORS = ("gt", "gte", "lt", "lte")
DATE_OPERATORS = ("is_date_before", "is_date_after")
SEMVER_COMPARISON_OPERATORS = (
"semver_eq",
"semver_neq",
"semver_gt",
"semver_gte",
"semver_lt",
"semver_lte",
)
SEMVER_RANGE_OPERATORS = ("semver_tilde", "semver_caret", "semver_wildcard")
SEMVER_OPERATORS = SEMVER_COMPARISON_OPERATORS + SEMVER_RANGE_OPERATORS

PROPERTY_OPERATORS = (
EQUALITY_OPERATORS
+ STRING_OPERATORS
+ NUMERIC_OPERATORS
+ DATE_OPERATORS
+ SEMVER_OPERATORS
)


class InconclusiveMatchError(Exception):
pass
Expand Down Expand Up @@ -385,6 +409,9 @@ def match_property(property, property_values) -> bool:
operator = property.get("operator") or "exact"
value = property.get("value")

if operator not in PROPERTY_OPERATORS:
raise InconclusiveMatchError(f"Unknown operator {operator}")

if key not in property_values:
raise InconclusiveMatchError(
"can't match properties without a given property value"
Expand Down Expand Up @@ -505,32 +532,15 @@ def compare(lhs, rhs, operator):
"The date provided must be a string or date object"
)

if operator in (
"semver_eq",
"semver_neq",
"semver_gt",
"semver_gte",
"semver_lt",
"semver_lte",
"semver_tilde",
"semver_caret",
"semver_wildcard",
):
if operator in SEMVER_OPERATORS:
try:
override_parsed = parse_semver(override_value)
except (ValueError, TypeError):
raise InconclusiveMatchError(
f"Person property value '{override_value}' is not a valid semver"
)

if operator in (
"semver_eq",
"semver_neq",
"semver_gt",
"semver_gte",
"semver_lt",
"semver_lte",
):
if operator in SEMVER_COMPARISON_OPERATORS:
try:
flag_parsed = parse_semver(value)
except (ValueError, TypeError):
Expand Down Expand Up @@ -578,7 +588,8 @@ def compare(lhs, rhs, operator):
)
return lower <= override_parsed < upper

# if we get here, we don't know how to handle the operator
# Unreachable: all operators in PROPERTY_OPERATORS are handled above,
# and unknown operators are rejected at the top of this function.
raise InconclusiveMatchError(f"Unknown operator {operator}")


Expand Down
Loading