Extract extract_result

This commit is contained in:
Jonathan Lange
2015-12-30 16:10:21 +00:00
parent 75bfee86a8
commit ba766cb340
6 changed files with 84 additions and 57 deletions

30
testtools/_deferred.py Normal file
View File

@@ -0,0 +1,30 @@
# Copyright (c) testtools developers. See LICENSE for details.
"""Utilities for Deferreds."""
class DeferredNotFired(Exception):
"""Raised when we extract a result from a Deferred that's not fired yet."""
def extract_result(deferred):
"""Extract the result from a fired deferred.
It can happen that you have an API that returns Deferreds for
compatibility with Twisted code, but is in fact synchronous, i.e. the
Deferreds it returns have always fired by the time it returns. In this
case, you can use this function to convert the result back into the usual
form for a synchronous API, i.e. the result itself or a raised exception.
It would be very bad form to use this as some way of checking if a
Deferred has fired.
"""
failures = []
successes = []
deferred.addCallbacks(successes.append, failures.append)
if len(failures) == 1:
failures[0].raiseException()
elif len(successes) == 1:
return successes[0]
else:
raise DeferredNotFired("%r has not fired yet." % (deferred,))

View File

@@ -7,8 +7,6 @@ you couldn't write this yourself, you should not be using it.
"""
__all__ = [
'DeferredNotFired',
'extract_result',
'NoResultError',
'not_reentrant',
'ReentryError',
@@ -54,33 +52,6 @@ def not_reentrant(function, _calls={}):
return mergeFunctionMetadata(function, decorated)
class DeferredNotFired(Exception):
"""Raised when we extract a result from a Deferred that's not fired yet."""
def extract_result(deferred):
"""Extract the result from a fired deferred.
It can happen that you have an API that returns Deferreds for
compatibility with Twisted code, but is in fact synchronous, i.e. the
Deferreds it returns have always fired by the time it returns. In this
case, you can use this function to convert the result back into the usual
form for a synchronous API, i.e. the result itself or a raised exception.
It would be very bad form to use this as some way of checking if a
Deferred has fired.
"""
failures = []
successes = []
deferred.addCallbacks(successes.append, failures.append)
if len(failures) == 1:
failures[0].raiseException()
elif len(successes) == 1:
return successes[0]
else:
raise DeferredNotFired("%r has not fired yet." % (deferred,))
def trap_unhandled_errors(function, *args, **kwargs):
"""Run a function, trapping any unhandled errors in Deferreds.

View File

@@ -31,8 +31,8 @@ import sys
from testtools.compat import StringIO
from testtools.content import text_content
from testtools.runtest import RunTest
from testtools._deferred import extract_result
from testtools._spinner import (
extract_result,
NoResultError,
Spinner,
TimeoutError,

View File

@@ -14,6 +14,7 @@ def test_suite():
test_compat,
test_content,
test_content_type,
test_deferred,
test_deferredmatchers,
test_deferredruntest,
test_distutilscmd,
@@ -35,6 +36,7 @@ def test_suite():
test_compat,
test_content,
test_content_type,
test_deferred,
test_deferredmatchers,
test_deferredruntest,
test_distutilscmd,

View File

@@ -0,0 +1,51 @@
# Copyright (c) testtools developers. See LICENSE for details.
"""Tests for testtools._deferred."""
from extras import try_import
from testtools.matchers import (
Equals,
MatchesException,
Raises,
)
from testtools.tests.test_spinner import NeedsTwistedTestCase
from testtools._deferred import DeferredNotFired, extract_result
defer = try_import('twisted.internet.defer')
Failure = try_import('twisted.python.failure.Failure')
class TestExtractResult(NeedsTwistedTestCase):
def test_not_fired(self):
# _spinner.extract_result raises _spinner.DeferredNotFired if it's
# given a Deferred that has not fired.
self.assertThat(
lambda: extract_result(defer.Deferred()),
Raises(MatchesException(DeferredNotFired)))
def test_success(self):
# _spinner.extract_result returns the value of the Deferred if it has
# fired successfully.
marker = object()
d = defer.succeed(marker)
self.assertThat(extract_result(d), Equals(marker))
def test_failure(self):
# _spinner.extract_result raises the failure's exception if it's given
# a Deferred that is failing.
try:
1/0
except ZeroDivisionError:
f = Failure()
d = defer.fail(f)
self.assertThat(
lambda: extract_result(d),
Raises(MatchesException(ZeroDivisionError)))
def test_suite():
from unittest2 import TestLoader, TestSuite
return TestLoader().loadTestsFromName(__name__)

View File

@@ -63,33 +63,6 @@ class TestNotReentrant(NeedsTwistedTestCase):
self.assertEqual(2, len(calls))
class TestExtractResult(NeedsTwistedTestCase):
def test_not_fired(self):
# _spinner.extract_result raises _spinner.DeferredNotFired if it's
# given a Deferred that has not fired.
self.assertThat(lambda:_spinner.extract_result(defer.Deferred()),
Raises(MatchesException(_spinner.DeferredNotFired)))
def test_success(self):
# _spinner.extract_result returns the value of the Deferred if it has
# fired successfully.
marker = object()
d = defer.succeed(marker)
self.assertThat(_spinner.extract_result(d), Equals(marker))
def test_failure(self):
# _spinner.extract_result raises the failure's exception if it's given
# a Deferred that is failing.
try:
1/0
except ZeroDivisionError:
f = Failure()
d = defer.fail(f)
self.assertThat(lambda:_spinner.extract_result(d),
Raises(MatchesException(ZeroDivisionError)))
class TestTrapUnhandledErrors(NeedsTwistedTestCase):
def test_no_deferreds(self):