Skip to content

Commit 6984e76

Browse files
authored
fix: adding currency property to events (#60)
1 parent fe1573e commit 6984e76

File tree

6 files changed

+99
-50
lines changed

6 files changed

+99
-50
lines changed

.github/workflows/publish-to-pypi.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ jobs:
3030
with:
3131
fetch-depth: 0
3232

33-
- name: Set up Python 3.7
33+
- name: Set up Python 3.8
3434
uses: actions/setup-python@v3
3535
with:
36-
python-version: 3.7
36+
python-version: 3.8
3737

3838
- name: Run Test
3939
run: python -m unittest discover -s ./src -p 'test_*.py'

.github/workflows/publish-to-test-pypi.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ jobs:
2121
steps:
2222
- uses: actions/checkout@v3
2323

24-
- name: Set up Python 3.7
24+
- name: Set up Python 3.8
2525
uses: actions/setup-python@v3
2626
with:
27-
python-version: 3.7
27+
python-version: 3.8
2828

2929
- name: Install dependencies
3030
run: python -m pip install build setuptools wheel twine

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
runs-on: ubuntu-latest
88
strategy:
99
matrix:
10-
python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11" ]
10+
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ]
1111
steps:
1212
- name: Checkout source code
1313
uses: actions/checkout@v3

src/amplitude/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
REVENUE_RECEIPT = "$receipt"
4141
REVENUE_RECEIPT_SIG = "$receiptSig"
4242
REVENUE = "$revenue"
43+
REVENUE_CURRENCY = "$currency"
4344
AMP_REVENUE_EVENT = "revenue_amount"
4445

4546
MAX_PROPERTY_KEYS = 1024

src/amplitude/event.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ def get_body(self):
145145
"price": ["price", float],
146146
"quantity": ["quantity", int],
147147
"revenue": ["revenue", float],
148+
"currency": ["currency", str],
148149
"product_id": ["productId", str],
149150
"revenue_type": ["revenueType", str],
150151
"location_lat": ["location_lat", float],
@@ -240,6 +241,7 @@ def __init__(self, user_id: Optional[str] = None,
240241
revenue: Optional[float] = None,
241242
product_id: Optional[str] = None,
242243
revenue_type: Optional[str] = None,
244+
currency: Optional[str] = None,
243245
location_lat: Optional[float] = None,
244246
location_lng: Optional[float] = None,
245247
ip: Optional[str] = None,
@@ -277,6 +279,7 @@ def __init__(self, user_id: Optional[str] = None,
277279
self.revenue: Optional[str] = None
278280
self.product_id: Optional[str] = None
279281
self.revenue_type: Optional[str] = None
282+
self.currency: Optional[str] = None
280283
self.location_lat: Optional[float] = None
281284
self.location_lng: Optional[float] = None
282285
self.ip: Optional[str] = None
@@ -313,6 +316,7 @@ def __init__(self, user_id: Optional[str] = None,
313316
self["revenue"] = revenue
314317
self["product_id"] = product_id
315318
self["revenue_type"] = revenue_type
319+
self["currency"] = currency
316320
self["location_lat"] = location_lat
317321
self["location_lng"] = location_lng
318322
self["ip"] = ip
@@ -484,6 +488,7 @@ def __init__(self, event_type: str,
484488
revenue: Optional[float] = None,
485489
product_id: Optional[str] = None,
486490
revenue_type: Optional[str] = None,
491+
currency: Optional[str] = None,
487492
location_lat: Optional[float] = None,
488493
location_lng: Optional[float] = None,
489494
ip: Optional[str] = None,
@@ -520,6 +525,7 @@ def __init__(self, event_type: str,
520525
revenue=revenue,
521526
product_id=product_id,
522527
revenue_type=revenue_type,
528+
currency=currency,
523529
location_lat=location_lat,
524530
location_lng=location_lng,
525531
ip=ip,
@@ -1042,7 +1048,8 @@ def __init__(self, price: float,
10421048
receipt: Optional[str] = None,
10431049
receipt_sig: Optional[str] = None,
10441050
properties: Optional[dict] = None,
1045-
revenue: Optional[float] = None):
1051+
revenue: Optional[float] = None,
1052+
currency: Optional[str] = None):
10461053
"""The constructor of the Revenue class"""
10471054
self.price: float = price
10481055
self.quantity: int = quantity
@@ -1052,6 +1059,7 @@ def __init__(self, price: float,
10521059
self.receipt_sig: Optional[str] = receipt_sig
10531060
self.properties: Optional[dict] = properties
10541061
self.revenue: Optional[float] = revenue
1062+
self.currency: Optional[str] = currency
10551063

10561064
def set_receipt(self, receipt: str, receipt_signature: str):
10571065
"""Set the receipt and signature
@@ -1098,7 +1106,8 @@ def get_event_properties(self):
10981106
constants.REVENUE_TYPE: self.revenue_type,
10991107
constants.REVENUE_RECEIPT: self.receipt,
11001108
constants.REVENUE_RECEIPT_SIG: self.receipt_sig,
1101-
constants.REVENUE: self.revenue})
1109+
constants.REVENUE: self.revenue,
1110+
constants.REVENUE_CURRENCY: self.currency})
11021111
return {key: value for key, value in event_properties.items() if value is not None}
11031112

11041113

@@ -1178,6 +1187,7 @@ def __init__(self, user_id: Optional[str] = None,
11781187
revenue: Optional[float] = None,
11791188
product_id: Optional[str] = None,
11801189
revenue_type: Optional[str] = None,
1190+
currency: Optional[str] = None,
11811191
location_lat: Optional[float] = None,
11821192
location_lng: Optional[float] = None,
11831193
ip: Optional[str] = None,
@@ -1219,6 +1229,7 @@ def __init__(self, user_id: Optional[str] = None,
12191229
revenue=revenue,
12201230
product_id=product_id,
12211231
revenue_type=revenue_type,
1232+
currency=currency,
12221233
location_lat=location_lat,
12231234
location_lng=location_lng,
12241235
ip=ip,

src/test/test_client.py

Lines changed: 80 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,15 @@ def test_amplitude_client_track_success(self):
3030
res = Response(HttpStatus.SUCCESS)
3131
post_method.return_value = res
3232
events = []
33+
self.assertion_errors = []
3334

3435
def callback_func(event, code, message=None):
35-
self.assertEqual(200, code)
36-
events.append(event.event_properties["id"])
36+
try:
37+
self.assertEqual(200, code)
38+
events.append(event.event_properties["id"])
39+
self.assertEqual('USD', event.currency)
40+
except AssertionError as e:
41+
self.assertion_errors.append(str(e))
3742

3843
self.client.configuration.callback = callback_func
3944
for use_batch in (True, False):
@@ -42,12 +47,14 @@ def callback_func(event, code, message=None):
4247
events.clear()
4348
self.client.configuration.use_batch = use_batch
4449
for i in range(25):
45-
self.client.track(BaseEvent("test_event", "test_user_id", event_properties={"id": i}))
50+
self.client.track(BaseEvent("test_event", "test_user_id",
51+
event_properties={"id": i}, currency='USD'))
4652
for flush_future in self.client.flush():
4753
if flush_future:
4854
flush_future.result()
4955
self.assertEqual(25, len(events))
5056
post_method.assert_called()
57+
self.assertEqual(0, len(self.assertion_errors))
5158

5259
def test_amplitude_client_track_invalid_api_key_log_error(self):
5360
post_method = MagicMock()
@@ -84,13 +91,17 @@ def test_amplitude_client_track_invalid_response_then_success_response(self):
8491
}
8592
success_res = Response(HttpStatus.SUCCESS)
8693
events = []
94+
self.assertion_errors = []
8795

8896
def callback_func(event, code, message=None):
89-
if event.event_properties["id"] in (1, 2, 5, 6, 8):
90-
self.assertEqual(400, code)
91-
else:
92-
self.assertEqual(200, code)
93-
events.append((event.event_properties["id"], event.retry))
97+
try:
98+
if event.event_properties["id"] in (1, 2, 5, 6, 8):
99+
self.assertEqual(400, code)
100+
else:
101+
self.assertEqual(200, code)
102+
events.append((event.event_properties["id"], event.retry))
103+
except AssertionError as e:
104+
self.assertion_errors.append(str(e))
94105

95106
self.client.configuration.callback = callback_func
96107
for use_batch in (True, False):
@@ -107,20 +118,25 @@ def callback_func(event, code, message=None):
107118
self.assertEqual(2, post_method.call_count)
108119
self.assertEqual([(1, 0), (2, 0), (5, 0), (6, 0), (8, 0),
109120
(0, 1), (3, 1), (4, 1), (7, 1), (9, 1)], events)
121+
self.assertEqual(0, len(self.assertion_errors))
110122

111123
def test_amplitude_client_identify_invalid_log_error_then_success(self):
112124
post_method = MagicMock()
113125
HttpClient.post = post_method
114126
res = Response(HttpStatus.SUCCESS)
115127
post_method.return_value = res
128+
self.assertion_errors = []
116129

117130
def callback_func(event, code, message=None):
118-
self.assertEqual(200, code)
119-
self.assertTrue(isinstance(event, IdentifyEvent))
120-
self.assertTrue("user_properties" in event)
121-
self.assertEqual("$identify", event["event_type"])
122-
self.assertEqual("test_user_id", event["user_id"])
123-
self.assertEqual("test_device_id", event["device_id"])
131+
try:
132+
self.assertEqual(200, code)
133+
self.assertTrue(isinstance(event, IdentifyEvent))
134+
self.assertTrue("user_properties" in event)
135+
self.assertEqual("$identify", event["event_type"])
136+
self.assertEqual("test_user_id", event["user_id"])
137+
self.assertEqual("test_device_id", event["device_id"])
138+
except AssertionError as e:
139+
self.assertion_errors.append(str(e))
124140

125141
self.client.configuration.callback = callback_func
126142
for use_batch in (True, False):
@@ -142,21 +158,26 @@ def callback_func(event, code, message=None):
142158
if flush_future:
143159
flush_future.result()
144160
post_method.assert_called_once()
161+
self.assertEqual(0, len(self.assertion_errors))
145162

146163
def test_amplitude_client_group_identify_invalid_log_error_then_success(self):
147164
post_method = MagicMock()
148165
HttpClient.post = post_method
149166
res = Response(HttpStatus.SUCCESS)
150167
post_method.return_value = res
168+
self.assertion_errors = []
151169

152170
def callback_func(event, code, message=None):
153-
self.assertEqual(200, code)
154-
self.assertTrue(isinstance(event, GroupIdentifyEvent))
155-
self.assertTrue("group_properties" in event)
156-
self.assertEqual("$groupidentify", event["event_type"])
157-
self.assertEqual("test_user_id", event["user_id"])
158-
self.assertEqual("test_device_id", event["device_id"])
159-
self.assertEqual({"Sports": "Football"}, event["groups"])
171+
try:
172+
self.assertEqual(200, code)
173+
self.assertTrue(isinstance(event, GroupIdentifyEvent))
174+
self.assertTrue("group_properties" in event)
175+
self.assertEqual("$groupidentify", event["event_type"])
176+
self.assertEqual("test_user_id", event["user_id"])
177+
self.assertEqual("test_device_id", event["device_id"])
178+
self.assertEqual({"Sports": "Football"}, event["groups"])
179+
except AssertionError as e:
180+
self.assertion_errors.append(str(e))
160181

161182
self.client.configuration.callback = callback_func
162183
for use_batch in (True, False):
@@ -179,22 +200,27 @@ def callback_func(event, code, message=None):
179200
if flush_future:
180201
flush_future.result()
181202
post_method.assert_called_once()
203+
self.assertEqual(0, len(self.assertion_errors))
182204

183205
def test_amplitude_set_group_success(self):
184206
post_method = MagicMock()
185207
HttpClient.post = post_method
186208
res = Response(HttpStatus.SUCCESS)
187209
post_method.return_value = res
210+
self.assertion_errors = []
188211

189212
def callback_func(event, code, message=None):
190-
self.assertEqual(200, code)
191-
self.assertTrue(isinstance(event, IdentifyEvent))
192-
self.assertTrue("groups" in event)
193-
self.assertEqual("$identify", event["event_type"])
194-
self.assertEqual("test_user_id", event["user_id"])
195-
self.assertEqual("test_device_id", event["device_id"])
196-
self.assertEqual({"type": ["test_group", "test_group_2"]}, event.groups)
197-
self.assertEqual({"$set": {"type": ["test_group", "test_group_2"]}}, event.user_properties)
213+
try:
214+
self.assertEqual(200, code)
215+
self.assertTrue(isinstance(event, IdentifyEvent))
216+
self.assertTrue("groups" in event)
217+
self.assertEqual("$identify", event["event_type"])
218+
self.assertEqual("test_user_id", event["user_id"])
219+
self.assertEqual("test_device_id", event["device_id"])
220+
self.assertEqual({"type": ["test_group", "test_group_2"]}, event.groups)
221+
self.assertEqual({"$set": {"type": ["test_group", "test_group_2"]}}, event.user_properties)
222+
except AssertionError as e:
223+
self.assertion_errors.append(str(e))
198224

199225
self.client.configuration.callback = callback_func
200226
for use_batch in (True, False):
@@ -207,30 +233,35 @@ def callback_func(event, code, message=None):
207233
if flush_future:
208234
flush_future.result()
209235
post_method.assert_called_once()
236+
self.assertEqual(0, len(self.assertion_errors))
210237

211238
def test_amplitude_client_revenue_invalid_log_error_then_success(self):
212239
post_method = MagicMock()
213240
HttpClient.post = post_method
214241
res = Response(HttpStatus.SUCCESS)
215242
post_method.return_value = res
243+
self.assertion_errors = []
216244

217245
def callback_func(event, code, message=None):
218-
self.assertEqual(200, code)
219-
self.assertTrue(isinstance(event, RevenueEvent))
220-
self.assertTrue("event_properties" in event)
221-
self.assertEqual("revenue_amount", event["event_type"])
222-
self.assertEqual("test_user_id", event["user_id"])
223-
self.assertEqual("test_device_id", event["device_id"])
224-
self.assertEqual({'$price': 60.2, '$productId': 'P63', '$quantity': 3, '$receipt': 'A0001',
225-
'$receiptSig': '0001A', 'other_property': 'test'},
226-
event["event_properties"])
246+
try:
247+
self.assertEqual(200, code)
248+
self.assertTrue(isinstance(event, RevenueEvent))
249+
self.assertTrue("event_properties" in event)
250+
self.assertEqual("revenue_amount", event["event_type"])
251+
self.assertEqual("test_user_id", event["user_id"])
252+
self.assertEqual("test_device_id", event["device_id"])
253+
self.assertEqual({'$price': 60.2, '$productId': 'P63', '$quantity': 3, '$receipt': 'A0001',
254+
'$currency': 'USD', '$receiptSig': '0001A', 'other_property': 'test'},
255+
event["event_properties"])
256+
except AssertionError as e:
257+
self.assertion_errors.append(str(e))
227258

228259
self.client.configuration.callback = callback_func
229260
for use_batch in (True, False):
230261
with self.subTest(use_batch=use_batch):
231262
post_method.reset_mock()
232263
self.client.configuration.use_batch = use_batch
233-
revenue_obj = Revenue(price="abc", quantity=3, product_id="P63", properties={"other_property": "test"})
264+
revenue_obj = Revenue(price="abc", quantity=3, product_id="P63", currency="USD", properties={"other_property": "test"})
234265
self.assertFalse(revenue_obj.is_valid())
235266
with self.assertLogs("test", "ERROR") as cm:
236267
self.client.configuration.logger = logging.getLogger("test")
@@ -244,18 +275,23 @@ def callback_func(event, code, message=None):
244275
if flush_future:
245276
flush_future.result()
246277
post_method.assert_called_once()
278+
self.assertEqual(0, len(self.assertion_errors))
247279

248280
def test_amplitude_client_flush_success(self):
249281
post_method = MagicMock()
250282
HttpClient.post = post_method
251283
res = Response(HttpStatus.SUCCESS)
252284
post_method.return_value = res
285+
self.assertion_errors = []
253286

254287
def callback_func(event, code, message=None):
255-
self.assertEqual(200, code)
256-
self.assertEqual("flush_test", event["event_type"])
257-
self.assertEqual("test_user_id", event["user_id"])
258-
self.assertEqual("test_device_id", event["device_id"])
288+
try:
289+
self.assertEqual(200, code)
290+
self.assertEqual("flush_test", event["event_type"])
291+
self.assertEqual("test_user_id", event["user_id"])
292+
self.assertEqual("test_device_id", event["device_id"])
293+
except AssertionError as e:
294+
self.assertion_errors.append(str(e))
259295

260296
self.client.configuration.callback = callback_func
261297
for use_batch in (True, False):
@@ -272,6 +308,7 @@ def callback_func(event, code, message=None):
272308
if flush_future:
273309
flush_future.result()
274310
post_method.assert_called_once()
311+
self.assertEqual(0, len(self.assertion_errors))
275312

276313
def test_amplitude_add_remove_plugins_success(self):
277314
timeline = self.client._Amplitude__timeline

0 commit comments

Comments
 (0)