prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  tornado.platform.twisted disappeared but did not explain its replacement
  Many years' worth of documentation explains that folks can do
  
  ```
  from tornado.platform.twisted import install
  reactor = install()
  ```
  
  I can see that in https://github.com/tornadoweb/tornado/commit/004de9c301cc4c2dae4d8f2507af1851d0c9763a#diff-77b5a8a33248ef0bcafbc1bb71e9f013 Twisted integration was removed, since we can all depend on the stdlib loop APIs.  This is great, but it also breaks a bunch of Jupyter notebooks, tutorials, etc.
  
  Could you be convinced to replace all those sprawling APIs with something like this:
  
  ```python3
  def install():
      from twisted.internet.asyncioreactor import install
      install()
      from twisted.internet import reactor
      reactor.startRunning()
      return reactor
  ```
  
  possibly with a `warnings.warn` explaining that users could just call these APIs directly, if that's the desired end-state?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `tornado/platform/twisted.py`
  Content:
  ```
  1 # Licensed under the Apache License, Version 2.0 (the "License"); you may
  2 # not use this file except in compliance with the License. You may obtain
  3 # a copy of the License at
  4 #
  5 #     http://www.apache.org/licenses/LICENSE-2.0
  6 #
  7 # Unless required by applicable law or agreed to in writing, software
  8 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  9 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  10 # License for the specific language governing permissions and limitations
  11 # under the License.
  12 """Bridges between the Twisted package and Tornado.
  13 """
  14 
  15 import socket
  16 import sys
  17 
  18 import twisted.internet.abstract  # type: ignore
  19 import twisted.internet.asyncioreactor  # type: ignore
  20 from twisted.internet.defer import Deferred  # type: ignore
  21 from twisted.python import failure  # type: ignore
  22 import twisted.names.cache  # type: ignore
  23 import twisted.names.client  # type: ignore
  24 import twisted.names.hosts  # type: ignore
  25 import twisted.names.resolve  # type: ignore
  26 
  27 
  28 from tornado.concurrent import Future, future_set_exc_info
  29 from tornado.escape import utf8
  30 from tornado import gen
  31 from tornado.netutil import Resolver
  32 
  33 import typing
  34 
  35 if typing.TYPE_CHECKING:
  36     from typing import Generator, Any, List, Tuple  # noqa: F401
  37 
  38 
  39 class TwistedResolver(Resolver):
  40     """Twisted-based asynchronous resolver.
  41 
  42     This is a non-blocking and non-threaded resolver.  It is
  43     recommended only when threads cannot be used, since it has
  44     limitations compared to the standard ``getaddrinfo``-based
  45     `~tornado.netutil.Resolver` and
  46     `~tornado.netutil.DefaultExecutorResolver`.  Specifically, it returns at
  47     most one result, and arguments other than ``host`` and ``family``
  48     are ignored.  It may fail to resolve when ``family`` is not
  49     ``socket.AF_UNSPEC``.
  50 
  51     Requires Twisted 12.1 or newer.
  52 
  53     .. versionchanged:: 5.0
  54        The ``io_loop`` argument (deprecated since version 4.1) has been removed.
  55     """
  56 
  57     def initialize(self) -> None:
  58         # partial copy of twisted.names.client.createResolver, which doesn't
  59         # allow for a reactor to be passed in.
  60         self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor()
  61 
  62         host_resolver = twisted.names.hosts.Resolver("/etc/hosts")
  63         cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor)
  64         real_resolver = twisted.names.client.Resolver(
  65             "/etc/resolv.conf", reactor=self.reactor
  66         )
  67         self.resolver = twisted.names.resolve.ResolverChain(
  68             [host_resolver, cache_resolver, real_resolver]
  69         )
  70 
  71     @gen.coroutine
  72     def resolve(
  73         self, host: str, port: int, family: int = 0
  74     ) -> "Generator[Any, Any, List[Tuple[int, Any]]]":
  75         # getHostByName doesn't accept IP addresses, so if the input
  76         # looks like an IP address just return it immediately.
  77         if twisted.internet.abstract.isIPAddress(host):
  78             resolved = host
  79             resolved_family = socket.AF_INET
  80         elif twisted.internet.abstract.isIPv6Address(host):
  81             resolved = host
  82             resolved_family = socket.AF_INET6
  83         else:
  84             deferred = self.resolver.getHostByName(utf8(host))
  85             fut = Future()  # type: Future[Any]
  86             deferred.addBoth(fut.set_result)
  87             resolved = yield fut
  88             if isinstance(resolved, failure.Failure):
  89                 try:
  90                     resolved.raiseException()
  91                 except twisted.names.error.DomainError as e:
  92                     raise IOError(e)
  93             elif twisted.internet.abstract.isIPAddress(resolved):
  94                 resolved_family = socket.AF_INET
  95             elif twisted.internet.abstract.isIPv6Address(resolved):
  96                 resolved_family = socket.AF_INET6
  97             else:
  98                 resolved_family = socket.AF_UNSPEC
  99         if family != socket.AF_UNSPEC and family != resolved_family:
  100             raise Exception(
  101                 "Requested socket family %d but got %d" % (family, resolved_family)
  102             )
  103         result = [(typing.cast(int, resolved_family), (resolved, port))]
  104         return result
  105 
  106 
  107 if hasattr(gen.convert_yielded, "register"):
  108 
  109     @gen.convert_yielded.register(Deferred)  # type: ignore
  110     def _(d: Deferred) -> Future:
  111         f = Future()  # type: Future[Any]
  112 
  113         def errback(failure: failure.Failure) -> None:
  114             try:
  115                 failure.raiseException()
  116                 # Should never happen, but just in case
  117                 raise Exception("errback called without error")
  118             except:
  119                 future_set_exc_info(f, sys.exc_info())
  120 
  121         d.addCallbacks(f.set_result, errback)
  122         return f
  123
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/tornado/platform/twisted.py b/tornado/platform/twisted.py
  --- a/tornado/platform/twisted.py
  +++ b/tornado/platform/twisted.py
  @@ -104,6 +104,30 @@
           return result
   
   
  +def install() -> None:
  +    """Install ``AsyncioSelectorReactor`` as the default Twisted reactor.
  +
  +    .. deprecated:: 5.1
  +
  +       This function is provided for backwards compatibility; code
  +       that does not require compatibility with older versions of
  +       Tornado should use
  +       ``twisted.internet.asyncioreactor.install()`` directly.
  +
  +    .. versionchanged:: 6.0.3
  +
  +       In Tornado 5.x and before, this function installed a reactor
  +       based on the Tornado ``IOLoop``. When that reactor
  +       implementation was removed in Tornado 6.0.0, this function was
  +       removed as well. It was restored in Tornado 6.0.3 using the
  +       ``asyncio`` reactor instead.
  +
  +    """
  +    from twisted.internet.asyncioreactor import install
  +
  +    install()
  +
  +
   if hasattr(gen.convert_yielded, "register"):
   
       @gen.convert_yielded.register(Deferred)  # type: ignore
  
verification_info: {"golden_diff": "diff --git a/tornado/platform/twisted.py b/tornado/platform/twisted.py\n--- a/tornado/platform/twisted.py\n+++ b/tornado/platform/twisted.py\n@@ -104,6 +104,30 @@\n         return result\n \n \n+def install() -> None:\n+    \"\"\"Install ``AsyncioSelectorReactor`` as the default Twisted reactor.\n+\n+    .. deprecated:: 5.1\n+\n+       This function is provided for backwards compatibility; code\n+       that does not require compatibility with older versions of\n+       Tornado should use\n+       ``twisted.internet.asyncioreactor.install()`` directly.\n+\n+    .. versionchanged:: 6.0.3\n+\n+       In Tornado 5.x and before, this function installed a reactor\n+       based on the Tornado ``IOLoop``. When that reactor\n+       implementation was removed in Tornado 6.0.0, this function was\n+       removed as well. It was restored in Tornado 6.0.3 using the\n+       ``asyncio`` reactor instead.\n+\n+    \"\"\"\n+    from twisted.internet.asyncioreactor import install\n+\n+    install()\n+\n+\n if hasattr(gen.convert_yielded, \"register\"):\n \n     @gen.convert_yielded.register(Deferred)  # type: ignore\n", "issue": "tornado.platform.twisted disappeared but did not explain its replacement\nMany years' worth of documentation explains that folks can do\r\n\r\n```\r\nfrom tornado.platform.twisted import install\r\nreactor = install()\r\n```\r\n\r\nI can see that in https://github.com/tornadoweb/tornado/commit/004de9c301cc4c2dae4d8f2507af1851d0c9763a#diff-77b5a8a33248ef0bcafbc1bb71e9f013 Twisted integration was removed, since we can all depend on the stdlib loop APIs.  This is great, but it also breaks a bunch of Jupyter notebooks, tutorials, etc.\r\n\r\nCould you be convinced to replace all those sprawling APIs with something like this:\r\n\r\n```python3\r\ndef install():\r\n    from twisted.internet.asyncioreactor import install\r\n    install()\r\n    from twisted.internet import reactor\r\n    reactor.startRunning()\r\n    return reactor\r\n```\r\n\r\npossibly with a `warnings.warn` explaining that users could just call these APIs directly, if that's the desired end-state?\n", "before_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\"\"\"Bridges between the Twisted package and Tornado.\n\"\"\"\n\nimport socket\nimport sys\n\nimport twisted.internet.abstract  # type: ignore\nimport twisted.internet.asyncioreactor  # type: ignore\nfrom twisted.internet.defer import Deferred  # type: ignore\nfrom twisted.python import failure  # type: ignore\nimport twisted.names.cache  # type: ignore\nimport twisted.names.client  # type: ignore\nimport twisted.names.hosts  # type: ignore\nimport twisted.names.resolve  # type: ignore\n\n\nfrom tornado.concurrent import Future, future_set_exc_info\nfrom tornado.escape import utf8\nfrom tornado import gen\nfrom tornado.netutil import Resolver\n\nimport typing\n\nif typing.TYPE_CHECKING:\n    from typing import Generator, Any, List, Tuple  # noqa: F401\n\n\nclass TwistedResolver(Resolver):\n    \"\"\"Twisted-based asynchronous resolver.\n\n    This is a non-blocking and non-threaded resolver.  It is\n    recommended only when threads cannot be used, since it has\n    limitations compared to the standard ``getaddrinfo``-based\n    `~tornado.netutil.Resolver` and\n    `~tornado.netutil.DefaultExecutorResolver`.  Specifically, it returns at\n    most one result, and arguments other than ``host`` and ``family``\n    are ignored.  It may fail to resolve when ``family`` is not\n    ``socket.AF_UNSPEC``.\n\n    Requires Twisted 12.1 or newer.\n\n    .. versionchanged:: 5.0\n       The ``io_loop`` argument (deprecated since version 4.1) has been removed.\n    \"\"\"\n\n    def initialize(self) -> None:\n        # partial copy of twisted.names.client.createResolver, which doesn't\n        # allow for a reactor to be passed in.\n        self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor()\n\n        host_resolver = twisted.names.hosts.Resolver(\"/etc/hosts\")\n        cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor)\n        real_resolver = twisted.names.client.Resolver(\n            \"/etc/resolv.conf\", reactor=self.reactor\n        )\n        self.resolver = twisted.names.resolve.ResolverChain(\n            [host_resolver, cache_resolver, real_resolver]\n        )\n\n    @gen.coroutine\n    def resolve(\n        self, host: str, port: int, family: int = 0\n    ) -> \"Generator[Any, Any, List[Tuple[int, Any]]]\":\n        # getHostByName doesn't accept IP addresses, so if the input\n        # looks like an IP address just return it immediately.\n        if twisted.internet.abstract.isIPAddress(host):\n            resolved = host\n            resolved_family = socket.AF_INET\n        elif twisted.internet.abstract.isIPv6Address(host):\n            resolved = host\n            resolved_family = socket.AF_INET6\n        else:\n            deferred = self.resolver.getHostByName(utf8(host))\n            fut = Future()  # type: Future[Any]\n            deferred.addBoth(fut.set_result)\n            resolved = yield fut\n            if isinstance(resolved, failure.Failure):\n                try:\n                    resolved.raiseException()\n                except twisted.names.error.DomainError as e:\n                    raise IOError(e)\n            elif twisted.internet.abstract.isIPAddress(resolved):\n                resolved_family = socket.AF_INET\n            elif twisted.internet.abstract.isIPv6Address(resolved):\n                resolved_family = socket.AF_INET6\n            else:\n                resolved_family = socket.AF_UNSPEC\n        if family != socket.AF_UNSPEC and family != resolved_family:\n            raise Exception(\n                \"Requested socket family %d but got %d\" % (family, resolved_family)\n            )\n        result = [(typing.cast(int, resolved_family), (resolved, port))]\n        return result\n\n\nif hasattr(gen.convert_yielded, \"register\"):\n\n    @gen.convert_yielded.register(Deferred)  # type: ignore\n    def _(d: Deferred) -> Future:\n        f = Future()  # type: Future[Any]\n\n        def errback(failure: failure.Failure) -> None:\n            try:\n                failure.raiseException()\n                # Should never happen, but just in case\n                raise Exception(\"errback called without error\")\n            except:\n                future_set_exc_info(f, sys.exc_info())\n\n        d.addCallbacks(f.set_result, errback)\n        return f\n", "path": "tornado/platform/twisted.py"}], "after_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\"\"\"Bridges between the Twisted package and Tornado.\n\"\"\"\n\nimport socket\nimport sys\n\nimport twisted.internet.abstract  # type: ignore\nimport twisted.internet.asyncioreactor  # type: ignore\nfrom twisted.internet.defer import Deferred  # type: ignore\nfrom twisted.python import failure  # type: ignore\nimport twisted.names.cache  # type: ignore\nimport twisted.names.client  # type: ignore\nimport twisted.names.hosts  # type: ignore\nimport twisted.names.resolve  # type: ignore\n\n\nfrom tornado.concurrent import Future, future_set_exc_info\nfrom tornado.escape import utf8\nfrom tornado import gen\nfrom tornado.netutil import Resolver\n\nimport typing\n\nif typing.TYPE_CHECKING:\n    from typing import Generator, Any, List, Tuple  # noqa: F401\n\n\nclass TwistedResolver(Resolver):\n    \"\"\"Twisted-based asynchronous resolver.\n\n    This is a non-blocking and non-threaded resolver.  It is\n    recommended only when threads cannot be used, since it has\n    limitations compared to the standard ``getaddrinfo``-based\n    `~tornado.netutil.Resolver` and\n    `~tornado.netutil.DefaultExecutorResolver`.  Specifically, it returns at\n    most one result, and arguments other than ``host`` and ``family``\n    are ignored.  It may fail to resolve when ``family`` is not\n    ``socket.AF_UNSPEC``.\n\n    Requires Twisted 12.1 or newer.\n\n    .. versionchanged:: 5.0\n       The ``io_loop`` argument (deprecated since version 4.1) has been removed.\n    \"\"\"\n\n    def initialize(self) -> None:\n        # partial copy of twisted.names.client.createResolver, which doesn't\n        # allow for a reactor to be passed in.\n        self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor()\n\n        host_resolver = twisted.names.hosts.Resolver(\"/etc/hosts\")\n        cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor)\n        real_resolver = twisted.names.client.Resolver(\n            \"/etc/resolv.conf\", reactor=self.reactor\n        )\n        self.resolver = twisted.names.resolve.ResolverChain(\n            [host_resolver, cache_resolver, real_resolver]\n        )\n\n    @gen.coroutine\n    def resolve(\n        self, host: str, port: int, family: int = 0\n    ) -> \"Generator[Any, Any, List[Tuple[int, Any]]]\":\n        # getHostByName doesn't accept IP addresses, so if the input\n        # looks like an IP address just return it immediately.\n        if twisted.internet.abstract.isIPAddress(host):\n            resolved = host\n            resolved_family = socket.AF_INET\n        elif twisted.internet.abstract.isIPv6Address(host):\n            resolved = host\n            resolved_family = socket.AF_INET6\n        else:\n            deferred = self.resolver.getHostByName(utf8(host))\n            fut = Future()  # type: Future[Any]\n            deferred.addBoth(fut.set_result)\n            resolved = yield fut\n            if isinstance(resolved, failure.Failure):\n                try:\n                    resolved.raiseException()\n                except twisted.names.error.DomainError as e:\n                    raise IOError(e)\n            elif twisted.internet.abstract.isIPAddress(resolved):\n                resolved_family = socket.AF_INET\n            elif twisted.internet.abstract.isIPv6Address(resolved):\n                resolved_family = socket.AF_INET6\n            else:\n                resolved_family = socket.AF_UNSPEC\n        if family != socket.AF_UNSPEC and family != resolved_family:\n            raise Exception(\n                \"Requested socket family %d but got %d\" % (family, resolved_family)\n            )\n        result = [(typing.cast(int, resolved_family), (resolved, port))]\n        return result\n\n\ndef install() -> None:\n    \"\"\"Install ``AsyncioSelectorReactor`` as the default Twisted reactor.\n\n    .. deprecated:: 5.1\n\n       This function is provided for backwards compatibility; code\n       that does not require compatibility with older versions of\n       Tornado should use\n       ``twisted.internet.asyncioreactor.install()`` directly.\n\n    .. versionchanged:: 6.0.3\n\n       In Tornado 5.x and before, this function installed a reactor\n       based on the Tornado ``IOLoop``. When that reactor\n       implementation was removed in Tornado 6.0.0, this function was\n       removed as well. It was restored in Tornado 6.0.3 using the\n       ``asyncio`` reactor instead.\n\n    \"\"\"\n    from twisted.internet.asyncioreactor import install\n\n    install()\n\n\nif hasattr(gen.convert_yielded, \"register\"):\n\n    @gen.convert_yielded.register(Deferred)  # type: ignore\n    def _(d: Deferred) -> Future:\n        f = Future()  # type: Future[Any]\n\n        def errback(failure: failure.Failure) -> None:\n            try:\n                failure.raiseException()\n                # Should never happen, but just in case\n                raise Exception(\"errback called without error\")\n            except:\n                future_set_exc_info(f, sys.exc_info())\n\n        d.addCallbacks(f.set_result, errback)\n        return f\n", "path": "tornado/platform/twisted.py"}]}