From: Ben Darnell Date: Sun, 7 Oct 2018 03:33:56 +0000 (-0400) Subject: web: Improve typings for HTTP verb methods X-Git-Tag: v6.0.0b1~28^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2d5ba2fad5f1272d2613243eb6eb0f5dbf3c97f6;p=thirdparty%2Ftornado.git web: Improve typings for HTTP verb methods Add py.typed marker file and test that client code can be type-checked. --- diff --git a/maint/test/mypy/.gitignore b/maint/test/mypy/.gitignore new file mode 100644 index 000000000..dc3112749 --- /dev/null +++ b/maint/test/mypy/.gitignore @@ -0,0 +1 @@ +UNKNOWN.egg-info diff --git a/maint/test/mypy/bad.py b/maint/test/mypy/bad.py new file mode 100644 index 000000000..3e6b6342e --- /dev/null +++ b/maint/test/mypy/bad.py @@ -0,0 +1,6 @@ +from tornado.web import RequestHandler + + +class MyHandler(RequestHandler): + def get(self) -> str: # Deliberate type error + return "foo" diff --git a/maint/test/mypy/good.py b/maint/test/mypy/good.py new file mode 100644 index 000000000..5ee2d3ddc --- /dev/null +++ b/maint/test/mypy/good.py @@ -0,0 +1,11 @@ +from tornado import gen +from tornado.web import RequestHandler + + +class MyHandler(RequestHandler): + def get(self) -> None: + self.write("foo") + + async def post(self) -> None: + await gen.sleep(1) + self.write("foo") diff --git a/maint/test/mypy/setup.py b/maint/test/mypy/setup.py new file mode 100644 index 000000000..606849326 --- /dev/null +++ b/maint/test/mypy/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup() diff --git a/maint/test/mypy/tox.ini b/maint/test/mypy/tox.ini new file mode 100644 index 000000000..42235252d --- /dev/null +++ b/maint/test/mypy/tox.ini @@ -0,0 +1,14 @@ +# Test that the py.typed marker file is respected and client +# application code can be typechecked using tornado's published +# annotations. +[tox] +envlist = py37 + +[testenv] +deps = + ../../.. + mypy +whitelist_externals = /bin/sh +commands = + mypy good.py + /bin/sh -c '! mypy bad.py' diff --git a/setup.py b/setup.py index 874e83248..38c40c2a5 100644 --- a/setup.py +++ b/setup.py @@ -144,6 +144,7 @@ setup( # data files need to be listed both here (which determines what gets # installed) and in MANIFEST.in (which determines what gets included # in the sdist tarball) + "tornado": ["py.typed"], "tornado.test": [ "README", "csv_translations/fr_FR.csv", @@ -161,7 +162,7 @@ setup( "templates/utf8.html", "test.crt", "test.key", - ] + ], }, author="Facebook", author_email="python-tornado@googlegroups.com", diff --git a/tornado/py.typed b/tornado/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/tornado/web.py b/tornado/web.py index 3f6760713..87e02308d 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -253,26 +253,16 @@ class RequestHandler(object): """An alias for `self.application.settings `.""" return self.application.settings - def head(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: + def _unimplemented_method(self, *args: str, **kwargs: str) -> None: raise HTTPError(405) - def get(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - raise HTTPError(405) - - def post(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - raise HTTPError(405) - - def delete(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - raise HTTPError(405) - - def patch(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - raise HTTPError(405) - - def put(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - raise HTTPError(405) - - def options(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - raise HTTPError(405) + head = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + get = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + post = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + delete = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + patch = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + put = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + options = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] def prepare(self) -> Optional[Awaitable[None]]: """Called at the beginning of a request before `get`/`post`/etc. @@ -2485,7 +2475,7 @@ class RedirectHandler(RequestHandler): self._url = url self._permanent = permanent - def get(self, *args: Any) -> None: # type: ignore + def get(self, *args: Any) -> None: to_url = self._url.format(*args) if self.request.query_arguments: # TODO: figure out typing for the next line. @@ -2579,7 +2569,7 @@ class StaticFileHandler(RequestHandler): with cls._lock: cls._static_hashes = {} - def head(self, path: str) -> "Future[None]": # type: ignore + def head(self, path: str) -> "Future[None]": return self.get(path, include_body=False) @gen.coroutine