Package couchdbkit :: Module resource
[hide private]
[frames] | no frames]

Source Code for Module couchdbkit.resource

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of couchdbkit released under the MIT license. 
  4  # See the NOTICE for more information. 
  5   
  6  """ 
  7  couchdb.resource 
  8  ~~~~~~~~~~~~~~~~~~~~~~ 
  9   
 10  This module providess a common interface for all CouchDB request. This 
 11  module makes HTTP request using :mod:`httplib2` module or :mod:`pycurl` 
 12  if available. Just use set transport argument for this. 
 13   
 14  Example: 
 15   
 16      >>> resource = CouchdbResource() 
 17      >>> info = resource.get() 
 18      >>> info['couchdb'] 
 19      u'Welcome' 
 20   
 21  """ 
 22  import base64 
 23  import re 
 24   
 25  from restkit import Resource, ClientResponse 
 26  from restkit.errors import ResourceError, RequestFailed, RequestError 
 27  from restkit.util import url_quote 
 28   
 29  from . import __version__ 
 30  from .exceptions import ResourceNotFound, ResourceConflict, \ 
 31  PreconditionFailed 
 32  from .utils import json 
 33   
 34  USER_AGENT = 'couchdbkit/%s' % __version__ 
 35   
 36  RequestFailed = RequestFailed 
37 38 -class CouchDBResponse(ClientResponse):
39 40 @property
41 - def json_body(self):
42 body = self.body_string() 43 44 # try to decode json 45 try: 46 return json.loads(body) 47 except ValueError: 48 return body
49
50 51 -class CouchdbResource(Resource):
52
53 - def __init__(self, uri="http://127.0.0.1:5984", **client_opts):
54 """Constructor for a `CouchdbResource` object. 55 56 CouchdbResource represent an HTTP resource to CouchDB. 57 58 @param uri: str, full uri to the server. 59 """ 60 client_opts['response_class'] = CouchDBResponse 61 62 Resource.__init__(self, uri=uri, **client_opts) 63 self.safe = ":/%"
64
65 - def copy(self, path=None, headers=None, **params):
66 """ add copy to HTTP verbs """ 67 return self.request('COPY', path=path, headers=headers, **params)
68
69 - def request(self, method, path=None, payload=None, headers=None, **params):
70 """ Perform HTTP call to the couchdb server and manage 71 JSON conversions, support GET, POST, PUT and DELETE. 72 73 Usage example, get infos of a couchdb server on 74 http://127.0.0.1:5984 : 75 76 77 import couchdbkit.CouchdbResource 78 resource = couchdbkit.CouchdbResource() 79 infos = resource.request('GET') 80 81 @param method: str, the HTTP action to be performed: 82 'GET', 'HEAD', 'POST', 'PUT', or 'DELETE' 83 @param path: str or list, path to add to the uri 84 @param data: str or string or any object that could be 85 converted to JSON. 86 @param headers: dict, optional headers that will 87 be added to HTTP request. 88 @param raw: boolean, response return a Response object 89 @param params: Optional parameterss added to the request. 90 Parameterss are for example the parameters for a view. See 91 `CouchDB View API reference 92 <http://wiki.apache.org/couchdb/HTTP_view_API>`_ for example. 93 94 @return: tuple (data, resp), where resp is an `httplib2.Response` 95 object and data a python object (often a dict). 96 """ 97 98 headers = headers or {} 99 headers.setdefault('Accept', 'application/json') 100 headers.setdefault('User-Agent', USER_AGENT) 101 102 if payload is not None: 103 #TODO: handle case we want to put in payload json file. 104 if not hasattr(payload, 'read') and not isinstance(payload, basestring): 105 payload = json.dumps(payload).encode('utf-8') 106 headers.setdefault('Content-Type', 'application/json') 107 108 params = encode_params(params) 109 try: 110 resp = Resource.request(self, method, path=path, 111 payload=payload, headers=headers, **params) 112 113 except ResourceError, e: 114 msg = getattr(e, 'msg', '') 115 if e.response and msg: 116 if e.response.headers.get('content-type') == 'application/json': 117 try: 118 msg = json.loads(msg) 119 except ValueError: 120 pass 121 122 if type(msg) is dict: 123 error = msg.get('reason') 124 else: 125 error = msg 126 127 if e.status_int == 404: 128 raise ResourceNotFound(error, http_code=404, 129 response=e.response) 130 131 elif e.status_int == 409: 132 raise ResourceConflict(error, http_code=409, 133 response=e.response) 134 elif e.status_int == 412: 135 raise PreconditionFailed(error, http_code=412, 136 response=e.response) 137 else: 138 raise 139 except: 140 raise 141 142 return resp
143
144 -def encode_params(params):
145 """ encode parameters in json if needed """ 146 _params = {} 147 if params: 148 for name, value in params.items(): 149 if name in ('key', 'startkey', 'endkey'): 150 value = json.dumps(value) 151 elif value is None: 152 continue 153 elif not isinstance(value, basestring): 154 value = json.dumps(value) 155 _params[name] = value 156 return _params
157
158 -def escape_docid(docid):
159 if docid.startswith('/'): 160 docid = docid[1:] 161 if docid.startswith('_design'): 162 docid = '_design/%s' % url_quote(docid[8:], safe='') 163 else: 164 docid = url_quote(docid, safe='') 165 return docid
166 167 re_sp = re.compile('\s')
168 -def encode_attachments(attachments):
169 for k, v in attachments.iteritems(): 170 if v.get('stub', False): 171 continue 172 else: 173 v['data'] = re_sp.sub('', base64.b64encode(v['data'])) 174 return attachments
175