From: Ben Darnell Date: Sun, 7 Oct 2018 04:26:16 +0000 (-0400) Subject: Merge remote-tracking branch 'origin/master' into mypy X-Git-Tag: v6.0.0b1~28^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=52c9ab860f4ce2d56218e888d966458ce80d6a27;p=thirdparty%2Ftornado.git Merge remote-tracking branch 'origin/master' into mypy --- 52c9ab860f4ce2d56218e888d966458ce80d6a27 diff --cc tornado/platform/asyncio.py index aa701d6b3,0ee5afe58..0b79f82ca --- a/tornado/platform/asyncio.py +++ b/tornado/platform/asyncio.py @@@ -62,9 -61,17 +63,17 @@@ class BaseAsyncIOLoop(IOLoop) if loop.is_closed(): del IOLoop._ioloop_for_asyncio[loop] IOLoop._ioloop_for_asyncio[asyncio_loop] = self + + self._thread_identity = 0 + super(BaseAsyncIOLoop, self).initialize(**kwargs) + def assign_thread_identity() -> None: + self._thread_identity = get_ident() + + self.add_callback(assign_thread_identity) + - def close(self, all_fds: bool=False) -> None: + def close(self, all_fds: bool = False) -> None: self.closing = True for fd in list(self.handlers): fileobj, handler_func = self.handlers[fd] @@@ -159,10 -166,14 +168,12 @@@ timeout.cancel() # type: ignore def add_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: + if get_ident() == self._thread_identity: + call_soon = self.asyncio_loop.call_soon + else: + call_soon = self.asyncio_loop.call_soon_threadsafe try: - self.asyncio_loop.call_soon_threadsafe( - self._run_callback, functools.partial(callback, *args, **kwargs) - ) - call_soon( - self._run_callback, - functools.partial(callback, *args, **kwargs)) ++ call_soon(self._run_callback, functools.partial(callback, *args, **kwargs)) except RuntimeError: # "Event loop is closed". Swallow the exception for # consistency with PollIOLoop (and logical consistency @@@ -171,14 -182,16 +182,22 @@@ # eventually execute). pass - add_callback_from_signal = add_callback - def add_callback_from_signal(self, callback: Callable, *args: Any, **kwargs: Any) -> None: ++ def add_callback_from_signal( ++ self, callback: Callable, *args: Any, **kwargs: Any ++ ) -> None: + try: + self.asyncio_loop.call_soon_threadsafe( - self._run_callback, - functools.partial(callback, *args, **kwargs)) ++ self._run_callback, functools.partial(callback, *args, **kwargs) ++ ) + except RuntimeError: + pass - def run_in_executor(self, executor: Optional[concurrent.futures.Executor], - func: Callable[..., _T], *args: Any) -> Awaitable[_T]: + def run_in_executor( + self, + executor: Optional[concurrent.futures.Executor], + func: Callable[..., _T], + *args: Any + ) -> Awaitable[_T]: return self.asyncio_loop.run_in_executor(executor, func, *args) def set_default_executor(self, executor: concurrent.futures.Executor) -> None: diff --cc tornado/test/httpclient_test.py index d0b46ebec,d11ceff86..c30c1b566 --- a/tornado/test/httpclient_test.py +++ b/tornado/test/httpclient_test.py @@@ -609,14 -552,18 +610,18 @@@ class SyncHTTPClientTest(unittest.TestC @gen.coroutine def init_server(): sock, self.port = bind_unused_port() - app = Application([('/', HelloWorldHandler)]) + app = Application([("/", HelloWorldHandler)]) self.server = HTTPServer(app) self.server.add_socket(sock) + event.set() - self.server_ioloop.run_sync(init_server) + def start(): + self.server_ioloop.run_sync(init_server) + self.server_ioloop.start() - self.server_thread = threading.Thread(target=self.server_ioloop.start) + self.server_thread = threading.Thread(target=start) self.server_thread.start() + event.wait() self.http_client = HTTPClient() diff --cc tornado/web.py index bbc977d7d,76337ea83..9742b88a6 --- a/tornado/web.py +++ b/tornado/web.py @@@ -2554,15 -2328,12 +2554,13 @@@ class StaticFileHandler(RequestHandler) .. versionchanged:: 3.1 Many of the methods for subclasses were added in Tornado 3.1. """ + CACHE_MAX_AGE = 86400 * 365 * 10 # 10 years - _static_hashes = {} # type: typing.Dict + _static_hashes = {} # type: Dict[str, Optional[str]] _lock = threading.Lock() # protects _static_hashes - def initialize( - self, path: str, default_filename: str = None - ) -> None: - def initialize(self, path, default_filename=None): ++ def initialize(self, path: str, default_filename: str = None) -> None: self.root = path self.default_filename = default_filename