Permalink
Browse files

Merge master

  • Loading branch information...
2 parents d0103de + 46b5a3e commit 3b9d00e864ef2e4423bcb433d2480073a15ce48d @paulosman paulosman committed Mar 5, 2012
View
@@ -145,6 +145,19 @@ Update your profile description: ::
'description': "a new description"
})
+Redirects
+---------
+
+By default, 301 or 302 redirects will be followed for idempotent methods. There are certain cases where you may want to disable this, for example: ::
+
+ import soundcloud
+
+ client = soundcloud.Client(access_token="a valid access token")
+ track = client.get('/tracks/293/stream', allow_redirects=False)
+ print track.location
+
+Will print a tracks streaming URL. If ``allow_redirects`` was omitted, a binary stream would be returned instead.
+
Running Tests
-------------
View
@@ -136,7 +136,11 @@ def make_request(method, url, params):
for key in empty:
del params[key]
+ # allow caller to disable automatic following of redirects
+ allow_redirects = params.get('allow_redirects', True)
+
kwargs = {
+ 'allow_redirects': allow_redirects,
'headers': {
'User-Agent': soundcloud.USER_AGENT
}
@@ -149,6 +153,8 @@ def make_request(method, url, params):
if 'proxies' in params:
kwargs['proxies'] = params['proxies']
del params['proxies']
+ if 'allow_redirects' in params:
+ del params['allow_redirects']
files = namespaced_query_string(extract_files_from_dict(params))
data = namespaced_query_string(remove_files_from_dict(params))
@@ -166,4 +172,10 @@ def make_request(method, url, params):
kwargs['files'] = files
result = request_func(url, **kwargs)
+ # if redirects are disabled, don't raise for 301 / 302
+ if result.status_code in [301, 302]:
+ if allow_redirects:
+ result.raise_for_status()
+ else:
+ result.raise_for_status()
return result
View
@@ -39,7 +39,11 @@ def wrapped_resource(response):
Lists will be returned as a ```ResourceList``` instance,
dicts will be returned as a ```Resource``` instance.
"""
- content = json.loads(response.content)
+ try:
+ content = json.loads(response.content)
+ except ValueError:
+ # not JSON
+ content = response.content
if isinstance(content, list):
result = ResourceList(content)
else:
@@ -77,7 +77,10 @@ def test_disabling_ssl_verification(fake_get):
'User-Agent': soundcloud.USER_AGENT
}
(fake_get.expects_call()
- .with_args(expected_url, verify_ssl=False, headers=headers)
+ .with_args(expected_url,
+ headers=headers,
+ verify_ssl=False,
+ allow_redirects=True)
.returns(MockResponse("{}")))
client.get('tracks', order='hotness', limit=5)
@@ -107,7 +110,7 @@ def test_method_dispatching_get_request_readonly(fake_get):
'User-Agent': soundcloud.USER_AGENT
}
(fake_get.expects_call()
- .with_args(expected_url, headers=headers)
+ .with_args(expected_url, headers=headers, allow_redirects=True)
.returns(MockResponse("{}")))
client.get('tracks', order='hotness', limit=5)
@@ -128,6 +131,9 @@ def test_method_dispatching_post_request(fake_post):
'User-Agent': soundcloud.USER_AGENT
}
(fake_post.expects_call()
- .with_args(expected_url, data=data, headers=headers)
+ .with_args(expected_url,
+ data=data,
+ headers=headers,
+ allow_redirects=True)
.returns(MockResponse("{}")))
client.post('tracks')
@@ -0,0 +1,49 @@
+from contextlib import contextmanager
+
+import fudge
+import soundcloud
+
+from nose.tools import raises, assert_raises
+from requests.exceptions import HTTPError
+
+from soundcloud.tests.utils import MockResponse
+
+
+@contextmanager
+def response_status(fake_http_request, status):
+ response = MockResponse('{}', status_code=status)
+ fake_http_request.expects_call().returns(response)
+ yield
+
+
+@fudge.patch('requests.get')
+def test_bad_responses(fake):
+ """Anything in the 400 or 500 range should raise an exception."""
+ client = soundcloud.Client(client_id='foo', client_secret='foo')
+ for status in range(400, 423):
+ with response_status(fake, status):
+ assert_raises(HTTPError, lambda: client.get('/me'))
+ for status in (500, 501, 502, 503, 504, 505):
+ with response_status(fake, status):
+ assert_raises(HTTPError, lambda: client.get('/me'))
+
+@fudge.patch('requests.get')
+def test_ok_response(fake):
+ """A 200 range response should be fine."""
+ client = soundcloud.Client(client_id='foo', client_secret='foo')
+ for status in (200, 201, 202, 203, 204, 205, 206):
+ with response_status(fake, status):
+ user = client.get('/me')
+
+@fudge.patch('requests.get')
+def test_redirects(fake):
+ """Make sure 300 responses raise an exception.
+
+ Note: ```requests``` transparently attempts redirects so if we get
+ this back it means the caller has disabled redirects or the max
+ number has been reached.
+ """
+ client = soundcloud.Client(client_id='foo', client_secret='foo')
+ for status in (300, 301, 302, 303, 304, 305, 307):
+ with response_status(fake, status):
+ assert_raises(HTTPError, lambda: client.get('/me'))
@@ -1,6 +1,9 @@
-class MockResponse(object):
+from requests.models import Response
+
+
+class MockResponse(Response):
def __init__(self, content, status_code=200, url=None, error=None):
- self.content = content
+ self._content = content
self.status_code = status_code
self.url = url
self.error = error

0 comments on commit 3b9d00e

Please sign in to comment.