123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- # -*- test-case-name: twisted.internet.test.test_inlinecb -*-
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- Tests for L{twisted.internet.defer.inlineCallbacks}.
- Some tests for inlineCallbacks are defined in L{twisted.test.test_defgen} as
- well.
- """
- from __future__ import division, absolute_import
- import sys
- from twisted.trial.unittest import TestCase
- from twisted.internet.defer import Deferred, returnValue, inlineCallbacks
- class StopIterationReturnTests(TestCase):
- """
- On Python 3.3 and newer generator functions may use the C{return} statement
- with a value, which is attached to the L{StopIteration} exception that is
- raised.
- L{inlineCallbacks} will use this value when it fires the C{callback}.
- """
- def test_returnWithValue(self):
- """
- If the C{return} statement has a value it is propagated back to the
- L{Deferred} that the C{inlineCallbacks} function returned.
- """
- environ = {"inlineCallbacks": inlineCallbacks}
- exec("""
- @inlineCallbacks
- def f(d):
- yield d
- return 14
- """, environ)
- d1 = Deferred()
- d2 = environ["f"](d1)
- d1.callback(None)
- self.assertEqual(self.successResultOf(d2), 14)
- if sys.version_info < (3, 3):
- StopIterationReturnTests.skip = "Test requires Python 3.3 or greater"
- class NonLocalExitTests(TestCase):
- """
- It's possible for L{returnValue} to be (accidentally) invoked at a stack
- level below the L{inlineCallbacks}-decorated function which it is exiting.
- If this happens, L{returnValue} should report useful errors.
- If L{returnValue} is invoked from a function not decorated by
- L{inlineCallbacks}, it will emit a warning if it causes an
- L{inlineCallbacks} function further up the stack to exit.
- """
- def mistakenMethod(self):
- """
- This method mistakenly invokes L{returnValue}, despite the fact that it
- is not decorated with L{inlineCallbacks}.
- """
- returnValue(1)
- def assertMistakenMethodWarning(self, resultList):
- """
- Flush the current warnings and assert that we have been told that
- C{mistakenMethod} was invoked, and that the result from the Deferred
- that was fired (appended to the given list) is C{mistakenMethod}'s
- result. The warning should indicate that an inlineCallbacks function
- called 'inline' was made to exit.
- """
- self.assertEqual(resultList, [1])
- warnings = self.flushWarnings(offendingFunctions=[self.mistakenMethod])
- self.assertEqual(len(warnings), 1)
- self.assertEqual(warnings[0]['category'], DeprecationWarning)
- self.assertEqual(
- warnings[0]['message'],
- "returnValue() in 'mistakenMethod' causing 'inline' to exit: "
- "returnValue should only be invoked by functions decorated with "
- "inlineCallbacks")
- def test_returnValueNonLocalWarning(self):
- """
- L{returnValue} will emit a non-local exit warning in the simplest case,
- where the offending function is invoked immediately.
- """
- @inlineCallbacks
- def inline():
- self.mistakenMethod()
- returnValue(2)
- yield 0
- d = inline()
- results = []
- d.addCallback(results.append)
- self.assertMistakenMethodWarning(results)
- def test_returnValueNonLocalDeferred(self):
- """
- L{returnValue} will emit a non-local warning in the case where the
- L{inlineCallbacks}-decorated function has already yielded a Deferred
- and therefore moved its generator function along.
- """
- cause = Deferred()
- @inlineCallbacks
- def inline():
- yield cause
- self.mistakenMethod()
- returnValue(2)
- effect = inline()
- results = []
- effect.addCallback(results.append)
- self.assertEqual(results, [])
- cause.callback(1)
- self.assertMistakenMethodWarning(results)
|