GithubHelp home page GithubHelp logo

mixpanel / mixpanel-python Goto Github PK

View Code? Open in Web Editor NEW
103.0 82.0 84.0 832 KB

Official Mixpanel Python library.

Home Page: https://mixpanel.com/help/reference/python

License: Other

Python 100.00%

mixpanel-python's Introduction

mixpanel-python

PyPI

PyPI - Python Version

PyPI - Downloads

image

This is the official Mixpanel Python library. This library allows for server-side integration of Mixpanel.

To import, export, transform, or delete your Mixpanel data, please see our mixpanel-utils package.

Installation

The library can be installed using pip:

pip install mixpanel

Getting Started

Typical usage usually looks like this:

from mixpanel import Mixpanel

mp = Mixpanel(YOUR_TOKEN)

# tracks an event with certain properties
mp.track(DISTINCT_ID, 'button clicked', {'color' : 'blue', 'size': 'large'})

# sends an update to a user profile
mp.people_set(DISTINCT_ID, {'$first_name' : 'Ilya', 'favorite pizza': 'margherita'})

You can use an instance of the Mixpanel class for sending all of your events and people updates.

Additional Information

mixpanel-python's People

Contributors

adamn avatar alexlouden avatar ashwch avatar captn3m0 avatar daemonburrito avatar dmitric avatar dror-fs avatar hugoarregui avatar jaredmixpanel avatar joeatwork avatar joeymalysz avatar mblayman avatar michaelstewart avatar mixpanelsteve avatar naoyak avatar safdariqbal avatar seizethedave avatar smcoll avatar yayc avatar zakj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mixpanel-python's Issues

Incorrect documentation for people_track_charge(...)

The current version of mixpanel on pypi is 4.0.2. at the time of writing.

The documentation (http://mixpanel.github.io/mixpanel-python/#mixpanel.Mixpanel.people_track_charge) depicts the behavior for 4.0.2+ though since the handling of the properties=None changed there (d92dd5f).

Possible solutions:

  1. Update the documentation and change the function signature to: people_track_charge(distinct_id, amount, properties, meta=None)
    OR
  2. Release version 4.0.3.

MixpanelException: <urlopen error EOF occurred in violation of protocol (_ssl.c:661)>

I am using mixpanel with mixpanel_async I keep getting this error on the logs

MixpanelException: <urlopen error EOF occurred in violation of protocol (_ssl.c:661)>

        at raise_from (/usr/local/lib/python2.7/site-packages/six.py:737)
        at _flush_endpoint (/usr/local/lib/python2.7/site-packages/mixpanel/__init__.py:466)
        at _sync_flush (/usr/local/lib/python2.7/site-packages/mixpanel_async/async_buffered_consumer.py:256)
        at run (/usr/local/lib/python2.7/site-packages/mixpanel_async/async_buffered_consumer.py:37)
        at __bootstrap_inner (/usr/local/lib/python2.7/threading.py:801)

Support for querying

It would be awesome if this library supported a way to grab some basic data from mixpanel (User profiles etc...), is this library still being developed?

Fail to install 4.0.1 due to missing README.md

$ sudo easy_install mixpanel-py
Searching for mixpanel-py
Reading https://pypi.python.org/simple/mixpanel-py/
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-2.0.0)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-2.0.1)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-3.0.0)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-3.1.1)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-3.1.2)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-3.1.3)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-3.2.0)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-3.2.1)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-4.0.0)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
/Library/Python/2.7/site-packages/setuptools-12.4-py2.7.egg/pkg_resources/init.py:2512: PEP440Warning: 'mixpanel (py-4.0.1)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
Best match: mixpanel-py 4.0.1
Downloading https://pypi.python.org/packages/source/m/mixpanel-py/mixpanel-py-4.0.1.tar.gz#md5=e9d45a9aa82f95e84c960259a9c4d520
Processing mixpanel-py-4.0.1.tar.gz
Writing /tmp/easy_install-UsdqLT/mixpanel-py-4.0.1/setup.cfg
Running mixpanel-py-4.0.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-UsdqLT/mixpanel-py-4.0.1/egg-dist-tmp-zhhP_i
error: README.md: No such file or directory
$

I would normally in such circumstances attempt to read the README file to see if I did something wrong, but, alas, I can't even do that.

pip package name incorrect in README

Running 'pip install mixpanel-python' as documented in the README actually installs a different Mixpanel package than this official release.

As suggested in the Mixpanel help docs, the correct install command is:

pip install mixpanel-py

Also noticed that the installed package name has a dash, which required some SyntaxError workarounds when trying to import. Any chance of renaming the installed package from 'mixpanel-py' to 'mixpanel_py' or just 'mixpanel'? Not clear on any existing package conflict issues there.

Thanks for an official release!

Not able to track old events by using mixpanel.import_data

Hi,
I'm not able to track the old events( > 5 days) by using mixpanel.import_data.
mixpanel.import_data(TEST2_MIXPANEL_TOKEN, actor_object_id, action_verb, action_time, properties=action_dict_data)
mixpanel.people_set(actor_object_id, {'$first_name': actor_first_name})

It creates people in "explore" section without any action-events. It doesn't throw any exception.

When I use mixpanel.track and log events from past 5days then everything works fine.
mixpanel.track(actor_object_id, action_verb, action_data)
mixpanel.people_set(actor_object_id, {'$first_name': actor_first_name})

python : v3.5.2

SSL: CERTIFICATE_VERIFY_FAILED

Since yesterday I've started receiving this error whenever I try to initialize mixpanel on my local machine.

This never happened the day before.

The full exception text:

<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)>

File ".env/lib/python3.7/site-packages/mixpanel/__init__.py" in track
  95.         self._consumer.send('events', json_dumps(event, cls=self._serializer))

File ".env/lib/python3.7/site-packages/mixpanel/__init__.py" in send
  488.             self._write_request(self._endpoints[endpoint], json_message, api_key)

File ".env/lib/python3.7/site-packages/mixpanel/__init__.py" in _write_request
  511.             six.raise_from(MixpanelException(e), e)

File "<string>" in raise_from
  3. # Permission is hereby granted, free of charge, to any person obtaining a copy

Deprecate api_key

Instead use API secret, which is now exposed in the UI, and is preferred for things like import, merge.

Py3k support?

Hey Guys,

is there any chance you will support python 3.4+ in a near future? I'm aware that there is a separate not official fork for it.

bufferedconsumer _api_secret problem

BufferedConsumer has this code:

        # Fixme: Don't stick these in the instance.
        self._api_key = api_key
        self._api_secret = api_secret

Classes that override send without setting these instance vars, such as your recommended AsyncBufferedConsumer, end up generating an error in _flush_endpoint

This could be considered an error in the async package as well (cf jessepollak/mixpanel-python-async#18), but considering you have a FIXME here, I suppose a recent change broke the interaction.

Make Mixpanel.alias() send synchronously, regardless of the consumer configuration

Aliases only take affect after the alias message is received by Mixpanel, which means in asynchronous or time-shifted cases if events or updates associated with a newly created alias arrive before the alias itself, they could be attributed to the wrong user. Change the python library to always send the messages associated with alias immediately when alias() is called.

Provide a way to send Super Properties

As far as I can tell from the documentation, it is only possible for one to send super properties from the javascript client. It would be fantastic to do this on the server side.

Import Legacy Data

Provide functionality to import data into Mixpanel older than 5 days.

json_dumps should be a part of the class to make overriding it easy

Currently json_dumps is a module level method which makes it difficult to override it.

It should be a class level method so that base classes can easily override it.

For example let's say I want to handle decimal.Decimal fields as well then currently I will have to do something like this:

from decimal import Decimal
import json
import mixpanel

class MixPanelDataSerializer(mixpanel.DatetimeSerializer):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return super(MixPanelDataSerializer, self).default(obj)


def json_dumps(data):
    return json.dumps(data, separators=(',', ':'), cls=MixPanelDataSerializer)

mixpanel.json_dumps = json_dumps  # assign the new function to the module object

What do you guys think?

__init__() takes exactly 3 arguments (2 given)

I'm getting this error trying to initialize Mixpanel.
Any idea what might be wrong?

screenshot 2016-02-22 18 19 25

I installed using pip and then did:

from mixpanel import Mixpanel
mp = Mixpanel('1234567890')

Thanks for any tips!

flush function for Buffered Consumer not working

Hi,
in class BufferedConsumer the flush function in line 338 should change to
def flush (self,api_key=None)

and then in line 444-445 should change to:
for endpoint in self._buffers.keys():
self._flush_endpoint(endpoint,api_key=api_key)

JS MixPanel lib variables

Hi. I am integrating MixPanel server side, but I would like to include the internal variables of the JS MixPanel library version, like the browser information, network etc.

Is there any MixPanel example that can guide us on this?

I was wondering if I can use the JS lib to collect the browser information (https://github.com/mixpanel/mixpanel-js/blob/master/src/utils.js) or if it is better to collect this data directly on the server.

screen shot 2017-01-09 at 2 56 43 am

Thanks in advance

Can't use mutable data types for function defaults

Many of the methods in the API use {} as a function default, however this can lead to serious issues. See this blog post on this python gotcha. You should use None and then, for example in track call all_properties.update(properties or {}).

Without this, subsequent calls that don't provide properties, after one that does, will send the old properties along, which will lead to all sorts of confusion. ๐Ÿ˜–

Make custom consumers easier to write

A Consumer-based workaround for #41 will likely require some cut-and-paste code, or referring to private Consumer methods, or both. The whole point of the Consumer architecture is to allow people to write their own custom consumers, and while many of them will ultimately delegate to our consumer, some (like the requests-based backend) will not. Writing a consumer for a different HTTP stack should be a half-page of code at most, and shouldn't duplicate code that is already in the library.

Add support for remove operation

There is currently no support for the $remove operation in the client, so there isn't a way to remove a list item value for a property name.

Allow doing people_set without updating last_seen

Sometimes I want to set a property on the user object retrospectively, and I want this not to update the last_seen value of the user object. Afaics there is no way of doing this. Should there be?

Connection reset by peer from BufferedConsumer

Since upgrading to 4.9.0, we've been getting the following error appearing frequently in sentry:

ConnectionResetError: [Errno 104] Connection reset by peer
  File "urllib3/connectionpool.py", line 699, in urlopen
    httplib_response = self._make_request(
  File "urllib3/connectionpool.py", line 445, in _make_request
    six.raise_from(e, None)
  File "<string>", line 3, in raise_from
    # Permission is hereby granted, free of charge, to any person obtaining a copy
  File "urllib3/connectionpool.py", line 440, in _make_request
    httplib_response = conn.getresponse()
  File "http/client.py", line 1344, in getresponse
    response.begin()
  File "http/client.py", line 307, in begin
    version, status, reason = self._read_status()
  File "http/client.py", line 268, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "socket.py", line 669, in readinto
    return self._sock.recv_into(b)
  File "ssl.py", line 1241, in recv_into
    return self.read(nbytes, buffer)
  File "ssl.py", line 1099, in read
    return self._sslobj.read(len, buffer)
ProtocolError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
  File "requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "urllib3/connectionpool.py", line 755, in urlopen
    retries = retries.increment(
  File "urllib3/util/retry.py", line 532, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "urllib3/packages/six.py", line 769, in reraise
    raise value.with_traceback(tb)
  File "urllib3/connectionpool.py", line 699, in urlopen
    httplib_response = self._make_request(
  File "urllib3/connectionpool.py", line 445, in _make_request
    six.raise_from(e, None)
  File "<string>", line 3, in raise_from
    # Permission is hereby granted, free of charge, to any person obtaining a copy
  File "urllib3/connectionpool.py", line 440, in _make_request
    httplib_response = conn.getresponse()
  File "http/client.py", line 1344, in getresponse
    response.begin()
  File "http/client.py", line 307, in begin
    version, status, reason = self._read_status()
  File "http/client.py", line 268, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "socket.py", line 669, in readinto
    return self._sock.recv_into(b)
  File "ssl.py", line 1241, in recv_into
    return self.read(nbytes, buffer)
  File "ssl.py", line 1099, in read
    return self._sslobj.read(len, buffer)
ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
  File "__init__.py", line 615, in _write_request
    response = self._session.post(
  File "requests/sessions.py", line 590, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "requests/sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 498, in send
    raise ConnectionError(err, request=request)
MixpanelException: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
  File "__init__.py", line 731, in _flush_endpoint
    self._consumer.send(endpoint, batch_json, api_key=self._api_key)
  File "__init__.py", line 594, in send
    self._write_request(self._endpoints[endpoint], json_message, api_key, api_secret)
  File "__init__.py", line 623, in _write_request
    six.raise_from(MixpanelException(e), e)
  File "<string>", line 3, in raise_from
    # Permission is hereby granted, free of charge, to any person obtaining a copy
MixpanelException: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
  File "/usr/src/app/./api/users/tracking.py", line 80, in _track
    mixpanel_track(
  File "/usr/src/app/./api/users/tracking.py", line 140, in mixpanel_track
    flush()
  File "/usr/src/app/./api/users/tracking.py", line 128, in flush
    current_app.mp_consumer.flush()
  File "__init__.py", line 722, in flush
    self._flush_endpoint(endpoint)
  File "__init__.py", line 736, in _flush_endpoint
    six.raise_from(mp_e, orig_e)
  File "<string>", line 3, in raise_from
    # Permission is hereby granted, free of charge, to any person obtaining a copy

This only started after upgrading and seems to be to do with the switch the requests. It happens when we flush the consumer.

deletion out of date

Hi, we've had an occurrence on our system where we've found that $delete no longer takes an empty string like described in the line below. Instead, a boolean value is now needed.

'$delete': "",

If this is the case, this SDK should be updated.

Support for unit tests with synchronous alias()

It's really convenient to test the library with pluggable consumers, except for calls to alias(), which are now synchronous and will require mocking urllib2 (or something).

Build some mechanism that allows for testing, perhaps by allowing callers to pass an alias() consumer along with the standard consumer on object construction.

Thanks @jarcoal for calling this out!

Document Proxy method for frontend events

An official document from Mixpanel Support recommends a backend proxy to avoid ad-blockers. This involves setting the api_host when initializing the frontend JS library. But I cannot seem to find anywhere that says how the backend should be configured to proxy.

Here is the help article, method number four here is what I'm speaking about: https://help.mixpanel.com/hc/en-us/articles/115004499463-Ad-Blockers-Affect-Mixpanel

Our backend is a flask-python application, and we already have a BE integration of Mixpanel for server-side events.


Self-Research

SSLError with the example code

Following the code in the README

from mixpanel import Mixpanel
mp = Mixpanel(MIXPANEL_TOKEN)
mp.track(USER_ID, 'Upload Done')

I get:

MixpanelException: HTTPSConnectionPool(host='api-eu.mixpanel.com', port=443): Max retries exceeded with url: /track (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))

I'm using Mixpanel 4.8.2, python '3.6.10 (default, Jun 6 2020, 21:56:05) \n[GCC 9.3.0]', certifi = ">=2017.4.17", requests 2.20.1, urllib3==1.24.1, Ubuntu 20.04.2 LTS. I also tried upgrading certifi to "2020.12.5" but that did not help.

If I try with

mp = Mixpanel(MIXPANEL_TOKEN, consumer=Consumer(verify_cert=False))

then it works (albeit with a warning).

Send requests to Mixpanel from background thread.

A Mixpanel DNS today took down our service because it blocked on Max Retries. Any chance these tracking events can be sent from a background thread so that in the event of an outage it doesn't hurt our service? We're using Django, so we'd need to spin up a separate worker to handle these events asyncโ€“ it would be awesome if this was all handled from Mixpanel-python directly.

MaxRetryError
HTTPSConnectionPool(host='api.mixpanel.com', port=443): Max retries exceeded with url: /track (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f387c261f10>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))

cert_reqs unicode is not well handled by urllib3 in python2

Hello,

I understand that urllib3 doesn't support python2 anymore, so maybe this is something you are not willing to fix, but I though about reporting it since we are still in the process of migrating to python3.

This is how mixpanel creates the connection pool:

        cert_reqs = 'CERT_REQUIRED' if verify_cert else 'CERT_NONE'
        self._http = urllib3.PoolManager(
            retries=retry_config,
            timeout=urllib3.Timeout(request_timeout),
            cert_reqs=cert_reqs,
        )

but since we are importing for future:

from __future__ import absolute_import, unicode_literals

both in python2 and python3 cert_reqs is a unicode. But please also notice that for python2 (unlike python3) unicode is not an instance of str, so in urllib3:


def resolve_cert_reqs(candidate):
    """
    Resolves the argument to a numeric constant, which can be passed to
    the wrap_socket function/method from the ssl module.
    Defaults to :data:`ssl.CERT_REQUIRED`.
    If given a string it is assumed to be the name of the constant in the
    :mod:`ssl` module or its abbreviation.
    (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
    If it's neither `None` nor a string we assume it is already the numeric
    constant which can directly be passed to wrap_socket.
    """
    if candidate is None:
        return CERT_REQUIRED

    if isinstance(candidate, str):
        res = getattr(ssl, candidate, None)
        if res is None:
            res = getattr(ssl, "CERT_" + candidate)
        return res

    return candidate

candidate will not be correctly resolved.

Mixpanel BufferedConsumer throws `MixpanelException: Mixpanel error: a temporary failure occurred`

I use python:3.7.3-stretch docker image. It is run in AWS EKS.
The mixpanel library version is mixpanel==4.5.0.

I use the BufferedConsumer.

from mixpanel import Mixpanel, BufferedConsumer
mxp_consumer = BufferedConsumer(max_size=BaseConfig.BATCH_SIZE*5)
mp = Mixpanel(BaseConfig.TOKEN, consumer=mxp_consumer)

I flush the endpoint once it reaches either the time threshold or the batch size threshold. The corresponding code snippet is given below.

if (((len(events) >= BaseConfig.BATCH_SIZE) or
     (datetime.now() > (start + timedelta(minutes=BaseConfig.BATCH_FLUSH_TIME)))) and
 (len(events) > 0)):

	try:
		await process_and_send_to_mixpanel(events, mp) 
		mxp_consumer.flush() # Flush the buffered consumer
		events.clear()  # Clear list
		start = datetime.now()  # Reset Time

	except Exception as e:
		logger.error(e, exc_info=True)
		logger.error(e)
		

inside the process_and_send_to_mixpanel(events, mp) function I make calls to both /engage /track endpoints using the below functions.

mp.people_set(str(distinct_id),
              people_properties,
              meta={"$time": datetime.now().isoformat()})
		

mp.track(str(distinct_id),
         str(mxp_event_event_name),
         {**mxp_event,
          "time": datetime.now().isoformat()})

This code works without errors for 95% of the time.

but I get the BELOW GIVEN ERROR

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/mixpanel/__init__.py", line 598, in _flush_endpoint
    self._consumer.send(endpoint, batch_json, self._api_key)
  File "/usr/local/lib/python3.7/site-packages/mixpanel/__init__.py", line 488, in send
    self._write_request(self._endpoints[endpoint], json_message, api_key)
  File "/usr/local/lib/python3.7/site-packages/mixpanel/__init__.py", line 519, in _write_request
    raise MixpanelException('Mixpanel error: {0}'.format(response['error']))
mixpanel.MixpanelException: Mixpanel error: a temporary failure occurred

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
    mxp_consumer.flush()
  File "/usr/local/lib/python3.7/site-packages/mixpanel/__init__.py", line 590, in flush
    self._flush_endpoint(endpoint)
  File "/usr/local/lib/python3.7/site-packages/mixpanel/__init__.py", line 603, in _flush_endpoint
    six.raise_from(mp_e, orig_e)
  File "<string>", line 3, in raise_from
mixpanel.MixpanelException: Mixpanel error: a temporary failure occurred

The response from the server is {'error': 'a temporary failure occurred', 'status': 0}.

I kill the process and re run again. There are no issues. But again, at random, this error arises.

Python Binding To Export Data From MixPanel

I have read your documentation regarding exporting data via the MixPanel API using Python and was wondering if there was an official Python binding aside from this module to allow our team to query MixPanel for our data.

We're specifically looking for a library that can be added as a requirement and installed via pip. If not, do you mind if we fork that module, package and a distribute it? Let me know if there is a better solution that I may have missed - thanks :)

Prevent 500 errors when service is down

This is only an issue when the API Ingestion is offline โ€“ which is hardly ever. When making any call using this library, the request hangs and then eventually times out.

It would be awesome if I could just call mixpanel.track() and not have to worry about whether or not the tracking event will cause our server to hang.

Example request

mixpanel = Mixpanel(MIXPANEL_KEY)
mixpanel.track(tracking_id, 'Test Tracking')

Stack trace

2015-01-28T22:56:21.775103+00:00 app[web.2]:   File "/app/accounts/views.py", line 279, in post
2015-01-28T22:56:21.775104+00:00 app[web.2]:     mp.track(tracking_id, 'Test Tracking')
2015-01-28T22:56:21.775099+00:00 app[web.2]:     response = self.handle_exception(exc)
2015-01-28T22:56:21.775094+00:00 app[web.2]:     return wrapped(*args, **kwargs)
2015-01-28T22:56:21.775105+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/site-packages/mixpanel/__init__.py", line 74, in track
2015-01-28T22:56:21.775106+00:00 app[web.2]:     self._consumer.send('events', json.dumps(event, separators=(',', ':')))
2015-01-28T22:56:21.775108+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/site-packages/mixpanel/__init__.py", line 336, in send
2015-01-28T22:56:21.775110+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/site-packages/mixpanel/__init__.py", line 357, in _write_request
2015-01-28T22:56:21.775109+00:00 app[web.2]:     self._write_request(self._endpoints[endpoint], json_message, api_key)
2015-01-28T22:56:21.775113+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/urllib2.py", line 127, in urlopen
2015-01-28T22:56:21.775114+00:00 app[web.2]:     return _opener.open(url, data, timeout)
2015-01-28T22:56:21.775111+00:00 app[web.2]:     response = urllib2.urlopen(request).read()
2015-01-28T22:56:21.775122+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/site-packages/newrelic-2.30.0.27/newrelic/hooks/external_urllib2.py", line 15, in _nr_wrapper_opener_director_open_
2015-01-28T22:56:21.775125+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/urllib2.py", line 404, in open
2015-01-28T22:56:21.775126+00:00 app[web.2]:     response = self._open(req, data)
2015-01-28T22:56:21.775123+00:00 app[web.2]:     return wrapped(*args, **kwargs)
2015-01-28T22:56:21.775127+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/urllib2.py", line 422, in _open
2015-01-28T22:56:21.775130+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/urllib2.py", line 382, in _call_chain
2015-01-28T22:56:21.775129+00:00 app[web.2]:     '_open', req)
2015-01-28T22:56:21.775131+00:00 app[web.2]:     result = func(*args)
2015-01-28T22:56:21.775132+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/urllib2.py", line 1222, in https_open
2015-01-28T22:56:21.775134+00:00 app[web.2]:     return self.do_open(httplib.HTTPSConnection, req)
2015-01-28T22:56:21.775135+00:00 app[web.2]:   File "/app/.heroku/python/lib/python2.7/urllib2.py", line 1184, in do_open
2015-01-28T22:56:21.775136+00:00 app[web.2]:     raise URLError(err)
2015-01-28T22:56:21.775138+00:00 app[web.2]: URLError: <urlopen error [Errno 104] Connection reset by peer>

import_data method not working

Hi there!

Summary: track() method works great, import_data() doesn't ๐Ÿ˜ข

The request appears to succeed โ€“ on inspecting the decoded response object it's {'error': None, 'status': 1} as expected

But in Mixpanel the data simply never shows up (I waited 24 hours in case it takes time to show)

I've only just noticed the other repo for importing/exporting but presumably import_data here should still work, right?

p.s. in case it helps, interestingly if I set my API secret to a random non-empty string, the request still succeeds with no errors ๐Ÿค”

Any ideas? :)

Documentation error (+tmp fix in my local)

Hi,

I think I found an error in your doc: https://developer.mixpanel.com/docs/python#section-scaling-your-server-side-tracking

If you're taking a look at

class LoggingConsumer(object):
    def __init__(self):
        self.mp_log = open("MIXPANEL_LOG.txt", "w+")

    def send(self, endpoint, json_message):
        self.mp_log.write("{0}::{1}\n".format(endpoint, message))

# Whenever you track with logging_mp, your messages will
# be written to MIXPANEL_LOG.txt rather than being sent
# to the Mixpanel servers
logging_mp = Mixpanel(YOUR_TOKEN, LoggingConsumer())

The send() function here takes 3 parameters. However, if you implement the code below:


# ...

mp = mixpanel.Mixpanel(YOUR_TOKEN, EnqueueingConsumer())

# Track just like you would in any other situation
# Example: mp.track(user_id, 'Sent Message')

# this will fail on import_data()
mp.track(str(user_id), event_name, {'time': date.strftime("%Y-%m-%dT%H:%M:%S")})
mp.import_data(_API_KEY, str(user_id), event_name, int(second_date.timestamp()))

# ...

Traceback (most recent call last):
...
File "/Users/XXXXXXX/.local/share/virtualenvs/XXXXXXX/lib/python3.7/site-packages/mixpanel/init.py", line 96, in track
self._consumer.send('events', dump)
TypeError: send() missing 1 required positional argument: 'api_key'

By looking deeper in your library, that's where the problem is coming from (as far as I think)

class Mixpanel(object):
    """Instances of Mixpanel are used for all events and profile updates.

    :param str token: your project's Mixpanel token
    :param consumer: can be used to alter the behavior of tracking (default
        :class:`~.Consumer`)
    :param json.JSONEncoder serializer: a JSONEncoder subclass used to handle
        JSON serialization (default :class:`~.DatetimeSerializer`)

    See `Built-in consumers`_ for details about the consumer interface.

    .. versionadded:: 4.2.0
        The *serializer* parameter.
    """

    def __init__(self, token, consumer=None, serializer=DatetimeSerializer):
        self._token = token
        self._consumer = consumer or Consumer()
        self._serializer = serializer

    def _now(self):
        return time.time()

    def track(self, distinct_id, event_name, properties=None, meta=None):
        """Record an event.

        :param str distinct_id: identifies the user triggering the event
        :param str event_name: a name describing the event
        :param dict properties: additional data to record; keys should be
            strings, and values should be strings, numbers, or booleans
        :param dict meta: overrides Mixpanel special properties

        ``properties`` should describe the circumstances of the event, or
        aspects of the source or user associated with it. ``meta`` is used
        (rarely) to override special values sent in the event object.
        """
        all_properties = {
            'token': self._token,
            'distinct_id': distinct_id,
            'time': int(self._now()),
            'mp_lib': 'python',
            '$lib_version': __version__,
        }
        if properties:
            all_properties.update(properties)
        event = {
            'event': event_name,
            'properties': all_properties,
        }
        if meta:
            event.update(meta)
        dump = json_dumps(event, cls=self._serializer)
        self._consumer.send('events', dump)

    def import_data(self, api_key, distinct_id, event_name, timestamp,
                    properties=None, meta=None):
        """Record an event that occured more than 5 days in the past.

        :param str api_key: your Mixpanel project's API key
        :param str distinct_id: identifies the user triggering the event
        :param str event_name: a name describing the event
        :param int timestamp: UTC seconds since epoch
        :param dict properties: additional data to record; keys should be
            strings, and values should be strings, numbers, or booleans
        :param dict meta: overrides Mixpanel special properties

        To avoid accidentally recording invalid events, the Mixpanel API's
        ``track`` endpoint disallows events that occurred too long ago. This
        method can be used to import such events. See our online documentation
        for `more details
        <https://mixpanel.com/docs/api-documentation/importing-events-older-than-31-days>`__.
        """
        all_properties = {
            'token': self._token,
            'distinct_id': distinct_id,
            'time': int(timestamp),
            'mp_lib': 'python',
            '$lib_version': __version__,
        }
        if properties:
            all_properties.update(properties)
        event = {
            'event': event_name,
            'properties': all_properties,
        }
        if meta:
            event.update(meta)
        self._consumer.send('imports', json_dumps(event, cls=self._serializer), api_key)

As you can notice, unlike def track(self, distinct_id, event_name, properties=None, meta=None):, the function def import_data(self, api_key, distinct_id, event_name, timestamp, properties=None, meta=None): calls self._consumer.send(...) with one more parameter, raising the following exception:

self._consumer.send('events', dump)
self._consumer.send('imports', json_dumps(event, cls=self._serializer), api_key)

REMIND :
Traceback (most recent call last):
...
File "/Users/XXXXXXX/.local/share/virtualenvs/XXXXXXX/lib/python3.7/site-packages/mixpanel/init.py", line 96, in track
self._consumer.send('events', dump)
TypeError: send() missing 1 required positional argument: 'api_key'

In order to fix it, I did the following:

class LoggingConsumer(object):
    def __init__(self):
        self.mp_log = open("MIXPANEL_LOG.txt", "w+")

    def send(self, endpoint, json_message, FIX_FOR_MIXPANEL_API_KEY_PARAMETER=None):
        self.mp_log.write("{0}::{1}\n".format(endpoint, message))

I am not at all a Python developer so if it's really an issue on your end and not mine, I won't propose any PR since I don't feel my level in Python good enough for such coding :)

Unspecified requirement

I was getting the following error:

  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mixpanel/__init__.py", line 24, in <module>
    from six.moves import urllib
ImportError: cannot import name urllib

Easily fixed with pip install six --upgrade, so you guys might want to add a requirements.txt file. I'm on Python 2.7.9.

Properties list

This exist any way to send multiple property values?

All that I found is https://mixpanel.com/docs/properties-or-segments/property-data-types

List
To send a list of values (for example, the products in a shopping cart), send them as a JSON array. This will allow you, in the segmentation report, when you query for a particular item, show all events where that item was included in the list.

But this is not working, I tried:

properties = {
'Brand': ['first', 'second'],
}

In mixpanel this displayed as ["first","second"]

And in http doc I can't find any references about list properties.

If this exist any way to set properties list, please let me know - I will implement this by my own.

I really need this mechanism.

Thanks,
Alex

Python 3.4 issue..simple fix

Traceback (most recent call last):
  File "ClientTokenQ.py", line 4, in <module>
    from lib import queueMixin as qm
  File "/home/creator/apps/xnainfra/lib/queueMixin.py", line 12, in <module>
    from mixpanel import Mixpanel
  File "/usr/local/lib/python3.4/site-packages/mixpanel/__init__.py", line 209
    except Exception, e:
except Exception as e:

Add documentation for people_set's meta argument

Hello,

I am trying to do a server side update and I don't want the last seen time to be changed.

I am calling my update with the flag $ignore_time to True but it is still updating the last seen. Am I doing something wrong?

Here is some code:

def get_people_dict(user):
try:
birth_date_string = convert_datetime_to_string(user.date_of_birth)
except:
birth_date_string = convert_datetime_to_string(datetime.date.today())

topics = [t.title for t in user.topics]
people_dict = {}
people_dict["$username"] = user.username
people_dict["$first_name"] = user.first_name
people_dict["$last_name"] = user.last_name
people_dict["$email"] = user.email
people_dict["$created"] = convert_datetime_to_string(user.date_joined)
people_dict["$ip"] = convert_datetime_to_string(user.current_ip)
people_dict["country"] = user.country
people_dict["date_of_birth"] = birth_date_string
people_dict["rating"] = user.rating
people_dict["topics"] = topics
people_dict["is_client"] = user.is_client
people_dict["is_editor"] = user.is_editor
people_dict["total_jobs"] = user.total_jobs
people_dict["total_spent_money"] = round(user.total_spent_money, 1)
people_dict["level"] = user.user_level.level_id
people_dict["activated"] = user.active
if user.native_language:
    people_dict["native_language"] = user.native_language.shortname
people_dict["is_senior_editor"] = user.is_senior_editor
people_dict["can_give_feedback"] = user.can_give_feedback
people_dict["is_copy_editor"] = user.is_copy_editor
people_dict = get_people_lang_pair_dict(user, people_dict)
people_dict["balance"] = round(user.get_balance(), 1)
# Do not update last seen
people_dict["$ignore_time"] = True
return people_dict

connection.people_set(user.username, people_dict)

`Mixpanel.alias` ignores any custom configuration

When Mixpanel.alias is used it creates it's own default Consumer instance and sends the event through it. This makes it ignore any custom configuration done on the side of a Consumer.

Usecase

The Scaling your server side tracking docs suggest implementing a custom consumer that logs the events into one file/stream and then send the events outside of main thread to not make the event sending synchronous with the application.

But since it's always a good idea to have secrets, such as Mixpanel token, in as fewer places as possible we decided to log the events with a placeholder token and replace it only before they are actually being sent to the Mixpanel servers. This approach makes it so that .alias method is not working at all.

I do get the idea that alias has to be created before any events with the new id are tracked (#7). But the current implementation is a bit too binding and unintuitive from the perspective of the library user.

Missing APIs

I'm missing insight and engagement specifically. Is it planned?

using import_data with Buffered consumer is not working

the send function used by the default consumer got the api_key as a parameter , the send function used by the Buffered consumer does not . So if you will try to run the import data with the Buffered Consumer it will result in an error.

version 4.7.0 leads to SSLError in AWS Lambda Python 3.6

When I deploy lambda functions with the new release, the functions fail with the following error. This doesn't happen with the previous release.

HTTPSConnectionPool(host='api.mixpanel.com', port=443): Max retries exceeded with url: /track (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),)): MixpanelException
Traceback (most recent call last):
  File "/var/task/common.py", line 346, in wrapper
    return handler(event, context)
  File "/var/task/common.py", line 69, in wrapper
    return handler(event, context)
  File "/var/task/common.py", line 223, in wrapper
    return handler(event, context)
  File "/var/task/handler.py", line 110, in add_distributor_retailer
    logger.log_uncaught_exception()
  File "/var/task/handler.py", line 83, in add_distributor_retailer
    mp.track(context.user_id, 'Added Distributor Retailer')
  File "/var/task/mixpanel/__init__.py", line 100, in track
    self._consumer.send('events', json_dumps(event, cls=self._serializer))
  File "/var/task/mixpanel/__init__.py", line 539, in send
    self._write_request(self._endpoints[endpoint], json_message, api_key)
  File "/var/task/mixpanel/__init__.py", line 560, in _write_request
    six.raise_from(MixpanelException(e), e)
  File "<string>", line 3, in raise_from
mixpanel.MixpanelException: HTTPSConnectionPool(host='api.mixpanel.com', port=443): Max retries exceeded with url: /track (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))

Example code used in functions:

mp = Mixpanel("MIXPANEL_TOKEN")
mp.track("unique_id", "event_name")

trying to fire an event in mixpanel but getting below error

Traceback (most recent call last):
File "mixpanelEvent.py", line 194, in
mp.track(123, 'ABC')
File "/usr/local/lib/python2.7/dist-packages/mixpanel/init.py", line 95, in track
self._consumer.send('events', json_dumps(event, cls=self._serializer))
File "/usr/local/lib/python2.7/dist-packages/mixpanel/init.py", line 488, in send
self._write_request(self._endpoints[endpoint], json_message, api_key)
File "/usr/local/lib/python2.7/dist-packages/mixpanel/init.py", line 511, in _write_request
six.raise_from(MixpanelException(e), e)
File "/usr/local/lib/python2.7/dist-packages/six.py", line 740, in raise_from
raise value
mixpanel.MixpanelException: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>

using python 2.7

Async support

Hey there, thanks for the neat library.

Do you have any plan to support native async features of Python?

e.g.:

from mixpanel import AsyncMixpanel

mp = AsyncMixpanel(YOUR_TOKEN)

# tracks an event with certain properties
await mp.track(DISTINCT_ID, 'button clicked', {'color' : 'blue', 'size': 'large'})

# sends an update to a user profile
await mp.people_set(DISTINCT_ID, {'$first_name' : 'Ilya', 'favorite pizza': 'margherita'})

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.