Skip to content

Commit e874feb

Browse files
committed
Added contracts to consumer.py
1 parent 02f309e commit e874feb

3 files changed

Lines changed: 59 additions & 4 deletions

File tree

snowplow_tracker/consumer.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,20 @@
2727
from celery.contrib.methods import task
2828
import redis
2929
import logging
30+
from contracts import contract, new_contract
3031

3132
logger = logging.getLogger(__name__)
3233
logger.setLevel(logging.DEBUG)
3334

3435
DEFAULT_MAX_LENGTH = 10
3536

37+
new_contract("method", lambda x: x == "http-get" or x == "http-post")
38+
39+
new_contract("function", lambda x: hasattr(x, "__call__"))
40+
41+
new_contract("redis", lambda x: isinstance(x, (redis.Redis, redis.StrictRedis)))
42+
43+
3644
try:
3745
# Check whether a custom Celery configuration module named "snowplow_celery_config" exists
3846
import snowplow_celery_config
@@ -50,8 +58,25 @@ class Consumer(object):
5058
Supports both GET and POST requests
5159
"""
5260

61+
@contract
5362
def __init__(self, endpoint, method="http-get", buffer_size=None, on_success=None, on_failure=None):
54-
63+
"""
64+
:param endpoint: The collector URL. Don't include "http://" - this is done automatically.
65+
:type endpoint: string
66+
:param method: The HTTP request method
67+
:type method: method
68+
:param buffer_size: The maximum number of queued events before the buffer is flushed. Default is 10.
69+
:type buffer_size: string | None
70+
:param on_success: Callback executed after every request in a flush is successful.
71+
Gets passed the number of events flushed.
72+
:type on_success: function | None
73+
:param on_failure: Callback executed after not every event in a flush is successful.
74+
Gets passed two arguments:
75+
1) The number of events which were successfully sent
76+
2) If method is "http-post": The unsent data in string form;
77+
If method is "http-get": An array of dictionaries corresponding to the unsent events' payloads
78+
:type on_failure: function | None
79+
"""
5580
self.endpoint = Consumer.as_collector_uri(endpoint)
5681

5782
self.method = method
@@ -68,13 +93,23 @@ def __init__(self, endpoint, method="http-get", buffer_size=None, on_success=Non
6893
self.on_failure = on_failure
6994

7095
@staticmethod
96+
@contract
7197
def as_collector_uri(endpoint):
98+
"""
99+
:param endpoint: The raw endpoint provided by the user
100+
:type endpoint: string
101+
:rtype: string
102+
"""
72103
return "http://" + endpoint + "/i"
73104

105+
@contract
74106
def input(self, payload):
75107
"""
76108
Adds an event to the buffer.
77109
If the maximum size has been reached, flushes the buffer.
110+
111+
:param payload: The name-value pairs for the event
112+
:type payload: dict(str:*)
78113
"""
79114
self.buffer.append(payload)
80115
if len(self.buffer) >= self.buffer_size:
@@ -85,7 +120,6 @@ def flush(self):
85120
"""
86121
Sends all events in the buffer to the collector.
87122
"""
88-
89123
if self.method == "http-post":
90124
data = json.dumps(self.buffer)
91125
buffer_length = len(self.buffer)
@@ -120,13 +154,23 @@ def flush(self):
120154
else:
121155
logger.warn(self.method + ' is not a recognised HTTP method. Use "http-get" or "http-post".')
122156

157+
@contract
123158
def http_post(self, data):
159+
"""
160+
:param data: The array of JSONs to be sent
161+
:type data: string
162+
"""
124163
logger.debug("Sending POST request...")
125164
r = requests.post(self.endpoint, data=data)
126165
logger.debug("POST request finished with status code: " + str(r.status_code))
127166
return r
128167

168+
@contract
129169
def http_get(self, payload):
170+
"""
171+
:param payload: The event properties
172+
:type payload: dict(str:*)
173+
"""
130174
logger.debug("Sending GET request...")
131175
r = requests.get(self.endpoint, params=payload)
132176
logger.debug("GET request finished with status code: " + str(r.status_code))
@@ -164,13 +208,24 @@ class RedisConsumer(object):
164208
"""
165209
Sends Snowplow events to a Redis database
166210
"""
211+
@contract
167212
def __init__(self, rdb=None, key="snowplow"):
213+
"""
214+
:param rdb: Optional custom Redis database
215+
:type rdb: redis | None
216+
:param key: The Redis key for the list of events
217+
:type key: string
218+
"""
168219
if rdb is None:
169220
rdb = redis.StrictRedis()
170221
self.rdb = rdb
171222
self.key = key
172223

173224
def input(self, payload):
225+
"""
226+
:param payload: The event properties
227+
:type payload: dict(str:*)
228+
"""
174229
logger.debug("Pushing event to Redis queue...")
175230
self.rdb.rpush(self.key, json.dumps(payload))
176231
logger.debug("Finished sending event to Redis.")

snowplow_tracker/test/integration/test_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def test_integration_page_view(self):
6161
t = tracker.Tracker(default_consumer, default_subject)
6262
with HTTMock(pass_response_content):
6363
t.track_page_view("http://savethearctic.org", "Save The Arctic", None)
64-
self.assertEquals(from_querystring("page", querystrings[-1]),"Save+The+Arctic")
64+
self.assertEquals(from_querystring("page", querystrings[-1]),"Save+The+Arctic")
6565

6666
def test_integration_ecommerce_transaction_item(self):
6767
t = tracker.Tracker(default_consumer, default_subject)

snowplow_tracker/tracker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import time
2323
import random
2424
import logging
25-
from snowplow_tracker import payload, _version, consumer
25+
from snowplow_tracker import payload, _version
2626
from contracts import contract, new_contract, disable_all
2727

2828

0 commit comments

Comments
 (0)