17
17
from __future__ import absolute_import , unicode_literals
18
18
import datetime
19
19
import json
20
+ import logging
20
21
import time
21
22
import uuid
22
23
23
24
import six
24
25
from six .moves import range
25
26
import urllib3
26
27
27
- __version__ = '4.7 .0'
28
+ __version__ = '4.8 .0'
28
29
VERSION = __version__ # TODO: remove when bumping major version.
29
30
31
+ logger = logging .getLogger (__name__ )
32
+
30
33
31
34
class DatetimeSerializer (json .JSONEncoder ):
32
35
def default (self , obj ):
@@ -100,23 +103,37 @@ def track(self, distinct_id, event_name, properties=None, meta=None):
100
103
self ._consumer .send ('events' , json_dumps (event , cls = self ._serializer ))
101
104
102
105
def import_data (self , api_key , distinct_id , event_name , timestamp ,
103
- properties = None , meta = None ):
106
+ properties = None , meta = None , api_secret = None ):
104
107
"""Record an event that occurred more than 5 days in the past.
105
108
106
- :param str api_key: your Mixpanel project's API key
109
+ :param str api_key: (DEPRECATED) your Mixpanel project's API key
107
110
:param str distinct_id: identifies the user triggering the event
108
111
:param str event_name: a name describing the event
109
112
:param int timestamp: UTC seconds since epoch
110
113
:param dict properties: additional data to record; keys should be
111
114
strings, and values should be strings, numbers, or booleans
112
115
:param dict meta: overrides Mixpanel special properties
116
+ :param str api_secret: Your Mixpanel project's API secret.
117
+
118
+ Important: Mixpanel's ``import`` HTTP endpoint requires the project API
119
+ secret found in your Mixpanel project's settings. The older API key is
120
+ no longer accessible in the Mixpanel UI, but will continue to work.
121
+ The api_key parameter will be removed in an upcoming release of
122
+ mixpanel-python.
123
+
124
+ .. versionadded:: 4.8.0
125
+ The *api_secret* parameter.
113
126
114
127
To avoid accidentally recording invalid events, the Mixpanel API's
115
128
``track`` endpoint disallows events that occurred too long ago. This
116
129
method can be used to import such events. See our online documentation
117
130
for `more details
118
131
<https://developer.mixpanel.com/docs/importing-old-events>`__.
119
132
"""
133
+
134
+ if api_secret is None :
135
+ logger .warning ("api_key will soon be removed from mixpanel-python; please use api_secret instead." )
136
+
120
137
all_properties = {
121
138
'token' : self ._token ,
122
139
'distinct_id' : distinct_id ,
@@ -133,7 +150,8 @@ def import_data(self, api_key, distinct_id, event_name, timestamp,
133
150
}
134
151
if meta :
135
152
event .update (meta )
136
- self ._consumer .send ('imports' , json_dumps (event , cls = self ._serializer ), api_key )
153
+
154
+ self ._consumer .send ('imports' , json_dumps (event , cls = self ._serializer ), api_key , api_secret )
137
155
138
156
def alias (self , alias_id , original , meta = None ):
139
157
"""Creates an alias which Mixpanel will use to remap one id to another.
@@ -166,19 +184,32 @@ def alias(self, alias_id, original, meta=None):
166
184
event .update (meta )
167
185
sync_consumer .send ('events' , json_dumps (event , cls = self ._serializer ))
168
186
169
- def merge (self , api_key , distinct_id1 , distinct_id2 , meta = None ):
187
+ def merge (self , api_key , distinct_id1 , distinct_id2 , meta = None , api_secret = None ):
170
188
"""
171
189
Merges the two given distinct_ids.
172
190
173
- :param str api_key: Your Mixpanel project's API key.
191
+ :param str api_key: (DEPRECATED) Your Mixpanel project's API key.
174
192
:param str distinct_id1: The first distinct_id to merge.
175
193
:param str distinct_id2: The second (other) distinct_id to merge.
176
194
:param dict meta: overrides Mixpanel special properties
195
+ :param str api_secret: Your Mixpanel project's API secret.
196
+
197
+ Important: Mixpanel's ``merge`` HTTP endpoint requires the project API
198
+ secret found in your Mixpanel project's settings. The older API key is
199
+ no longer accessible in the Mixpanel UI, but will continue to work.
200
+ The api_key parameter will be removed in an upcoming release of
201
+ mixpanel-python.
202
+
203
+ .. versionadded:: 4.8.0
204
+ The *api_secret* parameter.
177
205
178
206
See our online documentation for `more
179
207
details
180
208
<https://developer.mixpanel.com/docs/http#merge>`__.
181
209
"""
210
+ if api_secret is None :
211
+ logger .warning ("api_key will soon be removed from mixpanel-python; please use api_secret instead." )
212
+
182
213
event = {
183
214
'event' : '$merge' ,
184
215
'properties' : {
@@ -188,7 +219,7 @@ def merge(self, api_key, distinct_id1, distinct_id2, meta=None):
188
219
}
189
220
if meta :
190
221
event .update (meta )
191
- self ._consumer .send ('imports' , json_dumps (event , cls = self ._serializer ), api_key )
222
+ self ._consumer .send ('imports' , json_dumps (event , cls = self ._serializer ), api_key , api_secret )
192
223
193
224
def people_set (self , distinct_id , properties , meta = None ):
194
225
"""Set properties of a people record.
@@ -530,22 +561,27 @@ def __init__(self, events_url=None, people_url=None, import_url=None,
530
561
cert_reqs = cert_reqs ,
531
562
)
532
563
533
- def send (self , endpoint , json_message , api_key = None ):
564
+ def send (self , endpoint , json_message , api_key = None , api_secret = None ):
534
565
"""Immediately record an event or a profile update.
535
566
536
567
:param endpoint: the Mixpanel API endpoint appropriate for the message
537
568
:type endpoint: "events" | "people" | "groups" | "imports"
538
569
:param str json_message: a JSON message formatted for the endpoint
539
570
:param str api_key: your Mixpanel project's API key
571
+ :param str api_secret: your Mixpanel project's API secret
540
572
:raises MixpanelException: if the endpoint doesn't exist, the server is
541
573
unreachable, or the message cannot be processed
574
+
575
+
576
+ .. versionadded:: 4.8.0
577
+ The *api_secret* parameter.
542
578
"""
543
- if endpoint in self ._endpoints :
544
- self ._write_request (self ._endpoints [endpoint ], json_message , api_key )
545
- else :
579
+ if endpoint not in self ._endpoints :
546
580
raise MixpanelException ('No such endpoint "{0}". Valid endpoints are one of {1}' .format (endpoint , self ._endpoints .keys ()))
547
581
548
- def _write_request (self , request_url , json_message , api_key = None ):
582
+ self ._write_request (self ._endpoints [endpoint ], json_message , api_key , api_secret )
583
+
584
+ def _write_request (self , request_url , json_message , api_key = None , api_secret = None ):
549
585
data = {
550
586
'data' : json_message ,
551
587
'verbose' : 1 ,
@@ -554,11 +590,17 @@ def _write_request(self, request_url, json_message, api_key=None):
554
590
if api_key :
555
591
data .update ({'api_key' : api_key })
556
592
593
+ headers = None
594
+
595
+ if api_secret is not None :
596
+ headers = urllib3 .util .make_headers (basic_auth = "{}:" .format (api_secret ))
597
+
557
598
try :
558
599
response = self ._http .request (
559
600
'POST' ,
560
601
request_url ,
561
602
fields = data ,
603
+ headers = headers ,
562
604
encode_multipart = False , # URL-encode payload in POST body.
563
605
)
564
606
except Exception as e :
@@ -621,7 +663,7 @@ def __init__(self, max_size=50, events_url=None, people_url=None, import_url=Non
621
663
self ._max_size = min (50 , max_size )
622
664
self ._api_key = None
623
665
624
- def send (self , endpoint , json_message , api_key = None ):
666
+ def send (self , endpoint , json_message , api_key = None , api_secret = None ):
625
667
"""Record an event or profile update.
626
668
627
669
Internally, adds the message to a buffer, and then flushes the buffer
@@ -633,6 +675,7 @@ def send(self, endpoint, json_message, api_key=None):
633
675
:type endpoint: "events" | "people" | "groups" | "imports"
634
676
:param str json_message: a JSON message formatted for the endpoint
635
677
:param str api_key: your Mixpanel project's API key
678
+ :param str api_secret: your Mixpanel project's API secret
636
679
:raises MixpanelException: if the endpoint doesn't exist, the server is
637
680
unreachable, or any buffered message cannot be processed
638
681
@@ -644,8 +687,9 @@ def send(self, endpoint, json_message, api_key=None):
644
687
645
688
buf = self ._buffers [endpoint ]
646
689
buf .append (json_message )
647
- if api_key is not None :
648
- self ._api_key = api_key
690
+ # Fixme: Don't stick these in the instance.
691
+ self ._api_key = api_key
692
+ self ._api_secret = api_secret
649
693
if len (buf ) >= self ._max_size :
650
694
self ._flush_endpoint (endpoint )
651
695
@@ -664,7 +708,7 @@ def _flush_endpoint(self, endpoint):
664
708
batch = buf [:self ._max_size ]
665
709
batch_json = '[{0}]' .format (',' .join (batch ))
666
710
try :
667
- self ._consumer .send (endpoint , batch_json , self ._api_key )
711
+ self ._consumer .send (endpoint , batch_json , self ._api_key , self . _api_secret )
668
712
except MixpanelException as orig_e :
669
713
mp_e = MixpanelException (orig_e )
670
714
mp_e .message = batch_json
0 commit comments