{ "info": { "author": "Dillon Dixon", "author_email": "dillondixon@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6" ], "description": "mixpanel-jql\n============\n\n|PyPI Version| |Python Versions| |Coverage| |Build Status|\n\nA small Python library for running `JQL `__\nqueries against Mixpanel's JQL API. The data returned from the API is\nautomatically decompressed as it arrives, making it available for\nprocessing as soon as the first row arrives. This is to avoid buffering\nlarge result sets in memory.\n\nInstallation\n------------\n\nTo install the ``mixpanel-jql`` library, simply run the following in\nyour terminal:\n\n``pip install mixpanel-jql``\n\nSimple example\n--------------\n\nLet's do a simple count of our number of 'X' events over each day of May 2016. Our key for grouping will be the date the event was sent to Mixpanel in the format ``YYYY-MM-DD``. We can get that from our event's ``time`` property by specifying our key as ``new Date(e.time).toISOString().split('T')[0]``.\n\nThis is simple and fast to do with this library.\n\n.. code:: python\n\n from datetime import datetime\n from mixpanel_jql import JQL, Reducer, Events\n\n api_secret = '...'\n\n query = JQL(\n api_secret,\n events=Events({\n 'event_selectors': [{'event': \"X\"}],\n 'from_date': datetime(2016, 5, 1),\n 'to_date': datetime(2016, 5, 31)\n })\n ).group_by(\n keys=[\n \"new Date(e.time).toISOString().split('T')[0]\",\n ],\n accumulator=Reducer.count()\n )\n\n for row in query.send():\n date = row['key'][0]\n value = row['value']\n print(\"[%s] => %d\" % (date, value))\n # [2016-05-01] => 302\n # [2016-05-02] => 1102\n # ...\n # [2016-05-31] => 120\n\nBut what if we only want to count unique events? That is to say, what if we care about how many users spawned each event per day and not just the overall number of times the event occurred?\n\nWith some minor modification to our previous code, we can achieve this:\n\n.. code:: python\n\n query = JQL(\n api_secret,\n events=Events({\n 'event_selectors': [{'event': \"X\"}],\n 'from_date': datetime(2016, 5, 1),\n 'to_date': datetime(2016, 5, 31)\n })\n ).group_by_user(\n keys=[\n \"new Date(e.time).toISOString().split('T')[0]\",\n ],\n accumulator=\"function(){ return 1;}\"\n ).group_by(\n keys=[\"e.key.slice(1)\"],\n accumulator=Reducer.count()\n )\n\nWe replace our ``accumulator`` keyward argument with a JavaScript function returning ``1``, since each user will only be counted for once. ``group_by_user`` also adds the user ID into the key of our results. We can regroup our results by slicing that detail off with ``e.key.slice(1)`` and recounting.\n\nMore advanced examples\n----------------------\n\nLet's assume we want to count all events 'A' with a property 'B' that is\nequal to 2 and a property F that is equal to \"hello\". Events 'A' also\nhave a property 'C', which is some random string value. We want the\nresults grouped and tallied by values of 'C' to see how many property\n'C' events occurred over each day in the month of April 2016.\n\n.. code:: python\n\n from mixpanel_jql import JQL, Reducer, Events\n\n api_secret = '...'\n\n query = JQL(\n api_secret,\n events=Events({\n 'event_selectors': [{'event': \"A\"}],\n 'from_date': '2016-04-01',\n 'to_date': '2016-04-30'\n })\n ).filter(\n 'e.properties.B == 2'\n ).filter(\n 'e.properties.F == \"hello\"'\n ).group_by(\n keys=[\n \"new Date(e.time).toISOString().split('T')[0]\",\n \"e.property.C\"\n ],\n accumulator=Reducer.count()\n )\n\n for row in query.send():\n date, c = row['key']\n value = row['value']\n print(\"[%s] %s => %d\" % (date, c, value))\n # [2016-04-01] abc => 3\n # [2016-04-01] xyz => 1\n # ...\n\nIf we wanted to count only *unique* events (i.e. count each user causing\nthe event only once), we can change our query to *group by user*, to\nreduce the number of times they caused a particular ``e.properties.C``\nto just 1.\n\n.. code:: python\n\n query = JQL(\n api_secret,\n events=Events({\n 'event_selectors': [{'event': \"A\"}],\n 'from_date': '2016-04-01',\n 'to_date': '2016-04-30'\n })\n ).filter(\n 'e.properties.B == 2'\n ).filter(\n 'e.properties.F == \"hello\"'\n ).group_by_user(\n keys=[\n \"new Date(e.time).toISOString().split('T')[0]\",\n \"e.property.C\"\n ],\n accumulator=\"function(){ return 1;}\"\n ).group_by(\n keys=[\"e.key.slice(1)\"],\n accumulator=Reducer.count()\n )\n\nWhy are your filters not joined with ``&&``?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe could have also combined our ``.filter(...)`` methods into 1 method\nby doing, ``.filter('e.properties.B == 2 && e.properties.F == \"hello\"')``.\nSuccessive ``.filter(...)`` expressions are automatically ``&&``'ed. The\nmethod of expression you choose is stylistic.\n\nWhat is that ``Reducer`` thing?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe ``Reducer`` class is for convenience and contains shortcuts to all\nthe reducer functions (e.g. ``Reducer.count()`` returns\n``mixpanel.reducer.count()``, and ``Reducer.top(limit)`` returns\n``mixpanel.reducer.top(limit)``). Refer to the code for a list of all\nreducer shortcuts.\n\nTo write your own reducer, make sure to include a full JavaScript\nfunction body (i.e. ``function(){ ... }``).\n\nWhat about conversions?\n~~~~~~~~~~~~~~~~~~~~~~~\n\nThe ``Converter`` class is another convenience for that.\n\n.. code:: python\n\n from mixpanel_jql import Converter\n ...\n Converter.to_number('\"xyz\"') # Resolves to mixpanel.to_number(\"xyz\")\n\nWhat about queries over \"people\" and \"joins\"?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAll of the previous examples are concerned primarily with JQL queries\nover events. This library also supports queries over people and the join\nof people and events. The following gives a skeleton for how that works.\n\nYou are free to use only one of ``events`` and ``people``. ``join_params``\nis only used if both ``events`` and ``people`` are set.\n\n.. code:: python\n\n query = JQL(\n api_secret,\n events=Events({\n 'event_selectors': [\n {\n 'event': '...',\n 'selector': '...',\n 'label': '...'\n },\n ...\n ],\n 'from_date': '',\n 'to_date': ''\n }),\n people=People({\n 'user_selectors': [\n {\n 'selector': '...'\n },\n ...\n ]\n }),\n join_params={\n 'type': 'full',\n 'selectors': [\n {\n 'event': '...',\n 'selector': '...',\n },\n ...\n ]\n }\n ). ...\n\nWhat other functions are supported?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nMixpanel seems to be in a constant state of adding new functions beyond just ``filter`` and ``map``.\nThe following are presently supported by this library. Refer to the code for their usage.\n\n- ``filter``\n- ``map``\n- ``flatten``\n- ``sort_asc``\n- ``sort_desc``\n- ``reduce``\n- ``group_by``\n- ``group_by_user``\n\nHow do I see what the final JavaScript sent to Mixpanel will be?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nUse ``str`` method on your JQL query to view what the\nequivalent JavaScript will be.\n\n.. code:: python\n\n >>> str(query)\n 'function main() { return Events({\"event_selectors\": [{\"event\": \"A\"}], \"from_date\": \"2016-04-01\", \"to_date\": \"2016-04-30\"}).filter(function(e){return e.properties.B == 2}).filter(function(e){return e.properties.F == \"hello\"}).groupByUser([function(e){return new Date(e.time).toISOString().split(\\'T\\')[0]},function(e){return e.property.C}], function(){ return 1;}).groupBy([function(e){return e.key.slice(1)}], mixpanel.reducer.count()); }'\n\nThis can be quite helpful during debugging.\n\nBut what if you want something actually readable? That's now possible too with the ``.pretty`` method!\n\n.. code:: python\n\n >>> print(query.pretty)\n function main() {\n return Events({\n \"event_selectors\": [{\n \"event\": \"A\"\n }],\n \"from_date\": \"2016-04-01\",\n \"to_date\": \"2016-04-30\"\n }).filter(function(e) {\n return e.properties.B == 2\n }).filter(function(e) {\n return e.properties.F == \"hello\"\n }).groupByUser([function(e) {\n return new Date(e.time).toISOString().split('T')[0]\n }, function(e) {\n return e.property.C\n }], function() {\n return 1;\n }).groupBy([function(e) {\n return e.key.slice(1)\n }], mixpanel.reducer.count());\n }\n\nCaveats\n-------\n\n``.filter(...)`` automatically transforms whatever is within the\nparenthesis' into ``function(e){ return ... }``.\n\nTo override that behavior, and use things like the ``properties.x``\nshortcut syntax, use the ``raw(...)`` wrapper to insert whatever\nJavaScript you want into the ``filter``, ``map`` .etc parameters.\n\n.. code:: python\n\n from mixpanel_jql import JQL, raw\n ...\n query = JQL(\n api_secret,\n events=params\n ).filter(\n raw(\n \" function(e) {\"\n \" if (e.x > 3) {\"\n \" return true;\"\n \" } else {\"\n \" return false;\"\n \" }\"\n \" )\"\n )\n ).filter(\n 'e.properties.F == \"hello\"'\n )\n ...\n\nThis library cannot easily express everything possible in Mixpanel's JQL\nlanguage, but does try to simplify the general cases. If you have some\nideas for making this library more user friendly to a wider range of\npotential queries, please submit a pull request or create an issue.\n\nContributions are very welcome!\n\nWhere can I learn more about Mixpanel's JQL?\n--------------------------------------------\n\nFor more information on what you can do with JQL, refer to Mixpanel's\ndocumentation `here `__.\n\n.. |PyPI Version| image:: https://badge.fury.io/py/mixpanel-jql.svg\n :target: https://badge.fury.io/py/mixpanel-jql\n\n.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/mixpanel-jql.svg\n :target: https://github.com/ownaginatious/mixpanel-jql/blob/master/setup.py\n\n.. |Build Status| image:: https://travis-ci.org/ownaginatious/mixpanel-jql.svg?branch=master\n :target: https://travis-ci.org/ownaginatious/mixpanel-jql/\n\n.. |Coverage| image:: https://codecov.io/gh/ownaginatious/mixpanel-jql/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/ownaginatious/mixpanel-jql\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ownaginatious/mixpanel-jql", "keywords": "mixpanel", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "mixpanel-jql", "package_url": "https://pypi.org/project/mixpanel-jql/", "platform": "", "project_url": "https://pypi.org/project/mixpanel-jql/", "project_urls": { "Homepage": "https://github.com/ownaginatious/mixpanel-jql" }, "release_url": "https://pypi.org/project/mixpanel-jql/0.5.1/", "requires_dist": null, "requires_python": "", "summary": "A streaming library for making JQL queries to Mixpanel", "version": "0.5.1" }, "last_serial": 4342389, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "e381a07b39f19d7656d5bc8a12609fbb", "sha256": "e8feb04f3ab61a54ecbb6885e8843c1134e5b5671530b1bab70a0236d32a3762" }, "downloads": -1, "filename": "mixpanel-jql-0.1.tar.gz", "has_sig": false, "md5_digest": "e381a07b39f19d7656d5bc8a12609fbb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20829, "upload_time": "2016-05-13T19:39:07", "url": "https://files.pythonhosted.org/packages/bb/b1/b96a5d777bb998170d7afb4d4f78de0b6de12f4aa0b44f05e2355626e923/mixpanel-jql-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "412acbdce402e228c66234061bee05f1", "sha256": "4ad6ddaf0dc7e5d94e5ed985f492d80b7b526380d5ba8312135308dcdf154d64" }, "downloads": -1, "filename": "mixpanel-jql-0.2.tar.gz", "has_sig": false, "md5_digest": "412acbdce402e228c66234061bee05f1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20725, "upload_time": "2016-05-16T20:16:25", "url": "https://files.pythonhosted.org/packages/ce/39/b62f8272dbd09fc041fbd7c87710b4e8e994c37cf9560d7ea5c1a76e8f99/mixpanel-jql-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "1d713e8107341c626765d5aada93bcca", "sha256": "50e26967691023a47e25517eea744ea6d3bb599cb00451b171adc714cf14e3c1" }, "downloads": -1, "filename": "mixpanel-jql-0.3.tar.gz", "has_sig": false, "md5_digest": "1d713e8107341c626765d5aada93bcca", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21207, "upload_time": "2016-06-21T23:33:35", "url": "https://files.pythonhosted.org/packages/52/c9/060a841a07db2d3604eed9548f95eab155576486d92af31010cd18a7b9b5/mixpanel-jql-0.3.tar.gz" } ], "0.3.post16": [ { "comment_text": "", "digests": { "md5": "e9b800e49efeab1462fb23d4cb373117", "sha256": "ad35af54a931149de5c648db81e5188204cfb7fcc3f71bd520003bcb30b0cf2c" }, "downloads": -1, "filename": "mixpanel-jql-0.3.post16.tar.gz", "has_sig": false, "md5_digest": "e9b800e49efeab1462fb23d4cb373117", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21599, "upload_time": "2017-08-21T07:31:02", "url": "https://files.pythonhosted.org/packages/3b/09/83aebb394e6f0850d4d0135e9b5f3b86e28b057be8fb6782e7cd60cf1537/mixpanel-jql-0.3.post16.tar.gz" } ], "0.3.post18": [ { "comment_text": "", "digests": { "md5": "cba59be04945ff3594626ac34b89bac6", "sha256": "ead7a423eee9ad902b78f1ad657075c5e33175556d42942583764e10b628768f" }, "downloads": -1, "filename": "mixpanel-jql-0.3.post18.tar.gz", "has_sig": false, "md5_digest": "cba59be04945ff3594626ac34b89bac6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21674, "upload_time": "2017-10-11T00:16:04", "url": "https://files.pythonhosted.org/packages/c3/a3/ca15a90a200f0687f96e25888a0bd2d74ab63903cbc32b1a251cdf9f0aa3/mixpanel-jql-0.3.post18.tar.gz" } ], "0.3.post4": [ { "comment_text": "", "digests": { "md5": "0e503f1353005221a93115ed5a8d8159", "sha256": "8df4416c9a24f2090b3867c016fb7b0ea71d7a6cc2d9c6c9eb9cde9099bb7f45" }, "downloads": -1, "filename": "mixpanel-jql-0.3.post4.tar.gz", "has_sig": false, "md5_digest": "0e503f1353005221a93115ed5a8d8159", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21330, "upload_time": "2016-06-27T14:41:15", "url": "https://files.pythonhosted.org/packages/a4/12/1cced3d963e0103492f890c2f79647f44b2442fed1bcfe9798f3debe4b04/mixpanel-jql-0.3.post4.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "46b68c8542ba6b06cdfff6222f442406", "sha256": "37929f74fe13cdbc2c5c990919bb533181d8dc900b2c1e567390818e2fda7869" }, "downloads": -1, "filename": "mixpanel-jql-0.4.tar.gz", "has_sig": false, "md5_digest": "46b68c8542ba6b06cdfff6222f442406", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23117, "upload_time": "2017-11-06T20:04:48", "url": "https://files.pythonhosted.org/packages/65/3a/a79dedaa35bc040b6506af5888b0e32ddcf391071cba300bbf8720df33b6/mixpanel-jql-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "c9344458e0992198135b048c84d5ed0e", "sha256": "d8fba413fe9c6a5b3b456ff810f209c5826f47158afb281dc5f17afc1e8b6081" }, "downloads": -1, "filename": "mixpanel-jql-0.4.1.tar.gz", "has_sig": false, "md5_digest": "c9344458e0992198135b048c84d5ed0e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26517, "upload_time": "2018-01-09T00:38:06", "url": "https://files.pythonhosted.org/packages/44/09/713895d43bcca70724891b1fdabe990a1015ebc984d6c080c508cd06725b/mixpanel-jql-0.4.1.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "28a8938252c96732f6bd404596741136", "sha256": "6aeda85679d97b0876ebddaf0f553b9c420e74f66e7318a121c4fae959ef6ab7" }, "downloads": -1, "filename": "mixpanel-jql-0.5.tar.gz", "has_sig": false, "md5_digest": "28a8938252c96732f6bd404596741136", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27685, "upload_time": "2018-01-18T03:16:54", "url": "https://files.pythonhosted.org/packages/67/e0/1d0f2fc6d93f1744e496bc5f753f0a31f860768fcc9349ce1f313f104f82/mixpanel-jql-0.5.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "6473dbf3a35a31f9fbfcb52622569ad3", "sha256": "d8ea35b10fb9e37109ab1ee42aac0b978735a31337728e52785a9aecd73019e9" }, "downloads": -1, "filename": "mixpanel-jql-0.5.1.tar.gz", "has_sig": false, "md5_digest": "6473dbf3a35a31f9fbfcb52622569ad3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28116, "upload_time": "2018-10-05T00:23:27", "url": "https://files.pythonhosted.org/packages/ca/ee/41dab6da67375d3f0aa134a9fda8307e3249370f6db967ba87998314bd22/mixpanel-jql-0.5.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6473dbf3a35a31f9fbfcb52622569ad3", "sha256": "d8ea35b10fb9e37109ab1ee42aac0b978735a31337728e52785a9aecd73019e9" }, "downloads": -1, "filename": "mixpanel-jql-0.5.1.tar.gz", "has_sig": false, "md5_digest": "6473dbf3a35a31f9fbfcb52622569ad3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28116, "upload_time": "2018-10-05T00:23:27", "url": "https://files.pythonhosted.org/packages/ca/ee/41dab6da67375d3f0aa134a9fda8307e3249370f6db967ba87998314bd22/mixpanel-jql-0.5.1.tar.gz" } ] }