diff --git a/syncclient/client.py b/syncclient/client.py index 7061e3e..beaa968 100644 --- a/syncclient/client.py +++ b/syncclient/client.py @@ -101,19 +101,17 @@ def __init__(self, bid_assertion=None, client_state=None, 'key': credentials['key'] }) - def _request(self, method, url, *args, **kwargs): + def _request(self, method, url, **kwargs): """Utility to request an endpoint with the correct authentication setup, raises on errors and returns the JSON. """ url = self.api_endpoint.rstrip('/') + '/' + url.lstrip('/') - self.raw_resp = requests.request(method, url, - auth=self.auth, *args, **kwargs) + self.raw_resp = requests.request(method, url, auth=self.auth, **kwargs) self.raw_resp.raise_for_status() return self.raw_resp.json() - def info_collections(self, if_modified_since=None, - if_unmodified_since=None): + def info_collections(self, **kwargs): """ Returns an object mapping collection names associated with the account to the last-modified time for each collection. @@ -122,9 +120,9 @@ def info_collections(self, if_modified_since=None, with an expired token, so that clients can check for server-side changes before fetching an updated token from the Token Server. """ - return self._request('get', '/info/collections') + return self._request('get', '/info/collections', **kwargs) - def info_quota(self): + def info_quota(self, **kwargs): """ Returns a two-item list giving the user's current usage and quota (in KB). The second item will be null if the server does not enforce @@ -132,9 +130,9 @@ def info_quota(self): Note that usage numbers may be approximate. """ - return self._request('get', '/info/quota') + return self._request('get', '/info/quota', **kwargs) - def get_collection_usage(self): + def get_collection_usage(self, **kwargs): """ Returns an object mapping collection names associated with the account to the data volume used for each collection (in KB). @@ -142,22 +140,21 @@ def get_collection_usage(self): Note that these results may be very expensive as it calculates more detailed and accurate usage information than the info_quota method. """ - return self._request('get', '/info/collection_usage') + return self._request('get', '/info/collection_usage', **kwargs) - def get_collection_counts(self): + def get_collection_counts(self, **kwargs): """ Returns an object mapping collection names associated with the account to the total number of items in each collection. """ - return self._request('get', '/info/collection_counts') + return self._request('get', '/info/collection_counts', **kwargs) - def delete_all_records(self): + def delete_all_records(self, **kwargs): """Deletes all records for the user.""" - return self._request('delete', '/') + return self._request('delete', '/', **kwargs) def get_records(self, collection, full=True, ids=None, newer=None, - limit=None, offset=None, sort=None, if_modified_since=None, - if_unmodified_since=None): + limit=None, offset=None, sort=None, **kwargs): """ Returns a list of the BSOs contained in a collection. For example: @@ -193,7 +190,7 @@ def get_records(self, collection, full=True, ids=None, newer=None, "newest" - orders by last-modified time, largest first "index" - orders by the sortindex, highest weight first """ - params = {} + params = kwargs.pop('params', {}) if full: params['full'] = True if ids is not None: @@ -208,21 +205,21 @@ def get_records(self, collection, full=True, ids=None, newer=None, params['sort'] = sort return self._request('get', '/storage/%s' % collection.lower(), - params=params) + params=params, **kwargs) - def get_record(self, collection, record_id): + def get_record(self, collection, record_id, **kwargs): """Returns the BSO in the collection corresponding to the requested id. """ return self._request('get', '/storage/%s/%s' % (collection.lower(), - record_id)) + record_id), **kwargs) - def delete_record(self, collection, record_id): + def delete_record(self, collection, record_id, **kwargs): """Deletes the BSO at the given location. """ - return self._request('delete', '/storage/%s/%s' % (collection.lower(), - record_id)) + return self._request('delete', '/storage/%s/%s' % ( + collection.lower(), record_id), **kwargs) - def put_record(self, collection, record, if_unmodified_since=None): + def put_record(self, collection, record, **kwargs): """ Creates or updates a specific BSO within a collection. The passed record must be a python object containing new data for the @@ -238,10 +235,6 @@ def put_record(self, collection, record, if_unmodified_since=None): If the target BSO does not exist, then fields that are not provided in the python object will be set to their default value by the server. - :param if_unmodified_since: - Avoid overwriting the data if it has been changed since the client - fetched it. - Successful responses will return the new last-modified time for the collection. @@ -251,9 +244,9 @@ def put_record(self, collection, record, if_unmodified_since=None): record = record.copy() record_id = record.pop('id') return self._request('put', '/storage/%s/%s' % ( - collection.lower(), record_id), json=record) + collection.lower(), record_id), json=record, **kwargs) - def post_records(self, collection, records): + def post_records(self, collection, records, **kwargs): """ Takes a list of BSOs in the request body and iterates over them, effectively doing a series of individual PUTs with the same timestamp. diff --git a/tests/test_client.py b/tests/test_client.py index cdc136b..1fae1d7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -240,27 +240,50 @@ def test_info_collection(self): self.client.info_collections() self.client._request.assert_called_with('get', '/info/collections') + def test_info_collection_can_receive_requests_parameters(self): + self.client.info_collections(headers=mock.sentinel.headers) + self.client._request.assert_called_with('get', '/info/collections', + headers=mock.sentinel.headers) + def test_info_quota(self): self.client.info_quota() self.client._request.assert_called_with('get', '/info/quota') + def test_info_quota_can_receive_requests_parameters(self): + self.client.info_quota(headers=mock.sentinel.headers) + self.client._request.assert_called_with('get', '/info/quota', + headers=mock.sentinel.headers) + def test_collection_usage(self): self.client.get_collection_usage() self.client._request.assert_called_with( - 'get', - '/info/collection_usage') + 'get', '/info/collection_usage') + + def test_collection_usage_can_receive_requests_parameters(self): + self.client.get_collection_usage(headers=mock.sentinel.headers) + self.client._request.assert_called_with( + 'get', '/info/collection_usage', headers=mock.sentinel.headers) def test_collection_counts(self): self.client.get_collection_counts() self.client._request.assert_called_with( - 'get', - '/info/collection_counts') + 'get', '/info/collection_counts') + + def test_collection_counts_can_receive_requests_parameters(self): + self.client.get_collection_counts(headers=mock.sentinel.headers) + self.client._request.assert_called_with( + 'get', '/info/collection_counts', headers=mock.sentinel.headers) def test_delete_all_records(self): self.client.delete_all_records() self.client._request.assert_called_with( 'delete', '/') + def test_delete_all_records_can_receive_requests_parameters(self): + self.client.delete_all_records(headers=mock.sentinel.headers) + self.client._request.assert_called_with( + 'delete', '/', headers=mock.sentinel.headers) + def test_get_records_sets_full_by_default(self): self.client.get_records('mycollection') self.client._request.assert_called_with( @@ -326,11 +349,25 @@ def test_get_record(self): self.client._request.assert_called_with( 'get', '/storage/mycollection/1234') + def test_get_record_can_receive_requests_parameters(self): + self.client.get_record('myCollection', 1234, + headers=mock.sentinel.headers) + self.client._request.assert_called_with( + 'get', '/storage/mycollection/1234', + headers=mock.sentinel.headers) + def test_delete_record(self): self.client.delete_record('myCollection', 1234) self.client._request.assert_called_with( 'delete', '/storage/mycollection/1234') + def test_delete_record_can_receive_requests_parameters(self): + self.client.delete_record('myCollection', 1234, + headers=mock.sentinel.headers) + self.client._request.assert_called_with( + 'delete', '/storage/mycollection/1234', + headers=mock.sentinel.headers) + def test_put_record(self): record = {'id': 1234, 'foo': 'bar'} self.client.put_record('myCollection', record) @@ -338,6 +375,15 @@ def test_put_record(self): 'put', '/storage/mycollection/1234', json={'foo': 'bar'}) + def test_put_record_can_receive_requests_parameters(self): + record = {'id': 1234, 'foo': 'bar'} + self.client.put_record('myCollection', record, + headers=mock.sentinel.headers) + self.client._request.assert_called_with( + 'put', '/storage/mycollection/1234', + json={'foo': 'bar'}, + headers=mock.sentinel.headers) + def test_put_record_doesnt_modify_the_passed_object(self): record = {'id': 1234, 'foo': 'bar'} self.client.put_record('myCollection', record)