Пример #1
0
    def test_deferredFromCoroutine(self):
        """
        L{Deferred.fromCoroutine} will turn a coroutine into a L{Deferred}.
        """
        async def run():
            d = succeed("bar")
            await d
            res = await run2()
            return res

        async def run2():
            d = succeed("foo")
            res = await d
            return res

        # It's a coroutine...
        r = run()
        self.assertIsInstance(r, types.CoroutineType)

        # Now it's a Deferred.
        d = Deferred.fromCoroutine(r)
        self.assertIsInstance(d, Deferred)

        # The Deferred has the result we want.
        res = self.successResultOf(d)
        self.assertEqual(res, "foo")
Пример #2
0
    def test_DeferredfromCoroutine(self):
        """
        L{Deferred.fromCoroutine} will turn a coroutine into a L{Deferred}.
        """

        def run():
            d = succeed("bar")
            yield from d
            res = yield from run2()
            return res

        def run2():
            d = succeed("foo")
            res = yield from d
            return res

        # It's a generator...
        r = run()
        self.assertIsInstance(r, types.GeneratorType)

        # Now it's a Deferred.
        d = Deferred.fromCoroutine(r)
        self.assertIsInstance(d, Deferred)

        # The Deferred has the result we want.
        res = self.successResultOf(d)
        self.assertEqual(res, "foo")
Пример #3
0
    def test_basic(self):
        """
        L{Deferred.fromCoroutine} allows a function to C{await} on a
        L{Deferred}.
        """
        async def run():
            d = succeed("foo")
            res = await d
            return res

        d = Deferred.fromCoroutine(run())
        res = self.successResultOf(d)
        self.assertEqual(res, "foo")
Пример #4
0
    def test_exception(self):
        """
        An exception in a coroutine scheduled with L{Deferred.fromCoroutine}
        will cause the returned L{Deferred} to fire with a failure.
        """
        async def run():
            d = succeed("foo")
            await d
            raise ValueError("Oh no!")

        d = Deferred.fromCoroutine(run())
        res = self.failureResultOf(d)
        self.assertEqual(type(res.value), ValueError)
        self.assertEqual(res.value.args, ("Oh no!", ))
Пример #5
0
    def test_reraise(self):
        """
        Awaiting an already failed Deferred will raise the exception.
        """
        async def test():
            try:
                await fail(ValueError("Boom"))
            except ValueError as e:
                self.assertEqual(e.args, ("Boom", ))
                return 1
            return 0

        res = self.successResultOf(Deferred.fromCoroutine(test()))
        self.assertEqual(res, 1)
Пример #6
0
    def test_synchronousDeferredFailureTraceback(self):
        """
        When a Deferred is awaited upon that has already failed with a Failure
        that has a traceback, both the place that the synchronous traceback
        comes from and the awaiting line are shown in the traceback.
        """
        def raises():
            raise SampleException()

        it = maybeDeferred(raises)

        async def doomed():
            return await it

        failure = self.failureResultOf(Deferred.fromCoroutine(doomed()))

        self.assertIn(", in doomed\n", failure.getTraceback())
        self.assertIn(", in raises\n", failure.getTraceback())
Пример #7
0
    def test_twoDeep(self):
        """
        A coroutine scheduled with L{Deferred.fromCoroutine} that awaits a
        L{Deferred} suspends its execution until the inner L{Deferred} fires.
        """
        reactor = Clock()
        sections = []

        async def runone():
            sections.append(2)
            d = Deferred()
            reactor.callLater(1, d.callback, 2)
            await d
            sections.append(3)
            return "Yay!"

        async def run():
            sections.append(1)
            result = await runone()
            sections.append(4)
            d = Deferred()
            reactor.callLater(1, d.callback, 1)
            await d
            sections.append(5)
            return result

        d = Deferred.fromCoroutine(run())

        reactor.advance(0.9)
        self.assertEqual(sections, [1, 2])

        reactor.advance(0.1)
        self.assertEqual(sections, [1, 2, 3, 4])

        reactor.advance(0.9)
        self.assertEqual(sections, [1, 2, 3, 4])

        reactor.advance(0.1)
        self.assertEqual(sections, [1, 2, 3, 4, 5])

        res = self.successResultOf(d)
        self.assertEqual(res, "Yay!")
Пример #8
0
    def test_twoDeep(self):
        """
        An exception in a generator scheduled with L{Deferred.fromCoroutine}
        will cause the returned L{Deferred} to fire with a failure.
        """
        reactor = Clock()
        sections = []

        def runone():
            sections.append(2)
            d = Deferred()
            reactor.callLater(1, d.callback, None)
            yield from d
            sections.append(3)
            return "Yay!"

        def run():
            sections.append(1)
            result = yield from runone()
            sections.append(4)
            d = Deferred()
            reactor.callLater(1, d.callback, None)
            yield from d
            sections.append(5)
            return result

        d = Deferred.fromCoroutine(run())

        reactor.advance(0.9)
        self.assertEqual(sections, [1, 2])

        reactor.advance(0.1)
        self.assertEqual(sections, [1, 2, 3, 4])

        reactor.advance(0.9)
        self.assertEqual(sections, [1, 2, 3, 4])

        reactor.advance(0.1)
        self.assertEqual(sections, [1, 2, 3, 4, 5])

        res = self.successResultOf(d)
        self.assertEqual(res, "Yay!")
Пример #9
0
    def test_chained(self):
        """
        Awaiting a paused & chained Deferred will give the result when it has
        one.
        """
        reactor = Clock()

        async def test():
            d = Deferred()
            d2 = Deferred()
            d.addCallback(lambda ignored: d2)

            d.callback(None)
            reactor.callLater(0, d2.callback, "bye")
            return await d

        d = Deferred.fromCoroutine(test())
        reactor.advance(0.1)

        res = self.successResultOf(d)
        self.assertEqual(res, "bye")
Пример #10
0
    def test_asyncDeferredFailureTraceback(self):
        """
        When a Deferred is awaited upon that later fails with a Failure that
        has a traceback, both the place that the synchronous traceback comes
        from and the awaiting line are shown in the traceback.
        """
        def returnsFailure():
            try:
                raise SampleException()
            except SampleException:
                return Failure()

        it = Deferred()

        async def doomed():
            return await it

        started = Deferred.fromCoroutine(doomed())
        self.assertNoResult(started)
        it.errback(returnsFailure())
        failure = self.failureResultOf(started)
        self.assertIn(", in doomed\n", failure.getTraceback())
        self.assertIn(", in returnsFailure\n", failure.getTraceback())
Пример #11
0
def _flattenElement(request, root, write, slotData, renderFactory,
                    dataEscaper):
    """
    Make C{root} slightly more flat by yielding all its immediate contents as
    strings, deferreds or generators that are recursive calls to itself.

    @param request: A request object which will be passed to
        L{IRenderable.render}.

    @param root: An object to be made flatter.  This may be of type C{unicode},
        L{str}, L{slot}, L{Tag <twisted.web.template.Tag>}, L{tuple}, L{list},
        L{types.GeneratorType}, L{Deferred}, or an object that implements
        L{IRenderable}.

    @param write: A callable which will be invoked with each L{bytes} produced
        by flattening C{root}.

    @param slotData: A L{list} of L{dict} mapping L{str} slot names to data
        with which those slots will be replaced.

    @param renderFactory: If not L{None}, an object that provides
        L{IRenderable}.

    @param dataEscaper: A 1-argument callable which takes L{bytes} or
        L{unicode} and returns L{bytes}, quoted as appropriate for the
        rendering context.  This is really only one of two values:
        L{attributeEscapingDoneOutside} or L{escapeForContent}, depending on
        whether the rendering context is within an attribute or not.  See the
        explanation in L{writeWithAttributeEscaping}.

    @return: An iterator that eventually yields L{bytes} that should be written
        to the output.  However it may also yield other iterators or
        L{Deferred}s; if it yields another iterator, the caller will iterate
        it; if it yields a L{Deferred}, the result of that L{Deferred} will
        either be L{bytes}, in which case it's written, or another generator,
        in which case it is iterated.  See L{_flattenTree} for the trampoline
        that consumes said values.
    @rtype: An iterator which yields L{bytes}, L{Deferred}, and more iterators
        of the same type.
    """
    def keepGoing(newRoot,
                  dataEscaper=dataEscaper,
                  renderFactory=renderFactory,
                  write=write):
        return _flattenElement(request, newRoot, write, slotData,
                               renderFactory, dataEscaper)

    def keepGoingAsync(result):
        return result.addCallback(keepGoing)

    if isinstance(root, (bytes, str)):
        write(dataEscaper(root))
    elif isinstance(root, slot):
        slotValue = _getSlotValue(root.name, slotData, root.default)
        yield keepGoing(slotValue)
    elif isinstance(root, CDATA):
        write(b"<![CDATA[")
        write(escapedCDATA(root.data))
        write(b"]]>")
    elif isinstance(root, Comment):
        write(b"<!--")
        write(escapedComment(root.data))
        write(b"-->")
    elif isinstance(root, Tag):
        slotData.append(root.slotData)
        if root.render is not None:
            rendererName = root.render
            rootClone = root.clone(False)
            rootClone.render = None
            renderMethod = renderFactory.lookupRenderMethod(rendererName)
            result = renderMethod(request, rootClone)
            yield keepGoing(result)
            slotData.pop()
            return

        if not root.tagName:
            yield keepGoing(root.children)
            return

        write(b"<")
        if isinstance(root.tagName, str):
            tagName = root.tagName.encode("ascii")
        else:
            tagName = root.tagName
        write(tagName)
        for k, v in root.attributes.items():
            if isinstance(k, str):
                k = k.encode("ascii")
            write(b" " + k + b'="')
            # Serialize the contents of the attribute, wrapping the results of
            # that serialization so that _everything_ is quoted.
            yield keepGoing(v,
                            attributeEscapingDoneOutside,
                            write=writeWithAttributeEscaping(write))
            write(b'"')
        if root.children or nativeString(tagName) not in voidElements:
            write(b">")
            # Regardless of whether we're in an attribute or not, switch back
            # to the escapeForContent dataEscaper.  The contents of a tag must
            # be quoted no matter what; in the top-level document, just so
            # they're valid, and if they're within an attribute, they have to
            # be quoted so that after applying the *un*-quoting required to re-
            # parse the tag within the attribute, all the quoting is still
            # correct.
            yield keepGoing(root.children, escapeForContent)
            write(b"</" + tagName + b">")
        else:
            write(b" />")

    elif isinstance(root, (tuple, list, GeneratorType)):
        for element in root:
            yield keepGoing(element)
    elif isinstance(root, CharRef):
        escaped = "&#%d;" % (root.ordinal, )
        write(escaped.encode("ascii"))
    elif isinstance(root, Deferred):
        yield keepGoingAsync(_fork(root))
    elif iscoroutine(root):
        yield keepGoingAsync(Deferred.fromCoroutine(root))
    elif IRenderable.providedBy(root):
        result = root.render(request)
        yield keepGoing(result, renderFactory=root)
    else:
        raise UnsupportedType(root)