See the slumber documentation for using slumber. Use curling in the same way:

from curling.lib import API

Curling sniffs out Tastypie and automatically turns a list of records into a list. For example:

res =

The settings API returns a Tastypie style list. We turn it into a Python list.

We provide a few extra methods for accessing objects that mirror Django methods. For example:

res =

Will test that one and only one record is returned and access that object.

class curling.lib.TastypieResource(*args, **kw)
get(data=None, headers=None, **kwargs)

Allow a body in GET, because that’s just fine.


Calls get on a list, returns a 404 if the list isn’t there.

Similar to Djangos get_list_or_404.


Gets an object and checks that one and only one object is returned.

  • first it will convert a Tastypie style response into the list of objects.

  • then it will return the first element unless
    • if there is more than one element raises MultipleObjectsReturned
    • if there is less than one element raises ObjectDoesNotExist
  • if a list is not found but another item, that will be returned


Wrapper around get_object. The only difference is that if the server returns a HTTP 404, this then alters that into an ObjectDoesNotExist error.

If you’ve got URLs to items, then by_url can be a handy way to access them.

class curling.lib.CurlingBase
by_url(url, parser=None)

Converts a URL such as:

/generic/transaction/ > generic.transaction

And one such as:

/generic/transaction/8/ > generic.transaction(8)

This scheme is assuming that you’ve got two names and a primary key, if you would like a different parser you could pass in a new one.


Just like slumber any response in the 400 range is treated as HttpClientError. We’ll also assume that the response body contains JSON and parse that.

So in the example:

from lib import API, HttpClientError, HttpServerError

api = API('http://localhost:8001')

    api.by_url('/generic/buyer/').post(data={'foo': 'bar', 'uuid': 'asd'})
except (HttpClientError, HttpServerError), exc:
    print type(exc.content), exc.content
    print type(exc.message), exc.message

You’ll get:

<type 'dict'> {u'uuid': [u'Buyer with this Uuid already exists.']}
<type 'str'> Client Error 400: http://localhost:8001/generic/buyer/
  • content: the body parsed as JSON, if possible
  • message: the nice message of the error
  • response: the response object, so response.status_code will give you the status


Curling can add in OAuth headers, using OAuth 1.x. These OAuth headers are ones that solitude <> can understand, so might not implement the complete OAuth spec..

For example:

api = API('http://localhost:8001', format='jwt')
api.activate_oauth('key', 'secret', realm='optional.realm')

You can pass through extra parameters to go through to the oauth generation by using passing through params, e.g.:

api.activate_oauth('key', 'secret', realm='optional.realm',
                   params={'oauth_token': 'foo'})


Curling supports optional headers for GET, POST, PUT and PATCH methods. If a GET request contains the If-None-Match header with a proper Etag, a 304 response will be returned with an empty content, as expected.