An effortless Cloudant / CouchDB interface for Python.
pip install cloudant
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.
Cloudant-Python is minimal, performant, and effortless. Check it out:
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]
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.
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)
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.
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
To run Cloudant-Python's tests, just do:
python setup.py test
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.
MIT, yo.
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)
def active_tasks(self, **kwargs):
return self.get('_active_tasks', **kwargs)
def all_dbs(self, **kwargs):
return self.get('_all_dbs', **kwargs)
def database(self, name, **kwargs):
opts = dict(self.opts.items() + kwargs.items())
return Database(self._make_url(name), session=self._session, **opts)
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)
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)
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)
def logout(self, **kwargs):
return self.delete(self._reset_path('_session'), **kwargs)
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)
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)
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)
def session(self, **kwargs):
return self.get(self._reset_path('_session'), **kwargs)
def uuids(self, count=1, **kwargs):
params = dict(count=count)
return self.get('_uuids', params=params, **kwargs)
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)
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)
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)
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)
def design(self, name, **kwargs):
opts = dict(self.opts.items() + kwargs.items())
return Design(self._make_url('/'.join(['_design', name])), session=self._session, **opts)
def document(self, name, **kwargs):
opts = dict(self.opts.items() + kwargs.items())
return Document(self._make_url(name), session=self._session, **opts)
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)
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)
def logout(self, **kwargs):
return self.delete(self._reset_path('_session'), **kwargs)
def missing_revs(self, revs, **kwargs):
return self.post('_missing_revs', params=revs, **kwargs)
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)
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)
def revs_diff(self, revs, **kwargs):
return self.post('_revs_diff', params=revs, **kwargs)
def session(self, **kwargs):
return self.get(self._reset_path('_session'), **kwargs)
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)
def attachment(self, name, **kwargs):
opts = dict(self.opts.items() + kwargs.items())
return Attachment(self._make_url(name), session=self._session, **opts)
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)
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)
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)
def logout(self, **kwargs):
return self.delete(self._reset_path('_session'), **kwargs)
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)
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)
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)
def session(self, **kwargs):
return self.get(self._reset_path('_session'), **kwargs)
Connection to a design document, which stores custom indexes and other database functions.
Learn more about design documents from the Cloudant docs
def attachment(self, name, **kwargs):
opts = dict(self.opts.items() + kwargs.items())
return Attachment(self._make_url(name), session=self._session, **opts)
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)
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)
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)
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)
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)
def logout(self, **kwargs):
return self.delete(self._reset_path('_session'), **kwargs)
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)
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)
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)
Creates a Index
object referencing the search index at _search/{function}
. For example:
index = doc.search('index-name')
# refers to /DB/_design/DOC/_search/search-name
For more details on search indexes, see Searching for documents using Lucene queries
def search(self, function, **kwargs):
return self.index('/'.join(['_search', function]), **kwargs)
def session(self, **kwargs):
return self.get(self._reset_path('_session'), **kwargs)
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)
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)
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.
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)
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)
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)
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)
def logout(self, **kwargs):
return self.delete(self._reset_path('_session'), **kwargs)
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)
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)
def session(self, **kwargs):
return self.get(self._reset_path('_session'), **kwargs)
Attachment methods for a single document
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)
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)
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)
def logout(self, **kwargs):
return self.delete(self._reset_path('_session'), **kwargs)
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)
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)
def session(self, **kwargs):
return self.get(self._reset_path('_session'), **kwargs)