Browse Source

Properly type the request_data method

Getty Ritter 4 years ago
parent
commit
4971167132
2 changed files with 19 additions and 4 deletions
  1. 11 2
      lc/request.py
  2. 8 2
      lc/web.py

+ 11 - 2
lc/request.py

@@ -2,15 +2,24 @@ import abc
 from dataclasses import dataclass
 from dataclasses_json import dataclass_json
 from datetime import datetime
-from typing import List, Mapping, Optional
+from typing import List, Mapping, Optional, TypeVar, Type
 
 import lc.config as c
 
+T = TypeVar("T")
+
 
 class Request(metaclass=abc.ABCMeta):
     @classmethod
     @abc.abstractmethod
-    def from_form(cls, form: Mapping[str, str]):
+    def from_form(cls: Type[T], form: Mapping[str, str]) -> T:
+        pass
+
+    # technically this gets added by dataclass_json, but mypy isn't
+    # aware of it, so it's going to get declared here as though it
+    # weren't abstract and then dataclass_json will add it
+    @classmethod
+    def from_json(cls: Type[T], json: bytes) -> T:
         pass
 
 

+ 8 - 2
lc/web.py

@@ -1,9 +1,14 @@
 import flask
 import pystache
+from typing import TypeVar, Type
 
 import lc.config as c
 import lc.error as e
 import lc.model as m
+import lc.request as r
+
+
+T = TypeVar("T", bound=r.Request)
 
 
 class Endpoint:
@@ -33,13 +38,14 @@ class Endpoint:
             if u.authenticate(payload["password"]):
                 self.user = u
 
-    def request_data(self, cls):
+    def request_data(self, cls: Type[T]) -> T:
+        """Construct a Request model from either a JSON payload or a urlencoded payload"""
         if flask.request.content_type == "application/json":
             return cls.from_json(flask.request.data)
         elif flask.request.content_type == "application/x-www-form-urlencoded":
             return cls.from_form(flask.request.form)
         else:
-            raise e.BadContentType(flask.request.content_type)
+            raise e.BadContentType(flask.request.content_type or "unknown")
 
     def require_authentication(self, name: str) -> m.User:
         """