Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ DOCSDIR := $(PROJDIR)/docs

PYPI_REPOSITORY ?= pypi

all: lint test

.PHONY: lint
lint:
$(PROJDIR)/.runner lint
Expand Down
4 changes: 4 additions & 0 deletions RELNOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Riak Python Client Release Notes

## [`2.8.0` Release](https://github.com/basho/riak-python-client/issues?q=milestone%3Ariak-python-client-2.8.0)

* [Running expensive operations *now raise exceptions*](https://github.com/basho/riak-python-client/pull/518). You can disable these exceptions for development purposes but should not do so in production.

## [`2.7.0` Release](https://github.com/basho/riak-python-client/issues?q=milestone%3Ariak-python-client-2.7.0)
* Riak TS 1.5 support
* Support for `head` parameter
Expand Down
12 changes: 9 additions & 3 deletions riak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
operations, and run Linkwalking operations.
"""

from riak.riak_error import RiakError, ConflictError
from riak.riak_error import RiakError, ConflictError, ListError
from riak.client import RiakClient
from riak.bucket import RiakBucket, BucketType
from riak.table import Table
Expand All @@ -30,11 +30,17 @@

__all__ = ['RiakBucket', 'Table', 'BucketType', 'RiakNode',
'RiakObject', 'RiakClient', 'RiakMapReduce', 'RiakKeyFilter',
'RiakLink', 'RiakError', 'ConflictError',
'ONE', 'ALL', 'QUORUM', 'key_filter']
'RiakLink', 'RiakError', 'ConflictError', 'ListError',
'ONE', 'ALL', 'QUORUM', 'key_filter',
'disable_list_exceptions']

ONE = "one"
ALL = "all"
QUORUM = "quorum"

key_filter = RiakKeyFilter()

"""
Set to true to allow listing operations
"""
disable_list_exceptions = False
23 changes: 21 additions & 2 deletions riak/client/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
# limitations under the License.

import six

import riak.client.multi

from riak import ListError
from riak.client.transport import RiakClientTransport, \
retryable, retryableHttpOnly
retryable, retryableHttpOnly
from riak.client.index_page import IndexPage
from riak.datatypes import TYPES
from riak.table import Table
Expand Down Expand Up @@ -55,7 +55,11 @@ def get_buckets(self, transport, bucket_type=None, timeout=None):
:rtype: list of :class:`RiakBucket <riak.bucket.RiakBucket>`
instances
"""
if not riak.disable_list_exceptions:
raise ListError()

_validate_timeout(timeout)

if bucket_type:
bucketfn = self._bucket_type_bucket_builder
else:
Expand Down Expand Up @@ -100,6 +104,9 @@ def stream_buckets(self, bucket_type=None, timeout=None):
<riak.bucket.RiakBucket>` instances

"""
if not riak.disable_list_exceptions:
raise ListError()

_validate_timeout(timeout)

if bucket_type:
Expand Down Expand Up @@ -467,7 +474,11 @@ def get_keys(self, transport, bucket, timeout=None):
:type timeout: int
:rtype: list
"""
if not riak.disable_list_exceptions:
raise ListError()

_validate_timeout(timeout)

return transport.get_keys(bucket, timeout=timeout)

def stream_keys(self, bucket, timeout=None):
Expand Down Expand Up @@ -503,6 +514,9 @@ def stream_keys(self, bucket, timeout=None):
:type timeout: int
:rtype: iterator
"""
if not riak.disable_list_exceptions:
raise ListError()

_validate_timeout(timeout)

def make_op(transport):
Expand Down Expand Up @@ -678,10 +692,15 @@ def ts_stream_keys(self, table, timeout=None):
:type timeout: int
:rtype: iterator
"""
if not riak.disable_list_exceptions:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ahh, I missed this the first time, I thought it'd be in another file.

raise ListError()

t = table
if isinstance(t, six.string_types):
t = Table(self, table)

_validate_timeout(timeout)

resource = self._acquire()
transport = resource.object
stream = transport.ts_stream_keys(t, timeout)
Expand Down
17 changes: 10 additions & 7 deletions riak/mapreduce.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

from __future__ import print_function
from collections import Iterable, namedtuple
from riak import RiakError
from six import string_types, PY2
from riak.bucket import RiakBucket

import riak


#: Links are just bucket/key/tag tuples, this class provides a
Expand Down Expand Up @@ -128,8 +128,10 @@ def add_bucket(self, bucket, bucket_type=None):
:type bucket_type: string, None
:rtype: :class:`RiakMapReduce`
"""
if not riak.disable_list_exceptions:
raise riak.ListError()
self._input_mode = 'bucket'
if isinstance(bucket, RiakBucket):
if isinstance(bucket, riak.RiakBucket):
if bucket.bucket_type.is_default():
self._inputs = {'bucket': bucket.name}
else:
Expand Down Expand Up @@ -308,14 +310,15 @@ def run(self, timeout=None):

try:
result = self._client.mapred(self._inputs, query, timeout)
except RiakError as e:
except riak.RiakError as e:
if 'worker_startup_failed' in e.value:
for phase in self._phases:
if phase._language == 'erlang':
if type(phase._function) is str:
raise RiakError('May have tried erlang strfun '
'when not allowed\n'
'original error: ' + e.value)
raise riak.RiakError(
'May have tried erlang strfun '
'when not allowed\n'
'original error: ' + e.value)
raise e

# If the last phase is NOT a link phase, then return the result.
Expand Down
11 changes: 11 additions & 0 deletions riak/riak_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,14 @@ class ConflictError(RiakError):
"""
def __init__(self, message='Object in conflict'):
super(ConflictError, self).__init__(message)


class ListError(RiakError):
"""
Raised when a list operation is attempted and
riak.disable_list_exceptions is false.
"""
def __init__(self, message='Bucket and key list operations '
'are expensive and should not be '
'used in production.'):
super(ListError, self).__init__(message)
3 changes: 3 additions & 0 deletions riak/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# -*- coding: utf-8 -*-
import logging
import random
import riak

from riak.client import RiakClient
from riak.tests import HOST, PROTOCOL, PB_PORT, HTTP_PORT, SECURITY_CREDS
Expand Down Expand Up @@ -70,9 +71,11 @@ def create_client(cls, host=None, http_port=None, pb_port=None,
**kwargs)

def setUp(self):
riak.disable_list_exceptions = True
self.bucket_name = self.randname()
self.key_name = self.randname()
self.client = self.create_client()

def tearDown(self):
riak.disable_list_exceptions = False
self.client.close()
34 changes: 32 additions & 2 deletions riak/tests/test_kv.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

from six import string_types, PY2, PY3
from time import sleep
from riak import ConflictError, RiakBucket, RiakError
from riak import ConflictError, RiakError, ListError
from riak import RiakClient, RiakBucket, BucketType
from riak.resolver import default_resolver, last_written_resolver
from riak.tests import RUN_KV, RUN_RESOLVE, PROTOCOL
from riak.tests.base import IntegrationTestBase
Expand Down Expand Up @@ -63,7 +64,6 @@ def tearDownModule():


class NotJsonSerializable(object):

def __init__(self, *args, **kwargs):
self.args = list(args)
self.kwargs = kwargs
Expand All @@ -86,6 +86,36 @@ def __eq__(self, other):
return True


class KVUnitTests(unittest.TestCase):
def test_list_keys_exception(self):
c = RiakClient()
bt = BucketType(c, 'test')
b = RiakBucket(c, 'test', bt)
with self.assertRaises(ListError):
b.get_keys()

def test_stream_buckets_exception(self):
c = RiakClient()
with self.assertRaises(ListError):
bs = []
for bl in c.stream_buckets():
bs.extend(bl)

def test_stream_keys_exception(self):
c = RiakClient()
with self.assertRaises(ListError):
ks = []
for kl in c.stream_keys('test'):
ks.extend(kl)

def test_ts_stream_keys_exception(self):
c = RiakClient()
with self.assertRaises(ListError):
ks = []
for kl in c.ts_stream_keys('test'):
ks.extend(kl)


@unittest.skipUnless(RUN_KV, 'RUN_KV is 0')
class BasicKVTests(IntegrationTestBase, unittest.TestCase, Comparison):
def test_no_returnbody(self):
Expand Down
9 changes: 8 additions & 1 deletion riak/tests/test_mapreduce.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from six import PY2
from riak.mapreduce import RiakMapReduce
from riak import key_filter, RiakError
from riak import key_filter, RiakClient, RiakError, ListError
from riak.tests import RUN_MAPREDUCE, RUN_SECURITY, RUN_YZ
from riak.tests.base import IntegrationTestBase
from riak.tests.test_yokozuna import wait_for_yz_index
Expand All @@ -39,6 +39,13 @@ def tearDownModule():
yzTearDown(testrun_yz_mr)


class MapReduceUnitTests(unittest.TestCase):
def test_mapred_bucket_exception(self):
c = RiakClient()
with self.assertRaises(ListError):
c.add('bucket')


@unittest.skipUnless(RUN_MAPREDUCE, 'RUN_MAPREDUCE is 0')
class LinkTests(IntegrationTestBase, unittest.TestCase):
def test_store_and_get_links(self):
Expand Down
4 changes: 4 additions & 0 deletions riak/tests/yz_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import logging
import riak

from riak import RiakError
from riak.tests import RUN_YZ
Expand All @@ -21,6 +22,7 @@

def yzSetUp(*yzdata):
if RUN_YZ:
riak.disable_list_exceptions = True
c = IntegrationTestBase.create_client()
for yz in yzdata:
logging.debug("yzSetUp: %s", yz)
Expand All @@ -43,6 +45,7 @@ def yzSetUp(*yzdata):

def yzTearDown(c, *yzdata):
if RUN_YZ:
riak.disable_list_exceptions = True
c = IntegrationTestBase.create_client()
for yz in yzdata:
logging.debug("yzTearDown: %s", yz)
Expand All @@ -57,3 +60,4 @@ def yzTearDown(c, *yzdata):
for key in keys:
b.delete(key)
c.close()
riak.disable_list_exceptions = False