Skip to content

Commit 4a0b254

Browse files
committed
Merge pull request #1 from adafruit/error_handling
Add custom Adafruit IO error types.
2 parents f7ad55f + 2af9a0d commit 4a0b254

File tree

4 files changed

+75
-5
lines changed

4 files changed

+75
-5
lines changed

Adafruit_IO/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .client import Client
1+
from .client import Client, AdafruitIOError, RequestError, ThrottlingError

Adafruit_IO/client.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,29 @@
33
from urllib3 import connection_from_url
44
from urllib import urlencode, quote
55

6+
7+
class AdafruitIOError(Exception):
8+
"""Base class for all Adafruit IO request failures."""
9+
pass
10+
11+
class RequestError(Exception):
12+
"""General error for a failed Adafruit IO request."""
13+
def __init__(self, response):
14+
super(RequestError, self).__init__("Adafruit IO request failed: {0} {1}".format(
15+
response.status, response.reason))
16+
17+
class ThrottlingError(AdafruitIOError):
18+
"""Too many requests have been made to Adafruit IO in a short period of time.
19+
Reduce the rate of requests and try again later.
20+
"""
21+
def __init__(self):
22+
super(ThrottlingError, self).__init__("Exceeded the limit of Adafruit IO " \
23+
"requests in a short period of time. Please reduce the rate of requests " \
24+
"and try again later.")
25+
626
#fork of ApiClient Class: https://github.com/shazow/apiclient
727
class Client(object):
8-
#BASE_URL = 'http://localhost:3002/'
9-
BASE_URL = 'http://io.ladyada.org/'
28+
BASE_URL = 'https://io.adafruit.com/'
1029

1130
def __init__(self, key, rate_limit_lock=None):
1231
self.key = key
@@ -22,7 +41,17 @@ def _compose_url(self, path):
2241
def _compose_get_url(self, path, params=None):
2342
return self.BASE_URL + path + '?' + urlencode(params)
2443

44+
def _handle_error(sefl, response):
45+
# Handle explicit errors.
46+
if response.status == 429:
47+
raise ThrottlingError()
48+
# Handle all other errors (400 & 500 level HTTP responses)
49+
elif response.status >= 400:
50+
raise RequestError(response)
51+
# Else do nothing if there was no error.
52+
2553
def _handle_response(self, response):
54+
self._handle_error(response)
2655
return json.loads(response.data)
2756

2857
def _request(self, method, path, params=None):
@@ -37,7 +66,7 @@ def _request(self, method, path, params=None):
3766
r = self.connection_pool.urlopen(method.upper(), url, headers=headers)
3867
else:
3968
r = self.connection_pool.urlopen(method.upper(), url, headers=headers, body=json.dumps(params))
40-
69+
4170
return self._handle_response(r)
4271

4372
def _get(self, path, **params):
@@ -106,4 +135,3 @@ def groups(self, group_id_or_key):
106135
def create_group(self, group_id_or_key, data):
107136
path = "api/groups/{}".format(group_id_or_key)
108137
return self._post(path, data)
109-

tests/README.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Adafruit IO Python Client Test README
2+
3+
To run these tests you must have the pytest module installed. You can install
4+
this (assuming you have pip installed) by executing:
5+
sudo pip install pytest
6+
7+
Some tests require a valid Adafruit IO account to run, and they key for this
8+
account is provided in the ADAFRUIT_IO_KEY environment variable. Make sure to
9+
set this envirionment variable before running the tests, for example to run all
10+
the tests with a key execute in this directory:
11+
ADAFRUIT_IO_KEY=my_io_key_value py.test

tests/test_errors.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import os
2+
import time
3+
4+
import pytest
5+
6+
import Adafruit_IO
7+
8+
9+
def _get_client():
10+
"""Return an Adafruit IO client instance configured with the key specified in
11+
the ADAFRUIT_IO_KEY environment variable.
12+
"""
13+
key = os.environ.get('ADAFRUIT_IO_KEY', None)
14+
if key is None:
15+
raise RuntimeError("ADAFRUIT_IO_KEY environment variable must be set with " \
16+
"valid Adafruit IO key to run this test!")
17+
return Adafruit_IO.Client(key)
18+
19+
20+
class TestErrors:
21+
def test_request_error_from_bad_key(self):
22+
io = Adafruit_IO.Client("this is a bad key from a test")
23+
with pytest.raises(Adafruit_IO.RequestError):
24+
io.send("TestStream", 42)
25+
26+
def test_throttling_error_after_6_requests_in_short_period(self):
27+
io = _get_client()
28+
with pytest.raises(Adafruit_IO.ThrottlingError):
29+
for i in range(6):
30+
io.send("TestStream", 42)
31+
time.sleep(0.1) # Small delay to keep from hammering network.

0 commit comments

Comments
 (0)