Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Make async view classes function as mixins

This will allow better code reuse with N1QL

Change-Id: I05cf01f96a7c8e3981673310f670e97cfcca1675
Reviewed-on: http://review.couchbase.org/47402
Tested-by: Mark Nunberg <mark.nunberg@couchbase.com>
Reviewed-by: Volker Mische <volker.mische@gmail.com>
commit ddbb4b6d1fc61cb8819acaf5d1871d094aa91d10 1 parent 6b2a389
M. Nunberg mnunberg authored mnunberg committed
97 couchbase/async/rowsbase.py
View
@@ -0,0 +1,97 @@
+#
+# Copyright 2015, Couchbase, Inc.
+# All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License")
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+Abstract class for handling async row-based APIs (i.e. N1QL, Views, 2i, etc)
+"""
+
+from couchbase._pyport import PyErr_Restore
+
+
+class AsyncRowsBase(object):
+ # This class relies on having various properties defined in the base
+ # class. Unfortunately, abc doesn't allow the proper inheritance
+ # diagram.
+
+ def __iter__(self):
+ """
+ Unlike our base class, iterating does not make sense here
+ """
+ raise NotImplementedError("Iteration not supported on async view")
+
+ def on_error(self, ex):
+ """
+ Called when there is a failure with the response data
+
+ :param Exception ex: The exception caught.
+
+ This must be implemented in a subclass
+ """
+ raise NotImplementedError("Must be implemented in subclass")
+
+ def on_rows(self, rowiter):
+ """
+ Called when there are more processed views.
+
+ :param iterable rowiter: An iterable which will yield results
+ as defined by the :class:`RowProcessor` implementation
+
+ This method must be implemented in a subclass
+ """
+ raise NotImplementedError("Must be implemented in subclass")
+
+ def on_done(self):
+ """
+ Called when this request has completed. Once this method is called,
+ no other methods will be invoked on this object.
+
+ This method must be implemented in a subclass
+ """
+ raise NotImplementedError("Must be implemented in subclass")
+
+ def _callback(self, mres):
+ """
+ This is invoked as the row callback.
+ If 'rows' is true, then we are a row callback, otherwise
+ the request has ended and it's time to collect the other data
+ """
+ try:
+ rows = self._process_payload(self.raw.rows)
+ if rows:
+ self.on_rows(rows)
+ if self.raw.done:
+ self.on_done()
+ finally:
+ if self.raw.done:
+ self._clear()
+
+ def _errback(self, mres, ex_cls, ex_obj, ex_bt):
+ try:
+ PyErr_Restore(ex_cls, ex_obj, ex_bt)
+ except Exception as e:
+ self.on_error(e)
+ self.on_done()
+ finally:
+ self._clear()
+
+ def _start(self):
+ super(AsyncRowsBase, self)._start()
+ self._mres.callback = self._callback
+ self._mres.errback = self._errback
+
+ def start(self):
+ return self._start()
78 couchbase/async/view.py
View
@@ -18,13 +18,12 @@
"""
This file contains the view implementation for Async
"""
-import sys
from couchbase.views.iterator import View
-from couchbase.exceptions import CouchbaseError, ArgumentError
-from couchbase._pyport import PyErr_Restore
+from couchbase.async.rowsbase import AsyncRowsBase
-class AsyncViewBase(View):
+
+class AsyncViewBase(AsyncRowsBase, View):
def __init__(self, *args, **kwargs):
"""
Initialize a new AsyncViewBase object. This is intended to be
@@ -36,73 +35,4 @@ def __init__(self, *args, **kwargs):
:meth:`~couchbase.connection.Connection.query` method of the
connection object.
"""
- super(AsyncViewBase, self).__init__(*args, **kwargs)
-
- def __iter__(self):
- """
- Unlike our base class, iterating does not make sense here
- """
- raise NotImplementedError("Iteration not supported on async view")
-
- def _start(self):
- super(AsyncViewBase, self)._start()
- self._mres.callback = self._callback
- self._mres.errback = self._errback
-
- def start(self):
- self._start()
-
- def on_error(self, ex):
- """
- Called when there is a failure with the response data
-
- :param Exception ex: The exception caught.
-
- This must be implemented in a subclass
- """
- raise NotImplementedError("Must be implemented in subclass")
-
- def on_rows(self, rowiter):
- """
- Called when there are more processed views.
-
- :param iterable rowiter: An iterable which will yield results
- as defined by the :class:`RowProcessor` implementation
-
- This method must be implemented in a subclass
- """
- raise NotImplementedError("Must be implemented in subclass")
-
- def on_done(self):
- """
- Called when this request has completed. Once this method is called,
- no other methods will be invoked on this object.
-
- This method must be implemented in a subclass
- """
- raise NotImplementedError("Must be implemented in subclass")
-
- def _callback(self, mres):
- """
- This is invoked as the row callback.
- If 'rows' is true, then we are a row callback, otherwise
- the request has ended and it's time to collect the other data
- """
- try:
- rows = self._process_payload(self.raw.rows)
- if rows:
- self.on_rows(rows)
- if self.raw.done:
- self.on_done()
- finally:
- if self.raw.done:
- self._clear()
-
- def _errback(self, mres, ex_cls, ex_obj, ex_bt):
- try:
- PyErr_Restore(ex_cls, ex_obj, ex_bt)
- except Exception as e:
- self.on_error(e)
- self.on_done()
- finally:
- self._clear()
+ View.__init__(self, *args, **kwargs)
11 gcouchbase/bucket.py
View
@@ -10,14 +10,13 @@
from gcouchbase.iops_gevent10 import IOPS
-class GView(AsyncViewBase):
- def __init__(self, *args, **kwargs):
+class GRowsHandler(object):
+ def __init__(self):
"""
Subclass of :class:`~.AsyncViewBase`
This doesn't expose an API different from the normal
synchronous view API. It's just implemented differently
"""
- super(GView, self).__init__(*args, **kwargs)
# We use __double_underscore to mangle names. This is because
# the views class has quite a bit of data attached to it.
@@ -61,6 +60,12 @@ def __iter__(self):
self._do_iter = False
+class GView(GRowsHandler, AsyncViewBase):
+ def __init__(self, *args, **kwargs):
+ AsyncViewBase.__init__(self, *args, **kwargs)
+ GRowsHandler.__init__(self)
+
+
class Bucket(AsyncBucket):
def __init__(self, *args, **kwargs):
"""
14 txcouchbase/bucket.py
View
@@ -28,10 +28,11 @@
from couchbase.exceptions import CouchbaseError
from txcouchbase.iops import v0Iops
-class BatchedView(AsyncViewBase):
+
+class BatchedRowMixin(object):
def __init__(self, *args, **kwargs):
"""
- Iterator/Container object for a single-call view result.
+ Iterator/Container object for a single-call row-based results.
This functions as an iterator over all results of the query, once the
query has been completed.
@@ -41,7 +42,6 @@ def __init__(self, *args, **kwargs):
You will normally not need to construct this object manually.
"""
- super(BatchedView, self).__init__(*args, **kwargs)
self._d = Deferred()
self.__rows = None # likely a superlcass might have this?
@@ -49,7 +49,7 @@ def _getDeferred(self):
return self._d
def start(self):
- super(BatchedView, self).start()
+ super(BatchedRowMixin, self).start()
self.raw.rows_per_call = -1
return self
@@ -84,6 +84,12 @@ def __iter__(self):
return self.__rows
+class BatchedView(BatchedRowMixin, AsyncViewBase):
+ def __init__(self, *args, **kwargs):
+ AsyncViewBase.__init__(self, *args, **kwargs)
+ BatchedRowMixin.__init__(self, *args, **kwargs)
+
+
class TxEventQueue(EventQueue):
"""
Subclass of EventQueue. This implements the relevant firing methods,
Please sign in to comment.
Something went wrong with that request. Please try again.