From 44ae52ceb42fe277aba7321238268f7e87740724 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 3 Nov 2019 20:35:01 -0500 Subject: [PATCH] lint: Use newer mypy This required some minor code changes, mainly some adjustments in tests (which are now analyzed more thoroughly in spite of being mostly unannotated), and some changes to placement of type:ignore comments. --- setup.py | 2 + tornado/auth.py | 4 +- tornado/autoreload.py | 4 +- tornado/httpclient.py | 8 +-- tornado/httputil.py | 4 +- tornado/iostream.py | 2 +- tornado/netutil.py | 2 +- tornado/process.py | 19 ++++--- tornado/test/asyncio_test.py | 2 +- tornado/test/auth_test.py | 8 +-- tornado/test/concurrent_test.py | 13 +++-- tornado/test/http1connection_test.py | 3 ++ tornado/test/httpclient_test.py | 11 ++-- tornado/test/httpserver_test.py | 25 +++++---- tornado/test/ioloop_test.py | 11 ++-- tornado/test/iostream_test.py | 71 +++++++++++++++----------- tornado/test/netutil_test.py | 8 ++- tornado/test/queues_test.py | 24 +++++---- tornado/test/runtests.py | 4 +- tornado/test/simple_httpclient_test.py | 61 ++++++++++++---------- tornado/test/tcpclient_test.py | 5 +- tornado/test/testing_test.py | 2 +- tornado/test/web_test.py | 50 +++++++++++------- tornado/test/websocket_test.py | 17 ++++-- tornado/testing.py | 2 +- tornado/web.py | 12 +++-- tornado/websocket.py | 2 - tox.ini | 2 +- 28 files changed, 221 insertions(+), 157 deletions(-) diff --git a/setup.py b/setup.py index 62a952ec5..61ffec87c 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. +# type: ignore + import os import platform import sys diff --git a/tornado/auth.py b/tornado/auth.py index 0440f6d53..ed9018572 100644 --- a/tornado/auth.py +++ b/tornado/auth.py @@ -204,7 +204,7 @@ class OpenIdMixin(object): ) -> Dict[str, Any]: handler = cast(RequestHandler, self) if b"is_valid:true" not in response.body: - raise AuthError("Invalid OpenID response: %s" % response.body) + raise AuthError("Invalid OpenID response: %r" % response.body) # Make sure we got back at least an email from attribute exchange ax_ns = None @@ -556,7 +556,7 @@ class OAuth2Mixin(object): client_id: Optional[str] = None, client_secret: Optional[str] = None, extra_params: Optional[Dict[str, Any]] = None, - scope: Optional[str] = None, + scope: Optional[List[str]] = None, response_type: str = "code", ) -> None: """Redirects the user to obtain OAuth authorization for this service. diff --git a/tornado/autoreload.py b/tornado/autoreload.py index 1c47aaec1..af6c3d286 100644 --- a/tornado/autoreload.py +++ b/tornado/autoreload.py @@ -253,8 +253,8 @@ def _reload() -> None: # Unfortunately the errno returned in this case does not # appear to be consistent, so we can't easily check for # this error specifically. - os.spawnv( # type: ignore - os.P_NOWAIT, sys.executable, [sys.executable] + argv + os.spawnv( + os.P_NOWAIT, sys.executable, [sys.executable] + argv # type: ignore ) # At this point the IOLoop has been closed and finally # blocks will experience errors if we allow the stack to diff --git a/tornado/httpclient.py b/tornado/httpclient.py index 673c7470e..8418cd7f7 100644 --- a/tornado/httpclient.py +++ b/tornado/httpclient.py @@ -53,7 +53,7 @@ from tornado import gen, httputil from tornado.ioloop import IOLoop from tornado.util import Configurable -from typing import Type, Any, Union, Dict, Callable, Optional, cast, Awaitable +from typing import Type, Any, Union, Dict, Callable, Optional, cast class HTTPClient(object): @@ -251,7 +251,7 @@ class AsyncHTTPClient(Configurable): request: Union[str, "HTTPRequest"], raise_error: bool = True, **kwargs: Any - ) -> Awaitable["HTTPResponse"]: + ) -> "Future[HTTPResponse]": """Executes a request, asynchronously returning an `HTTPResponse`. The request may be either a string URL or an `HTTPRequest` object. @@ -506,7 +506,7 @@ class HTTPRequest(object): """ # Note that some of these attributes go through property setters # defined below. - self.headers = headers + self.headers = headers # type: ignore if if_modified_since: self.headers["If-Modified-Since"] = httputil.format_timestamp( if_modified_since @@ -518,7 +518,7 @@ class HTTPRequest(object): self.proxy_auth_mode = proxy_auth_mode self.url = url self.method = method - self.body = body + self.body = body # type: ignore self.body_producer = body_producer self.auth_username = auth_username self.auth_password = auth_password diff --git a/tornado/httputil.py b/tornado/httputil.py index 3234803b0..bd32cd0c4 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -387,7 +387,9 @@ class HTTPServerRequest(object): def cookies(self) -> Dict[str, http.cookies.Morsel]: """A dictionary of ``http.cookies.Morsel`` objects.""" if not hasattr(self, "_cookies"): - self._cookies = http.cookies.SimpleCookie() + self._cookies = ( + http.cookies.SimpleCookie() + ) # type: http.cookies.SimpleCookie if "Cookie" in self.headers: try: parsed = parse_cookie(self.headers["Cookie"]) diff --git a/tornado/iostream.py b/tornado/iostream.py index 23ad0da3d..89d87a566 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -1131,7 +1131,7 @@ class IOStream(BaseIOStream): del data def connect( - self: _IOStreamType, address: tuple, server_hostname: Optional[str] = None + self: _IOStreamType, address: Any, server_hostname: Optional[str] = None ) -> "Future[_IOStreamType]": """Connects the socket to a remote address without blocking. diff --git a/tornado/netutil.py b/tornado/netutil.py index b309d67d1..6951b0f00 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -387,7 +387,7 @@ def _resolve_addr( results = [] for fam, socktype, proto, canonname, address in addrinfo: results.append((fam, address)) - return results + return results # type: ignore class DefaultExecutorResolver(Resolver): diff --git a/tornado/process.py b/tornado/process.py index 422365986..90f6bdd0d 100644 --- a/tornado/process.py +++ b/tornado/process.py @@ -55,7 +55,7 @@ def cpu_count() -> int: except NotImplementedError: pass try: - return os.sysconf("SC_NPROCESSORS_CONF") + return os.sysconf("SC_NPROCESSORS_CONF") # type: ignore except (AttributeError, ValueError): pass gen_log.error("Could not detect number of processors; assuming 1") @@ -117,6 +117,10 @@ def fork_processes( Availability: Unix """ + if sys.platform == "win32": + # The exact form of this condition matters to mypy; it understands + # if but not assert in this context. + raise Exception("fork not available on windows") if max_restarts is None: max_restarts = 100 @@ -349,7 +353,7 @@ class Subprocess(object): @classmethod def _try_cleanup_process(cls, pid: int) -> None: try: - ret_pid, status = os.waitpid(pid, os.WNOHANG) + ret_pid, status = os.waitpid(pid, os.WNOHANG) # type: ignore except ChildProcessError: return if ret_pid == 0: @@ -359,11 +363,14 @@ class Subprocess(object): subproc.io_loop.add_callback_from_signal(subproc._set_returncode, status) def _set_returncode(self, status: int) -> None: - if os.WIFSIGNALED(status): - self.returncode = -os.WTERMSIG(status) + if sys.platform == "win32": + self.returncode = -1 else: - assert os.WIFEXITED(status) - self.returncode = os.WEXITSTATUS(status) + if os.WIFSIGNALED(status): + self.returncode = -os.WTERMSIG(status) + else: + assert os.WIFEXITED(status) + self.returncode = os.WEXITSTATUS(status) # We've taken over wait() duty from the subprocess.Popen # object. If we don't inform it of the process's return code, # it will log a warning at destruction in python 3.6+. diff --git a/tornado/test/asyncio_test.py b/tornado/test/asyncio_test.py index aa9c2f9f1..3f9f3389a 100644 --- a/tornado/test/asyncio_test.py +++ b/tornado/test/asyncio_test.py @@ -181,7 +181,7 @@ class AnyThreadEventLoopPolicyTest(unittest.TestCase): self.assertIsInstance(self.executor.submit(accessor).result(), expected_type) # Clean up to silence leak warnings. Always use asyncio since # IOLoop doesn't (currently) close the underlying loop. - self.executor.submit(lambda: asyncio.get_event_loop().close()).result() + self.executor.submit(lambda: asyncio.get_event_loop().close()).result() # type: ignore def test_asyncio_accessor(self): self.run_policy_test(asyncio.get_event_loop, asyncio.AbstractEventLoop) diff --git a/tornado/test/auth_test.py b/tornado/test/auth_test.py index 7807ae56e..8de863eb2 100644 --- a/tornado/test/auth_test.py +++ b/tornado/test/auth_test.py @@ -41,7 +41,7 @@ class OpenIdClientLoginHandler(RequestHandler, OpenIdMixin): raise Exception("user is None") self.finish(user) return - res = self.authenticate_redirect() + res = self.authenticate_redirect() # type: ignore assert res is None @@ -131,7 +131,7 @@ class OAuth2ClientLoginHandler(RequestHandler, OAuth2Mixin): self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth2/server/authorize") def get(self): - res = self.authorize_redirect() + res = self.authorize_redirect() # type: ignore assert res is None @@ -152,7 +152,7 @@ class FacebookClientLoginHandler(RequestHandler, FacebookGraphMixin): ) self.write(user) else: - yield self.authorize_redirect( + self.authorize_redirect( redirect_uri=self.request.full_url(), client_id=self.settings["facebook_api_key"], extra_params={"scope": "read_stream,offline_access"}, @@ -547,7 +547,7 @@ class GoogleLoginHandler(RequestHandler, GoogleOAuth2Mixin): user["access_token"] = access["access_token"] self.write(user) else: - yield self.authorize_redirect( + self.authorize_redirect( redirect_uri=self._OAUTH_REDIRECT_URI, client_id=self.settings["google_oauth"]["key"], client_secret=self.settings["google_oauth"]["secret"], diff --git a/tornado/test/concurrent_test.py b/tornado/test/concurrent_test.py index 488b7ddd6..612a30cdf 100644 --- a/tornado/test/concurrent_test.py +++ b/tornado/test/concurrent_test.py @@ -16,6 +16,7 @@ from concurrent import futures import logging import re import socket +import typing import unittest from tornado.concurrent import ( @@ -98,6 +99,8 @@ class GeneratorCapClient(BaseCapClient): class ClientTestMixin(object): + client_class = None # type: typing.Callable + def setUp(self): super(ClientTestMixin, self).setUp() # type: ignore self.server = CapServer() @@ -109,19 +112,19 @@ class ClientTestMixin(object): self.server.stop() super(ClientTestMixin, self).tearDown() # type: ignore - def test_future(self): + def test_future(self: typing.Any): future = self.client.capitalize("hello") self.io_loop.add_future(future, self.stop) self.wait() self.assertEqual(future.result(), "HELLO") - def test_future_error(self): + def test_future_error(self: typing.Any): future = self.client.capitalize("HELLO") self.io_loop.add_future(future, self.stop) self.wait() - self.assertRaisesRegexp(CapError, "already capitalized", future.result) + self.assertRaisesRegexp(CapError, "already capitalized", future.result) # type: ignore - def test_generator(self): + def test_generator(self: typing.Any): @gen.coroutine def f(): result = yield self.client.capitalize("hello") @@ -129,7 +132,7 @@ class ClientTestMixin(object): self.io_loop.run_sync(f) - def test_generator_error(self): + def test_generator_error(self: typing.Any): @gen.coroutine def f(): with self.assertRaisesRegexp(CapError, "already capitalized"): diff --git a/tornado/test/http1connection_test.py b/tornado/test/http1connection_test.py index 023c02a30..159a6941b 100644 --- a/tornado/test/http1connection_test.py +++ b/tornado/test/http1connection_test.py @@ -1,4 +1,5 @@ import socket +import typing from tornado.http1connection import HTTP1Connection from tornado.httputil import HTTPMessageDelegate @@ -9,6 +10,8 @@ from tornado.testing import AsyncTestCase, bind_unused_port, gen_test class HTTP1ConnectionTest(AsyncTestCase): + code = None # type: typing.Optional[int] + def setUp(self): super(HTTP1ConnectionTest, self).setUp() self.asyncSetUp() diff --git a/tornado/test/httpclient_test.py b/tornado/test/httpclient_test.py index 11a4ee022..7b2a43c54 100644 --- a/tornado/test/httpclient_test.py +++ b/tornado/test/httpclient_test.py @@ -125,6 +125,7 @@ class AllMethodsHandler(RequestHandler): SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ("OTHER",) # type: ignore def method(self): + assert self.request.method is not None self.write(self.request.method) get = head = post = put = delete = options = patch = other = method # type: ignore @@ -177,6 +178,7 @@ class HTTPClientCommonTestCase(AsyncHTTPTestCase): self.assertEqual(response.code, 200) self.assertEqual(response.headers["Content-Type"], "text/plain") self.assertEqual(response.body, b"Hello world!") + assert response.request_time is not None self.assertEqual(int(response.request_time), 0) response = self.fetch("/hello?name=Ben") @@ -281,7 +283,7 @@ Transfer-Encoding: chunked # important thing is that they don't fall back to basic auth # on an unknown mode. with ExpectLog(gen_log, "uncaught exception", required=False): - with self.assertRaises((ValueError, HTTPError)): + with self.assertRaises((ValueError, HTTPError)): # type: ignore self.fetch( "/auth", auth_username="Aladdin", @@ -521,6 +523,8 @@ X-XSS-Protection: 1; def test_future_http_error(self): with self.assertRaises(HTTPError) as context: yield self.http_client.fetch(self.get_url("/notfound")) + assert context.exception is not None + assert context.exception.response is not None self.assertEqual(context.exception.code, 404) self.assertEqual(context.exception.response.code, 404) @@ -551,7 +555,7 @@ X-XSS-Protection: 1; response = yield self.http_client.fetch(request) self.assertEqual(response.code, 200) - with self.assertRaises((ValueError, HTTPError)) as context: + with self.assertRaises((ValueError, HTTPError)) as context: # type: ignore request = HTTPRequest(url, network_interface="not-interface-or-ip") yield self.http_client.fetch(request) self.assertIn("not-interface-or-ip", str(context.exception)) @@ -642,6 +646,7 @@ X-XSS-Protection: 1; self.assertLess(response.request_time, 1.0) # A very crude check to make sure that start_time is based on # wall time and not the monotonic clock. + assert response.start_time is not None self.assertLess(abs(response.start_time - start_time), 1.0) for k, v in response.time_info.items(): @@ -698,7 +703,7 @@ class RequestProxyTest(unittest.TestCase): class HTTPResponseTestCase(unittest.TestCase): def test_str(self): response = HTTPResponse( # type: ignore - HTTPRequest("http://example.com"), 200, headers={}, buffer=BytesIO() + HTTPRequest("http://example.com"), 200, buffer=BytesIO() ) s = str(response) self.assertTrue(s.startswith("HTTPResponse(")) diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 7a552d19c..63052ba12 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -73,6 +73,8 @@ async def read_stream_body(stream): class HandlerBaseTestCase(AsyncHTTPTestCase): + Handler = None + def get_app(self): return Application([("/", self.__class__.Handler)]) @@ -121,21 +123,21 @@ class SSLTestMixin(object): def get_ssl_version(self): raise NotImplementedError() - def test_ssl(self): + def test_ssl(self: typing.Any): response = self.fetch("/") self.assertEqual(response.body, b"Hello world") - def test_large_post(self): + def test_large_post(self: typing.Any): response = self.fetch("/", method="POST", body="A" * 5000) self.assertEqual(response.body, b"Got 5000 bytes in POST") - def test_non_ssl_request(self): + def test_non_ssl_request(self: typing.Any): # Make sure the server closes the connection when it gets a non-ssl # connection, rather than waiting for a timeout or otherwise # misbehaving. with ExpectLog(gen_log, "(SSL Error|uncaught exception)"): with ExpectLog(gen_log, "Uncaught exception", required=False): - with self.assertRaises((IOError, HTTPError)): + with self.assertRaises((IOError, HTTPError)): # type: ignore self.fetch( self.get_url("/").replace("https:", "http:"), request_timeout=3600, @@ -143,10 +145,10 @@ class SSLTestMixin(object): raise_error=True, ) - def test_error_logging(self): + def test_error_logging(self: typing.Any): # No stack traces are logged for SSL errors. with ExpectLog(gen_log, "SSL Error") as expect_log: - with self.assertRaises((IOError, HTTPError)): + with self.assertRaises((IOError, HTTPError)): # type: ignore self.fetch( self.get_url("/").replace("https:", "http:"), raise_error=True ) @@ -961,7 +963,7 @@ class KeepAliveTest(AsyncHTTPTestCase): self.close() -class GzipBaseTest(object): +class GzipBaseTest(AsyncHTTPTestCase): def get_app(self): return Application([("/", EchoHandler)]) @@ -1182,14 +1184,11 @@ class BodyLimitsTest(AsyncHTTPTestCase): self.bytes_read = 0 def prepare(self): + conn = typing.cast(HTTP1Connection, self.request.connection) if "expected_size" in self.request.arguments: - self.request.connection.set_max_body_size( - int(self.get_argument("expected_size")) - ) + conn.set_max_body_size(int(self.get_argument("expected_size"))) if "body_timeout" in self.request.arguments: - self.request.connection.set_body_timeout( - float(self.get_argument("body_timeout")) - ) + conn.set_body_timeout(float(self.get_argument("body_timeout"))) def data_received(self, data): self.bytes_read += len(data) diff --git a/tornado/test/ioloop_test.py b/tornado/test/ioloop_test.py index 293ea3562..cbf58e251 100644 --- a/tornado/test/ioloop_test.py +++ b/tornado/test/ioloop_test.py @@ -38,9 +38,9 @@ class TestIOLoop(AsyncTestCase): test.calls += 1 old_add_callback(callback, *args, **kwargs) - loop.add_callback = types.MethodType(add_callback, loop) - loop.add_callback(lambda: {}) - loop.add_callback(lambda: []) + loop.add_callback = types.MethodType(add_callback, loop) # type: ignore + loop.add_callback(lambda: {}) # type: ignore + loop.add_callback(lambda: []) # type: ignore loop.add_timeout(datetime.timedelta(milliseconds=50), loop.stop) loop.start() self.assertLess(self.calls, 10) @@ -161,7 +161,7 @@ class TestIOLoop(AsyncTestCase): self.io_loop.add_handler(client.fileno(), handler, IOLoop.READ) self.io_loop.add_timeout( - self.io_loop.time() + 0.01, functools.partial(server.send, b"asdf") + self.io_loop.time() + 0.01, functools.partial(server.send, b"asdf") # type: ignore ) self.wait() self.io_loop.remove_handler(client.fileno()) @@ -415,7 +415,7 @@ class TestIOLoop(AsyncTestCase): # automatically set as current. class TestIOLoopCurrent(unittest.TestCase): def setUp(self): - self.io_loop = None + self.io_loop = None # type: typing.Optional[IOLoop] IOLoop.clear_current() def tearDown(self): @@ -441,6 +441,7 @@ class TestIOLoopCurrent(unittest.TestCase): def f(): self.current_io_loop = IOLoop.current() + assert self.io_loop is not None self.io_loop.stop() self.io_loop.add_callback(f) diff --git a/tornado/test/iostream_test.py b/tornado/test/iostream_test.py index 5c1f73eab..d9e2c666b 100644 --- a/tornado/test/iostream_test.py +++ b/tornado/test/iostream_test.py @@ -30,6 +30,7 @@ import platform import random import socket import ssl +import typing from unittest import mock import unittest @@ -53,7 +54,7 @@ class TestIOStreamWebMixin(object): def get_app(self): return Application([("/", HelloHandler)]) - def test_connection_closed(self): + def test_connection_closed(self: typing.Any): # When a server sends a response and then closes the connection, # the client must be allowed to read the data before the IOStream # closes itself. Epoll reports closed connections with a separate @@ -64,7 +65,7 @@ class TestIOStreamWebMixin(object): response.rethrow() @gen_test - def test_read_until_close(self): + def test_read_until_close(self: typing.Any): stream = self._make_client_iostream() yield stream.connect(("127.0.0.1", self.get_http_port())) stream.write(b"GET / HTTP/1.0\r\n\r\n") @@ -74,7 +75,7 @@ class TestIOStreamWebMixin(object): self.assertTrue(data.endswith(b"Hello")) @gen_test - def test_read_zero_bytes(self): + def test_read_zero_bytes(self: typing.Any): self.stream = self._make_client_iostream() yield self.stream.connect(("127.0.0.1", self.get_http_port())) self.stream.write(b"GET / HTTP/1.0\r\n\r\n") @@ -94,7 +95,7 @@ class TestIOStreamWebMixin(object): self.stream.close() @gen_test - def test_write_while_connecting(self): + def test_write_while_connecting(self: typing.Any): stream = self._make_client_iostream() connect_fut = stream.connect(("127.0.0.1", self.get_http_port())) # unlike the previous tests, try to write before the connection @@ -116,7 +117,7 @@ class TestIOStreamWebMixin(object): stream.close() @gen_test - def test_future_interface(self): + def test_future_interface(self: typing.Any): """Basic test of IOStream's ability to return Futures.""" stream = self._make_client_iostream() connect_result = yield stream.connect(("127.0.0.1", self.get_http_port())) @@ -133,7 +134,7 @@ class TestIOStreamWebMixin(object): stream.close() @gen_test - def test_future_close_while_reading(self): + def test_future_close_while_reading(self: typing.Any): stream = self._make_client_iostream() yield stream.connect(("127.0.0.1", self.get_http_port())) yield stream.write(b"GET / HTTP/1.0\r\n\r\n") @@ -142,7 +143,7 @@ class TestIOStreamWebMixin(object): stream.close() @gen_test - def test_future_read_until_close(self): + def test_future_read_until_close(self: typing.Any): # Ensure that the data comes through before the StreamClosedError. stream = self._make_client_iostream() yield stream.connect(("127.0.0.1", self.get_http_port())) @@ -174,7 +175,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_future_delayed_close_callback(self): + def test_future_delayed_close_callback(self: typing.Any): # Same as test_delayed_close_callback, but with the future interface. rs, ws = yield self.make_iostream_pair() @@ -190,7 +191,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_close_buffered_data(self): + def test_close_buffered_data(self: typing.Any): # Similar to the previous test, but with data stored in the OS's # socket buffers instead of the IOStream's read buffer. Out-of-band # close notifications must be delayed until all data has been @@ -216,7 +217,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_until_close_after_close(self): + def test_read_until_close_after_close(self: typing.Any): # Similar to test_delayed_close_callback, but read_until_close takes # a separate code path so test it separately. rs, ws = yield self.make_iostream_pair() @@ -235,7 +236,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_large_read_until(self): + def test_large_read_until(self: typing.Any): # Performance test: read_until used to have a quadratic component # so a read_until of 4MB would take 8 seconds; now it takes 0.25 # seconds. @@ -260,7 +261,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_close_callback_with_pending_read(self): + def test_close_callback_with_pending_read(self: typing.Any): # Regression test for a bug that was introduced in 2.3 # where the IOStream._close_callback would never be called # if there were pending reads. @@ -284,7 +285,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_future_close_callback(self): + def test_future_close_callback(self: typing.Any): # Regression test for interaction between the Future read interfaces # and IOStream._maybe_add_error_listener. rs, ws = yield self.make_iostream_pair() @@ -309,7 +310,7 @@ class TestReadWriteMixin(object): ws.close() @gen_test - def test_write_memoryview(self): + def test_write_memoryview(self: typing.Any): rs, ws = yield self.make_iostream_pair() try: fut = rs.read_bytes(4) @@ -321,7 +322,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_bytes_partial(self): + def test_read_bytes_partial(self: typing.Any): rs, ws = yield self.make_iostream_pair() try: # Ask for more than is available with partial=True @@ -346,7 +347,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_until_max_bytes(self): + def test_read_until_max_bytes(self: typing.Any): rs, ws = yield self.make_iostream_pair() closed = Event() rs.set_close_callback(closed.set) @@ -374,7 +375,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_until_max_bytes_inline(self): + def test_read_until_max_bytes_inline(self: typing.Any): rs, ws = yield self.make_iostream_pair() closed = Event() rs.set_close_callback(closed.set) @@ -393,7 +394,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_until_max_bytes_ignores_extra(self): + def test_read_until_max_bytes_ignores_extra(self: typing.Any): rs, ws = yield self.make_iostream_pair() closed = Event() rs.set_close_callback(closed.set) @@ -410,7 +411,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_until_regex_max_bytes(self): + def test_read_until_regex_max_bytes(self: typing.Any): rs, ws = yield self.make_iostream_pair() closed = Event() rs.set_close_callback(closed.set) @@ -438,7 +439,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_until_regex_max_bytes_inline(self): + def test_read_until_regex_max_bytes_inline(self: typing.Any): rs, ws = yield self.make_iostream_pair() closed = Event() rs.set_close_callback(closed.set) @@ -473,7 +474,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_small_reads_from_large_buffer(self): + def test_small_reads_from_large_buffer(self: typing.Any): # 10KB buffer size, 100KB available to read. # Read 1KB at a time and make sure that the buffer is not eagerly # filled. @@ -488,7 +489,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_small_read_untils_from_large_buffer(self): + def test_small_read_untils_from_large_buffer(self: typing.Any): # 10KB buffer size, 100KB available to read. # Read 1KB at a time and make sure that the buffer is not eagerly # filled. @@ -521,7 +522,7 @@ class TestReadWriteMixin(object): ws.close() @gen_test - def test_read_into(self): + def test_read_into(self: typing.Any): rs, ws = yield self.make_iostream_pair() def sleep_some(): @@ -563,7 +564,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_into_partial(self): + def test_read_into_partial(self: typing.Any): rs, ws = yield self.make_iostream_pair() try: @@ -592,7 +593,7 @@ class TestReadWriteMixin(object): rs.close() @gen_test - def test_read_into_zero_bytes(self): + def test_read_into_zero_bytes(self: typing.Any): rs, ws = yield self.make_iostream_pair() try: buf = bytearray() @@ -661,7 +662,7 @@ class TestIOStreamMixin(TestReadWriteMixin): raise NotImplementedError() @gen.coroutine - def make_iostream_pair(self, **kwargs): + def make_iostream_pair(self: typing.Any, **kwargs): listener, port = bind_unused_port() server_stream_fut = Future() # type: Future[IOStream] @@ -679,7 +680,7 @@ class TestIOStreamMixin(TestReadWriteMixin): raise gen.Return((server_stream, client_stream)) @gen_test - def test_connection_refused(self): + def test_connection_refused(self: typing.Any): # When a connection is refused, the connect callback should not # be run. (The kqueue IOLoop used to behave differently from the # epoll IOLoop in this respect) @@ -696,7 +697,7 @@ class TestIOStreamMixin(TestReadWriteMixin): self.assertTrue(isinstance(stream.error, ConnectionRefusedError), stream.error) @gen_test - def test_gaierror(self): + def test_gaierror(self: typing.Any): # Test that IOStream sets its exc_info on getaddrinfo error. # It's difficult to reliably trigger a getaddrinfo error; # some resolvers own't even return errors for malformed names, @@ -713,7 +714,7 @@ class TestIOStreamMixin(TestReadWriteMixin): self.assertTrue(isinstance(stream.error, socket.gaierror)) @gen_test - def test_read_until_close_with_error(self): + def test_read_until_close_with_error(self: typing.Any): server, client = yield self.make_iostream_pair() try: with mock.patch( @@ -729,7 +730,7 @@ class TestIOStreamMixin(TestReadWriteMixin): @skipIfNonUnix @skipPypy3V58 @gen_test - def test_inline_read_error(self): + def test_inline_read_error(self: typing.Any): # An error on an inline read is raised without logging (on the # assumption that it will eventually be noticed or logged further # up the stack). @@ -867,7 +868,9 @@ class TestIOStreamStartTLS(AsyncTestCase): self.server_stream = None self.server_accepted = Future() # type: Future[None] netutil.add_accept_handler(self.listener, self.accept) - self.client_stream = IOStream(socket.socket()) + self.client_stream = IOStream( + socket.socket() + ) # type: typing.Optional[IOStream] self.io_loop.add_future( self.client_stream.connect(("127.0.0.1", self.port)), self.stop ) @@ -894,22 +897,28 @@ class TestIOStreamStartTLS(AsyncTestCase): @gen.coroutine def client_send_line(self, line): + assert self.client_stream is not None self.client_stream.write(line) + assert self.server_stream is not None recv_line = yield self.server_stream.read_until(b"\r\n") self.assertEqual(line, recv_line) @gen.coroutine def server_send_line(self, line): + assert self.server_stream is not None self.server_stream.write(line) + assert self.client_stream is not None recv_line = yield self.client_stream.read_until(b"\r\n") self.assertEqual(line, recv_line) def client_start_tls(self, ssl_options=None, server_hostname=None): + assert self.client_stream is not None client_stream = self.client_stream self.client_stream = None return client_stream.start_tls(False, ssl_options, server_hostname) def server_start_tls(self, ssl_options=None): + assert self.server_stream is not None server_stream = self.server_stream self.server_stream = None return server_stream.start_tls(True, ssl_options) diff --git a/tornado/test/netutil_test.py b/tornado/test/netutil_test.py index 32807e2ba..8ebc8e6ab 100644 --- a/tornado/test/netutil_test.py +++ b/tornado/test/netutil_test.py @@ -39,8 +39,10 @@ else: class _ResolverTestMixin(object): + resolver = None # type: typing.Any + @gen_test - def test_localhost(self): + def test_localhost(self: typing.Any): addrinfo = yield self.resolver.resolve("localhost", 80, socket.AF_UNSPEC) self.assertIn((socket.AF_INET, ("127.0.0.1", 80)), addrinfo) @@ -48,8 +50,10 @@ class _ResolverTestMixin(object): # It is impossible to quickly and consistently generate an error in name # resolution, so test this case separately, using mocks as needed. class _ResolverErrorTestMixin(object): + resolver = None # type: typing.Any + @gen_test - def test_bad_host(self): + def test_bad_host(self: typing.Any): with self.assertRaises(IOError): yield self.resolver.resolve("an invalid domain", 80, socket.AF_UNSPEC) diff --git a/tornado/test/queues_test.py b/tornado/test/queues_test.py index 8e527dbb3..98a29a8d0 100644 --- a/tornado/test/queues_test.py +++ b/tornado/test/queues_test.py @@ -101,8 +101,8 @@ class QueueGetTest(AsyncTestCase): def test_blocking_get_wait(self): q = queues.Queue() # type: queues.Queue[int] q.put(0) - self.io_loop.call_later(0.01, q.put, 1) - self.io_loop.call_later(0.02, q.put, 2) + self.io_loop.call_later(0.01, q.put_nowait, 1) + self.io_loop.call_later(0.02, q.put_nowait, 2) self.assertEqual(0, (yield q.get(timeout=timedelta(seconds=1)))) self.assertEqual(1, (yield q.get(timeout=timedelta(seconds=1)))) @@ -213,8 +213,12 @@ class QueuePutTest(AsyncTestCase): def test_blocking_put_wait(self): q = queues.Queue(1) # type: queues.Queue[int] q.put_nowait(0) - self.io_loop.call_later(0.01, q.get) - self.io_loop.call_later(0.02, q.get) + + def get_and_discard(): + q.get() + + self.io_loop.call_later(0.01, get_and_discard) + self.io_loop.call_later(0.02, get_and_discard) futures = [q.put(0), q.put(1)] self.assertFalse(any(f.done() for f in futures)) yield futures @@ -307,12 +311,12 @@ class QueueJoinTest(AsyncTestCase): queue_class = queues.Queue def test_task_done_underflow(self): - q = self.queue_class() + q = self.queue_class() # type: queues.Queue self.assertRaises(ValueError, q.task_done) @gen_test def test_task_done(self): - q = self.queue_class() + q = self.queue_class() # type: queues.Queue for i in range(100): q.put_nowait(i) @@ -335,9 +339,9 @@ class QueueJoinTest(AsyncTestCase): @gen_test def test_task_done_delay(self): # Verify it is task_done(), not get(), that unblocks join(). - q = self.queue_class() + q = self.queue_class() # type: queues.Queue q.put_nowait(0) - join = q.join() + join = asyncio.ensure_future(q.join()) self.assertFalse(join.done()) yield q.get() self.assertFalse(join.done()) @@ -348,13 +352,13 @@ class QueueJoinTest(AsyncTestCase): @gen_test def test_join_empty_queue(self): - q = self.queue_class() + q = self.queue_class() # type: queues.Queue yield q.join() yield q.join() @gen_test def test_join_timeout(self): - q = self.queue_class() + q = self.queue_class() # type: queues.Queue q.put(0) with self.assertRaises(TimeoutError): yield q.join(timeout=timedelta(seconds=0.01)) diff --git a/tornado/test/runtests.py b/tornado/test/runtests.py index 44cbacd4f..9156be701 100644 --- a/tornado/test/runtests.py +++ b/tornado/test/runtests.py @@ -69,13 +69,13 @@ def test_runner_factory(stderr): result = super(TornadoTextTestRunner, self).run(test) if result.skipped: skip_reasons = set(reason for (test, reason) in result.skipped) - self.stream.write( + self.stream.write( # type: ignore textwrap.fill( "Some tests were skipped because: %s" % ", ".join(sorted(skip_reasons)) ) ) - self.stream.write("\n") + self.stream.write("\n") # type: ignore return result return TornadoTextTestRunner diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index 2933ea50e..a883786dc 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -142,9 +142,14 @@ class RespondInPrepareHandler(RequestHandler): class SimpleHTTPClientTestMixin(object): - def get_app(self): + def create_client(self, **kwargs): + raise NotImplementedError() + + def get_app(self: typing.Any): # callable objects to finish pending /trigger requests - self.triggers = collections.deque() # type: typing.Deque[str] + self.triggers = ( + collections.deque() + ) # type: typing.Deque[typing.Callable[[], None]] return Application( [ url( @@ -170,7 +175,7 @@ class SimpleHTTPClientTestMixin(object): gzip=True, ) - def test_singleton(self): + def test_singleton(self: typing.Any): # Class "constructor" reuses objects on the same IOLoop self.assertTrue(SimpleAsyncHTTPClient() is SimpleAsyncHTTPClient()) # unless force_instance is used @@ -188,7 +193,7 @@ class SimpleHTTPClientTestMixin(object): client2 = io_loop2.run_sync(make_client) self.assertTrue(client1 is not client2) - def test_connection_limit(self): + def test_connection_limit(self: typing.Any): with closing(self.create_client(max_clients=2)) as client: self.assertEqual(client.max_clients, 2) seen = [] @@ -219,13 +224,13 @@ class SimpleHTTPClientTestMixin(object): self.assertEqual(len(self.triggers), 0) @gen_test - def test_redirect_connection_limit(self): + def test_redirect_connection_limit(self: typing.Any): # following redirects should not consume additional connections with closing(self.create_client(max_clients=1)) as client: response = yield client.fetch(self.get_url("/countdown/3"), max_redirects=3) response.rethrow() - def test_max_redirects(self): + def test_max_redirects(self: typing.Any): response = self.fetch("/countdown/5", max_redirects=3) self.assertEqual(302, response.code) # We requested 5, followed three redirects for 4, 3, 2, then the last @@ -234,14 +239,14 @@ class SimpleHTTPClientTestMixin(object): self.assertTrue(response.effective_url.endswith("/countdown/2")) self.assertTrue(response.headers["Location"].endswith("/countdown/1")) - def test_header_reuse(self): + def test_header_reuse(self: typing.Any): # Apps may reuse a headers object if they are only passing in constant # headers like user-agent. The header object should not be modified. headers = HTTPHeaders({"User-Agent": "Foo"}) self.fetch("/hello", headers=headers) self.assertEqual(list(headers.get_all()), [("User-Agent", "Foo")]) - def test_see_other_redirect(self): + def test_see_other_redirect(self: typing.Any): for code in (302, 303): response = self.fetch("/see_other_post", method="POST", body="%d" % code) self.assertEqual(200, response.code) @@ -252,7 +257,7 @@ class SimpleHTTPClientTestMixin(object): @skipOnTravis @gen_test - def test_connect_timeout(self): + def test_connect_timeout(self: typing.Any): timeout = 0.1 cleanup_event = Event() @@ -280,7 +285,7 @@ class SimpleHTTPClientTestMixin(object): yield gen.sleep(0.2) @skipOnTravis - def test_request_timeout(self): + def test_request_timeout(self: typing.Any): timeout = 0.1 if os.name == "nt": timeout = 0.5 @@ -292,7 +297,7 @@ class SimpleHTTPClientTestMixin(object): self.io_loop.run_sync(lambda: gen.sleep(0)) @skipIfNoIPv6 - def test_ipv6(self): + def test_ipv6(self: typing.Any): [sock] = bind_sockets(0, "::1", family=socket.AF_INET6) port = sock.getsockname()[1] self.http_server.add_socket(sock) @@ -305,7 +310,7 @@ class SimpleHTTPClientTestMixin(object): response = self.fetch(url) self.assertEqual(response.body, b"Hello world!") - def test_multiple_content_length_accepted(self): + def test_multiple_content_length_accepted(self: typing.Any): response = self.fetch("/content_length?value=2,2") self.assertEqual(response.body, b"ok") response = self.fetch("/content_length?value=2,%202,2") @@ -317,20 +322,20 @@ class SimpleHTTPClientTestMixin(object): with self.assertRaises(HTTPStreamClosedError): self.fetch("/content_length?value=2,%202,3", raise_error=True) - def test_head_request(self): + def test_head_request(self: typing.Any): response = self.fetch("/head", method="HEAD") self.assertEqual(response.code, 200) self.assertEqual(response.headers["content-length"], "7") self.assertFalse(response.body) - def test_options_request(self): + def test_options_request(self: typing.Any): response = self.fetch("/options", method="OPTIONS") self.assertEqual(response.code, 200) self.assertEqual(response.headers["content-length"], "2") self.assertEqual(response.headers["access-control-allow-origin"], "*") self.assertEqual(response.body, b"ok") - def test_no_content(self): + def test_no_content(self: typing.Any): response = self.fetch("/no_content") self.assertEqual(response.code, 204) # 204 status shouldn't have a content-length @@ -339,7 +344,7 @@ class SimpleHTTPClientTestMixin(object): # in HTTP204NoContentTestCase. self.assertNotIn("Content-Length", response.headers) - def test_host_header(self): + def test_host_header(self: typing.Any): host_re = re.compile(b"^127.0.0.1:[0-9]+$") response = self.fetch("/host_echo") self.assertTrue(host_re.match(response.body)) @@ -348,7 +353,7 @@ class SimpleHTTPClientTestMixin(object): response = self.fetch(url) self.assertTrue(host_re.match(response.body), response.body) - def test_connection_refused(self): + def test_connection_refused(self: typing.Any): cleanup_func, port = refusing_port() self.addCleanup(cleanup_func) with ExpectLog(gen_log, ".*", required=False): @@ -368,7 +373,7 @@ class SimpleHTTPClientTestMixin(object): expected_message = os.strerror(errno.ECONNREFUSED) self.assertTrue(expected_message in str(cm.exception), cm.exception) - def test_queue_timeout(self): + def test_queue_timeout(self: typing.Any): with closing(self.create_client(max_clients=1)) as client: # Wait for the trigger request to block, not complete. fut1 = client.fetch(self.get_url("/trigger"), request_timeout=10) @@ -384,7 +389,7 @@ class SimpleHTTPClientTestMixin(object): self.triggers.popleft()() self.io_loop.run_sync(lambda: fut1) - def test_no_content_length(self): + def test_no_content_length(self: typing.Any): response = self.fetch("/no_content_length") if response.body == b"HTTP/1 required": self.skipTest("requires HTTP/1.x") @@ -401,14 +406,14 @@ class SimpleHTTPClientTestMixin(object): yield gen.moment yield write(b"5678") - def test_sync_body_producer_chunked(self): + def test_sync_body_producer_chunked(self: typing.Any): response = self.fetch( "/echo_post", method="POST", body_producer=self.sync_body_producer ) response.rethrow() self.assertEqual(response.body, b"12345678") - def test_sync_body_producer_content_length(self): + def test_sync_body_producer_content_length(self: typing.Any): response = self.fetch( "/echo_post", method="POST", @@ -418,14 +423,14 @@ class SimpleHTTPClientTestMixin(object): response.rethrow() self.assertEqual(response.body, b"12345678") - def test_async_body_producer_chunked(self): + def test_async_body_producer_chunked(self: typing.Any): response = self.fetch( "/echo_post", method="POST", body_producer=self.async_body_producer ) response.rethrow() self.assertEqual(response.body, b"12345678") - def test_async_body_producer_content_length(self): + def test_async_body_producer_content_length(self: typing.Any): response = self.fetch( "/echo_post", method="POST", @@ -435,7 +440,7 @@ class SimpleHTTPClientTestMixin(object): response.rethrow() self.assertEqual(response.body, b"12345678") - def test_native_body_producer_chunked(self): + def test_native_body_producer_chunked(self: typing.Any): async def body_producer(write): await write(b"1234") import asyncio @@ -447,7 +452,7 @@ class SimpleHTTPClientTestMixin(object): response.rethrow() self.assertEqual(response.body, b"12345678") - def test_native_body_producer_content_length(self): + def test_native_body_producer_content_length(self: typing.Any): async def body_producer(write): await write(b"1234") import asyncio @@ -464,13 +469,13 @@ class SimpleHTTPClientTestMixin(object): response.rethrow() self.assertEqual(response.body, b"12345678") - def test_100_continue(self): + def test_100_continue(self: typing.Any): response = self.fetch( "/echo_post", method="POST", body=b"1234", expect_100_continue=True ) self.assertEqual(response.body, b"1234") - def test_100_continue_early_response(self): + def test_100_continue_early_response(self: typing.Any): def body_producer(write): raise Exception("should not be called") @@ -482,7 +487,7 @@ class SimpleHTTPClientTestMixin(object): ) self.assertEqual(response.code, 403) - def test_streaming_follow_redirects(self): + def test_streaming_follow_redirects(self: typing.Any): # When following redirects, header and streaming callbacks # should only be called for the final result. # TODO(bdarnell): this test belongs in httpclient_test instead of diff --git a/tornado/test/tcpclient_test.py b/tornado/test/tcpclient_test.py index ab08cbf57..b6105e0eb 100644 --- a/tornado/test/tcpclient_test.py +++ b/tornado/test/tcpclient_test.py @@ -93,6 +93,7 @@ class TCPClientTest(AsyncTestCase): stream = yield self.client.connect( host, port, source_ip=source_ip, source_port=source_port ) + assert self.server is not None server_stream = yield self.server.queue.get() with closing(stream): stream.write(b"hello") @@ -208,8 +209,8 @@ class ConnectorTest(AsyncTestCase): super(ConnectorTest, self).setUp() self.connect_futures = ( {} - ) # type: Dict[Tuple[int, Tuple], Future[ConnectorTest.FakeStream]] - self.streams = {} # type: Dict[Tuple, ConnectorTest.FakeStream] + ) # type: Dict[Tuple[int, typing.Any], Future[ConnectorTest.FakeStream]] + self.streams = {} # type: Dict[typing.Any, ConnectorTest.FakeStream] self.addrinfo = [(AF1, "a"), (AF1, "b"), (AF2, "c"), (AF2, "d")] def tearDown(self): diff --git a/tornado/test/testing_test.py b/tornado/test/testing_test.py index 03b3401aa..594d4af2f 100644 --- a/tornado/test/testing_test.py +++ b/tornado/test/testing_test.py @@ -343,7 +343,7 @@ class GetNewIOLoopTest(AsyncTestCase): self.new_loop.close() def test_loop(self): - self.assertIs(self.io_loop.asyncio_loop, self.new_loop) + self.assertIs(self.io_loop.asyncio_loop, self.new_loop) # type: ignore if __name__ == "__main__": diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 7c1322e0b..76a1d6210 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -85,6 +85,8 @@ class SimpleHandlerTestCase(WebTestCase): To use, define a nested class named ``Handler``. """ + Handler = None + def get_handlers(self): return [("/", self.Handler)] @@ -100,9 +102,11 @@ class CookieTestRequestHandler(RequestHandler): # don't call super.__init__ self._cookies = {} # type: typing.Dict[str, bytes] if key_version is None: - self.application = ObjectDict(settings=dict(cookie_secret=cookie_secret)) + self.application = ObjectDict( # type: ignore + settings=dict(cookie_secret=cookie_secret) + ) else: - self.application = ObjectDict( + self.application = ObjectDict( # type: ignore settings=dict(cookie_secret=cookie_secret, key_version=key_version) ) @@ -215,6 +219,8 @@ class SecureCookieV2Test(unittest.TestCase): class FinalReturnTest(WebTestCase): + final_return = None # type: Future + def get_handlers(self): test = self @@ -273,7 +279,9 @@ class CookieTest(WebTestCase): class GetCookieHandler(RequestHandler): def get(self): - self.write(self.get_cookie("foo", "default")) + cookie = self.get_cookie("foo", "default") + assert cookie is not None + self.write(cookie) class SetCookieDomainHandler(RequestHandler): def get(self): @@ -385,6 +393,7 @@ class CookieTest(WebTestCase): def test_set_cookie_expires_days(self): response = self.fetch("/set_expires_days") header = response.headers.get("Set-Cookie") + assert header is not None match = re.match("foo=bar; expires=(?P.+); Path=/", header) assert match is not None @@ -492,12 +501,12 @@ class EchoHandler(RequestHandler): for key in self.request.arguments: if type(key) != str: raise Exception("incorrect type for key: %r" % type(key)) - for value in self.request.arguments[key]: - if type(value) != bytes: - raise Exception("incorrect type for value: %r" % type(value)) - for value in self.get_arguments(key): - if type(value) != unicode_type: - raise Exception("incorrect type for value: %r" % type(value)) + for bvalue in self.request.arguments[key]: + if type(bvalue) != bytes: + raise Exception("incorrect type for value: %r" % type(bvalue)) + for svalue in self.get_arguments(key): + if type(svalue) != unicode_type: + raise Exception("incorrect type for value: %r" % type(svalue)) for arg in path_args: if type(arg) != unicode_type: raise Exception("incorrect type for path arg: %r" % type(arg)) @@ -649,7 +658,7 @@ class MultiHeaderHandler(RequestHandler): class RedirectHandler(RequestHandler): def get(self): if self.get_argument("permanent", None) is not None: - self.redirect("/", permanent=int(self.get_argument("permanent"))) + self.redirect("/", permanent=bool(int(self.get_argument("permanent")))) elif self.get_argument("status", None) is not None: self.redirect("/", status=int(self.get_argument("status"))) else: @@ -689,7 +698,7 @@ class GetArgumentHandler(RequestHandler): elif self.get_argument("source", None) == "body": method = self.get_body_argument else: - method = self.get_argument + method = self.get_argument # type: ignore self.finish(method("foo", "default")) @@ -1060,7 +1069,7 @@ class StaticFileTest(WebTestCase): def get_handlers(self): class StaticUrlHandler(RequestHandler): def get(self, path): - with_v = int(self.get_argument("include_version", 1)) + with_v = int(self.get_argument("include_version", "1")) self.write(self.static_url(path, include_version=with_v)) class AbsoluteStaticUrlHandler(StaticUrlHandler): @@ -1644,7 +1653,8 @@ class StatusReasonTest(SimpleHandlerTestCase): def get(self): reason = self.request.arguments.get("reason", []) self.set_status( - int(self.get_argument("code")), reason=reason[0] if reason else None + int(self.get_argument("code")), + reason=to_unicode(reason[0]) if reason else None, ) def get_http_client(self): @@ -1909,7 +1919,7 @@ class UIMethodUIModuleTest(SimpleHandlerTestCase): def render(self, x): return "In MyModule(%s) with handler value %s." % ( x, - self.handler.value(), + typing.cast(UIMethodUIModuleTest.Handler, self.handler).value(), ) loader = DictLoader( @@ -2100,6 +2110,7 @@ class UnimplementedNonStandardMethodsTest(SimpleHandlerTestCase): class AllHTTPMethodsTest(SimpleHandlerTestCase): class Handler(RequestHandler): def method(self): + assert self.request.method is not None self.write(self.request.method) get = delete = options = post = put = method # type: ignore @@ -2359,7 +2370,7 @@ class BaseStreamingRequestFlowControlTest(object): return SimpleAsyncHTTPClient() # Test all the slightly different code paths for fixed, chunked, etc bodies. - def test_flow_control_fixed_body(self): + def test_flow_control_fixed_body(self: typing.Any): response = self.fetch("/", body="abcdefghijklmnopqrstuvwxyz", method="POST") response.rethrow() self.assertEqual( @@ -2375,7 +2386,7 @@ class BaseStreamingRequestFlowControlTest(object): ), ) - def test_flow_control_chunked_body(self): + def test_flow_control_chunked_body(self: typing.Any): chunks = [b"abcd", b"efgh", b"ijkl"] @gen.coroutine @@ -2398,7 +2409,7 @@ class BaseStreamingRequestFlowControlTest(object): ), ) - def test_flow_control_compressed_body(self): + def test_flow_control_compressed_body(self: typing.Any): bytesio = BytesIO() gzip_file = gzip.GzipFile(mode="w", fileobj=bytesio) gzip_file.write(b"abcdefghijklmnopqrstuvwxyz") @@ -2520,14 +2531,14 @@ class ClientCloseTest(SimpleHandlerTestCase): # server should respond gracefully (without logging errors # because we were unable to write out as many bytes as # Content-Length said we would) - self.request.connection.stream.close() + self.request.connection.stream.close() # type: ignore self.write("hello") else: # TODO: add a HTTP2-compatible version of this test. self.write("requires HTTP/1.x") def test_client_close(self): - with self.assertRaises((HTTPClientError, unittest.SkipTest)): + with self.assertRaises((HTTPClientError, unittest.SkipTest)): # type: ignore response = self.fetch("/", raise_error=True) if response.body == b"requires HTTP/1.x": self.skipTest("requires HTTP/1.x") @@ -2922,6 +2933,7 @@ class XSRFCookieKwargsTest(SimpleHandlerTestCase): self.assertIn("httponly;", response.headers["Set-Cookie"].lower()) self.assertIn("expires=", response.headers["Set-Cookie"].lower()) header = response.headers.get("Set-Cookie") + assert header is not None match = re.match(".*; expires=(?P.+);.*", header) assert match is not None diff --git a/tornado/test/websocket_test.py b/tornado/test/websocket_test.py index d4b7a7412..3c1134204 100644 --- a/tornado/test/websocket_test.py +++ b/tornado/test/websocket_test.py @@ -1,6 +1,7 @@ import asyncio import functools import traceback +import typing import unittest from tornado.concurrent import Future @@ -88,7 +89,7 @@ class HeaderHandler(TestWebSocketHandler): try: # In a websocket context, many RequestHandler methods # raise RuntimeErrors. - method() + method() # type: ignore raise Exception("did not get expected exception") except RuntimeError: pass @@ -639,8 +640,11 @@ class CompressionTestMixin(object): def get_client_compression_options(self): return None + def verify_wire_bytes(self, bytes_in: int, bytes_out: int) -> None: + raise NotImplementedError() + @gen_test - def test_message_sizes(self): + def test_message_sizes(self: typing.Any): ws = yield self.ws_connect( "/echo", compression_options=self.get_client_compression_options() ) @@ -655,7 +659,7 @@ class CompressionTestMixin(object): self.verify_wire_bytes(ws.protocol._wire_bytes_in, ws.protocol._wire_bytes_out) @gen_test - def test_size_limit(self): + def test_size_limit(self: typing.Any): ws = yield self.ws_connect( "/limited", compression_options=self.get_client_compression_options() ) @@ -673,7 +677,7 @@ class CompressionTestMixin(object): class UncompressedTestMixin(CompressionTestMixin): """Specialization of CompressionTestMixin when we expect no compression.""" - def verify_wire_bytes(self, bytes_in, bytes_out): + def verify_wire_bytes(self: typing.Any, bytes_in, bytes_out): # Bytes out includes the 4-byte mask key per message. self.assertEqual(bytes_out, 3 * (len(self.MESSAGE) + 6)) self.assertEqual(bytes_in, 3 * (len(self.MESSAGE) + 2)) @@ -710,7 +714,10 @@ class DefaultCompressionTest(CompressionTestMixin, WebSocketBaseTestCase): class MaskFunctionMixin(object): # Subclasses should define self.mask(mask, data) - def test_mask(self): + def mask(self, mask: bytes, data: bytes) -> bytes: + raise NotImplementedError() + + def test_mask(self: typing.Any): self.assertEqual(self.mask(b"abcd", b""), b"") self.assertEqual(self.mask(b"abcd", b"b"), b"\x03") self.assertEqual(self.mask(b"abcd", b"54321"), b"TVPVP") diff --git a/tornado/testing.py b/tornado/testing.py index 551af60aa..da275cbce 100644 --- a/tornado/testing.py +++ b/tornado/testing.py @@ -293,7 +293,7 @@ class AsyncTestCase(unittest.TestCase): self, condition: Optional[Callable[..., bool]] = None, timeout: Optional[float] = None, - ) -> None: + ) -> Any: """Runs the `.IOLoop` until stop is called or timeout has passed. In the event of a timeout, an exception will be thrown. The diff --git a/tornado/web.py b/tornado/web.py index 47a739ba0..ccf9fbd81 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -624,7 +624,9 @@ class RequestHandler(object): # Don't let us accidentally inject bad stuff raise ValueError("Invalid cookie %r: %r" % (name, value)) if not hasattr(self, "_new_cookie"): - self._new_cookie = http.cookies.SimpleCookie() + self._new_cookie = ( + http.cookies.SimpleCookie() + ) # type: http.cookies.SimpleCookie if name in self._new_cookie: del self._new_cookie[name] self._new_cookie[name] = value @@ -1784,11 +1786,11 @@ class RequestHandler(object): args = [value.status_code, self._request_summary()] + list(value.args) gen_log.warning(format, *args) else: - app_log.error( # type: ignore + app_log.error( "Uncaught exception %s\n%r", self._request_summary(), self.request, - exc_info=(typ, value, tb), + exc_info=(typ, value, tb), # type: ignore ) def _ui_module(self, name: str, module: Type["UIModule"]) -> Callable[..., str]: @@ -1927,8 +1929,8 @@ class _ApplicationRouter(ReversibleRuleRouter): rule = super(_ApplicationRouter, self).process_rule(rule) if isinstance(rule.target, (list, tuple)): - rule.target = _ApplicationRouter( # type: ignore - self.application, rule.target + rule.target = _ApplicationRouter( + self.application, rule.target # type: ignore ) return rule diff --git a/tornado/websocket.py b/tornado/websocket.py index bbf81312d..93ceedb66 100644 --- a/tornado/websocket.py +++ b/tornado/websocket.py @@ -280,8 +280,6 @@ class WebSocketHandler(tornado.web.RequestHandler): self.set_status(426, "Upgrade Required") self.set_header("Sec-WebSocket-Version", "7, 8, 13") - stream = None - @property def ping_interval(self) -> Optional[float]: """The interval for websocket keep-alive pings. diff --git a/tox.ini b/tox.ini index 6fad80def..7a9feeee2 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ deps = docs: -r{toxinidir}/docs/requirements.txt lint: flake8 lint: black==19.10b0 - lint: mypy==0.701 + lint: mypy==0.740 setenv = # Treat the extension as mandatory in testing (but not on pypy) -- 2.47.2