From 3da35893ff427fbff6b43a6afb2e90146a4820a0 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Sun, 17 Sep 2017 15:20:17 +0530 Subject: [PATCH 01/14] Added cloudant's couch library. --- requirements.txt | 2 ++ setup.py | 1 + 2 files changed, 3 insertions(+) diff --git a/requirements.txt b/requirements.txt index c9da5f5..34f0eaa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ restkit>=4.2.2 +jsonobject>=0.6.0 +cloudant==2.7.0 diff --git a/setup.py b/setup.py index 5280b06..3ef5aec 100755 --- a/setup.py +++ b/setup.py @@ -52,6 +52,7 @@ install_requires = [ 'restkit>=4.2.2', 'jsonobject>=0.6.0', + 'cloudant==2.7.0', ], provides=['couchdbkit'], obsoletes=['couchdbkit'], From 952f0420ef9541f312e9c6efc71f3f6493212251 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 18:18:16 -0500 Subject: [PATCH 02/14] Added six as dependency. --- requirements.txt | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 34f0eaa..29c9513 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ restkit>=4.2.2 jsonobject>=0.6.0 cloudant==2.7.0 +six==1.11.0 diff --git a/setup.py b/setup.py index 3ef5aec..43cb205 100755 --- a/setup.py +++ b/setup.py @@ -53,6 +53,7 @@ 'restkit>=4.2.2', 'jsonobject>=0.6.0', 'cloudant==2.7.0', + 'six==1.11.0', ], provides=['couchdbkit'], obsoletes=['couchdbkit'], From 998744b82681756ee8484d278e29d97575a3760b Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Sun, 17 Sep 2017 15:36:27 +0530 Subject: [PATCH 03/14] add couchdb server Comment about the admin party --- couchdbkit/client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 6c6cfed..1ec8c25 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -36,6 +36,7 @@ from mimetypes import guess_type import time +from cloudant.client import CouchDB from restkit.util import url_quote from .exceptions import InvalidAttachment, NoResultFound, \ @@ -104,6 +105,8 @@ def __init__(self, uri='http://127.0.0.1:5984', else: self.res = self.resource_class(uri, **client_opts) self._uuids = deque() + # admin_party is true, because the username/pass is passed in uri for now + self.cloudant_client = CouchDB('', '', url=uri, admin_party=True, connect=True) def info(self): """ info of server From 1f5d0b649dc73633104fdb1fda7f18874e9dda9a Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Sun, 17 Sep 2017 16:51:39 +0530 Subject: [PATCH 04/14] Some cloudant endpoints more cloudant Fix name fix variable --- couchdbkit/client.py | 62 +++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 1ec8c25..2f3e722 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -37,7 +37,10 @@ import time from cloudant.client import CouchDB +from cloudant.database import CouchDatabase +from cloudant.document import Document from restkit.util import url_quote +from six.moves.urllib.parse import urljoin, unquote from .exceptions import InvalidAttachment, NoResultFound, \ ResourceNotFound, ResourceConflict, BulkSaveError, MultipleResultsFound @@ -108,6 +111,10 @@ def __init__(self, uri='http://127.0.0.1:5984', # admin_party is true, because the username/pass is passed in uri for now self.cloudant_client = CouchDB('', '', url=uri, admin_party=True, connect=True) + @property + def _request_session(self): + return self.cloudant_client.r_session + def info(self): """ info of server @@ -115,17 +122,18 @@ def info(self): """ try: - resp = self.res.get() + resp = self._request_session.get(self.uri) + resp.raise_for_status() except Exception: return UNKOWN_INFO - return resp.json_body + return resp.json() def all_dbs(self): """ get list of databases in CouchDb host """ - return self.res.get('/_all_dbs').json_body + return self.cloudant_client.all_dbs() def get_db(self, dbname, **params): """ @@ -210,14 +218,12 @@ def __getitem__(self, dbname): return Database(self._db_uri(dbname), server=self) def __delitem__(self, dbname): - ret = self.res.delete('/%s/' % url_quote(dbname, - safe=":")).json_body - return ret + self.cloudant_client.delete_database(dbname) def __contains__(self, dbname): try: - self.res.head('/%s/' % url_quote(dbname, safe=":")) - except: + self.cloudant_client[dbname] + except KeyError: return False return True @@ -254,6 +260,7 @@ def __init__(self, uri, create=False, server=None, **params): """ self.uri = uri.rstrip('/') self.server_uri, self.dbname = self.uri.rsplit("/", 1) + self.cloudant_dbname = unquote(self.dbname) if server is not None: if not hasattr(server, 'next_uuid'): @@ -263,14 +270,15 @@ def __init__(self, uri, create=False, server=None, **params): else: self.server = server = Server(self.server_uri, **params) + self.cloudant_client = self.server.cloudant_client + validate_dbname(self.dbname) + self.cloudant_database = CouchDatabase(self.cloudant_client, self.cloudant_dbname) if create: - try: - self.server.res.head('/%s/' % self.dbname) - except ResourceNotFound: - self.server.res.put('/%s/' % self.dbname, **params).json_body + self.cloudant_database.create() self.res = server.res(self.dbname) + self._request_session = self.server._request_session def __repr__(self): return "<%s %s>" % (self.__class__.__name__, self.dbname) @@ -281,15 +289,15 @@ def info(self): @return: dict """ - return self.res.get().json_body + return self.cloudant_database.metadata() def set_security(self, secobj): """ set database securrity object """ - return self.res.put("/_security", payload=secobj).json_body + return self._request_session.put(urljoin(self.uri, "/_security"), data=secobj).json() def get_security(self): """ get database secuirity object """ - return self.res.get("/_security").json_body + return self._request_session.get(urljoin(self.uri, "/_security"), data=secobj).json() def compact(self, dname=None): """ compact database @@ -299,14 +307,13 @@ def compact(self, dname=None): path = "/_compact" if dname is not None: path = "%s/%s" % (path, resource.escape_docid(dname)) - res = self.res.post(path, headers={"Content-Type": + path = urljoin(self.uri, path) + res = self._request_session.post(path, headers={"Content-Type": "application/json"}) - return res.json_body + return res.json() def view_cleanup(self): - res = self.res.post('/_view_cleanup', headers={"Content-Type": - "application/json"}) - return res.json_body + return self.cloudant_database.view_cleanup() def flush(self): """ Remove all docs from a database @@ -339,9 +346,7 @@ def flush(self): # we let a chance to the system to sync times = 0 while times < 10: - try: - self.server.res.head('/%s/' % self.dbname) - except ResourceNotFound: + if self.dbname in self.server: break time.sleep(0.2) times += 1 @@ -356,12 +361,8 @@ def doc_exist(self, docid): @param docid: str, document id @return: boolean, True if document exist """ - - try: - self.res.head(resource.escape_docid(docid)) - except ResourceNotFound: - return False - return True + doc = Document(self.cloudant_database, docid) + return doc.exists() def open_doc(self, docid, **params): """Get document from database @@ -1089,6 +1090,3 @@ def __len__(self): def __nonzero__(self): return bool(len(self)) - - - From 69b845dbd4a8f26af8fcaff086b11b61952bf6a6 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Sun, 17 Sep 2017 18:08:53 +0530 Subject: [PATCH 05/14] More cloudant lib stuff --- couchdbkit/client.py | 24 ++++++++++++++++-------- tests/client_test.py | 6 +++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 2f3e722..2295501 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -39,6 +39,7 @@ from cloudant.client import CouchDB from cloudant.database import CouchDatabase from cloudant.document import Document +from cloudant.security_document import SecurityDocument from restkit.util import url_quote from six.moves.urllib.parse import urljoin, unquote @@ -279,10 +280,14 @@ def __init__(self, uri, create=False, server=None, **params): self.res = server.res(self.dbname) self._request_session = self.server._request_session + self.database_url = self.cloudant_database.database_url def __repr__(self): return "<%s %s>" % (self.__class__.__name__, self.dbname) + def _database_path(self, path): + return '/'.join([self.database_url, path]) + def info(self): """ Get database information @@ -293,11 +298,17 @@ def info(self): def set_security(self, secobj): """ set database securrity object """ - return self._request_session.put(urljoin(self.uri, "/_security"), data=secobj).json() + with SecurityDocument(self.cloudant_database) as sec_doc: + # context manager saves + for key in sec_doc: + del sec_doc[key] + for k, v in secobj.items(): + sec_doc[k] = v + return self.get_security() def get_security(self): """ get database secuirity object """ - return self._request_session.get(urljoin(self.uri, "/_security"), data=secobj).json() + return self.cloudant_database.get_security_document() def compact(self, dname=None): """ compact database @@ -307,9 +318,8 @@ def compact(self, dname=None): path = "/_compact" if dname is not None: path = "%s/%s" % (path, resource.escape_docid(dname)) - path = urljoin(self.uri, path) - res = self._request_session.post(path, headers={"Content-Type": - "application/json"}) + path = self._database_path(path) + res = self._request_session.post(path, headers={"Content-Type": "application/json"}) return res.json() def view_cleanup(self): @@ -320,9 +330,7 @@ def flush(self): except design docs.""" # save ddocs - all_ddocs = self.all_docs(startkey="_design", - endkey="_design/"+u"\u9999", - include_docs=True) + all_ddocs = self.all_docs(startkey="_design", endkey="_design/"+u"\u9999", include_docs=True) ddocs = [] for ddoc in all_ddocs: doc = ddoc['doc'] diff --git a/tests/client_test.py b/tests/client_test.py index dad1fd6..dac8b0d 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -566,8 +566,9 @@ def testCopy(self): def testSetSecurity(self): db = self.Server.create_db('couchdbkit_test') - res = db.set_security({"meta": "test"}) - self.assert_(res['ok'] == True) + sec_doc = {"meta": "test"} + res = db.set_security(sec_doc) + self.assertEquals(res, sec_doc) del self.Server['couchdbkit_test'] def testGetSecurity(self): @@ -824,4 +825,3 @@ class B(Document): if __name__ == '__main__': unittest.main() - From 8cbcb10a653361975d34824aa214ca7fcdc507d4 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Sun, 17 Sep 2017 18:16:38 +0530 Subject: [PATCH 06/14] more cloudant --- couchdbkit/client.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 2295501..6d98765 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -36,6 +36,7 @@ from mimetypes import guess_type import time +import cloudant from cloudant.client import CouchDB from cloudant.database import CouchDatabase from cloudant.document import Document @@ -184,21 +185,19 @@ def replicate(self, source, target, **params): http://wiki.apache.org/couchdb/Replication """ - payload = { - "source": source, - "target": target, - } - payload.update(params) - resp = self.res.post('/_replicate', payload=payload) - return resp.json_body + replicator = cloudant.replicator.Replication(self.cloudant_client) + source_db = Database(self.cloudant_client, source) + target_db = Database(self.cloudant_client, target) + return replicator.create_replication(source_db, target_db, **params) def active_tasks(self): """ return active tasks """ - resp = self.res.get('/_active_tasks') - return resp.json_body + resp = self._request_session.get(urljoin(self.uri, '/_active_tasks')) + return resp.json() def uuids(self, count=1): - return self.res.get('/_uuids', count=count).json_body + resp = self._request_session.get(urljoin(self.uri, '/_uuids'), params={'count': count}) + return resp.json() def next_uuid(self, count=None): """ From 1a4890bf7e6b7e0432cdcf546e884f1e20d6ba69 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Mon, 18 Sep 2017 08:25:23 +0530 Subject: [PATCH 07/14] open_doc uses cloudant --- couchdbkit/client.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 6d98765..df34e21 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -41,8 +41,10 @@ from cloudant.database import CouchDatabase from cloudant.document import Document from cloudant.security_document import SecurityDocument +from requests.exceptions import HTTPError from restkit.util import url_quote -from six.moves.urllib.parse import urljoin, unquote +import six +from six.moves.urllib.parse import quote, urljoin, unquote from .exceptions import InvalidAttachment, NoResultFound, \ ResourceNotFound, ResourceConflict, BulkSaveError, MultipleResultsFound @@ -393,8 +395,15 @@ def open_doc(self, docid, **params): raise TypeError("invalid schema") wrapper = schema.wrap - docid = resource.escape_docid(docid) - doc = self.res.get(docid, **params).json_body + if isinstance(docid, six.text_type): + docid = docid.encode('utf-8') + doc = Document(self.cloudant_database, docid) + try: + doc.fetch() + except HTTPError as e: + if e.response.status_code == 404: + raise ResourceNotFound + raise if wrapper is not None: if not callable(wrapper): raise TypeError("wrapper isn't a callable") From 19a325dde476f19f31b3d5aea95eb4ead00874e3 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 00:02:27 -0500 Subject: [PATCH 08/14] cloudant ensure full commit Fix full commit --- couchdbkit/client.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index df34e21..c3b935f 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -875,9 +875,7 @@ def delete_attachment(self, doc, name, headers=None): doc.update(new_doc) return res['ok'] - - def fetch_attachment(self, id_or_doc, name, stream=False, - headers=None): + def fetch_attachment(self, id_or_doc, name, stream=False, headers=None): """ get attachment in a document @param id_or_doc: str or dict, doc id or document dict @@ -903,9 +901,9 @@ def fetch_attachment(self, id_or_doc, name, stream=False, def ensure_full_commit(self): """ commit all docs in memory """ - return self.res.post('_ensure_full_commit', headers={ - "Content-Type": "application/json" - }).json_body + path = self._database_path('_ensure_full_commit') + res = self._request_session.post(path, headers={"Content-Type": "application/json"}) + return res.json() def __len__(self): return self.info()['doc_count'] @@ -920,9 +918,8 @@ def __setitem__(self, docid, doc): doc['_id'] = docid self.save_doc(doc) - def __delitem__(self, docid): - self.delete_doc(docid) + self.delete_doc(docid) def __iter__(self): return self.documents().iterator() @@ -930,6 +927,7 @@ def __iter__(self): def __nonzero__(self): return (len(self) > 0) + class ViewResults(object): """ Object to retrieve view results. From 506a327686bc6f5018fb20570a65ef277277c4f8 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 00:48:56 -0500 Subject: [PATCH 09/14] save_doc(s) uses cloudant lib half of save_doc clean up save_doc save_docs uses cloudant lib --- couchdbkit/client.py | 52 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index c3b935f..5d24816 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -32,7 +32,9 @@ from collections import deque +from copy import deepcopy from itertools import groupby +import json from mimetypes import guess_type import time @@ -56,6 +58,7 @@ DEFAULT_UUID_BATCH_COUNT = 1000 + def _maybe_serialize(doc): if hasattr(doc, "to_json"): # try to validate doc first @@ -70,6 +73,7 @@ def _maybe_serialize(doc): return doc, False + class Server(object): """ Server object that allows you to access and manage a couchdb node. A Server object can be used like any `dict` object. @@ -246,6 +250,7 @@ def _db_uri(self, dbname): dbname = url_quote(dbname, safe=":") return "/".join([self.uri, dbname]) + class Database(object): """ Object that abstract access to a CouchDB database A Database object can act as a Dict object. @@ -529,30 +534,28 @@ def save_doc(self, doc, encode_attachments=True, force_update=False, doc1['_attachments'] = resource.encode_attachments(doc['_attachments']) if '_id' in doc1: - docid = doc1['_id'] - docid1 = resource.escape_docid(doc1['_id']) + docid = doc1['_id'].encode('utf-8') + couch_doc = Document(self.cloudant_database, docid) + couch_doc.update(doc1) try: - res = self.res.put(docid1, payload=doc1, - **params).json_body - except ResourceConflict: + couch_doc.save() + except HTTPError as e: + if e.response.status_code != 409: + raise + if force_update: - doc1['_rev'] = self.get_rev(docid) - res =self.res.put(docid1, payload=doc1, - **params).json_body + couch_doc['_rev'] = self.get_rev(docid) + couch_doc.save() else: - raise + raise ResourceConflict + res = couch_doc else: - try: - doc['_id'] = self.server.next_uuid() - res = self.res.put(doc['_id'], payload=doc1, - **params).json_body - except: - res = self.res.post(payload=doc1, **params).json_body + res = self.cloudant_database.create_document(doc1) - if 'batch' in params and 'id' in res: - doc1.update({ '_id': res['id']}) + if 'batch' in params and ('id' in res or '_id' in res): + doc1.update({ '_id': res.get('_id')}) else: - doc1.update({'_id': res['id'], '_rev': res['rev']}) + doc1.update({'_id': res.get('_id'), '_rev': res.get('_rev')}) if schema: for key, value in doc.__class__.wrap(doc1).iteritems(): @@ -598,13 +601,14 @@ def is_id(doc): if nextid: doc['_id'] = nextid - payload = { "docs": docs1 } + payload = {"docs": docs1} if new_edits is not None: payload["new_edits"] = new_edits # update docs - results = self.res.post('/_bulk_docs', - payload=payload, **params).json_body + results = self._request_session.post( + self._database_path('_bulk_docs'), data=json.dumps(payload), + headers={"Content-Type": "application/json"}, **params).json() errors = [] for i, res in enumerate(results): @@ -787,8 +791,6 @@ def documents(self, schema=None, wrapper=None, **params): wrapper=wrapper, schema=schema, params=params) iterdocuments = documents - - def put_attachment(self, doc, content, name=None, content_type=None, content_length=None, headers=None): """ Add attachement to a document. All attachments are streamed. @@ -828,11 +830,13 @@ def put_attachment(self, doc, content, name=None, content_type=None, if not content: content = "" content_length = 0 + if name is None: if hasattr(content, "name"): name = content.name else: raise InvalidAttachment('You should provide a valid attachment name') + name = url_quote(name, safe="") if content_type is None: content_type = ';'.join(filter(None, guess_type(name))) @@ -841,7 +845,7 @@ def put_attachment(self, doc, content, name=None, content_type=None, headers['Content-Type'] = content_type # add appropriate headers - if content_length and content_length is not None: + if content_length: headers['Content-Length'] = content_length doc1, schema = _maybe_serialize(doc) From 9f4451c6429eadd1d80049d79fd07d86016b6df0 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 10:36:18 -0500 Subject: [PATCH 10/14] Fix importer lint --- couchdbkit/client.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 5d24816..e9dc8da 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -26,11 +26,6 @@ >>> del server['simplecouchdb_test'] """ -from couchdbkit.logging import error_logger - -UNKOWN_INFO = {} - - from collections import deque from copy import deepcopy from itertools import groupby @@ -46,10 +41,11 @@ from requests.exceptions import HTTPError from restkit.util import url_quote import six -from six.moves.urllib.parse import quote, urljoin, unquote +from six.moves.urllib.parse import urljoin, unquote +from couchdbkit.logging import error_logger from .exceptions import InvalidAttachment, NoResultFound, \ -ResourceNotFound, ResourceConflict, BulkSaveError, MultipleResultsFound + ResourceNotFound, ResourceConflict, BulkSaveError, MultipleResultsFound from . import resource from .utils import validate_dbname @@ -57,6 +53,7 @@ DEFAULT_UUID_BATCH_COUNT = 1000 +UNKOWN_INFO = {} def _maybe_serialize(doc): From 3ea6072c75c3461127214e6dcd53e7d8df6e887b Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 10:46:27 -0500 Subject: [PATCH 11/14] cloudant lib get rev --- couchdbkit/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index e9dc8da..7413a63 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -502,8 +502,8 @@ def get_rev(self, docid): @return rev: str, the last revision of document. """ - response = self.res.head(resource.escape_docid(docid)) - return response['etag'].strip('"') + response = self._request_session.head(self._database_path(docid)) + return response.headers['ETag'].strip('"') def save_doc(self, doc, encode_attachments=True, force_update=False, **params): From 79d953909070ab983c39a3a682caf969b6aec4bb Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 11:04:36 -0500 Subject: [PATCH 12/14] delete doc cloudant lib --- couchdbkit/client.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index 7413a63..a3ddcea 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -673,16 +673,22 @@ def delete_doc(self, doc, **params): result = { 'ok': False } doc1, schema = _maybe_serialize(doc) + if isinstance(doc1, dict): if not '_id' or not '_rev' in doc1: raise KeyError('_id and _rev are required to delete a doc') - docid = resource.escape_docid(doc1['_id']) - result = self.res.delete(docid, rev=doc1['_rev'], **params).json_body + couch_doc = Document(self.cloudant_database, doc1['_id']) + couch_doc['_rev'] = doc1['_rev'] elif isinstance(doc1, basestring): # we get a docid - rev = self.get_rev(doc1) - docid = resource.escape_docid(doc1) - result = self.res.delete(docid, rev=rev, **params).json_body + couch_doc = Document(self.cloudant_database, doc1) + couch_doc['_rev'] = self.get_rev(doc1) + + # manual request because cloudant library doesn't return result + result = self._request_session.delete( + couch_doc.document_url, + params={"rev": couch_doc["_rev"]}, + ).json() if schema: doc._doc.update({ From 8bf4554f28a118545ee8fddc81a5ac1d0f320892 Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 11:11:39 -0500 Subject: [PATCH 13/14] raise for status --- couchdbkit/client.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index a3ddcea..d0e2ac3 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -196,10 +196,12 @@ def replicate(self, source, target, **params): def active_tasks(self): """ return active tasks """ resp = self._request_session.get(urljoin(self.uri, '/_active_tasks')) + resp.raise_for_status() return resp.json() def uuids(self, count=1): resp = self._request_session.get(urljoin(self.uri, '/_uuids'), params={'count': count}) + resp.raise_for_status() return resp.json() def next_uuid(self, count=None): @@ -323,6 +325,7 @@ def compact(self, dname=None): path = "%s/%s" % (path, resource.escape_docid(dname)) path = self._database_path(path) res = self._request_session.post(path, headers={"Content-Type": "application/json"}) + res.raise_for_status() return res.json() def view_cleanup(self): @@ -503,6 +506,7 @@ def get_rev(self, docid): @return rev: str, the last revision of document. """ response = self._request_session.head(self._database_path(docid)) + response.raise_for_status() return response.headers['ETag'].strip('"') def save_doc(self, doc, encode_attachments=True, force_update=False, @@ -603,9 +607,11 @@ def is_id(doc): payload["new_edits"] = new_edits # update docs - results = self._request_session.post( + res = self._request_session.post( self._database_path('_bulk_docs'), data=json.dumps(payload), - headers={"Content-Type": "application/json"}, **params).json() + headers={"Content-Type": "application/json"}, **params) + res.raise_for_status() + results = res.json() errors = [] for i, res in enumerate(results): @@ -685,10 +691,12 @@ def delete_doc(self, doc, **params): couch_doc['_rev'] = self.get_rev(doc1) # manual request because cloudant library doesn't return result - result = self._request_session.delete( + res = self._request_session.delete( couch_doc.document_url, params={"rev": couch_doc["_rev"]}, - ).json() + ) + res.raise_for_status() + result = res.json() if schema: doc._doc.update({ @@ -910,6 +918,7 @@ def ensure_full_commit(self): """ commit all docs in memory """ path = self._database_path('_ensure_full_commit') res = self._request_session.post(path, headers={"Content-Type": "application/json"}) + res.raise_for_status() return res.json() def __len__(self): From 158d95277d32057e7cba5368b6f75e289a2cd1ff Mon Sep 17 00:00:00 2001 From: Jonathan Emord Date: Fri, 17 Nov 2017 11:21:33 -0500 Subject: [PATCH 14/14] cloudant lib copy doc --- couchdbkit/client.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/couchdbkit/client.py b/couchdbkit/client.py index d0e2ac3..b1141d7 100644 --- a/couchdbkit/client.py +++ b/couchdbkit/client.py @@ -723,7 +723,7 @@ def copy_doc(self, doc, dest=None, headers=None): if isinstance(doc1, basestring): docid = doc1 else: - if not '_id' in doc1: + if '_id' not in doc1: raise KeyError('_id is required to copy a doc') docid = doc1['_id'] @@ -743,10 +743,11 @@ def copy_doc(self, doc, dest=None, headers=None): if destination: headers.update({"Destination": str(destination)}) - result = self.res.copy('/%s' % docid, headers=headers).json_body - return result + resp = self._request_session.request('copy', self._database_path(docid), headers=headers) + resp.raise_for_status() + return resp.json() - return { 'ok': False } + return {'ok': False} def raw_view(self, view_path, params): if 'keys' in params: