Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Python 3 #379

Merged
merged 5 commits into from
Dec 9, 2014
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions THANKS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ The following people have contributed to the Riak Python client:
Andrew Thompson
Andy Gross
Armon Dadgar
Brett Hazen
Brett Hoerner
Brian Roach
Bryan Fink
Expand Down
10 changes: 4 additions & 6 deletions commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ def _create_and_activate_type(self, name, props):
except CalledProcessError as e:
status = e.output

exists = ('not an existing bucket type' not in status)
active = ('is active' in status)
exists = ('not an existing bucket type' not in status.decode('ascii'))
active = ('is active' in status.decode('ascii'))

if exists or active:
log.info("Updating {0} bucket-type with props {1}"
Expand All @@ -146,8 +146,6 @@ def _create_and_activate_type(self, name, props):
json.dumps({'props': props},
separators=(',', ':')))
else:
print name
print props
log.info("Creating {0} bucket-type with props {1}"
.format(repr(name), repr(props)))
self.check_btype_command("create", name,
Expand Down Expand Up @@ -395,7 +393,7 @@ def _update_riak_conf(self):
https_host = self.host + ':' + self.https_port
pb_host = self.host + ':' + self.pb_port
self._backup_file(self.riak_conf)
f = open(self.riak_conf, 'r', False)
f = open(self.riak_conf, 'r', buffering=1)
conf = f.read()
f.close()
conf = re.sub(r'search\s+=\s+off', r'search = on', conf)
Expand Down Expand Up @@ -423,7 +421,7 @@ def _update_riak_conf(self):
r'listener.protobuf.internal = ' + pb_host,
conf)
conf += 'check_crl = off\n'
f = open(self.riak_conf, 'w', False)
f = open(self.riak_conf, 'w', buffering=1)
f.write(conf)
f.close()

Expand Down
8 changes: 4 additions & 4 deletions docs/query.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ process in one payload, so you can also :meth:`stream the results

for keys in bucket.stream_index("bmonth_int", 1):
# keys is a list of matching keys
print keys
print(keys)

Both the regular :meth:`~riak.bucket.RiakBucket.get_index` method and
the :meth:`~riak.bucket.RiakBucket.stream_index` method allow you to
Expand Down Expand Up @@ -369,15 +369,15 @@ Here is a brief example of loading and querying data:::
"scoville_high_i": 350000}).store()
results = bucket.search("name_s:/c.*/", index='jalapeno')
# Yields single document 'chipotle'
print results['docs'][0]['name_s']
print(results['docs'][0]['name_s'])
results = bucket.search("scoville_high_i:[20000 TO 500000]")
# Yields two documents
for result in results['docs']:
print result['name_s']
print(result['name_s'])
results = bucket.search('name_s:*', index='jalapeno',
sort="scoville_low_i desc")
# Yields all documents, sorted in descending order. We take the top one
print "The hottest pepper is {0}".format(results['docs'][0]['name_s'])
print("The hottest pepper is {0}".format(results['docs'][0]['name_s']))

The results returned by :meth:`~riak.bucket.RiakBucket.search` is a dictionary
with lots of search metadata like the number of results, the maxium
Expand Down
10 changes: 5 additions & 5 deletions riak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ def __init__(self, message="Object in conflict"):
super(ConflictError, self).__init__(message)


from client import RiakClient
from bucket import RiakBucket, BucketType
from node import RiakNode
from riak_object import RiakObject
from mapreduce import RiakKeyFilter, RiakMapReduce, RiakLink
from riak.client import RiakClient
from riak.bucket import RiakBucket, BucketType
from riak.node import RiakNode
from riak.riak_object import RiakObject
from riak.mapreduce import RiakKeyFilter, RiakMapReduce, RiakLink

ONE = "one"
ALL = "all"
Expand Down
21 changes: 14 additions & 7 deletions riak/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,17 @@ def next(self):
else:
if self.rehearse:
gc.collect()
print ("-" * 59)
print
print("-" * 59)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For safety, shouldn't the Python 2 version from __future__ import print_function?

print()
print_header()

self.count -= 1
return self

def __next__(self):
# Python 3.x Version
self.next()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably return self.next().


def report(self, name):
"""
Returns a report for the current step of the benchmark.
Expand All @@ -124,22 +128,25 @@ def print_rehearsal_header():
Prints the header for the rehearsal phase of a benchmark.
"""
print
print "Rehearsal -------------------------------------------------"
print("Rehearsal -------------------------------------------------")


def print_report(label, user, system, real):
"""
Prints the report of one step of a benchmark.
"""
print "{:<12s} {:12f} {:12f} ( {:12f} )".format(label, user, system, real)
print("{:<12s} {:12f} {:12f} ( {:12f} )".format(label,
user,
system,
real))


def print_header():
"""
Prints the header for the normal phase of a benchmark.
"""
print "{:<12s} {:<12s} {:<12s} ( {:<12s} )"\
.format('', 'user', 'system', 'real')
print("{:<12s} {:<12s} {:<12s} ( {:<12s} )"
.format('', 'user', 'system', 'real'))


class BenchmarkReport(object):
Expand All @@ -164,5 +171,5 @@ def __exit__(self, exc_type, exc_val, exc_tb):
elif exc_type is KeyboardInterrupt:
return False
else:
print "EXCEPTION! %r" % ((exc_type, exc_val, exc_tb),)
print("EXCEPTION! %r" % ((exc_type, exc_val, exc_tb),))
return True
36 changes: 22 additions & 14 deletions riak/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
specific language governing permissions and limitations
under the License.
"""
from six import string_types, PY2
import mimetypes
from riak.util import lazy_property

Expand Down Expand Up @@ -50,13 +51,14 @@ def __init__(self, client, name, bucket_type):
:param bucket_type: The parent bucket type of this bucket
:type bucket_type: :class:`BucketType`
"""
try:
if isinstance(name, basestring):
name = name.encode('ascii')
else:
raise TypeError('Bucket name must be a string')
except UnicodeError:
raise TypeError('Unicode bucket names are not supported.')
if PY2:
try:
if isinstance(name, string_types):
name = name.encode('ascii')
else:
raise TypeError('Bucket name must be a string')
except UnicodeError:
raise TypeError('Unicode bucket names are not supported.')

if not isinstance(bucket_type, BucketType):
raise TypeError('Parent bucket type must be a BucketType instance')
Expand Down Expand Up @@ -173,11 +175,12 @@ def new(self, key=None, data=None, content_type='application/json',
if self.bucket_type.datatype:
return TYPES[self.bucket_type.datatype](bucket=self, key=key)

try:
if isinstance(data, basestring):
data = data.encode('ascii')
except UnicodeError:
raise TypeError('Unicode data values are not supported.')
if PY2:
try:
if isinstance(data, string_types):
data = data.encode('ascii')
except UnicodeError:
raise TypeError('Unicode data values are not supported.')

obj = RiakObject(self._client, self, key)
obj.content_type = content_type
Expand Down Expand Up @@ -411,7 +414,12 @@ def new_from_file(self, key, filename):
binary_data = bytearray(binary_data)
if not mimetype:
mimetype = 'application/octet-stream'
return self.new(key, encoded_data=binary_data, content_type=mimetype)
if PY2:
return self.new(key, encoded_data=binary_data,
content_type=mimetype)
else:
return self.new(key, encoded_data=bytes(binary_data),
content_type=mimetype)

def search_enabled(self):
"""
Expand Down Expand Up @@ -730,5 +738,5 @@ def __ne__(self, other):
return True


from riak_object import RiakObject
from riak.riak_object import RiakObject
from riak.datatypes import TYPES
69 changes: 55 additions & 14 deletions riak/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,46 @@
from riak.transports.http import RiakHttpPool
from riak.transports.pbc import RiakPbcPool
from riak.security import SecurityCreds
from riak.util import lazy_property
from riak.util import lazy_property, bytes_to_str, str_to_bytes
from six import string_types, PY2


def default_encoder(obj):
"""
Default encoder for JSON datatypes, which returns UTF-8 encoded
json instead of the default bloated \uXXXX escaped ASCII strings.
json instead of the default bloated backslash u XXXX escaped ASCII strings.
"""
return json.dumps(obj, ensure_ascii=False).encode("utf-8")
if type(obj) == bytes:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not isinstance(obj, bytes)?

return json.dumps(bytes_to_str(obj),
ensure_ascii=False).encode("utf-8")
else:
return json.dumps(obj, ensure_ascii=False).encode("utf-8")


def binary_json_encoder(obj):
"""
Default encoder for JSON datatypes, which returns UTF-8 encoded
json instead of the default bloated backslash u XXXX escaped ASCII strings.
"""
if type(obj) == bytes:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here.

return json.dumps(bytes_to_str(obj),
ensure_ascii=False).encode("utf-8")
else:
return json.dumps(obj, ensure_ascii=False).encode("utf-8")


def binary_json_decoder(obj):
"""
Default decoder from JSON datatypes.
"""
return json.loads(bytes_to_str(obj))


def binary_encoder_decoder(obj):
"""
Assumes value is already in binary format, so passes unchanged.
"""
return obj


class RiakClient(RiakMapReduceChain, RiakClientOperations):
Expand Down Expand Up @@ -90,12 +121,22 @@ def __init__(self, protocol='pbc', transport_options={}, nodes=None,
self._http_pool = RiakHttpPool(self, **transport_options)
self._pb_pool = RiakPbcPool(self, **transport_options)

self._encoders = {'application/json': default_encoder,
'text/json': default_encoder,
'text/plain': str}
self._decoders = {'application/json': json.loads,
'text/json': json.loads,
'text/plain': str}
if PY2:
self._encoders = {'application/json': default_encoder,
'text/json': default_encoder,
'text/plain': str}
self._decoders = {'application/json': json.loads,
'text/json': json.loads,
'text/plain': str}
else:
self._encoders = {'application/json': binary_json_encoder,
'text/json': binary_json_encoder,
'text/plain': str_to_bytes,
'binary/octet-stream': binary_encoder_decoder}
self._decoders = {'application/json': binary_json_decoder,
'text/json': binary_json_decoder,
'text/plain': bytes_to_str,
'binary/octet-stream': binary_encoder_decoder}
self._buckets = WeakValueDictionary()
self._bucket_types = WeakValueDictionary()

Expand Down Expand Up @@ -167,7 +208,7 @@ def set_encoder(self, content_type, encoder):
:param content_type: the requested media type
:type content_type: str
:param encoder: an encoding function, takes a single object
argument and returns a string
argument and returns encoded data
:type encoder: function
"""
self._encoders[content_type] = encoder
Expand All @@ -188,7 +229,7 @@ def set_decoder(self, content_type, decoder):

:param content_type: the requested media type
:type content_type: str
:param decoder: a decoding function, takes a string and
:param decoder: a decoding function, takes encoded data and
returns a Python type
:type decoder: function
"""
Expand Down Expand Up @@ -217,10 +258,10 @@ def bucket(self, name, bucket_type='default'):
:rtype: :class:`RiakBucket <riak.bucket.RiakBucket>`

"""
if not isinstance(name, basestring):
if not isinstance(name, string_types):
raise TypeError('Bucket name must be a string')

if isinstance(bucket_type, basestring):
if isinstance(bucket_type, string_types):
bucket_type = self.bucket_type(bucket_type)
elif not isinstance(bucket_type, BucketType):
raise TypeError('bucket_type must be a string '
Expand All @@ -243,7 +284,7 @@ def bucket_type(self, name):
:type name: str
:rtype: :class:`BucketType <riak.bucket.BucketType>`
"""
if not isinstance(name, basestring):
if not isinstance(name, string_types):
raise TypeError('Bucket name must be a string')

if name in self._bucket_types:
Expand Down
18 changes: 11 additions & 7 deletions riak/client/multiget.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
"""

from collections import namedtuple
from Queue import Queue
from threading import Thread, Lock, Event
from multiprocessing import cpu_count
from six import PY2
if PY2:
from Queue import Queue
else:
from queue import Queue

__all__ = ['multiget', 'MultiGetPool']

Expand Down Expand Up @@ -202,15 +206,15 @@ def multiget(client, keys, **options):
from riak import RiakClient
import riak.benchmark as benchmark
client = RiakClient(protocol='pbc')
bkeys = [('default', 'multiget', str(key)) for key in xrange(10000)]
bkeys = [('default', 'multiget', str(key)) for key in range(10000)]

data = open(__file__).read()

print "Benchmarking multiget:"
print " CPUs: {0}".format(cpu_count())
print " Threads: {0}".format(POOL_SIZE)
print " Keys: {0}".format(len(bkeys))
print
print("Benchmarking multiget:")
print(" CPUs: {0}".format(cpu_count()))
print(" Threads: {0}".format(POOL_SIZE))
print(" Keys: {0}".format(len(bkeys)))
print()

with benchmark.measure() as b:
with b.report('populate'):
Expand Down
Loading