Skip to content

Commit 988085f

Browse files
committed
Merge branch 'pyBatch'
2 parents 9af5f21 + f566443 commit 988085f

File tree

6 files changed

+85
-6
lines changed

6 files changed

+85
-6
lines changed

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,25 @@ Once you have your Project ID, use the client like so:
3636
client.add_event("sign_ups", {
3737
"username": "lloyd",
3838
"referred_by": "harry"
39-
}
39+
})
40+
41+
##### Send Batch Events to Keen IO
42+
43+
You can upload Events in a batch, like so:
44+
45+
client.add_events({
46+
"sign_ups": [
47+
{ "username": "nameuser1" },
48+
{ "username": "nameuser2" }
49+
],
50+
"purchases": [
51+
{ "price": 5 },
52+
{ "price": 6 }
53+
]
54+
})
4055

41-
That's it! After running your code, check your Keen IO Project to see the event has been added.
56+
57+
That's it! After running your code, check your Keen IO Project to see the event/events has been added.
4258

4359
##### Do analysis with Keen IO
4460

@@ -82,6 +98,10 @@ Here are some examples of querying. Let's assume you've added some events to th
8298

8399
### Changelog
84100

101+
##### 0.1.9
102+
103+
+ Added support for publishing events in batches
104+
85105
##### 0.1.8
86106

87107
+ Added querying support

keen/api.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import requests
2+
import json
23
from keen import exceptions
34
import json
45

@@ -16,6 +17,8 @@ class KeenApi(object):
1617
# the default version of the Keen API
1718
api_version = "3.0"
1819

20+
# self says it belongs to KeenApi/andOr is the object passed into KeenApi
21+
# __init__ create keenapi object whenever KeenApi class is invoked
1922
def __init__(self, project_id,
2023
write_key=None, read_key=None,
2124
base_url=None, api_version=None):
@@ -30,6 +33,7 @@ def __init__(self, project_id,
3033
:param api_version: string, optional, set this to override what API
3134
version is used
3235
"""
36+
# super? recreates the object with values passed into KeenApi
3337
super(KeenApi, self).__init__()
3438
self.project_id = project_id
3539
self.write_key = write_key
@@ -55,6 +59,7 @@ def post_event(self, event):
5559
event.event_collection)
5660
headers = {"Content-Type": "application/json", "Authorization": self.write_key}
5761
payload = event.to_json()
62+
print payload
5863
response = requests.post(url, data=payload, headers=headers)
5964
if response.status_code != 201:
6065
error = response.json()
@@ -80,4 +85,26 @@ def query(self, analysis_type, params):
8085
error = response.json()
8186
raise exceptions.KeenApiError(error)
8287

83-
return response.json()["result"]
88+
return response.json()["result"]
89+
90+
def post_events(self, events):
91+
92+
"""
93+
Posts a single event to the Keen IO API. The write key must be set first.
94+
95+
:param event: an Event to upload
96+
"""
97+
if not self.write_key:
98+
raise Exception("The Keen IO API requires a write key to send events. "
99+
"Please set a 'write_key' when initializing the "
100+
"KeenApi object.")
101+
102+
url = "{0}/{1}/projects/{2}/events".format(self.base_url, self.api_version,
103+
self.project_id)
104+
headers = {"Content-Type": "application/json", "Authorization": self.write_key}
105+
payload = json.dumps(events)
106+
response = requests.post(url, data=payload, headers=headers)
107+
print payload
108+
if response.status_code != 200:
109+
error = response.json()
110+
raise exceptions.KeenApiError(error)

keen/client.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,17 @@ def add_event(self, event_collection, event_body, timestamp=None):
9898
timestamp=timestamp)
9999
self.persistence_strategy.persist(event)
100100

101+
def add_events(self, events):
102+
""" Adds a batch of events
103+
104+
Depending on the persistence strategy of the client,
105+
this will either result in the event being uploaded to Keen
106+
immediately or will result in saving the event to some local cache.
107+
108+
:param events: dictionary of events
109+
"""
110+
self.persistence_strategy.batch_persist(events)
111+
101112
def count(self, event_collection, timeframe=None, timezone=None, interval=None, filters=None, group_by=None):
102113
""" Performs a count query
103114
@@ -357,4 +368,5 @@ def get_params(self, event_collection=None, timeframe=None, timezone=None, inter
357368
if steps:
358369
params["steps"] = json.dumps(steps)
359370

360-
return params
371+
return params
372+

keen/persistence_strategies.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ def persist(self, event):
3636
"""
3737
self.api.post_event(event)
3838

39+
def batch_persist(self, events):
40+
""" Posts the given events directly to the Keen API.
41+
42+
:param events: a batch of events to persist
43+
"""
44+
self.api.post_events(events)
3945

4046
class RedisPersistenceStrategy(BasePersistenceStrategy):
4147
"""

keen/tests/base_test_case.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,4 @@ def to_mixed(cls, underscore_input):
6464
for i in range(1, word_count):
6565
word_list[i] = string.capwords(word_list[i])
6666
ret = ''.join(word_list)
67-
return ret
67+
return ret

keen/tests/client_tests.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ def test_direct_persistence_strategy(self):
5656
read_key = scoped_keys.encrypt(api_key, {"allowed_operations": ["read"]})
5757
client = KeenClient(project_id, write_key=write_key, read_key=read_key)
5858
client.add_event("python_test", {"hello": "goodbye"})
59+
client.add_event("python_test", {"hello": "goodbye"})
60+
client.add_events(
61+
{"sign_ups": [
62+
{
63+
"username": "timmy",
64+
"referred_by": "steve",
65+
"son_of": "my_mom"
66+
},
67+
],
68+
"purchases": [
69+
{ "price": 5 },
70+
{ "price": 6 },
71+
{ "price": 7 }
72+
]})
5973

6074
class QueryTests(BaseTestCase):
6175
def setUp(self):
@@ -127,4 +141,4 @@ def test_group_by(self):
127141

128142
def test_interval(self):
129143
resp = self.client.count("query test", timeframe="this_2_days", interval="daily")
130-
assert type(resp) is list
144+
assert type(resp) is list

0 commit comments

Comments
 (0)