From: Ben Darnell Date: Sat, 21 Jul 2018 17:05:53 +0000 (-0400) Subject: *: Add mypy tox config and get it passing X-Git-Tag: v6.0.0b1~39^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb5bab79deb4266b8e390d120f09e7298f572f4d;p=thirdparty%2Ftornado.git *: Add mypy tox config and get it passing Touch up the old annotations; it's simpler now that we're 3.5+. But most of the additions here are type:ignore comments. --- diff --git a/.travis.yml b/.travis.yml index af41517c6..71ef19382 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,7 @@ install: # version supported. But Python 3.7 requires slower-to-start VMs, # so we run it on 3.6 to minimize total CI run time. - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then travis_retry pip install sphinx sphinx_rtd_theme; fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then travis_retry pip install flake8; fi + - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then travis_retry pip install flake8 mypy; fi # On travis the extension should always be built - if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then export TORNADO_EXTENSION=1; fi - travis_retry python setup.py install @@ -91,9 +91,10 @@ script: # make coverage reports for Codecov to find - if [[ "$RUN_COVERAGE" == 1 ]]; then coverage xml; fi - export TORNADO_EXTENSION=0 - - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then cd ../docs && mkdir sphinx-out && sphinx-build -E -n -W -b html . sphinx-out; fi - - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then cd ../docs && mkdir sphinx-doctest-out && sphinx-build -E -n -b doctest . sphinx-out; fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then cd .. && flake8; fi + - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then (cd ../docs && mkdir sphinx-out && sphinx-build -E -n -W -b html . sphinx-out); fi + - if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then (cd ../docs && mkdir sphinx-doctest-out && sphinx-build -E -n -b doctest . sphinx-out); fi + - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then (cd .. && flake8); fi + - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then (cd .. && mypy tornado); fi after_success: # call codecov from project root diff --git a/tornado/autoreload.py b/tornado/autoreload.py index 01951fccf..c973fdd65 100644 --- a/tornado/autoreload.py +++ b/tornado/autoreload.py @@ -93,7 +93,7 @@ from tornado.util import exec_in try: import signal except ImportError: - signal = None + signal = None # type: ignore # os.execv is broken on Windows and can't properly parse command line # arguments and executable name if they contain whitespaces. subprocess diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 51dbe4540..51b5dd1e4 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -45,6 +45,8 @@ from tornado.concurrent import Future, is_future, chain_future, future_set_exc_i from tornado.log import app_log from tornado.util import Configurable, TimeoutError, unicode_type, import_object +import typing # noqa + class IOLoop(Configurable): """A level-triggered I/O loop. @@ -135,7 +137,7 @@ class IOLoop(Configurable): ERROR = 0x018 # In Python 3, _ioloop_for_asyncio maps from asyncio loops to IOLoops. - _ioloop_for_asyncio = dict() + _ioloop_for_asyncio = dict() # type: typing.Dict[typing.Any, typing.Any] @classmethod def configure(cls, impl, **kwargs): diff --git a/tornado/iostream.py b/tornado/iostream.py index ba8284f3f..514c36f50 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -42,7 +42,7 @@ from tornado.util import errno_from_exception try: from tornado.platform.posix import _set_nonblocking except ImportError: - _set_nonblocking = None + _set_nonblocking = None # type: ignore # These errnos indicate that a non-blocking operation must be retried # at a later time. On most platforms they're the same value, but on diff --git a/tornado/log.py b/tornado/log.py index c0171ba16..46fcfde13 100644 --- a/tornado/log.py +++ b/tornado/log.py @@ -35,14 +35,14 @@ from tornado.escape import _unicode from tornado.util import unicode_type, basestring_type try: - import colorama + import colorama # type: ignore except ImportError: colorama = None try: import curses # type: ignore except ImportError: - curses = None + curses = None # type: ignore # Logger objects for internal tornado use access_log = logging.getLogger("tornado.access") diff --git a/tornado/platform/asyncio.py b/tornado/platform/asyncio.py index b139c9002..9211e2146 100644 --- a/tornado/platform/asyncio.py +++ b/tornado/platform/asyncio.py @@ -268,7 +268,7 @@ def to_asyncio_future(tornado_future): return convert_yielded(tornado_future) -class AnyThreadEventLoopPolicy(asyncio.DefaultEventLoopPolicy): +class AnyThreadEventLoopPolicy(asyncio.DefaultEventLoopPolicy): # type: ignore """Event loop policy that allows loop creation on any thread. The default `asyncio` event loop policy only automatically creates diff --git a/tornado/platform/windows.py b/tornado/platform/windows.py index 274937f86..86293a908 100644 --- a/tornado/platform/windows.py +++ b/tornado/platform/windows.py @@ -1,11 +1,11 @@ # NOTE: win32 support is currently experimental, and not recommended # for production use. -import ctypes # type: ignore -import ctypes.wintypes # type: ignore +import ctypes +import ctypes.wintypes # See: http://msdn.microsoft.com/en-us/library/ms724935(VS.85).aspx -SetHandleInformation = ctypes.windll.kernel32.SetHandleInformation +SetHandleInformation = ctypes.windll.kernel32.SetHandleInformation # type: ignore SetHandleInformation.argtypes = (ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD) # noqa: E501 SetHandleInformation.restype = ctypes.wintypes.BOOL diff --git a/tornado/routing.py b/tornado/routing.py index 8122faf5b..2af2fcad5 100644 --- a/tornado/routing.py +++ b/tornado/routing.py @@ -373,7 +373,7 @@ class ReversibleRuleRouter(ReversibleRouter, RuleRouter): """ def __init__(self, rules=None): - self.named_rules = {} # type: typing.Dict[str] + self.named_rules = {} # type: typing.Dict[str, Any] super(ReversibleRuleRouter, self).__init__(rules) def process_rule(self, rule): diff --git a/tornado/test/httpclient_test.py b/tornado/test/httpclient_test.py index 578f1f39d..4b4e3b538 100644 --- a/tornado/test/httpclient_test.py +++ b/tornado/test/httpclient_test.py @@ -103,7 +103,7 @@ class PatchHandler(RequestHandler): class AllMethodsHandler(RequestHandler): - SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ('OTHER',) + SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ('OTHER',) # type: ignore def method(self): self.write(self.request.method) diff --git a/tornado/test/routing_test.py b/tornado/test/routing_test.py index 722662555..158156082 100644 --- a/tornado/test/routing_test.py +++ b/tornado/test/routing_test.py @@ -16,6 +16,8 @@ from tornado.testing import AsyncHTTPTestCase from tornado.web import Application, HTTPError, RequestHandler from tornado.wsgi import WSGIContainer +import typing # noqa + class BasicRouter(Router): def find_handler(self, request, **kwargs): @@ -44,7 +46,7 @@ class BasicRouterTestCase(AsyncHTTPTestCase): self.assertEqual(response.body, b"OK") -resources = {} +resources = {} # type: typing.Dict[str, bytes] class GetResource(RequestHandler): diff --git a/tornado/test/twisted_test.py b/tornado/test/twisted_test.py index 5d90272a8..1d8d10ef2 100644 --- a/tornado/test/twisted_test.py +++ b/tornado/test/twisted_test.py @@ -33,7 +33,7 @@ from tornado.web import RequestHandler, Application try: from twisted.internet.defer import Deferred, inlineCallbacks, returnValue # type: ignore from twisted.internet.protocol import Protocol # type: ignore - from twisted.internet.asyncioreactor import AsyncioSelectorReactor + from twisted.internet.asyncioreactor import AsyncioSelectorReactor # type: ignore from twisted.web.client import Agent, readBody # type: ignore from twisted.web.resource import Resource # type: ignore from twisted.web.server import Site # type: ignore diff --git a/tornado/test/util.py b/tornado/test/util.py index 60e787b7d..81012c28f 100644 --- a/tornado/test/util.py +++ b/tornado/test/util.py @@ -30,7 +30,7 @@ skipNotCPython = unittest.skipIf(platform.python_implementation() != 'CPython', # TODO: remove this after pypy3 5.8 is obsolete. skipPypy3V58 = unittest.skipIf(platform.python_implementation() == 'PyPy' and sys.version_info > (3,) and - sys.pypy_version_info < (5, 9), + sys.pypy_version_info < (5, 9), # type: ignore 'pypy3 5.8 has buggy ssl module') diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index cb1ab353c..6d79f0560 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -1938,7 +1938,7 @@ class AllHTTPMethodsTest(SimpleHandlerTestCase): class PatchMethodTest(SimpleHandlerTestCase): class Handler(RequestHandler): - SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ('OTHER',) + SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ('OTHER',) # type: ignore def patch(self): self.write('patch') diff --git a/tornado/test/websocket_test.py b/tornado/test/websocket_test.py index 23dc2805d..ed0254317 100644 --- a/tornado/test/websocket_test.py +++ b/tornado/test/websocket_test.py @@ -30,7 +30,7 @@ from tornado.websocket import ( try: from tornado import speedups except ImportError: - speedups = None + speedups = None # type: ignore class TestWebSocketHandler(WebSocketHandler): diff --git a/tornado/util.py b/tornado/util.py index e2802ac1d..be86e013c 100644 --- a/tornado/util.py +++ b/tornado/util.py @@ -24,24 +24,15 @@ bytes_type = bytes unicode_type = str basestring_type = str -try: - import typing # noqa - from typing import cast - - _ObjectDictBase = typing.Dict[str, typing.Any] -except ImportError: - _ObjectDictBase = dict +import typing - def cast(typ, x): - return x -else: - # More imports that are only needed in type comments. - import datetime # noqa - import types # noqa - from typing import Any, AnyStr, Union, Optional, Dict, Mapping # noqa - from typing import Tuple, Match, Callable # noqa +# More imports that are only needed in type annotations. +import datetime # noqa +import types +from typing import Any, AnyStr, Union, Optional, Dict, Mapping, List # noqa +from typing import Tuple, Match, Callable # noqa - _BaseString = str +_BaseString = str try: from sys import is_finalizing @@ -70,7 +61,7 @@ class TimeoutError(Exception): """ -class ObjectDict(_ObjectDictBase): +class ObjectDict(typing.Dict[str, typing.Any]): """Makes a dictionary behave like an object, with attribute-style access. """ def __getattr__(self, name): @@ -151,10 +142,10 @@ def import_object(name): # on python 2 a byte string is required. name = name.encode('utf-8') if name.count('.') == 0: - return __import__(name, None, None) + return __import__(name) parts = name.split('.') - obj = __import__('.'.join(parts[:-1]), None, None, [parts[-1]], 0) + obj = __import__('.'.join(parts[:-1]), fromlist=[parts[-1]]) try: return getattr(obj, parts[-1]) except AttributeError: @@ -170,10 +161,10 @@ def exec_in(code, glob, loc=None): exec(code, glob, loc) -def raise_exc_info(exc_info): - # type: (Tuple[type, BaseException, types.TracebackType]) -> None +def raise_exc_info(exc_info: Optional[Tuple[type, BaseException, types.TracebackType]]) -> None: try: - raise exc_info[1].with_traceback(exc_info[2]) + if exc_info is not None: + raise exc_info[1].with_traceback(exc_info[2]) finally: exc_info = None @@ -356,7 +347,7 @@ class ArgReplacer(object): # type: (Callable, str) -> None self.name = name try: - self.arg_pos = self._getargnames(func).index(name) + self.arg_pos = self._getargnames(func).index(name) # type: Optional[int] except ValueError: # Not a positional parameter self.arg_pos = None diff --git a/tox.ini b/tox.ini index 84c631ce9..ee44788e9 100644 --- a/tox.ini +++ b/tox.ini @@ -38,6 +38,7 @@ envlist = py3-sphinx-doctest, py3-lint + py3-mypy [testenv] # Most of these are defaults, but if you specify any you can't fall back @@ -125,3 +126,8 @@ commands = [testenv:py3-lint] commands = flake8 {posargs:} changedir = {toxinidir} + +[testenv:py3-mypy] +commands = mypy {posargs:tornado} +changedir = {toxinidir} +deps = mypy