web_routedef.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import abc
  2. import os # noqa
  3. from typing import (
  4. TYPE_CHECKING,
  5. Any,
  6. Callable,
  7. Dict,
  8. Iterator,
  9. List,
  10. Optional,
  11. Sequence,
  12. Type,
  13. Union,
  14. overload,
  15. )
  16. import attr
  17. from . import hdrs
  18. from .abc import AbstractView
  19. from .typedefs import Handler, PathLike
  20. if TYPE_CHECKING:
  21. from .web_request import Request
  22. from .web_response import StreamResponse
  23. from .web_urldispatcher import AbstractRoute, UrlDispatcher
  24. else:
  25. Request = StreamResponse = UrlDispatcher = AbstractRoute = None
  26. __all__ = (
  27. "AbstractRouteDef",
  28. "RouteDef",
  29. "StaticDef",
  30. "RouteTableDef",
  31. "head",
  32. "options",
  33. "get",
  34. "post",
  35. "patch",
  36. "put",
  37. "delete",
  38. "route",
  39. "view",
  40. "static",
  41. )
  42. class AbstractRouteDef(abc.ABC):
  43. @abc.abstractmethod
  44. def register(self, router: UrlDispatcher) -> List[AbstractRoute]:
  45. pass # pragma: no cover
  46. _HandlerType = Union[Type[AbstractView], Handler]
  47. @attr.s(auto_attribs=True, frozen=True, repr=False, slots=True)
  48. class RouteDef(AbstractRouteDef):
  49. method: str
  50. path: str
  51. handler: _HandlerType
  52. kwargs: Dict[str, Any]
  53. def __repr__(self) -> str:
  54. info = []
  55. for name, value in sorted(self.kwargs.items()):
  56. info.append(f", {name}={value!r}")
  57. return "<RouteDef {method} {path} -> {handler.__name__!r}{info}>".format(
  58. method=self.method, path=self.path, handler=self.handler, info="".join(info)
  59. )
  60. def register(self, router: UrlDispatcher) -> List[AbstractRoute]:
  61. if self.method in hdrs.METH_ALL:
  62. reg = getattr(router, "add_" + self.method.lower())
  63. return [reg(self.path, self.handler, **self.kwargs)]
  64. else:
  65. return [
  66. router.add_route(self.method, self.path, self.handler, **self.kwargs)
  67. ]
  68. @attr.s(auto_attribs=True, frozen=True, repr=False, slots=True)
  69. class StaticDef(AbstractRouteDef):
  70. prefix: str
  71. path: PathLike
  72. kwargs: Dict[str, Any]
  73. def __repr__(self) -> str:
  74. info = []
  75. for name, value in sorted(self.kwargs.items()):
  76. info.append(f", {name}={value!r}")
  77. return "<StaticDef {prefix} -> {path}{info}>".format(
  78. prefix=self.prefix, path=self.path, info="".join(info)
  79. )
  80. def register(self, router: UrlDispatcher) -> List[AbstractRoute]:
  81. resource = router.add_static(self.prefix, self.path, **self.kwargs)
  82. routes = resource.get_info().get("routes", {})
  83. return list(routes.values())
  84. def route(method: str, path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  85. return RouteDef(method, path, handler, kwargs)
  86. def head(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  87. return route(hdrs.METH_HEAD, path, handler, **kwargs)
  88. def options(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  89. return route(hdrs.METH_OPTIONS, path, handler, **kwargs)
  90. def get(
  91. path: str,
  92. handler: _HandlerType,
  93. *,
  94. name: Optional[str] = None,
  95. allow_head: bool = True,
  96. **kwargs: Any,
  97. ) -> RouteDef:
  98. return route(
  99. hdrs.METH_GET, path, handler, name=name, allow_head=allow_head, **kwargs
  100. )
  101. def post(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  102. return route(hdrs.METH_POST, path, handler, **kwargs)
  103. def put(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  104. return route(hdrs.METH_PUT, path, handler, **kwargs)
  105. def patch(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  106. return route(hdrs.METH_PATCH, path, handler, **kwargs)
  107. def delete(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef:
  108. return route(hdrs.METH_DELETE, path, handler, **kwargs)
  109. def view(path: str, handler: Type[AbstractView], **kwargs: Any) -> RouteDef:
  110. return route(hdrs.METH_ANY, path, handler, **kwargs)
  111. def static(prefix: str, path: PathLike, **kwargs: Any) -> StaticDef:
  112. return StaticDef(prefix, path, kwargs)
  113. _Deco = Callable[[_HandlerType], _HandlerType]
  114. class RouteTableDef(Sequence[AbstractRouteDef]):
  115. """Route definition table"""
  116. def __init__(self) -> None:
  117. self._items: List[AbstractRouteDef] = []
  118. def __repr__(self) -> str:
  119. return f"<RouteTableDef count={len(self._items)}>"
  120. @overload
  121. def __getitem__(self, index: int) -> AbstractRouteDef: ...
  122. @overload
  123. def __getitem__(self, index: slice) -> List[AbstractRouteDef]: ...
  124. def __getitem__(self, index): # type: ignore[no-untyped-def]
  125. return self._items[index]
  126. def __iter__(self) -> Iterator[AbstractRouteDef]:
  127. return iter(self._items)
  128. def __len__(self) -> int:
  129. return len(self._items)
  130. def __contains__(self, item: object) -> bool:
  131. return item in self._items
  132. def route(self, method: str, path: str, **kwargs: Any) -> _Deco:
  133. def inner(handler: _HandlerType) -> _HandlerType:
  134. self._items.append(RouteDef(method, path, handler, kwargs))
  135. return handler
  136. return inner
  137. def head(self, path: str, **kwargs: Any) -> _Deco:
  138. return self.route(hdrs.METH_HEAD, path, **kwargs)
  139. def get(self, path: str, **kwargs: Any) -> _Deco:
  140. return self.route(hdrs.METH_GET, path, **kwargs)
  141. def post(self, path: str, **kwargs: Any) -> _Deco:
  142. return self.route(hdrs.METH_POST, path, **kwargs)
  143. def put(self, path: str, **kwargs: Any) -> _Deco:
  144. return self.route(hdrs.METH_PUT, path, **kwargs)
  145. def patch(self, path: str, **kwargs: Any) -> _Deco:
  146. return self.route(hdrs.METH_PATCH, path, **kwargs)
  147. def delete(self, path: str, **kwargs: Any) -> _Deco:
  148. return self.route(hdrs.METH_DELETE, path, **kwargs)
  149. def options(self, path: str, **kwargs: Any) -> _Deco:
  150. return self.route(hdrs.METH_OPTIONS, path, **kwargs)
  151. def view(self, path: str, **kwargs: Any) -> _Deco:
  152. return self.route(hdrs.METH_ANY, path, **kwargs)
  153. def static(self, prefix: str, path: PathLike, **kwargs: Any) -> None:
  154. self._items.append(StaticDef(prefix, path, kwargs))