Skip to content

Commit f58f433

Browse files
committed
refactor: stringify value in _buffer_event so all layers accept the broad type
DB stores value as string, so it must be string on the wire. Move the conversion to the single deepest point (`_buffer_event`) instead of forcing callers / Flagsmith.* to stringify. All public methods now accept Optional[Union[str, int, float, bool]] symmetrically; get_experiment_flag just passes flag.value through.
1 parent cdc6c98 commit f58f433

3 files changed

Lines changed: 26 additions & 8 deletions

File tree

flagsmith/analytics.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def track_event(
109109
self,
110110
event: str,
111111
identifier: typing.Optional[str] = None,
112-
value: typing.Optional[typing.Union[str, int, float]] = None,
112+
value: typing.Optional[typing.Union[str, int, float, bool]] = None,
113113
traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
114114
metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
115115
) -> None:
@@ -126,7 +126,7 @@ def track_exposure_event(
126126
self,
127127
feature_name: str,
128128
identifier: typing.Optional[str] = None,
129-
value: typing.Optional[str] = None,
129+
value: typing.Optional[typing.Union[str, int, float, bool]] = None,
130130
traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
131131
metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
132132
) -> None:
@@ -144,7 +144,7 @@ def _buffer_event(
144144
event: str,
145145
feature_name: typing.Optional[str],
146146
identifier: typing.Optional[str],
147-
value: typing.Optional[typing.Union[str, int, float]],
147+
value: typing.Optional[typing.Union[str, int, float, bool]],
148148
traits: typing.Optional[typing.Dict[str, typing.Any]],
149149
metadata: typing.Optional[typing.Dict[str, typing.Any]],
150150
) -> None:
@@ -155,7 +155,7 @@ def _buffer_event(
155155
"event": event,
156156
"feature_name": feature_name,
157157
"identifier": identifier,
158-
"value": value,
158+
"value": str(value) if value is not None else None,
159159
"traits": dict(traits) if traits else None,
160160
"metadata": {**(metadata or {}), "sdk_version": __version__},
161161
"timestamp": int(datetime.now().timestamp() * 1000),

flagsmith/flagsmith.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ def get_experiment_flag(
365365
self.track_exposure_event(
366366
feature_name=feature_name,
367367
identifier=identifier,
368-
value=str(flag.value) if flag.value is not None else None,
368+
value=flag.value,
369369
traits=traits,
370370
)
371371
return flag
@@ -374,7 +374,7 @@ def track_event(
374374
self,
375375
event: str,
376376
identifier: typing.Optional[str] = None,
377-
value: typing.Optional[typing.Union[str, int, float]] = None,
377+
value: typing.Optional[typing.Union[str, int, float, bool]] = None,
378378
traits: typing.Optional[TraitMapping] = None,
379379
metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
380380
) -> None:
@@ -392,7 +392,7 @@ def track_exposure_event(
392392
self,
393393
feature_name: str,
394394
identifier: typing.Optional[str] = None,
395-
value: typing.Optional[str] = None,
395+
value: typing.Optional[typing.Union[str, int, float, bool]] = None,
396396
traits: typing.Optional[TraitMapping] = None,
397397
metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
398398
) -> None:

tests/test_event_processor.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,31 @@ def test_track_event_buffers_event(event_processor: EventProcessor) -> None:
2525
assert event["event"] == "purchase"
2626
assert event["feature_name"] is None
2727
assert event["identifier"] == "user1"
28-
assert event["value"] == 99.5
28+
assert event["value"] == "99.5"
2929
assert event["traits"] == {"plan": "premium"}
3030
assert event["metadata"]["sku"] == "abc"
3131
assert "sdk_version" in event["metadata"]
3232
assert isinstance(event["timestamp"], int)
3333

3434

35+
def test_buffer_stringifies_non_string_values(
36+
event_processor: EventProcessor,
37+
) -> None:
38+
event_processor.track_event(event="purchase", value=99.5)
39+
event_processor.track_event(event="opt_in", value=True)
40+
event_processor.track_event(event="count", value=3)
41+
event_processor.track_event(event="variant", value="control")
42+
event_processor.track_event(event="empty")
43+
44+
assert [e["value"] for e in event_processor._buffer] == [
45+
"99.5",
46+
"True",
47+
"3",
48+
"control",
49+
None,
50+
]
51+
52+
3553
def test_track_event_defaults_timestamp_to_now(
3654
event_processor: EventProcessor,
3755
) -> None:

0 commit comments

Comments
 (0)