from __future__ import absolute_import, division, print_function
+import asyncio
+from concurrent import futures
import gc
-import contextlib
import datetime
-import functools
import platform
import sys
import textwrap
import time
import weakref
-import warnings
from tornado.concurrent import Future
-from tornado.escape import url_escape
-from tornado.httpclient import AsyncHTTPClient
from tornado.ioloop import IOLoop
from tornado.log import app_log
-from tornado import stack_context
from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test
-from tornado.test.util import unittest, skipOnTravis, skipBefore33, skipBefore35, skipNotCPython, exec_test, ignore_deprecation # noqa: E501
-from tornado.web import Application, RequestHandler, asynchronous, HTTPError
+from tornado.test.util import unittest, skipOnTravis, skipBefore33, skipBefore35, skipNotCPython, exec_test
+from tornado.web import Application, RequestHandler, HTTPError
from tornado import gen
-try:
- from concurrent import futures
-except ImportError:
- futures = None
-
-try:
- import asyncio
-except ImportError:
- asyncio = None
-
class GenBasicTest(AsyncTestCase):
@gen.coroutine
from tornado.util import ObjectDict, unicode_type, PY3
from tornado.web import (
Application, RequestHandler, StaticFileHandler, RedirectHandler as WebRedirectHandler,
- HTTPError, MissingArgumentError, ErrorHandler, authenticated, asynchronous, url,
+ HTTPError, MissingArgumentError, ErrorHandler, authenticated, url,
_create_signature_v1, create_signed_value, decode_signed_value, get_signature_key_version,
UIModule, Finish, stream_request_body, removeslash, addslash, GZipContentEncoding,
)
'log_message': 'Missing argument foo'})
-class MultipleExceptionTest(SimpleHandlerTestCase):
- class Handler(RequestHandler):
- exc_count = 0
-
- with ignore_deprecation():
- @asynchronous
- def get(self):
- IOLoop.current().add_callback(lambda: 1 / 0)
- IOLoop.current().add_callback(lambda: 1 / 0)
-
- def log_exception(self, typ, value, tb):
- MultipleExceptionTest.Handler.exc_count += 1
-
- def test_multi_exception(self):
- with ignore_deprecation():
- # This test verifies that multiple exceptions raised into the same
- # ExceptionStackContext do not generate extraneous log entries
- # due to "Cannot send error response after headers written".
- # log_exception is called, but it does not proceed to send_error.
- response = self.fetch('/')
- self.assertEqual(response.code, 500)
- response = self.fetch('/')
- self.assertEqual(response.code, 500)
- # Each of our two requests generated two exceptions, we should have
- # seen at least three of them by now (the fourth may still be
- # in the queue).
- self.assertGreater(MultipleExceptionTest.Handler.exc_count, 2)
-
-
@wsgi_safe
class SetLazyPropertiesTest(SimpleHandlerTestCase):
class Handler(RequestHandler):
self.clear_header(h)
-def asynchronous(method):
- """Wrap request handler methods with this if they are asynchronous.
-
- This decorator is for callback-style asynchronous methods; for
- coroutines, use the ``@gen.coroutine`` decorator without
- ``@asynchronous``. (It is legal for legacy reasons to use the two
- decorators together provided ``@asynchronous`` is first, but
- ``@asynchronous`` will be ignored in this case)
-
- This decorator should only be applied to the :ref:`HTTP verb
- methods <verbs>`; its behavior is undefined for any other method.
- This decorator does not *make* a method asynchronous; it tells
- the framework that the method *is* asynchronous. For this decorator
- to be useful the method must (at least sometimes) do something
- asynchronous.
-
- If this decorator is given, the response is not finished when the
- method returns. It is up to the request handler to call
- `self.finish() <RequestHandler.finish>` to finish the HTTP
- request. Without this decorator, the request is automatically
- finished when the ``get()`` or ``post()`` method returns. Example:
-
- .. testcode::
-
- class MyRequestHandler(RequestHandler):
- @asynchronous
- def get(self):
- http = httpclient.AsyncHTTPClient()
- http.fetch("http://friendfeed.com/", self._on_download)
-
- def _on_download(self, response):
- self.write("Downloaded!")
- self.finish()
-
- .. testoutput::
- :hide:
-
- .. versionchanged:: 3.1
- The ability to use ``@gen.coroutine`` without ``@asynchronous``.
-
- .. versionchanged:: 4.3 Returning anything but ``None`` or a
- yieldable object from a method decorated with ``@asynchronous``
- is an error. Such return values were previously ignored silently.
-
- .. deprecated:: 5.1
-
- This decorator is deprecated and will be removed in Tornado 6.0.
- Use coroutines instead.
- """
- warnings.warn("@asynchronous is deprecated, use coroutines instead",
- DeprecationWarning)
- # Delay the IOLoop import because it's not available on app engine.
- from tornado.ioloop import IOLoop
-
- @functools.wraps(method)
- def wrapper(self, *args, **kwargs):
- self._auto_finish = False
- with stack_context.ExceptionStackContext(
- self._stack_context_handle_exception, delay_warning=True):
- result = method(self, *args, **kwargs)
- if result is not None:
- result = gen.convert_yielded(result)
-
- # If @asynchronous is used with @gen.coroutine, (but
- # not @gen.engine), we can automatically finish the
- # request when the future resolves. Additionally,
- # the Future will swallow any exceptions so we need
- # to throw them back out to the stack context to finish
- # the request.
- def future_complete(f):
- f.result()
- if not self._finished:
- self.finish()
- IOLoop.current().add_future(result, future_complete)
- # Once we have done this, hide the Future from our
- # caller (i.e. RequestHandler._when_complete), which
- # would otherwise set up its own callback and
- # exception handler (resulting in exceptions being
- # logged twice).
- return None
- return result
- return wrapper
-
-
def stream_request_body(cls):
"""Apply to `RequestHandler` subclasses to enable streaming body support.