Skip to content

Commit 98850b8

Browse files
committed
fix: support hexadecimal OpenFeature numeric variants
1 parent f5cbdef commit 98850b8

3 files changed

Lines changed: 42 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
pypi/openfeature-provider-posthog: patch
3+
---
4+
5+
Support hexadecimal numeric variants in the OpenFeature provider.

‎openfeature-provider/openfeature/contrib/provider/posthog/provider.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from __future__ import annotations
99

1010
import logging
11+
import re
1112
from typing import Any, Callable, Mapping, Optional, Sequence, TypeVar, Union
1213

1314
from openfeature.evaluation_context import EvaluationContext
@@ -53,7 +54,9 @@ class PostHogProvider(AbstractProvider):
5354
Flag-type mapping (all via ``get_feature_flag_result``):
5455
* boolean -> ``enabled``
5556
* string -> the multivariate ``variant`` key
56-
* int/float -> the ``variant`` parsed to a number
57+
* int/float -> the ``variant`` parsed to a number, including unsigned
58+
hexadecimal integers such as ``0x10`` (returned as int or float,
59+
respectively)
5760
* object -> the flag's JSON ``payload``
5861
5962
Args:
@@ -213,7 +216,10 @@ def _resolve_number(
213216
f"Flag '{flag_key}' has no variant to parse as {ctor.__name__}."
214217
)
215218
try:
216-
value = ctor(result.variant)
219+
variant = result.variant
220+
if re.fullmatch(r"0[xX][0-9a-fA-F]+", variant.strip()):
221+
variant = str(int(variant, 16))
222+
value = ctor(variant)
217223
except (TypeError, ValueError) as exc:
218224
raise TypeMismatchError(
219225
f"Flag '{flag_key}' variant '{result.variant}' is not a valid "

‎openfeature-provider/tests/test_provider_unit.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,35 @@ def test_number_variant_parse_failure(fake_client, resolver, variant):
100100
getattr(_provider(fake_client), resolver)("n", 0, EvaluationContext("u"))
101101

102102

103+
@pytest.mark.parametrize(
104+
"resolver", ["resolve_integer_details", "resolve_float_details"]
105+
)
106+
@pytest.mark.parametrize(
107+
("variant", "expected"),
108+
[("0x10", 16), ("0Xff", 255), (" 0xA0 ", 160), ("0x0", 0), ("042", 42)],
109+
)
110+
def test_hex_number_variant(fake_client, resolver, variant, expected):
111+
fake_client.get_feature_flag_result.return_value = make_result(variant=variant)
112+
details = getattr(_provider(fake_client), resolver)("n", 0, EvaluationContext("u"))
113+
assert details.value == expected
114+
assert type(details.value) is (
115+
int if resolver == "resolve_integer_details" else float
116+
)
117+
assert details.variant == variant
118+
119+
120+
@pytest.mark.parametrize(
121+
"resolver", ["resolve_integer_details", "resolve_float_details"]
122+
)
123+
@pytest.mark.parametrize(
124+
"variant", ["0x", "0xgg", "0x1.5", "0x_10", "0x1_0", "-0x10", "+0x10"]
125+
)
126+
def test_invalid_hex_number_variant(fake_client, resolver, variant):
127+
fake_client.get_feature_flag_result.return_value = make_result(variant=variant)
128+
with pytest.raises(TypeMismatchError):
129+
getattr(_provider(fake_client), resolver)("n", 0, EvaluationContext("u"))
130+
131+
103132
def test_object_payload(fake_client):
104133
fake_client.get_feature_flag_result.return_value = make_result(
105134
enabled=True, variant="v1", payload={"color": "blue"}

0 commit comments

Comments
 (0)