From 0dcd641f712bda056405b402a785d39064ffd8c1 Mon Sep 17 00:00:00 2001 From: Jeremy Self Date: Wed, 3 Aug 2011 20:34:33 -0400 Subject: [PATCH 1/4] force unicode keys and bucket names --- riak/bucket.py | 4 ++-- riak/riak_object.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/riak/bucket.py b/riak/bucket.py index cef43271..a65d86d0 100644 --- a/riak/bucket.py +++ b/riak/bucket.py @@ -38,8 +38,8 @@ def __init__(self, client, name): :param name: The bucket name :type name: string """ - if isinstance(name, unicode): - raise TypeError('Unicode bucket names are not supported.') + if not isinstance(name, unicode): + name = unicode(name) self._client = client self._name = name diff --git a/riak/riak_object.py b/riak/riak_object.py index 3d552900..bd21a5e5 100644 --- a/riak/riak_object.py +++ b/riak/riak_object.py @@ -38,8 +38,8 @@ def __init__(self, client, bucket, key=None): is generated by the server when :func:`store` is called. :type key: string """ - if isinstance(key, unicode): - raise TypeError('Unicode keys are not supported.') + if isinstance(key, str): + key = unicode(key) self._client = client self._bucket = bucket From 3110fe956e53bc362d1a0edc241e9a797b6dfe57 Mon Sep 17 00:00:00 2001 From: Jeremy Self Date: Thu, 4 Aug 2011 00:41:50 -0400 Subject: [PATCH 2/4] Add syntactic sugar for dictionary style access --- riak/bucket.py | 6 ++++ riak/client.py | 6 ++++ riak/riak_object.py | 87 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/riak/bucket.py b/riak/bucket.py index a65d86d0..0400311d 100644 --- a/riak/bucket.py +++ b/riak/bucket.py @@ -253,6 +253,12 @@ def get(self, key, r=None): r = self.get_r(r) return obj.reload(r) + def __getitem__(self, key): + """ + Shortcut to get + """ + return self.get(key) + def get_binary(self, key, r=None): """ Retrieve a binary/string object from Riak. diff --git a/riak/client.py b/riak/client.py index 867cd2e4..38972a54 100644 --- a/riak/client.py +++ b/riak/client.py @@ -237,6 +237,12 @@ def bucket(self, name): """ return RiakBucket(self, name) + def __getitem__(self, name): + """ + Shortcut to bucket + """ + return self.bucket(name) + def is_alive(self): """ Check if the Riak server for this ``RiakClient`` instance is alive. diff --git a/riak/riak_object.py b/riak/riak_object.py index bd21a5e5..9690e5b6 100644 --- a/riak/riak_object.py +++ b/riak/riak_object.py @@ -21,6 +21,18 @@ from metadata import * from riak import RiakError +def check_dict(f): + def newf(cls, *args, **kwargs): + ctype = cls._metadata.get(MD_CTYPE, None) + if cls._is_multi: + raise RiakError("Multiple objects return, check siblings") + if ctype and ctype != 'application/json': + raise RiakError("Invalid content type for dictionary access") + elif ctype is None: + cls.set_data({}) + return f(cls, *args, **kwargs) + return newf + class RiakObject(object): """ The RiakObject holds meta information about a Riak object, plus the @@ -51,6 +63,13 @@ def __init__(self, client, bucket, key=None): self._links = [] self._siblings = [] self._exists = False + self._is_multi = False + + def is_multi(self): + """ + Returns if this was a multi return with multiple vector clocks + """ + return self._is_multi def get_bucket(self): """ @@ -81,6 +100,73 @@ def get_data(self): """ return self._data + @check_dict + def __getitem__(self, key): + """ + Returns the key of a json dictionary if this type is json + """ + return self.get_data()[key] + + @check_dict + def __setitem__(self, key, value): + """ + Convenience function used to update dictionary if this is of type json + """ + if not self._data: + self.set_data({key:value}) + else: + self._data[key] = value + + @check_dict + def __delitem__(self, key): + """ + Convenience function to delete key of internal dict + """ + if self._data and isinstance(self._data, dict): + del self._data[key] + + @check_dict + def __iter__(self): + """ + Iterates keys as dict + """ + if self._data and isinstance(self._data, dict): + return self._data.__iter__() + return iter({}) + + def iterkeys(self): + """ + Iterates keys + """ + return self.__iter__() + + @check_dict + def iteritems(self): + """ + Returns self._data.iteritems() + """ + if self._data and isinstance(self._data, dict): + return self._data.iteritems() + return {}.iteritems() + + @check_dict + def keys(self): + """ + Returns self._data.keys + """ + if self._data and isinstance(self._data, dict): + return self._data.keys() + return [] + + @check_dict + def values(self): + """ + Returns self._data.values + """ + if self._data and isinstance(self._data, dict): + return self._data.values() + return [] + def set_data(self, data): """ Set the data stored in this object. This data will be @@ -374,6 +460,7 @@ def populate(self, Result) : if Result is None: return self elif type(Result) == types.ListType: + self._is_multi = True self.set_siblings(Result) elif type(Result) == types.TupleType: (vclock, contents) = Result From 9e00326cd342d05d42007101a529f2efd8ffc9cc Mon Sep 17 00:00:00 2001 From: Jeremy Self Date: Thu, 4 Aug 2011 00:44:06 -0400 Subject: [PATCH 3/4] add convenience function on bucket for search --- riak/bucket.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/riak/bucket.py b/riak/bucket.py index 0400311d..524674e5 100644 --- a/riak/bucket.py +++ b/riak/bucket.py @@ -429,6 +429,12 @@ def new_binary_from_file(self, key, filename): mimetype = 'application/octet-stream' return self.new_binary(key, binary_data, mimetype) + def search(self, *args): + """ + Convenience function to search bucket + """ + return self._client.search(self._name, *args) + def search_enabled(self): """ Returns True if the search precommit hook is enabled for this bucket. From e49ebdae1761ac9743e150b63cc323b65555cf9d Mon Sep 17 00:00:00 2001 From: Jeremy Self Date: Thu, 4 Aug 2011 02:46:38 -0400 Subject: [PATCH 4/4] protect url when pycurl is expecting string from being unicode --- riak/transports/http.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riak/transports/http.py b/riak/transports/http.py index c719b8d1..6e8972bf 100644 --- a/riak/transports/http.py +++ b/riak/transports/http.py @@ -411,9 +411,9 @@ def http_request(cls, method, host, port, url, headers = None, obj = '') : if not headers: headers = {} if HAS_PYCURL: - return cls.pycurl_request(method, host, port, url, headers, obj) + return cls.pycurl_request(method, host, port, str(url), headers, obj) else: - return cls.httplib_request(method, host, port, url, headers, obj) + return cls.httplib_request(method, host, port, str(url), headers, obj) @classmethod