Check-in [9de48dcace]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added the methods callback, errback and chainDeferred. And it's a twisted standard I should follow.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:9de48dcace8680195e7c61a728baa89a6da4f1d5
User & Date: yusuke 2010-10-25 18:41:58
Context
2010-10-25
20:26
Incompatible change by my misunderstanding. It fixed by twisted deferred design. Then it released as 0.1. check-in: b69ee71d75 user: yusuke tags: trunk
18:41
Added the methods callback, errback and chainDeferred. And it's a twisted standard I should follow. check-in: 9de48dcace user: yusuke tags: trunk
2010-10-24
03:12
rename a file check-in: 4a7afc2e29 user: yusuke tags: trunk, 0.1dev
Changes

Changes to README.txt.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    Setup test environment. (These steps are meanless for actual use, just for doctest)
    >>> import sys
    >>> sys.path.insert(0, '.')
    >>> from tests.test_deferred import value, increase, must_be
    >>> from tests.conftest import mimic_defer
    >>> deferred.defer = mimic_defer

    >>> d = Deferred(value, 5)
    >>> d.addCallback(increase, 10)

    An alias exists for addCallback
    >>> d.next(must_be, 15)

    The deferred to be executed on an asynchronous task.
    >>> deferred.defer(d)

How to test
-----------

Like this.:: bash

  $ py.test --appengine=${your appengine path} --doctest-glob='*.rst'







|






|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    Setup test environment. (These steps are meanless for actual use, just for doctest)
    >>> import sys
    >>> sys.path.insert(0, '.')
    >>> from tests.test_deferred import value, increase, must_be
    >>> from tests.conftest import mimic_defer
    >>> deferred.defer = mimic_defer

    >>> d = Deferred()
    >>> d.addCallback(increase, 10)

    An alias exists for addCallback
    >>> d.next(must_be, 15)

    The deferred to be executed on an asynchronous task.
    >>> deferred.defer(d.callback, 5)

How to test
-----------

Like this.:: bash

  $ py.test --appengine=${your appengine path} --doctest-glob='*.rst'

Changes to gaedeferred/__init__.py.

49
50
51
52
53
54
55
56


57


58
59
60
61
62
63
64
..
74
75
76
77
78
79
80

81












82
83
84
85
86
87
88
89

90


91
92
93
94
95
96
97
    if func == deferred.invoke_member:
        args = args[0:2] + (result,) + args[2:]
    else:
        args = (result,) + args
    return func(*args, **kwargs)

class Deferred(object):
    def __init__(self, obj, *args, **kwargs):


        self.startup = deferred.serialize(obj, *args, **kwargs)


        self.callback_pairs = []

    def _callback_chain(self):
        while self.callback_pairs:
            callback, errback = self.callback_pairs.pop(0)
            if self._in_callback:
                if callback:
................................................................................
            self._in_callback = True
        except deferred.PermanentTaskFailure:
            raise
        except Exception:
            result = Failure(*exc_info()[:2])
            logging.debug("An exception occurs in the startup execution.", exc_info=True)
            self._in_callback = False














        for callback in self._callback_chain():
            try:
                result = run_with_result(callback, result)
                logging.debug("The result of a callback is %s", result)
                self._in_callback = True
                if isinstance(result, Deferred):
                    result.callback_pairs.extend(self.callback_pairs)
                    # assign the result deferred to new task.

                    deferred.defer(result)


            except deferred.PermanentTaskFailure:
                raise
            except Exception:
                result = Failure(*exc_info()[:2])
                logging.debug("An exception occurs in callback.", exc_info=True)
                self._in_callback = False








|
>
>
|
>
>







 







>

>
>
>
>
>
>
>
>
>
>
>
>







|
>
|
>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    if func == deferred.invoke_member:
        args = args[0:2] + (result,) + args[2:]
    else:
        args = (result,) + args
    return func(*args, **kwargs)

class Deferred(object):
    def __init__(self, *args, **kwargs):
        if args:
            obj, args = args[0], args[1:]
            self.startup = deferred.serialize(obj, *args, **kwargs)
        else:
            self.startup = None
        self.callback_pairs = []

    def _callback_chain(self):
        while self.callback_pairs:
            callback, errback = self.callback_pairs.pop(0)
            if self._in_callback:
                if callback:
................................................................................
            self._in_callback = True
        except deferred.PermanentTaskFailure:
            raise
        except Exception:
            result = Failure(*exc_info()[:2])
            logging.debug("An exception occurs in the startup execution.", exc_info=True)
            self._in_callback = False
        self._callback(result)

    def callback(self, result):
        self._in_callback = True
        self._callback(result)

    def errback(self, failure):
        self._in_callback = False
        self._callback(failure)

    def chainDeferred(self, d):
        self.addCallbacks(callback=d.callback, errback=d.errback)

    def _callback(self, result):
        for callback in self._callback_chain():
            try:
                result = run_with_result(callback, result)
                logging.debug("The result of a callback is %s", result)
                self._in_callback = True
                if isinstance(result, Deferred):
                    result.callback_pairs.extend(self.callback_pairs)
                    # assign new task the result deferred.
                    if result.startup:
                        deferred.defer(result)
                    else:
                        deferred.defer(result.callback, None)
            except deferred.PermanentTaskFailure:
                raise
            except Exception:
                result = Failure(*exc_info()[:2])
                logging.debug("An exception occurs in callback.", exc_info=True)
                self._in_callback = False

Changes to setup.py.

20
21
22
23
24
25
26
27
28
29
30
31
      license='MIT License',
      packages=find_packages(exclude=['tests']),
      include_package_data=True,
      zip_safe=True,
      install_requires=[
          # -*- Extra requirements: -*-
      ],
      test_requires=['py'],
      entry_points="""
      # -*- Entry points: -*-
      """,
      )







|




20
21
22
23
24
25
26
27
28
29
30
31
      license='MIT License',
      packages=find_packages(exclude=['tests']),
      include_package_data=True,
      zip_safe=True,
      install_requires=[
          # -*- Extra requirements: -*-
      ],
      tests_require=['py'],
      entry_points="""
      # -*- Entry points: -*-
      """,
      )

Changes to tests/test_deferred.py.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
55
56
57
58
59
60
61








62
63
64
65


66
67
68
69
70










LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

from gaedeferred import Deferred, Failure

def value(value=0):
    return value

def increase(result, value=1):
    return result + value

def raise_(result):
    raise Exception("This exception occured from raise_.")

................................................................................
    d.next(must_be, 10)
    d.next(raise_)
    d.addErrback(must_be_failure)
    d.next(raise_)
    d.error(must_be_failure) # test for the alias
    context.defer(d)









def test_chain(context):
    d1 = Deferred(value, 0)
    d2 = Deferred(value, 10)
    d1.next(increase, 5)


    d1.next(value, d2)
    d2.next(increase, 3)
    d2.next(must_be, 13)
    d1.next(must_be, 13)
    context.defer(d1)

















|
|







 







>
>
>
>
>
>
>
>

|
|

>
>




|
>
>
>
>
>
>
>
>
>
>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

from gaedeferred import Deferred, Failure

def value(result):
    return result

def increase(result, value=1):
    return result + value

def raise_(result):
    raise Exception("This exception occured from raise_.")

................................................................................
    d.next(must_be, 10)
    d.next(raise_)
    d.addErrback(must_be_failure)
    d.next(raise_)
    d.error(must_be_failure) # test for the alias
    context.defer(d)

    d = Deferred()
    d.next(must_be, 5)
    context.defer(d.callback, 5)

    d = Deferred()
    d.error(must_be, 10)
    context.defer(d.errback, 10)

def test_chain(context):
    d1 = Deferred()
    d2 = Deferred()
    d1.next(increase, 5)
    # you don't need to assing ext.defer deferred
    # a deferred treats it's next callback when you return a deferred in callback.
    d1.next(value, d2)
    d2.next(increase, 3)
    d2.next(must_be, 13)
    d1.next(must_be, 13)
    context.defer(d1.callback, 5)

    d1 = Deferred()
    d2 = Deferred()
    d1.chainDeferred(d2)
    d1.next(increase, 5)
    d2.next(increase, 3)
    d2.next(must_be, 13)
    d1.next(must_be, 13)
    context.defer(d1.callback, 5)