def __init__(self, uri, create=False, server=None): """Constructor for Database @param uri: str, Database uri @param create: boolean, False by default, if True try to create the database. @param server: Server instance """ uri_parsed = urlparse.urlparse(uri) self.server_uri = "%s://%s" % (uri_parsed.scheme, uri_parsed.netloc) self.dbname = uri_parsed.path.strip("/") if server is not None: if not hasattr(server, 'next_uuid'): raise TypeError('%s is not a couchdbkit.server instance' % server.__class__.__name__) self.server = server else: self.server = server = Server(self.server_uri) try: self.server.res.head('/%s/' % url_quote(self.dbname, safe=":")) except resource.ResourceNotFound: if create: self.server.res.put('/%s/' % url_quote(self.dbname, safe=":")) else: raise self.res = server.res.clone() if "/" in self.dbname: self.res.safe = ":/%" self.res.update_uri('/%s' % url_quote(self.dbname, safe=":"))
def escape_docid(docid): if docid.startswith("/"): docid = docid[1:] if docid.startswith("_design"): docid = "_design/%s" % util.url_quote(docid[8:], safe="") else: docid = util.url_quote(docid, safe="") return docid
def escape_docid(docid): if docid.startswith('/'): docid = docid[1:] if docid.startswith('_design'): docid = '_design/%s' % url_quote(docid[8:], safe='') else: docid = url_quote(docid, safe='') return docid
def escape_docid(docid): if docid.startswith('/'): docid = docid[1:] if docid.startswith('_design'): docid = '_design/%s' % util.url_quote(docid[8:], safe='') else: docid = util.url_quote(docid, safe='') return docid
def form_encode(obj, charset="utf8"): if hasattr( obj, 'items' ): obj = obj.items() lines = [ ( u"%s=%s" % ( url_quote(key), url_quote(value) ) ).encode( charset ) for (key, value) in obj ] return to_bytestring( "&".join( lines ) )
def fetch_attachment(self, id_or_doc, name, stream=False, headers=None, **params): """ get attachment in a document @param id_or_doc: str or dict, doc id or document dict @param name: name of attachment default: default result @param stream: boolean, if True return a file object @param params, list of optionnal params. @return: `restkit.httpc.Response` object """ if isinstance(id_or_doc, basestring): docid = id_or_doc else: doc, schema = _maybe_serialize(id_or_doc) docid = doc['_id'] if not 'rev' in params.keys(): params['rev'] = doc['_rev'] docid = resource.escape_docid(docid) name = url_quote(name, safe="") resp = self.res(docid).get(name, headers=headers, **params) if stream: return resp.body_stream() return resp.body_string(charset="utf-8")
def __init__(self, name, value, fname=None, filetype=None, filesize=None): self.name = url_quote(name) if value is not None and not hasattr(value, 'read'): value = self.encode_unreadable_value(value) self.size = len(value) self.value = value if fname is not None: if isinstance(fname, unicode): fname = fname.encode("utf-8").encode("string_escape").replace( '"', '\\"') else: fname = fname.encode("string_escape").replace('"', '\\"') self.fname = fname if filetype is not None: filetype = to_bytestring(filetype) self.filetype = filetype if isinstance(value, file) and filesize is None: try: value.flush() except IOError: pass self.size = int(os.fstat(value.fileno())[6]) self._encoded_hdr = None self._encoded_bdr = None
def put_attachment(self, doc, content=None, name=None, headers=None): """ Add attachement to a document. All attachments are streamed. @param doc: dict, document object @param content: string, iterator, fileobj @param name: name or attachment (file name). @param headers: optionnal headers like `Content-Length` or `Content-Type` @return: updated document object """ headers = {} content = content or "" if name is None: if hasattr(content, "name"): name = content.name else: raise InvalidAttachment('You should provid a valid ' + 'attachment name') name = util.url_quote(name, safe="") res = self.res.put("%s/%s" % (escape_docid(doc['_id']), name), payload=content, headers=headers, rev=doc['_rev']) json_res = res.json_body if 'ok' in json_res: return doc.update(self.open_doc(doc['_id'])) return False
def put_attachment(self, doc, content=None, name=None, headers=None): """ Add attachement to a document. All attachments are streamed. @param doc: dict, document object @param content: string, iterator, fileobj @param name: name or attachment (file name). @param headers: optionnal headers like `Content-Length` or `Content-Type` @return: updated document object """ headers = {} content = content or "" if name is None: if hasattr(content, "name"): name = content.name else: raise InvalidAttachment( 'You should provid a valid attachment name') name = util.url_quote(name, safe="") res = self.put("%s/%s" % (escape_docid(doc['_id']), name), payload=content, headers=headers, rev=doc['_rev']) json_res = res.json_body if 'ok' in json_res: return doc.update(self.open_doc(doc['_id'])) return False
def __init__(self, name, value, fname=None, filetype=None, filesize=None): self.name = url_quote(name) if value is not None and not hasattr(value, 'read'): value = self.encode_unreadable_value(value) self.size = len(value) self.value = value if fname is not None: if isinstance(fname, unicode): fname = fname.encode("utf-8").encode("string_escape").replace('"', '\\"') else: fname = fname.encode("string_escape").replace('"', '\\"') self.fname = fname if filetype is not None: filetype = to_bytestring(filetype) self.filetype = filetype if isinstance(value, file) and filesize is None: try: value.flush() except IOError: pass self.size = int(os.fstat(value.fileno())[6]) self._encoded_hdr = None self._encoded_bdr = None
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: updated document object """ name = util.url_quote(name, safe="") self.res.delete("%s/%s" % (escape_docid(doc["_id"]), name), rev=doc["_rev"]).json_body return doc.update(self.open_doc(doc["_id"]))
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: updated document object """ name = util.url_quote(name, safe="") self.res.delete("%s/%s" % (escape_docid(doc['_id']), name), rev=doc['_rev']).json_body return doc.update(self.open_doc(doc['_id']))
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ docid = resource.escape_docid(doc["_id"]) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc["_rev"]).json_body if res["ok"]: doc.update({"_rev": res["rev"]}) return res["ok"]
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ docid = resource.escape_docid(doc['_id']) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc['_rev']).json_body if res['ok']: new_doc = self.get(doc['_id'], rev=res['rev']) doc.update(new_doc) return res['ok']
def delete_attachment(self, doc, name, headers=None): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ doc1, schema = _maybe_serialize(doc) docid = resource.escape_docid(doc1["_id"]) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc1["_rev"], headers=headers).json_body if res["ok"]: new_doc = self.get(doc1["_id"], rev=res["rev"]) doc.update(new_doc) return res["ok"]
def delete_attachment(self, doc, name): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @return: dict, with member ok set to True if delete was ok. """ doc1, schema = _maybe_serialize(doc) docid = resource.escape_docid(doc1['_id']) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc1['_rev']).json_body if res['ok']: new_doc = self.get(doc1['_id'], rev=res['rev']) doc.update(new_doc) return res['ok']
def make_uri(base, *args, **kwargs): """Assemble a uri based on a base, any number of path segments, and query string parameters. """ # get encoding parameters charset = kwargs.pop("charset", "utf-8") safe = kwargs.pop("safe", "/:") encode_keys = kwargs.pop("encode_keys", True) base_trailing_slash = False if base and base.endswith("/"): base_trailing_slash = True base = base[:-1] retval = [base] # build the path _path = [] trailing_slash = False for s in args: if s is not None and isinstance(s, basestring): if len(s) > 1 and s.endswith('/'): trailing_slash = True else: trailing_slash = False _path.append(url_quote(s.strip('/'), charset, safe)) path_str = "" if _path: path_str = "/".join([''] + _path) if trailing_slash: path_str = path_str + "/" elif base_trailing_slash: path_str = path_str + "/" if path_str: retval.append(path_str) params_str = url_encode(kwargs, charset, encode_keys, safe) if params_str: retval.extend(['?', params_str]) return ''.join(retval)
def encode_hdr(self, boundary): """Returns the header of the encoding of this parameter""" boundary = url_quote(boundary) headers = ["--%s" % boundary] if self.fname: disposition = 'form-data; name="%s"; filename="%s"' % (self.name, self.fname) else: disposition = 'form-data; name="%s"' % self.name headers.append("Content-Disposition: %s" % disposition) if self.filetype: filetype = self.filetype else: filetype = "text/plain; charset=utf-8" headers.append("Content-Type: %s" % filetype) headers.append("Content-Length: %i" % self.size) headers.append("") headers.append("") return "\r\n".join(headers)
def delete_attachment(self, doc, name, headers=None, **params): """ delete attachement to the document @param doc: dict, document object in python @param name: name of attachement @param params, list of optionnal params. @return: dict, with member ok set to True if delete was ok. """ doc1, schema = _maybe_serialize(doc) docid = resource.escape_docid(doc1['_id']) name = url_quote(name, safe="") res = self.res(docid).delete(name, rev=doc1['_rev'], headers=headers, **params).json_body if res['ok']: new_doc = self.get(doc1['_id'], rev=res['rev']) doc.update(new_doc) return res['ok']
def fetch_attachment(self, id_or_doc, name, stream=False): """ get attachment in a document @param id_or_doc: str or dict, doc id or document dict @param name: name of attachment default: default result @param stream: boolean, if True return a file object @return: `restkit.httpc.Response` object """ if isinstance(id_or_doc, basestring): docid = id_or_doc else: docid = id_or_doc['_id'] docid = resource.escape_docid(docid) name = url_quote(name, safe="") resp = self.res(docid).get(name) if stream: return resp.body_file return resp.body_string(charset="utf-8")
def _make_uri(self, base, *path, **query): """Assemble a uri based on a base, any number of path segments, and query string parameters. """ base_trailing_slash = False if base and base.endswith("/"): base_trailing_slash = True base = base[:-1] retval = [base] # build the path _path = [] trailing_slash = False for s in path: if s is not None and isinstance(s, basestring): if len(s) > 1 and s.endswith('/'): trailing_slash = True else: trailing_slash = False _path.append(util.url_quote(s.strip('/'), self.charset, self.safe)) path_str ="" if _path: path_str = "/".join([''] + _path) if trailing_slash: path_str = path_str + "/" elif base_trailing_slash: path_str = path_str + "/" if path_str: retval.append(path_str) params_str = util.url_encode(query, self.charset, self.encode_keys) if params_str: retval.extend(['?', params_str]) return ''.join(retval)
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. @param doc: dict, document object @param content: string or :obj:`File` object. @param name: name or attachment (file name). @param content_type: string, mimetype of attachment. If you don't set it, it will be autodetected. @param content_lenght: int, size of attachment. @return: bool, True if everything was ok. Example: >>> from simplecouchdb import server >>> server = server() >>> db = server.create_db('couchdbkit_test') >>> doc = { 'string': 'test', 'number': 4 } >>> db.save(doc) >>> text_attachment = u'un texte attaché' >>> db.put_attachment(doc, text_attachment, "test", "text/plain") True >>> file = db.fetch_attachment(doc, 'test') >>> result = db.delete_attachment(doc, 'test') >>> result['ok'] True >>> db.fetch_attachment(doc, 'test') >>> del server['couchdbkit_test'] {u'ok': True} """ if not headers: headers = {} 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))) if content_type: headers['Content-Type'] = content_type # add appropriate headers if content_length and content_length is not None: headers['Content-Length'] = content_length doc1, schema = _maybe_serialize(doc) docid = resource.escape_docid(doc1['_id']) res = self.res(docid).put(name, payload=content, headers=headers, rev=doc1['_rev']).json_body if res['ok']: new_doc = self.get(doc1['_id'], rev=res['rev']) doc.update(new_doc) return res['ok']
def _db_uri(self, dbname): if dbname.startswith("/"): dbname = dbname[1:] dbname = url_quote(dbname, safe=":") return "/".join([self.uri, dbname])
def __contains__(self, dbname): try: self.res.head('/%s/' % url_quote(dbname, safe=":")) except: return False return True
def __delitem__(self, dbname): ret = self.res.delete('/%s/' % url_quote(dbname, safe=":")).json_body return ret
def encode_unreadable_value(self, value): return url_quote(value)
def form_encode(obj, charser="utf8"): tmp = [] for key, value in obj.items(): tmp.append("%s=%s" % (url_quote(key), url_quote(value))) return to_bytestring("&".join(tmp))
def main(): usage = '%prog [options]\n See %prog --help for a full list of options.' parser = optparse.OptionParser(usage=usage) parser.add_option('--source-url', action='store', dest='source_url', help='Url of the source server.') parser.add_option('--target-url', action='store', dest='target_url', help='Url of the target server.') parser.add_option('--source-db', action='store', dest='source_db', help='Source database name.') parser.add_option('--target-db', action='store', dest='target_db', help='Target database name.') parser.add_option('--continuous', action='store_true', dest='continuous', help='Set as a continuous replication.') parser.add_option('--cancel', action='store_true', dest='cancel', help='Cancel continuous replication.') parser.add_option('--create-dbs', action='store_true', dest='create_dbs', help='Create databases if missing.') options, args = parser.parse_args() if not options.target_url or (not options.source_url) or (not options.source_db) or (not options.target_db): parser.error('--source-url, --target-url, --source-db and --target-db are required.') sys.exit(1) start = time.time() if options.source_url.endswith('/'): options.source_url = options.source_url.rstrip('/') if options.target_url.endswith('/'): options.target_url = options.target_url.rstrip('/') if options.create_dbs: source_db = Database(options.source_url + '/' + options.source_db, create=True) target_db = Database(options.target_url + '/' + options.target_db, create=True) else: try: source_db = Database(options.source_url + '/' + options.source_db) except ResourceNotFound: db_missing(options.source_url, options.source_db) try: target_db = Database(options.target_url + '/' + options.target_db) except ResourceNotFound: db_missing(options.target_url, options.target_db) print 'Starting replication...\n', sys.stdout.flush() continuous = options.continuous or False cancel = options.cancel or False body = { "source": url_quote(options.source_url) + '/' + options.source_db, "target": url_quote(options.target_url) + '/' + options.target_db, "continuous": continuous, "cancel": cancel } res = CouchdbResource(uri=url_quote(options.source_url)) try: resp = res.request('POST', '/_replicate', payload=body) print resp.json_body print 'Replication time: %.1f s\n' % (time.time() - start) except ResourceNotFound: print dict(status=404, msg='Replication task not found.') except PreconditionFailed: print dict(status=412, msg='Precondition not met.') except RequestFailed, e: print dict(status=400, msg='Request failed.')
def __delitem__(self, dbname): return self.res.delete('/%s/' % url_quote(dbname, safe=":"))