Skip to content

Commit 935401a

Browse files
authored
feat: support sending evaluated user properties in local evaluation assignment tracking (#51)
1 parent fdb1b6c commit 935401a

File tree

4 files changed

+25
-9
lines changed

4 files changed

+25
-9
lines changed

src/amplitude_experiment/assignment/assignment_config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
class AssignmentConfig(amplitude.Config):
5-
def __init__(self, cache_capacity: int = 65536, **kw):
5+
def __init__(self, cache_capacity: int = 65536, send_evaluated_props: bool = False, **kw):
66
super(AssignmentConfig, self).__init__(**kw)
77
self.cache_capacity = cache_capacity
8+
self.send_evaluated_props = send_evaluated_props

src/amplitude_experiment/assignment/assignment_service.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,21 @@
88
FLAG_TYPE_HOLDOUT_GROUP = "holdout-group"
99

1010

11-
def to_event(assignment: Assignment) -> BaseEvent:
11+
def to_event(assignment: Assignment, send_evaluated_props: bool) -> BaseEvent:
1212
event = BaseEvent(event_type='[Experiment] Assignment', user_id=assignment.user.user_id,
1313
device_id=assignment.user.device_id, event_properties={}, user_properties={})
14+
15+
# If send_evaluated_props is True, populate event with all relevant user attributes
16+
if send_evaluated_props:
17+
user_attributes = [
18+
"country", "city", "region", "dma", "language",
19+
"platform", "version", "os", "device_manufacturer",
20+
"device_brand", "device_model", "carrier"
21+
]
22+
for attr in user_attributes:
23+
setattr(event, attr, getattr(assignment.user, attr, None))
24+
event.user_properties = assignment.user.user_properties
25+
1426
set_props = {}
1527
unset_props = {}
1628

@@ -46,10 +58,11 @@ def to_event(assignment: Assignment) -> BaseEvent:
4658

4759

4860
class AssignmentService:
49-
def __init__(self, amplitude: Amplitude, assignment_filter: AssignmentFilter):
61+
def __init__(self, amplitude: Amplitude, assignment_filter: AssignmentFilter, send_evaluated_props: bool):
5062
self.amplitude = amplitude
5163
self.assignmentFilter = assignment_filter
64+
self.send_evaluated_props = send_evaluated_props
5265

5366
def track(self, assignment: Assignment):
5467
if self.assignmentFilter.should_track(assignment):
55-
self.amplitude.track(to_event(assignment))
68+
self.amplitude.track(to_event(assignment, self.send_evaluated_props))

src/amplitude_experiment/local/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def __init__(self, api_key: str, config: LocalEvaluationConfig = None):
4747
if config and config.assignment_config:
4848
instance = Amplitude(config.assignment_config.api_key, config.assignment_config)
4949
self.assignment_service = AssignmentService(instance, AssignmentFilter(
50-
config.assignment_config.cache_capacity))
50+
config.assignment_config.cache_capacity), config.assignment_config.send_evaluated_props)
5151
self.logger = logging.getLogger("Amplitude")
5252
self.logger.addHandler(logging.StreamHandler())
5353
if self.config.debug:

tests/local/assignment/assignment_service_test.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from src.amplitude_experiment.assignment import AssignmentFilter, Assignment, DAY_MILLIS, to_event, AssignmentService
99
from src.amplitude_experiment.util import hash_code
1010

11-
user = User(user_id='user', device_id='device')
11+
user = User(user_id='user', device_id='device', user_properties={'user_prop': True}, country='country')
1212

1313

1414
class AssignmentServiceTestCase(unittest.TestCase):
@@ -61,10 +61,11 @@ def test_to_event(self):
6161
'empty_variant': empty_variant,
6262
}
6363
assignment = Assignment(user, results)
64-
event = to_event(assignment)
64+
event = to_event(assignment, True)
6565
self.assertEqual(user.user_id, event.user_id)
6666
self.assertEqual(user.device_id, event.device_id)
6767
self.assertEqual('[Experiment] Assignment', event.event_type)
68+
self.assertEqual('country', event.country)
6869
# Validate event properties
6970
event_properties = event.event_properties
7071
self.assertEqual('control', event_properties['basic.variant'])
@@ -89,6 +90,7 @@ def test_to_event(self):
8990
self.assertEqual('on', set_properties['[Experiment] empty_metadata'])
9091
unset_properties = user_properties['$unset']
9192
self.assertEqual('-', unset_properties['[Experiment] default'])
93+
self.assertTrue(user_properties['user_prop'])
9294

9395
# Validate insert id
9496
canonicalization = 'user device basic control default off different_value on empty_metadata on holdout ' \
@@ -99,11 +101,11 @@ def test_to_event(self):
99101
def test_tracking_called(self):
100102
instance = Amplitude('')
101103
instance.track = MagicMock()
102-
service = AssignmentService(instance, AssignmentFilter(2))
104+
service = AssignmentService(instance, AssignmentFilter(2), False)
103105
results = {'flag-key-1': Variant(key='on')}
104106
service.track(Assignment(user, results))
105107
self.assertTrue(instance.track.called)
106108

107109

108110
if __name__ == '__main__':
109-
unittest.main()
111+
unittest.main()

0 commit comments

Comments
 (0)