From: Ben Darnell Date: Sat, 16 Jan 2016 22:07:48 +0000 (-0500) Subject: Move towards mypy-friendly patterns. X-Git-Tag: v4.4.0b1~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b22da52c781d4d03e57f3674afa0d1473f06a33b;p=thirdparty%2Ftornado.git Move towards mypy-friendly patterns. This change eliminates warnings in several of Tornado's lower-level modules (although there's not much actual type checking yet). --- diff --git a/tornado/concurrent.py b/tornado/concurrent.py index 5f8cdc414..42ab08034 100644 --- a/tornado/concurrent.py +++ b/tornado/concurrent.py @@ -38,6 +38,11 @@ try: except ImportError: futures = None +try: + import typing +except ImportError: + typing = None + # Can the garbage collector handle cycles that include __del__ methods? # This is true in cpython beginning with version 3.4 (PEP 442). @@ -338,7 +343,7 @@ class Future(object): TracebackFuture = Future if futures is None: - FUTURES = Future + FUTURES = Future # type: typing.Union[type, typing.Tuple[type, ...]] else: FUTURES = (futures.Future, Future) diff --git a/tornado/escape.py b/tornado/escape.py index 23cc9cde4..c8d062867 100644 --- a/tornado/escape.py +++ b/tornado/escape.py @@ -22,32 +22,22 @@ have crept in over time. from __future__ import absolute_import, division, print_function, with_statement +import json import re import sys -from tornado.util import unicode_type, basestring_type - -try: - from urllib.parse import parse_qs as _parse_qs # py3 -except ImportError: - from urlparse import parse_qs as _parse_qs # Python 2.6+ - -try: - import htmlentitydefs # py2 -except ImportError: - import html.entities as htmlentitydefs # py3 - -try: - import urllib.parse as urllib_parse # py3 -except ImportError: - import urllib as urllib_parse # py2 +from tornado.util import PY3, unicode_type, basestring_type -import json - -try: - unichr -except NameError: +if PY3: + from urllib.parse import parse_qs as _parse_qs + import html.entities as htmlentitydefs + import urllib.parse as urllib_parse unichr = chr +else: + from urlparse import parse_qs as _parse_qs + import htmlentitydefs + import urllib as urllib_parse + _XHTML_ESCAPE_RE = re.compile('[&<>"\']') _XHTML_ESCAPE_DICT = {'&': '&', '<': '<', '>': '>', '"': '"', @@ -116,7 +106,7 @@ def url_escape(value, plus=True): # python 3 changed things around enough that we need two separate # implementations of url_unescape. We also need our own implementation # of parse_qs since python 3's version insists on decoding everything. -if sys.version_info[0] < 3: +if not PY3: def url_unescape(value, encoding='utf-8', plus=True): """Decodes the given value from a URL. diff --git a/tornado/gen.py b/tornado/gen.py index bf184e548..29e8cb50b 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -88,7 +88,7 @@ from tornado.concurrent import Future, TracebackFuture, is_future, chain_future from tornado.ioloop import IOLoop from tornado.log import app_log from tornado import stack_context -from tornado.util import raise_exc_info +from tornado.util import PY3, raise_exc_info try: try: @@ -124,9 +124,9 @@ except ImportError: def isawaitable(x): return False -try: - import builtins # py3 -except ImportError: +if PY3: + import builtins +else: import __builtin__ as builtins diff --git a/tornado/ioloop.py b/tornado/ioloop.py index c23cb33e4..c3aeced2a 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -45,20 +45,20 @@ import math from tornado.concurrent import TracebackFuture, is_future from tornado.log import app_log, gen_log +from tornado.platform.auto import set_close_exec, Waker from tornado import stack_context -from tornado.util import Configurable, errno_from_exception, timedelta_to_seconds +from tornado.util import PY3, Configurable, errno_from_exception, timedelta_to_seconds try: import signal except ImportError: signal = None -try: - import thread # py2 -except ImportError: - import _thread as thread # py3 -from tornado.platform.auto import set_close_exec, Waker +if PY3: + import _thread as thread +else: + import thread _POLL_TIMEOUT = 3600.0 diff --git a/tornado/log.py b/tornado/log.py index 040889a98..c8821169a 100644 --- a/tornado/log.py +++ b/tornado/log.py @@ -183,7 +183,8 @@ def enable_pretty_logging(options=None, logger=None): and `tornado.options.parse_config_file`. """ if options is None: - from tornado.options import options + import tornado.options + options = tornado.options.options if options.logging is None or options.logging.lower() == 'none': return if logger is None: @@ -228,7 +229,8 @@ def define_logging_options(options=None): """ if options is None: # late import to prevent cycle - from tornado.options import options + import tornado.options + options = tornado.options.options options.define("logging", default="info", help=("Set the Python log level. If 'none', tornado won't touch the " "logging configuration."), diff --git a/tornado/netutil.py b/tornado/netutil.py index 3c2b61643..b249945e8 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -27,7 +27,7 @@ import stat from tornado.concurrent import dummy_executor, run_on_executor from tornado.ioloop import IOLoop from tornado.platform.auto import set_close_exec -from tornado.util import Configurable, errno_from_exception +from tornado.util import PY3, Configurable, errno_from_exception try: import ssl @@ -44,10 +44,8 @@ except ImportError: else: raise -try: - xrange # py2 -except NameError: - xrange = range # py3 +if PY3: + xrange = range if hasattr(ssl, 'match_hostname') and hasattr(ssl, 'CertificateError'): # python 3.2+ ssl_match_hostname = ssl.match_hostname diff --git a/tornado/platform/auto.pyi b/tornado/platform/auto.pyi new file mode 100644 index 000000000..a1c97228a --- /dev/null +++ b/tornado/platform/auto.pyi @@ -0,0 +1,4 @@ +# auto.py is full of patterns mypy doesn't like, so for type checking +# purposes we replace it with interface.py. + +from .interface import * diff --git a/tornado/speedups.pyi b/tornado/speedups.pyi new file mode 100644 index 000000000..9e8def483 --- /dev/null +++ b/tornado/speedups.pyi @@ -0,0 +1 @@ +def websocket_mask(mask: bytes, data: bytes) -> bytes: ... diff --git a/tornado/util.py b/tornado/util.py index 5e083961a..ba252803e 100644 --- a/tornado/util.py +++ b/tornado/util.py @@ -17,18 +17,28 @@ import os import sys import zlib +PY3 = sys.version_info >= (3,) -try: - xrange # py2 -except NameError: - xrange = range # py3 +if PY3: + xrange = range # inspect.getargspec() raises DeprecationWarnings in Python 3.5. # The two functions have compatible interfaces for the parts we need. -try: - from inspect import getfullargspec as getargspec # py3 -except ImportError: - from inspect import getargspec # py2 +if PY3: + from inspect import getfullargspec as getargspec +else: + from inspect import getargspec + +# Aliases for types that are spelled differently in different Python +# versions. bytes_type is deprecated and no longer used in Tornado +# itself but is left in case anyone outside Tornado is using it. +unicode_type = type(u'') +bytes_type = bytes +if PY3: + basestring_type = str +else: + # The name basestring doesn't exist in py3 so silence flake8. + basestring_type = basestring # noqa class ObjectDict(dict): @@ -84,16 +94,6 @@ class GzipDecompressor(object): return self.decompressobj.flush() -if not isinstance(b'', type('')): - unicode_type = str - basestring_type = str -else: - # These names don't exist in py3, so use noqa comments to disable - # warnings in flake8. - unicode_type = unicode # noqa - basestring_type = basestring # noqa - - def import_object(name): """Imports an object by name. @@ -126,11 +126,16 @@ def import_object(name): raise ImportError("No module named %s" % parts[-1]) -# Deprecated alias that was used before we dropped py25 support. -# Left here in case anyone outside Tornado is using it. -bytes_type = bytes +# Stubs to make mypy happy (and later for actual type-checking). +def raise_exc_info(exc_info): + pass + + +def exec_in(code, glob, loc=None): + pass + -if sys.version_info > (3,): +if PY3: exec(""" def raise_exc_info(exc_info): raise exc_info[1].with_traceback(exc_info[2]) @@ -192,8 +197,8 @@ class Configurable(object): `configurable_base` and `configurable_default`, and use the instance method `initialize` instead of ``__init__``. """ - __impl_class = None - __impl_kwargs = None + __impl_class = None # type: type + __impl_kwargs = None # type: dict def __new__(cls, *args, **kwargs): base = cls.configurable_base()