AaronOpfer: Looks like my `__del__` method has some problems, I'll fix them.
AaronOpfer: It looks like implementing the `__del__` method broke various unit tests which expected no consequences of letting half-finished coroutines get garbage collected. These test cases pass but log errors about uncaught future exceptions, failing the overall test. I fixed one instance of this in `queues_test.py` locally but there seems to be many more instances where this can occur.

I can continue to clean up instances like these but first I'd like a Tornado developer to tell me if I'm on the right path with this or if I should just leave the `__del__` change out and quit while I'm ahead.
bdarnell: >  It is difficult to imagine a situation where Runners being garbage collected before the future has a result being a desired behavior, though.

It doesn't make sense for the `Runner` to be collected *before* the `Future`, but they could be collected at the same time. I think that's what's happening in the tests. I think this is legitimate and we want to allow it. Besides, after the first change to use the `WeakKeyDictionary`, what other scenarios would this destructor be guarding against? I'd just get rid of it.

I think I'd make the `WeakKeyDictionary` a global. I'm not seeing any benefit to giving each coroutine function its own dict (which could possibly go out of scope if the decorated function does. 

I'm concerned about the performance impact of a `WeakKeyDictionary` - will it increase GC overhead? I'd like to see some benchmarks showing no significant impact before merging this. 
AaronOpfer: I agree with your points. I'll remove the `__del__` method and make the `WeakKeyDictionary` a global.

I agree that we should test the performance. Does Tornado have any existing performance benchmarking suites we can use for testing performance after my changes?
bdarnell: We don't have great benchmarks. What we do have is in `demos/benchmark/benchmark.py` (and a few other scripts, but benchmark.py is the main one). It should be enough to show the impact of this change. Run it with `--keepalive` since that removes some of the networking overhead. 

    demos/benchmark/benchmark.py --keepalive --quiet --num_runs=5|grep "Requests per second"
AaronOpfer: I ran the performance benchmarks and I saw no differences between my implementation and the previous implementation. The tests were highly variable, I ran each multiple times and they would vary between 1100 req/sec and 1600 req/sec.
AaronOpfer: I believe this changeset addresses all of your concerns @bdarnell , let me know if you'd like to see any other adjustments.
diff --git a/.travis.yml b/.travis.yml
index 7d6b79a5..16f61830 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,13 +30,9 @@ install:
     - curl-config --version; pip freeze
 
 script:
-    # Run the tests once from the source directory to detect issues
-    # involving relative __file__ paths; see
-    # https://github.com/tornadoweb/tornado/issues/1780
-    - unset TORNADO_EXTENSION && python -m tornado.test
-    # For all other test variants, get out of the source directory before
-    # running tests to ensure that we get the installed speedups module
-    # instead of the source directory which doesn't have it.
+    # Get out of the source directory before running tests to avoid PYTHONPATH
+    # confusion.  This is necessary to ensure that the speedups module can
+    # be found in the installation directory.
     - cd maint
     # Copy the coveragerc down so coverage.py can find it.
     - cp ../.coveragerc .
diff --git a/demos/chat/static/chat.js b/demos/chat/static/chat.js
index 151a5880..0054c710 100644
--- a/demos/chat/static/chat.js
+++ b/demos/chat/static/chat.js
@@ -16,16 +16,15 @@ $(document).ready(function() {
     if (!window.console) window.console = {};
     if (!window.console.log) window.console.log = function() {};
 
-    $("#messageform").on("submit", function() {
+    $("#messageform").live("submit", function() {
         newMessage($(this));
         return false;
     });
-    $("#messageform").on("keypress", function(e) {
+    $("#messageform").live("keypress", function(e) {
         if (e.keyCode == 13) {
             newMessage($(this));
             return false;
         }
-        return true;
     });
     $("#message").select();
     updater.poll();
@@ -57,13 +56,13 @@ jQuery.postJSON = function(url, args, callback) {
             success: function(response) {
         if (callback) callback(eval("(" + response + ")"));
     }, error: function(response) {
-        console.log("ERROR:", response);
+        console.log("ERROR:", response)
     }});
 };
 
 jQuery.fn.formToDict = function() {
     var fields = this.serializeArray();
-    var json = {};
+    var json = {}
     for (var i = 0; i < fields.length; i++) {
         json[fields[i].name] = fields[i].value;
     }
diff --git a/demos/chat/templates/index.html b/demos/chat/templates/index.html
index 58433b44..8916c350 100644
--- a/demos/chat/templates/index.html
+++ b/demos/chat/templates/index.html
@@ -16,7 +16,7 @@
         <form action="/a/message/new" method="post" id="messageform">
           <table>
             <tr>
-              <td><input type="text" name="body" id="message" style="width:500px"></td>
+              <td><input name="body" id="message" style="width:500px"></td>
               <td style="padding-left:5px">
                 <input type="submit" value="{{ _("Post") }}">
                 <input type="hidden" name="next" value="{{ request.path }}">
@@ -27,7 +27,7 @@
         </form>
       </div>
     </div>
-    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js" type="text/javascript"></script>
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
     <script src="{{ static_url("chat.js") }}" type="text/javascript"></script>
   </body>
 </html>
diff --git a/demos/tcpecho/README.md b/demos/tcpecho/README.md
deleted file mode 100644
index 60d0b70c..00000000
--- a/demos/tcpecho/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-TCP echo demo
-=============
-
-This demo shows how to use Tornado's asynchronous TCP client and
-server by implementing `handle_stream` as a coroutine.
-
-To run the server:
-
-```
-$ python server.py
-```
-
-The client will send the message given with the `--message` option
-(which defaults to "ping"), wait for a response, then quit. To run:
-
-```
-$ python client.py --message="your message here"
-```
-
-Alternatively, you can interactively send messages to the echo server
-with a telnet client. For example:
-
-```
-$ telnet localhost 9888
-Trying ::1...
-Connected to localhost.
-Escape character is '^]'.
-ping
-ping
-```
diff --git a/demos/tcpecho/client.py b/demos/tcpecho/client.py
deleted file mode 100644
index a369fa47..00000000
--- a/demos/tcpecho/client.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from __future__ import print_function
-from tornado.ioloop import IOLoop
-from tornado import gen
-from tornado.tcpclient import TCPClient
-from tornado.options import options, define
-
-define("host", default="localhost", help="TCP server host")
-define("port", default=9888, help="TCP port to connect to")
-define("message", default="ping", help="Message to send")
-
-
-@gen.coroutine
-def send_message():
-    stream = yield TCPClient().connect(options.host, options.port)
-    yield stream.write((options.message + "\n").encode())
-    print("Sent to server:", options.message)
-    reply = yield stream.read_until(b"\n")
-    print("Response from server:", reply.decode().strip())
-
-
-if __name__ == "__main__":
-    options.parse_command_line()
-    IOLoop.current().run_sync(send_message)
diff --git a/demos/tcpecho/server.py b/demos/tcpecho/server.py
deleted file mode 100644
index bc0b054a..00000000
--- a/demos/tcpecho/server.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import logging
-from tornado.ioloop import IOLoop
-from tornado import gen
-from tornado.iostream import StreamClosedError
-from tornado.tcpserver import TCPServer
-from tornado.options import options, define
-
-define("port", default=9888, help="TCP port to listen on")
-logger = logging.getLogger(__name__)
-
-
-class EchoServer(TCPServer):
-    @gen.coroutine
-    def handle_stream(self, stream, address):
-        while True:
-            try:
-                data = yield stream.read_until(b"\n")
-                logger.info("Received bytes: %s", data)
-                if not data.endswith(b"\n"):
-                    data = data + b"\n"
-                yield stream.write(data)
-            except StreamClosedError:
-                logger.warning("Lost client at host %s", address[0])
-                break
-            except Exception as e:
-                print(e)
-
-
-if __name__ == "__main__":
-    options.parse_command_line()
-    server = EchoServer()
-    server.listen(options.port)
-    logger.info("Listening on TCP port %d", options.port)
-    IOLoop.current().start()
diff --git a/demos/websocket/static/chat.js b/demos/websocket/static/chat.js
index 4e7ec049..b4bb18a9 100644
--- a/demos/websocket/static/chat.js
+++ b/demos/websocket/static/chat.js
@@ -16,11 +16,11 @@ $(document).ready(function() {
     if (!window.console) window.console = {};
     if (!window.console.log) window.console.log = function() {};
 
-    $("#messageform").on("submit", function() {
+    $("#messageform").live("submit", function() {
         newMessage($(this));
         return false;
     });
-    $("#messageform").on("keypress", function(e) {
+    $("#messageform").live("keypress", function(e) {
         if (e.keyCode == 13) {
             newMessage($(this));
             return false;
diff --git a/demos/websocket/templates/index.html b/demos/websocket/templates/index.html
index 91a45363..cbf2b23d 100644
--- a/demos/websocket/templates/index.html
+++ b/demos/websocket/templates/index.html
@@ -27,7 +27,7 @@
         </form>
       </div>
     </div>
-    <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js" type="text/javascript"></script>
+    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
     <script src="{{ static_url("chat.js") }}" type="text/javascript"></script>
   </body>
 </html>
diff --git a/docs/releases/v4.1.0.rst b/docs/releases/v4.1.0.rst
index 29ad1914..c38511b8 100644
--- a/docs/releases/v4.1.0.rst
+++ b/docs/releases/v4.1.0.rst
@@ -24,7 +24,7 @@ Backwards-compatibility notes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 * `.HTTPServer` now calls ``start_request`` with the correct
-  arguments.  This change is backwards-incompatible, affecting any
+  arguments.  This change is backwards-incompatible, afffecting any
   application which implemented `.HTTPServerConnectionDelegate` by
   following the example of `.Application` instead of the documented
   method signatures.
diff --git a/tornado/gen.py b/tornado/gen.py
index b308ca7d..73f9ba10 100644
--- a/tornado/gen.py
+++ b/tornado/gen.py
@@ -83,6 +83,7 @@ import os
 import sys
 import textwrap
 import types
+import weakref
 
 from tornado.concurrent import Future, TracebackFuture, is_future, chain_future
 from tornado.ioloop import IOLoop
@@ -244,6 +245,24 @@ def coroutine(func, replace_callback=True):
     """
     return _make_coroutine_wrapper(func, replace_callback=True)
 
+# Ties lifetime of runners to their result futures. Github Issue #1769
+# Generators, like any object in Python, must be strong referenced
+# in order to not be cleaned up by the garbage collector. When using
+# coroutines, the Runner object is what strong-refs the inner
+# generator. However, the only item that strong-reffed the Runner
+# was the last Future that the inner generator yielded (via the
+# Future's internal done_callback list). Usually this is enough, but
+# it is also possible for this Future to not have any strong references
+# other than other objects referenced by the Runner object (usually
+# when using other callback patterns and/or weakrefs). In this
+# situation, if a garbage collection ran, a cycle would be detected and
+# Runner objects could be destroyed along with their inner generators
+# and everything in their local scope.
+# This map provides strong references to Runner objects as long as
+# their result future objects also have strong references (typically
+# from the parent coroutine's Runner). This keeps the coroutine's
+# Runner alive.
+_futures_to_runners = weakref.WeakKeyDictionary()
 
 def _make_coroutine_wrapper(func, replace_callback):
     """The inner workings of ``@gen.coroutine`` and ``@gen.engine``.
@@ -294,7 +313,7 @@ def _make_coroutine_wrapper(func, replace_callback):
                 except Exception:
                     future.set_exc_info(sys.exc_info())
                 else:
-                    Runner(result, future, yielded)
+                    _futures_to_runners[future] = Runner(result, future, yielded)
                 try:
                     return future
                 finally:
diff --git a/tornado/platform/asyncio.py b/tornado/platform/asyncio.py
index 9556da61..3fd67dbd 100644
--- a/tornado/platform/asyncio.py
+++ b/tornado/platform/asyncio.py
@@ -14,9 +14,9 @@ loops.
 
 .. note::
 
-   Tornado requires the `~asyncio.AbstractEventLoop.add_reader` family of
-   methods, so it is not compatible with the `~asyncio.ProactorEventLoop` on
-   Windows. Use the `~asyncio.SelectorEventLoop` instead.
+   Tornado requires the `~asyncio.BaseEventLoop.add_reader` family of methods,
+   so it is not compatible with the `~asyncio.ProactorEventLoop` on Windows.
+   Use the `~asyncio.SelectorEventLoop` instead.
 """
 
 from __future__ import absolute_import, division, print_function, with_statement
diff --git a/tornado/tcpserver.py b/tornado/tcpserver.py
index 54837f7a..0839d392 100644
--- a/tornado/tcpserver.py
+++ b/tornado/tcpserver.py
@@ -39,21 +39,7 @@ class TCPServer(object):
     r"""A non-blocking, single-threaded TCP server.
 
     To use `TCPServer`, define a subclass which overrides the `handle_stream`
-    method. For example, a simple echo server could be defined like this::
-
-      from tornado.tcpserver import TCPServer
-      from tornado.iostream import StreamClosedError
-      from tornado import gen
-
-      class EchoServer(TCPServer):
-          @gen.coroutine
-          def handle_stream(self, stream, address):
-              while True:
-                  try:
-                      data = yield stream.read_until(b"\n")
-                      yield stream.write(data)
-                  except StreamClosedError:
-                      break
+    method.
 
     To make this server serve SSL traffic, send the ``ssl_options`` keyword
     argument with an `ssl.SSLContext` object. For compatibility with older
diff --git a/tornado/web.py b/tornado/web.py
index 96b204eb..f54c4d03 100644
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -527,7 +527,7 @@ class RequestHandler(object):
 
         Additional keyword arguments are set on the Cookie.Morsel
         directly.
-        See https://docs.python.org/2/library/cookie.html#Cookie.Morsel
+        See http://docs.python.org/library/cookie.html#morsel-objects
         for available attributes.
         """
         # The cookie library only accepts type str, in both python 2 and 3

Runner objects can get GCed unexpectedly
Hi,

This is probably a little unusual and I am not sure I understand the whole object graph, but I believe I have reduced my production issue to this test case.

If a coroutine is waiting on a future, and the only hard references to that future are entirely inside the body of the inner generator of the coroutine, a garbage collection run can sweep away the in-progress coroutine and its runner object, leave the coroutine's future unresolved forever, and in some cases leave the application in a stuck state.

Ran on Python 3.4 with Tornado 4.3.

```python
from tornado.ioloop import IOLoop
from tornado.gen import Future, coroutine
import weakref
import gc

wr_fut = None

def count_runners():
    runners = len([
        x for x in gc.get_objects()
        if x.__class__.__name__ == "Runner"
    ])
    print("There are",runners,"Runners")

def resolve_fut():
    count_runners()
    gc.collect(2)
    count_runners()
    fut = wr_fut()
    if not fut:
        print('failure! The app is going to hang forever now')
    else:
        fut.set_result(1)

@coroutine
def main():
    global wr_fut
    my_fut = Future()
    wr_fut = weakref.ref(my_fut)
    IOLoop.current().add_callback(resolve_fut)
    yield my_fut
    print('success!')

IOLoop.current().run_sync(main)
```
This program hangs forever despite using run_sync. That's because the future returned by the coroutine in main() still exists, it just no longer has a Runner object to actually make the future do anything useful. This is _very_ surprising behavior. I would expect the generator/coroutine/Runner/frame objects to be alive for as long as {{run_sync}} is waiting.

Also, note that explicit call to ```gc.collect(2)``` ; this bug actually requires the garbage collector to run for the bug to trigger, which made this bug *very* difficult to track down.

I have managed hack tornado into making it so that the Runner cannot die while its Future is alive which causes my test case to work:

```python
# gen.py line 1241 tornado 4.3
                except (StopIteration, Return) as e:
                    future.set_result(_value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    # this is the original code below:
                    #Runner(result, future, yielded)
                    # this hack makes the Runner not die and my test case work
                    future._the_runner = Runner(result, future, yielded)
                try:
                    return future
```

So the real-world scenario: I have a proprietary networking library that is using weakrefs for event callbacks and a wrapper library that converts these events into futures. Because I have gone out of my way to avoid creating garbage collection cycles (so that my network client can be GCed when it is no longer in use, unlike a lot of async clients available to tornado), it appears I have discovered this issue.

What is the most appropriate bugfix for this? I personally feel that Runner objects should have their lifecycle tied directly to the future they're driving so that Runners cannot die while their future is alive. However, an argument could also be made that Runner should have a `__del__` method that marks the future as canceled (or `.set_exception(RuntimeError("GCed"))`) instead so that developers can more clearly see that they hit this failure mode.

Please don't tell me the answer is "don't use weakrefs"! I believe it may be possible to create a test case that presents the same problem without using weakrefs but it would have to abuse certain behaviors of sockets, filenos and IOLoop's fd handlers to more closely emulate the actual workings of my network library.
diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py
index 4c873f4b..bfaba567 100644
--- a/tornado/test/gen_test.py
+++ b/tornado/test/gen_test.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import, division, print_function, with_statement
 
+import gc
 import contextlib
 import datetime
 import functools
@@ -25,7 +26,6 @@ try:
 except ImportError:
     futures = None
 
-
 class GenEngineTest(AsyncTestCase):
     def setUp(self):
         super(GenEngineTest, self).setUp()
@@ -1368,5 +1368,28 @@ class WaitIteratorTest(AsyncTestCase):
                                gen.WaitIterator(gen.sleep(0)).next())
 
 
+class RunnerGCTest(AsyncTestCase):
+    """Github issue 1769: Runner objects can get GCed unexpectedly"""
+    @gen_test
+    def test_gc(self):
+        """Runners shouldn't GC if future is alive"""
+        # Create the weakref
+        weakref_scope = [None]
+        def callback():
+            gc.collect(2)
+            weakref_scope[0]().set_result(123)
+
+        @gen.coroutine
+        def tester():
+            fut = Future()
+            weakref_scope[0] = weakref.ref(fut)
+            self.io_loop.add_callback(callback)
+            yield fut
+
+        yield gen.with_timeout(
+            datetime.timedelta(seconds=0.2),
+            tester()
+        )
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tornado/test/options_test.py b/tornado/test/options_test.py
index c050cb64..f7b215c5 100644
--- a/tornado/test/options_test.py
+++ b/tornado/test/options_test.py
@@ -36,7 +36,7 @@ class OptionsTest(unittest.TestCase):
         options.define("port", default=80)
         options.define("username", default='foo')
         options.define("my_path")
-        config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+        config_path = os.path.join(os.path.dirname(__file__),
                                    "options_test.cfg")
         options.parse_config_file(config_path)
         self.assertEqual(options.port, 443)

pip install -e .
parse_log_pytest
pytest
futures mock monotonic trollius pytest
apt-get update apt-get install -y gcc
3.5
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
futures==2.2.0
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
mock==5.2.0
monotonic==1.6
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
six==1.17.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
-e git+https://github.com/tornadoweb/tornado.git@4c95212cadfe8de91cc3f1d2e7644b8255c0d6b1#egg=tornado
trollius==2.1.post2
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: tornado
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - futures==2.2.0
      - mock==5.2.0
      - monotonic==1.6
      - six==1.17.0
      - trollius==2.1.post2
prefix: /opt/conda/envs/tornado

tornado/test/gen_test.py::RunnerGCTest::test_gc
tornado/test/gen_test.py::GenEngineTest::test_arguments tornado/test/gen_test.py::GenEngineTest::test_async_raise_return tornado/test/gen_test.py::GenEngineTest::test_async_raise_return_value tornado/test/gen_test.py::GenEngineTest::test_async_raise_return_value_tuple tornado/test/gen_test.py::GenEngineTest::test_bogus_yield tornado/test/gen_test.py::GenEngineTest::test_bogus_yield_tuple tornado/test/gen_test.py::GenEngineTest::test_exception_in_task_phase1 tornado/test/gen_test.py::GenEngineTest::test_exception_in_task_phase2 tornado/test/gen_test.py::GenEngineTest::test_exception_in_yield tornado/test/gen_test.py::GenEngineTest::test_exception_phase1 tornado/test/gen_test.py::GenEngineTest::test_exception_phase2 tornado/test/gen_test.py::GenEngineTest::test_future tornado/test/gen_test.py::GenEngineTest::test_inline_cb tornado/test/gen_test.py::GenEngineTest::test_ioloop_cb tornado/test/gen_test.py::GenEngineTest::test_key_mismatch tornado/test/gen_test.py::GenEngineTest::test_key_mismatch_tuple tornado/test/gen_test.py::GenEngineTest::test_key_reuse tornado/test/gen_test.py::GenEngineTest::test_key_reuse_tuple tornado/test/gen_test.py::GenEngineTest::test_leaked_callback tornado/test/gen_test.py::GenEngineTest::test_leaked_callback_tuple tornado/test/gen_test.py::GenEngineTest::test_multi tornado/test/gen_test.py::GenEngineTest::test_multi_dict tornado/test/gen_test.py::GenEngineTest::test_multi_dict_future tornado/test/gen_test.py::GenEngineTest::test_multi_empty tornado/test/gen_test.py::GenEngineTest::test_multi_exceptions tornado/test/gen_test.py::GenEngineTest::test_multi_future tornado/test/gen_test.py::GenEngineTest::test_multi_future_delayed tornado/test/gen_test.py::GenEngineTest::test_multi_future_dict_delayed tornado/test/gen_test.py::GenEngineTest::test_multi_future_duplicate tornado/test/gen_test.py::GenEngineTest::test_multi_future_exceptions tornado/test/gen_test.py::GenEngineTest::test_multi_mixed_types tornado/test/gen_test.py::GenEngineTest::test_multi_performance tornado/test/gen_test.py::GenEngineTest::test_multi_yieldpoint_delayed tornado/test/gen_test.py::GenEngineTest::test_multi_yieldpoint_dict_delayed tornado/test/gen_test.py::GenEngineTest::test_no_yield tornado/test/gen_test.py::GenEngineTest::test_orphaned_callback tornado/test/gen_test.py::GenEngineTest::test_parallel_callback tornado/test/gen_test.py::GenEngineTest::test_raise_after_stop tornado/test/gen_test.py::GenEngineTest::test_resume_after_exception_in_yield tornado/test/gen_test.py::GenEngineTest::test_return_value tornado/test/gen_test.py::GenEngineTest::test_return_value_tuple tornado/test/gen_test.py::GenEngineTest::test_reuse tornado/test/gen_test.py::GenEngineTest::test_stack_context_leak tornado/test/gen_test.py::GenEngineTest::test_stack_context_leak_exception tornado/test/gen_test.py::GenEngineTest::test_sync_raise_return tornado/test/gen_test.py::GenEngineTest::test_sync_raise_return_value tornado/test/gen_test.py::GenEngineTest::test_sync_raise_return_value_tuple tornado/test/gen_test.py::GenEngineTest::test_task tornado/test/gen_test.py::GenEngineTest::test_task_refcounting tornado/test/gen_test.py::GenEngineTest::test_task_transfer_stack_context tornado/test/gen_test.py::GenEngineTest::test_wait_all tornado/test/gen_test.py::GenEngineTest::test_wait_transfer_stack_context tornado/test/gen_test.py::GenEngineTest::test_with_arg tornado/test/gen_test.py::GenEngineTest::test_with_arg_tuple tornado/test/gen_test.py::GenCoroutineTest::test_async_await tornado/test/gen_test.py::GenCoroutineTest::test_async_await_mixed_multi_native_future tornado/test/gen_test.py::GenCoroutineTest::test_async_await_mixed_multi_native_yieldpoint tornado/test/gen_test.py::GenCoroutineTest::test_async_early_return tornado/test/gen_test.py::GenCoroutineTest::test_async_gen_return tornado/test/gen_test.py::GenCoroutineTest::test_async_raise tornado/test/gen_test.py::GenCoroutineTest::test_async_return tornado/test/gen_test.py::GenCoroutineTest::test_async_return_no_value tornado/test/gen_test.py::GenCoroutineTest::test_async_with_timeout tornado/test/gen_test.py::GenCoroutineTest::test_moment tornado/test/gen_test.py::GenCoroutineTest::test_pass_callback tornado/test/gen_test.py::GenCoroutineTest::test_py3_leak_exception_context tornado/test/gen_test.py::GenCoroutineTest::test_replace_context_exception tornado/test/gen_test.py::GenCoroutineTest::test_replace_yieldpoint_exception tornado/test/gen_test.py::GenCoroutineTest::test_sleep tornado/test/gen_test.py::GenCoroutineTest::test_swallow_context_exception tornado/test/gen_test.py::GenCoroutineTest::test_swallow_yieldpoint_exception tornado/test/gen_test.py::GenCoroutineTest::test_sync_gen_return tornado/test/gen_test.py::GenCoroutineTest::test_sync_raise tornado/test/gen_test.py::GenCoroutineTest::test_sync_return tornado/test/gen_test.py::GenCoroutineTest::test_sync_return_no_value tornado/test/gen_test.py::GenWebTest::test_async_prepare_error_handler tornado/test/gen_test.py::GenWebTest::test_coroutine_exception_handler tornado/test/gen_test.py::GenWebTest::test_coroutine_sequence_handler tornado/test/gen_test.py::GenWebTest::test_coroutine_unfinished_sequence_handler tornado/test/gen_test.py::GenWebTest::test_exception_handler tornado/test/gen_test.py::GenWebTest::test_native_coroutine_handler tornado/test/gen_test.py::GenWebTest::test_sequence_handler tornado/test/gen_test.py::GenWebTest::test_task_handler tornado/test/gen_test.py::GenWebTest::test_undecorated_coroutines tornado/test/gen_test.py::GenWebTest::test_yield_exception_handler tornado/test/gen_test.py::WithTimeoutTest::test_already_resolved tornado/test/gen_test.py::WithTimeoutTest::test_completed_concurrent_future tornado/test/gen_test.py::WithTimeoutTest::test_completes_before_timeout tornado/test/gen_test.py::WithTimeoutTest::test_fails_before_timeout tornado/test/gen_test.py::WithTimeoutTest::test_timeout tornado/test/gen_test.py::WithTimeoutTest::test_timeout_concurrent_future tornado/test/gen_test.py::WaitIteratorTest::test_already_done tornado/test/gen_test.py::WaitIteratorTest::test_empty_iterator tornado/test/gen_test.py::WaitIteratorTest::test_iterator tornado/test/gen_test.py::WaitIteratorTest::test_iterator_async_await tornado/test/gen_test.py::WaitIteratorTest::test_no_ref tornado/test/options_test.py::OptionsTest::test_as_dict tornado/test/options_test.py::OptionsTest::test_dash_underscore_cli tornado/test/options_test.py::OptionsTest::test_dash_underscore_file tornado/test/options_test.py::OptionsTest::test_dash_underscore_introspection tornado/test/options_test.py::OptionsTest::test_error_redefine tornado/test/options_test.py::OptionsTest::test_getitem tornado/test/options_test.py::OptionsTest::test_group_dict tornado/test/options_test.py::OptionsTest::test_help tornado/test/options_test.py::OptionsTest::test_items tornado/test/options_test.py::OptionsTest::test_iter tornado/test/options_test.py::OptionsTest::test_mock_patch tornado/test/options_test.py::OptionsTest::test_multiple_int tornado/test/options_test.py::OptionsTest::test_multiple_string tornado/test/options_test.py::OptionsTest::test_parse_callbacks tornado/test/options_test.py::OptionsTest::test_parse_command_line tornado/test/options_test.py::OptionsTest::test_parse_config_file tornado/test/options_test.py::OptionsTest::test_setattr tornado/test/options_test.py::OptionsTest::test_setattr_type_check tornado/test/options_test.py::OptionsTest::test_setattr_with_callback tornado/test/options_test.py::OptionsTest::test_setitem tornado/test/options_test.py::OptionsTest::test_subcommand tornado/test/options_test.py::OptionsTest::test_types
demos/websocket/static/chat.js tornado/web.py tornado/gen.py tornado/platform/asyncio.py demos/chat/static/chat.js tornado/tcpserver.py demos/tcpecho/README.md .travis.yml demos/chat/templates/index.html docs/releases/v4.1.0.rst demos/tcpecho/server.py demos/websocket/templates/index.html demos/tcpecho/client.py
demos/websocket/static/chat.js tornado/web.py tornado/gen.py tornado/platform/asyncio.py demos/chat/static/chat.js tornado/tcpserver.py demos/tcpecho/README.md .travis.yml demos/chat/templates/index.html docs/releases/v4.1.0.rst demos/tcpecho/server.py demos/websocket/templates/index.html demos/tcpecho/client.py