]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
web: Improve typings for HTTP verb methods
authorBen Darnell <ben@bendarnell.com>
Sun, 7 Oct 2018 03:33:56 +0000 (23:33 -0400)
committerBen Darnell <ben@bendarnell.com>
Sun, 7 Oct 2018 03:33:56 +0000 (23:33 -0400)
Add py.typed marker file and test that client code can be type-checked.

maint/test/mypy/.gitignore [new file with mode: 0644]
maint/test/mypy/bad.py [new file with mode: 0644]
maint/test/mypy/good.py [new file with mode: 0644]
maint/test/mypy/setup.py [new file with mode: 0644]
maint/test/mypy/tox.ini [new file with mode: 0644]
setup.py
tornado/py.typed [new file with mode: 0644]
tornado/web.py

diff --git a/maint/test/mypy/.gitignore b/maint/test/mypy/.gitignore
new file mode 100644 (file)
index 0000000..dc31127
--- /dev/null
@@ -0,0 +1 @@
+UNKNOWN.egg-info
diff --git a/maint/test/mypy/bad.py b/maint/test/mypy/bad.py
new file mode 100644 (file)
index 0000000..3e6b634
--- /dev/null
@@ -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 (file)
index 0000000..5ee2d3d
--- /dev/null
@@ -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 (file)
index 0000000..6068493
--- /dev/null
@@ -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 (file)
index 0000000..4223525
--- /dev/null
@@ -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'
index 874e832488ed7e1854d93c2ab533908797e6abc8..38c40c2a5d92dea4cba5d19592e833af6c22da3a 100644 (file)
--- 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 (file)
index 0000000..e69de29
index 3f6760713340f542299b316481a171d0c0e4820e..87e02308dc842136f6be67dcd727c2054fc50676 100644 (file)
@@ -253,26 +253,16 @@ class RequestHandler(object):
         """An alias for `self.application.settings <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