From ba766cb34068a3db25abe87328f33f73a30b987a Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Wed, 30 Dec 2015 16:10:21 +0000 Subject: [PATCH] Extract `extract_result` --- testtools/_deferred.py | 30 +++++++++++++++++++ testtools/_spinner.py | 29 ------------------ testtools/deferredruntest.py | 2 +- testtools/tests/__init__.py | 2 ++ testtools/tests/test_deferred.py | 51 ++++++++++++++++++++++++++++++++ testtools/tests/test_spinner.py | 27 ----------------- 6 files changed, 84 insertions(+), 57 deletions(-) create mode 100644 testtools/_deferred.py create mode 100644 testtools/tests/test_deferred.py diff --git a/testtools/_deferred.py b/testtools/_deferred.py new file mode 100644 index 0000000..1bd508c --- /dev/null +++ b/testtools/_deferred.py @@ -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,)) diff --git a/testtools/_spinner.py b/testtools/_spinner.py index baf455a..9c58055 100644 --- a/testtools/_spinner.py +++ b/testtools/_spinner.py @@ -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. diff --git a/testtools/deferredruntest.py b/testtools/deferredruntest.py index 721bafe..13239fb 100644 --- a/testtools/deferredruntest.py +++ b/testtools/deferredruntest.py @@ -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, diff --git a/testtools/tests/__init__.py b/testtools/tests/__init__.py index 6314bf9..355b6af 100644 --- a/testtools/tests/__init__.py +++ b/testtools/tests/__init__.py @@ -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, diff --git a/testtools/tests/test_deferred.py b/testtools/tests/test_deferred.py new file mode 100644 index 0000000..4fe72eb --- /dev/null +++ b/testtools/tests/test_deferred.py @@ -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__) diff --git a/testtools/tests/test_spinner.py b/testtools/tests/test_spinner.py index 31110ca..5052031 100644 --- a/testtools/tests/test_spinner.py +++ b/testtools/tests/test_spinner.py @@ -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):