Skip to content

Instantly share code, notes, and snippets.

@ei-grad
Last active April 6, 2016 09:57
Show Gist options
  • Save ei-grad/111c6b681735dd3c240bf22d4c43294d to your computer and use it in GitHub Desktop.
Save ei-grad/111c6b681735dd3c240bf22d4c43294d to your computer and use it in GitHub Desktop.
Mixpanel API client with python2/python3 support and data export API support
#! /usr/bin/env python
#
# Mixpanel, Inc. -- http://mixpanel.com/
#
# Python API client library to consume mixpanel.com analytics data.
#
# Copyright 2010-2013 Mixpanel, Inc
# Copyright 2016 Edadeal, LCC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import codecs
import hashlib
import json
import time
from six import b
import requests
def sign(params, secret):
if 'sig' in params:
del params['sig']
# fix arrays (mixpanel wants them json-encoded)
for key, value in params.items():
if isinstance(value, list):
params[key] = json.dumps(value)
args = list(sorted(params.items()))
result = hashlib.md5()
for k, v in args:
result.update(b(k))
result.update(b('='))
result.update(b(str(v)))
result.update(b(secret))
params['sig'] = result.hexdigest()
class MixpanelAPI(object):
def __init__(self, api_key, api_secret):
self.api_key = api_key
self.api_secret = api_secret
def request(self, methods, params, http_method='GET', format='json',
timeout=300):
"""
methods - List of methods to be joined, e.g. ['events', 'properties', 'values']
will give us http://mixpanel.com/api/2.0/events/properties/values/
params - Extra parameters associated with method
"""
params = dict(params)
params['api_key'] = self.api_key
if 'expire' not in params:
params['expire'] = int(time.time()) + timeout
params['format'] = format
sign(params, self.api_secret)
request_url = 'https://mixpanel.com/api/2.0/' + '/'.join(methods)
if http_method == 'GET':
resp = requests.request(
http_method, request_url,
params=params,
timeout=timeout
)
else:
resp = requests.request(
http_method, request_url,
data=params,
timeout=timeout
)
return resp.json()
def engage(self, params, **kwargs):
return self.request(['engage'], params, **kwargs)
def export(self, from_date, to_date=None, event=None, where=None, timeout=3600):
if to_date is None:
to_date = from_date
params = {
'from_date': from_date,
'to_date': to_date,
}
if event is not None:
params['event'] = event
if where is not None:
params['where'] = where
params['api_key'] = self.api_key
params['expire'] = int(time.time()) + 3600 * 2
params['expire'] = params['expire'] - params['expire'] % 3600
sign(params, self.api_secret)
request_url = 'https://data.mixpanel.com/api/2.0/export/'
return requests.get(request_url, params=params, timeout=timeout,
stream=True)
def export_to_file(self, fp, from_date, to_date, event=None, where=None,
timeout=3600):
response = self.export(from_date, to_date, event, where)
chunks = response.iter_content(4096)
if hasattr(fp, 'encoding'):
chunks = codecs.iterdecode(chunks, 'utf-8')
for chunk in chunks:
fp.write(chunk)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment