Jump To …

Cloudant-Python

Build Status Coverage Status PyPi version PyPi downloads

An effortless Cloudant / CouchDB interface for Python.

Install

pip install cloudant

Usage

Cloudant-Python is a wrapper around Python Requests for interacting with CouchDB or Cloudant instances. Check it out:

import cloudant

# connect to your account
# in this case, https://garbados.cloudant.com
USERNAME = 'garbados'
account = cloudant.Account(USERNAME)

# login, so we can make changes
login = account.login(USERNAME, PASSWORD)
assert login.status_code == 200

# create a database object
db = account.database('test')

# now, create the database on the server
response = db.put()
print response.json()
# {'ok': True}

HTTP requests return Response objects, right from Requests.

Cloudant-Python can also make asynchronous requests by passing async=True to an object's constructor, like so:

import cloudant

# connect to your account
# in this case, https://garbados.cloudant.com
USERNAME = 'garbados'
account = cloudant.Account(USERNAME, async=True)

# login, so we can make changes
future = account.login(USERNAME, PASSWORD)
# block until we get the response body
login = future.result()
assert login.status_code == 200

Asynchronous HTTP requests return Future objects, which will await the return of the HTTP response. Call result() to get the Response object.

See the API reference for all the details you could ever want.

Philosophy

Cloudant-Python is minimal, performant, and effortless. Check it out:

Pythonisms

Cloudant and CouchDB expose REST APIs that map easily into native Python objects. As much as possible, Cloudant-Python uses native Python objects as shortcuts to the raw API, so that such convenience never obscures what's going on underneath. For example:

import cloudant

# connect to http://localhost:5984
account = cloudant.Account()
db = account.database('test')
same_db = account['test']
assert db.uri == same_db.uri
# True

Cloudant-Python expose raw interactions -- HTTP requests, etc. -- through special methods, so we provide syntactical sugar without obscuring the underlying API. Built-ins, such as __getitem__, act as Pythonic shortcuts to those methods. For example:

import cloudant

account = cloudant.Account('garbados')

db_name = 'test'
db = account.database(db_name)
doc = db.document('test_doc')

# create the document
resp = doc.put(params={
  '_id': 'hello_world',
  'herp': 'derp'
  })

# delete the document
rev = resp.json()['_rev']
doc.delete(rev).raise_for_status()

# but this also creates a document
db['hello_world'] = {'herp': 'derp'}

# and this deletes the database
del account[db_name]

Iterate over Indexes

Indexes, such as views and Cloudant's search indexes, act as iterators. Check it out:

import cloudant

account = cloudant.Account('garbados')
db = account.database('test')
view = db.all_docs() # returns all docs in the database
for doc in db:
  # iterates over every doc in the database
  pass
for doc in view:
  # and so does this!
  pass
for doc in view.iter(descending=True):
  # use `iter` to pass options to a view and then iterate over them
  pass

Behind the scenes, Cloudant-Python yields documents only as you consume them, so you only load into memory the documents you're using.

Special Endpoints

If CouchDB has a special endpoint for something, it's in Cloudant-Python as a special method, so any special circumstances are taken care of automagically. As a rule, any endpoint like _METHOD is in Cloudant-Python as Object.METHOD. For example:

  • https://garbados.cloudant.com/_all_dbs -> Account('garbados').all_dbs()
  • http://localhost:5984/DB/_all_docs -> Account().database(DB).all_docs()
  • http://localhost:5984/DB/_design/DOC/_view/INDEX -> Account().database(DB).design(DOC).view(INDEX)

Asynchronous

If you instantiate an object with the async=True option, its HTTP request methods (such as get and post) will return Future objects, which represent an eventual response. This allows your code to keep executing while the request is off doing its business in cyberspace. To get the Response object (waiting until it arrives if necessary) use the result method, like so:

import cloudant

account = cloudant.Account(async=True)
db = account['test']
future = db.put()
response = future.result()
print db.get().result().json()
# {'db_name': 'test', ...}

As a result, any methods which must make an HTTP request return a Future object.

Option Inheritance

If you use one object to create another, the child will inherit the parents' settings. So, you can create a Database object explicitly, or use Account.database to inherit cookies and other settings from the Account object. For example:

import cloudant

account = cloudant.Account('garbados')
db = account.database('test')
doc = db.document('test_doc')

url = 'https://garbados.cloudant.com'
path = '/test/test_doc'
otherdoc = cloudant.Document(url + path)

assert doc.uri == otherdoc.uri
# True

Testing

To run Cloudant-Python's tests, just do:

python setup.py test

Documentation

The API reference is automatically generated from the docstrings of each class and its methods. To install Cloudant-Python with the necessary extensions to build the docs, do this:

pip install -e cloudant[docs]

Then, in Cloudant-Python's root directory, do this:

python docs

Note: docstrings are in Markdown.

License

MIT, yo.

API Reference

Account

An account to a Cloudant or CouchDB account.

account = cloudant.Account()
response = account.login(USERNAME, PASSWORD)
print response.json()
# { "ok": True, ... }

Like all Cloudant-Python objects, pass async=True to make asynchronous requests, like this:

account = cloudant.Account(async=True)
future = account.login(USERNAME, PASSWORD)
response = future.result()
print response.json()
# { "ok": True, ... }

Although you can use login to request a cookie, you can also set account._session.auth to make Cloudant-Python use those credentials on every request, like this:

account = cloudant.Account()
account._session.auth = (username, password)
#

active_tasks

List replication, compaction, and indexer tasks currently running.

    def active_tasks(self, **kwargs):
        
        return self.get('_active_tasks', **kwargs)
#

all_dbs

List all databases.

    def all_dbs(self, **kwargs):
        
        return self.get('_all_dbs', **kwargs)
#

database

Create a Database object prefixed with this account's URL.

    def database(self, name, **kwargs):
        
        opts = dict(self.opts.items() + kwargs.items())
        return Database(self._make_url(name), session=self._session, **opts)
#

delete

Make a DELETE request against the object's URI joined with path. kwargs are passed directly to Requests.

    def delete(self, path='', **kwargs):
        
        return self._make_request('delete', path, **kwargs)
#

get

Make a GET request against the object's URI joined with path. kwargs are passed directly to Requests.

    def get(self, path='', **kwargs):
        
        return self._make_request('get', path, **kwargs)
#

login

Authenticate the connection via cookie.

    def login(self, username, password, **kwargs):
        
        # set headers, body explicitly
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        data = "name=%s&password=%s" % (username, password)
        return self.post(self._reset_path('_session'), headers=headers, data=data, **kwargs)
#

logout

De-authenticate the connection's cookie.

    def logout(self, **kwargs):
        
        return self.delete(self._reset_path('_session'), **kwargs)
#

post

Make a POST request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def post(self, path='', **kwargs):
        
        return self._make_request('post', path, **kwargs)
#

put

Make a PUT request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def put(self, path='', **kwargs):
        
        return self._make_request('put', path, **kwargs)
#

replicate

Begin a replication job. opts contains replication options such as whether the replication should create the target (create_target) or whether the replication is continuous (continuous).

Note: unless continuous, will not return until the job is finished.

    def replicate(self, source, target, opts={}, **kwargs):
        

        params = {
            'source': source,
            'target': target
        }

        params.update(opts)
        if 'params' in kwargs:
            params.update(kwargs['params'])
            del kwargs['params']

        return self.post('_replicate', params=params, **kwargs)
#

session

Get current user's authentication and authorization status.

    def session(self, **kwargs):
        
        return self.get(self._reset_path('_session'), **kwargs)
#

uuids

Generate an arbitrary number of UUIDs.

    def uuids(self, count=1, **kwargs):
        
        params = dict(count=count)
        return self.get('_uuids', params=params, **kwargs)

Database

Connection to a specific database.

Learn more about the raw API from the Cloudant docs.

#

all_docs

Return an Index object referencing all documents in the database. You can treat it like an iterator:

for doc in db.all_docs():
    print doc
    def all_docs(self, **kwargs):
        
        return Index(self._make_url('_all_docs'), session=self._session, **kwargs)
#

bulk_docs

Save many docs, all at once. Each doc argument must be a dict, like this:

    db.bulk_docs({...}, {...}, {...})
    # saves all documents in one HTTP request

For more detail on bulk operations, see Creating or updating multiple documents

    def bulk_docs(self, *docs, **kwargs):
        
        params = {
            'docs': docs
        }
        return self.post('_bulk_docs', params=params, **kwargs)
#

changes

Gets a list of the changes made to the database. This can be used to monitor for update and modifications to the database for post processing or synchronization.

Automatically adjusts the request to handle the different response behavior of polling, longpolling, and continuous modes.

For more information about the _changes feed, see the docs.

    def changes(self, **kwargs):
        
        if 'params' in kwargs:
            if 'feed' in kwargs['params']:
                if kwargs['params']['feed'] == 'continuous':
                    kwargs['stream'] = True

        return self.get('_changes', **kwargs)
#

delete

Make a DELETE request against the object's URI joined with path. kwargs are passed directly to Requests.

    def delete(self, path='', **kwargs):
        
        return self._make_request('delete', path, **kwargs)
#

design

Create a Design object from name, like so:

db.design('test')
# refers to DB/_design/test
    def design(self, name, **kwargs):
        
        opts = dict(self.opts.items() + kwargs.items())
        return Design(self._make_url('/'.join(['_design', name])), session=self._session, **opts)
#

document

Create a Document object from name.

    def document(self, name, **kwargs):
        
        opts = dict(self.opts.items() + kwargs.items())
        return Document(self._make_url(name), session=self._session, **opts)
#

get

Make a GET request against the object's URI joined with path. kwargs are passed directly to Requests.

    def get(self, path='', **kwargs):
        
        return self._make_request('get', path, **kwargs)
#

login

Authenticate the connection via cookie.

    def login(self, username, password, **kwargs):
        
        # set headers, body explicitly
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        data = "name=%s&password=%s" % (username, password)
        return self.post(self._reset_path('_session'), headers=headers, data=data, **kwargs)
#

logout

De-authenticate the connection's cookie.

    def logout(self, **kwargs):
        
        return self.delete(self._reset_path('_session'), **kwargs)
#

missing_revs

Refers to this method.

    def missing_revs(self, revs, **kwargs):
        
        return self.post('_missing_revs', params=revs, **kwargs)
#

post

Make a POST request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def post(self, path='', **kwargs):
        
        return self._make_request('post', path, **kwargs)
#

put

Make a PUT request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def put(self, path='', **kwargs):
        
        return self._make_request('put', path, **kwargs)
#

revs_diff

Refers to this method

    def revs_diff(self, revs, **kwargs):
        
        return self.post('_revs_diff', params=revs, **kwargs)
#

session

Get current user's authentication and authorization status.

    def session(self, **kwargs):
        
        return self.get(self._reset_path('_session'), **kwargs)
#

view_cleanup

Cleans up the cached view output on disk for a given view. For example:

print db.view_cleanup().result().json()
# {'ok': True}
    def view_cleanup(self, **kwargs):
        
        return self.post('_view_cleanup', **kwargs)

Document

Connection to a specific document.

Learn more about the raw API from the Cloudant docs

#

attachment

Create an Attachment object from name and the settings for the current database.

    def attachment(self, name, **kwargs):
        
        opts = dict(self.opts.items() + kwargs.items())
        return Attachment(self._make_url(name), session=self._session, **opts)
#

delete

Delete the given revision of the current document. For example:

rev = doc.get().result().json()['_rev']
doc.delete(rev)
    def delete(self, rev, **kwargs):
        
        return super(Document, self).delete(params={'rev': rev}, **kwargs)
#

get

Make a GET request against the object's URI joined with path. kwargs are passed directly to Requests.

    def get(self, path='', **kwargs):
        
        return self._make_request('get', path, **kwargs)
#

login

Authenticate the connection via cookie.

    def login(self, username, password, **kwargs):
        
        # set headers, body explicitly
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        data = "name=%s&password=%s" % (username, password)
        return self.post(self._reset_path('_session'), headers=headers, data=data, **kwargs)
#

logout

De-authenticate the connection's cookie.

    def logout(self, **kwargs):
        
        return self.delete(self._reset_path('_session'), **kwargs)
#

merge

Merge change into the document, and then PUT the updated document back to the server.

    def merge(self, change, **kwargs):
        
        response = self.get()
        # block until result if the object is using async
        if hasattr(response, 'result'):
            response = response.result()
        # handle upserts
        if response.status_code == 404:
            doc = {}
        else:
            doc = response.json()
        # merge!
        doc.update(change)
        return self.put(params=doc, **kwargs)
#

post

Make a POST request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def post(self, path='', **kwargs):
        
        return self._make_request('post', path, **kwargs)
#

put

Make a PUT request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def put(self, path='', **kwargs):
        
        return self._make_request('put', path, **kwargs)
#

session

Get current user's authentication and authorization status.

    def session(self, **kwargs):
        
        return self.get(self._reset_path('_session'), **kwargs)

Design

Connection to a design document, which stores custom indexes and other database functions.

Learn more about design documents from the Cloudant docs

#

attachment

Create an Attachment object from name and the settings for the current database.

    def attachment(self, name, **kwargs):
        
        opts = dict(self.opts.items() + kwargs.items())
        return Attachment(self._make_url(name), session=self._session, **opts)
#

delete

Delete the given revision of the current document. For example:

rev = doc.get().result().json()['_rev']
doc.delete(rev)
    def delete(self, rev, **kwargs):
        
        return super(Document, self).delete(params={'rev': rev}, **kwargs)
#

get

Make a GET request against the object's URI joined with path. kwargs are passed directly to Requests.

    def get(self, path='', **kwargs):
        
        return self._make_request('get', path, **kwargs)
#

index

Create a Index object referencing the function at path. For example:

index = doc.index('_view/index-name')
# refers to /DB/_design/DOC/_view/index-name
    def index(self, path, **kwargs):
        
        opts = dict(self.opts.items() + kwargs.items())
        return Index(self._make_url(path), session=self._session, **opts)
#

list

Make a GET request to the list function at _list/{function}/{index}. For example:

future = doc.list('list-name', 'index-name')
# refers to /DB/_design/DOC/_list/list-name/index-name

For more details on list functions, see Querying List Functions.

    def list(self, function, index, **kwargs):
        
        return self.get(self._make_url('/'.join(['_list', function, index])), **kwargs)
#

login

Authenticate the connection via cookie.

    def login(self, username, password, **kwargs):
        
        # set headers, body explicitly
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        data = "name=%s&password=%s" % (username, password)
        return self.post(self._reset_path('_session'), headers=headers, data=data, **kwargs)
#

logout

De-authenticate the connection's cookie.

    def logout(self, **kwargs):
        
        return self.delete(self._reset_path('_session'), **kwargs)
#

merge

Merge change into the document, and then PUT the updated document back to the server.

    def merge(self, change, **kwargs):
        
        response = self.get()
        # block until result if the object is using async
        if hasattr(response, 'result'):
            response = response.result()
        # handle upserts
        if response.status_code == 404:
            doc = {}
        else:
            doc = response.json()
        # merge!
        doc.update(change)
        return self.put(params=doc, **kwargs)
#

post

Make a POST request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def post(self, path='', **kwargs):
        
        return self._make_request('post', path, **kwargs)
#

put

Make a PUT request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def put(self, path='', **kwargs):
        
        return self._make_request('put', path, **kwargs)
#

session

Get current user's authentication and authorization status.

    def session(self, **kwargs):
        
        return self.get(self._reset_path('_session'), **kwargs)
#

show

Make a GET request to the show function at _show/{function}/{id}. For example:

future = doc.show('show-name', 'document-id')
# refers to /DB/_design/DOC/_show/show-name/document-id

For more details on show functions, see Querying Show Functions.

    def show(self, function, id, **kwargs):
        
        return self.get(self._make_url('/'.join(['_show', function, id])), **kwargs)
#

view

Create a Index object referencing the secondary index at _view/{function}. For example:

index = doc.view('index-name')
# refers to /DB/_design/DOC/_view/index-name

For more on secondary indices, see Querying a View

    def view(self, function, **kwargs):
        
        return self.index('/'.join(['_view', function]), **kwargs)

Index

Methods for design document indexes. Different kinds of indexes will behave differently, so here are helpful docs:

Then, you just use basic HTTP methods to perform queries, like this:

index.get(params=QUERY_ARGUMENTS)

Remember, before you can query an index, you have to make sure it's in your database. See these docs for how to do that.

#

delete

Make a DELETE request against the object's URI joined with path. kwargs are passed directly to Requests.

    def delete(self, path='', **kwargs):
        
        return self._make_request('delete', path, **kwargs)
#

get

Make a GET request against the object's URI joined with path. kwargs are passed directly to Requests.

    def get(self, path='', **kwargs):
        
        return self._make_request('get', path, **kwargs)
#

iter

Like the magic method __iter__, but allows you to pass query parameters, like so:

view = db.view('...')
options = {
    'key': 'thegoodstuff',
    'include_docs': True
}
for row in view.iter(params=options):
    # emits only rows with the key 'thegoodstuff'
    # with each row's emitting document
    def iter(self, **kwargs):
        
        return self.__iter__(**kwargs)
#

login

Authenticate the connection via cookie.

    def login(self, username, password, **kwargs):
        
        # set headers, body explicitly
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        data = "name=%s&password=%s" % (username, password)
        return self.post(self._reset_path('_session'), headers=headers, data=data, **kwargs)
#

logout

De-authenticate the connection's cookie.

    def logout(self, **kwargs):
        
        return self.delete(self._reset_path('_session'), **kwargs)
#

post

Make a POST request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def post(self, path='', **kwargs):
        
        return self._make_request('post', path, **kwargs)
#

put

Make a PUT request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def put(self, path='', **kwargs):
        
        return self._make_request('put', path, **kwargs)
#

session

Get current user's authentication and authorization status.

    def session(self, **kwargs):
        
        return self.get(self._reset_path('_session'), **kwargs)

Attachment

Attachment methods for a single document

#

delete

Make a DELETE request against the object's URI joined with path. kwargs are passed directly to Requests.

    def delete(self, path='', **kwargs):
        
        return self._make_request('delete', path, **kwargs)
#

get

Make a GET request against the object's URI joined with path. kwargs are passed directly to Requests.

    def get(self, path='', **kwargs):
        
        return self._make_request('get', path, **kwargs)
#

login

Authenticate the connection via cookie.

    def login(self, username, password, **kwargs):
        
        # set headers, body explicitly
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        data = "name=%s&password=%s" % (username, password)
        return self.post(self._reset_path('_session'), headers=headers, data=data, **kwargs)
#

logout

De-authenticate the connection's cookie.

    def logout(self, **kwargs):
        
        return self.delete(self._reset_path('_session'), **kwargs)
#

post

Make a POST request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def post(self, path='', **kwargs):
        
        return self._make_request('post', path, **kwargs)
#

put

Make a PUT request against the object's URI joined with path.

kwargs['params'] are turned into JSON before being passed to Requests. If you want to indicate the message body without it being modified, use kwargs['data'].

    def put(self, path='', **kwargs):
        
        return self._make_request('put', path, **kwargs)
#

session

Get current user's authentication and authorization status.

    def session(self, **kwargs):
        
        return self.get(self._reset_path('_session'), **kwargs)