Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UrlDispatcher - add_routes returns a list of AbstractRoutes #4141

Merged
merged 13 commits into from
Oct 18, 2019
3 changes: 3 additions & 0 deletions CHANGES/3866.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`web.UrlDispatcher.add_routes` and `web.Application.add_routes` return a list
of registered `AbstractRoute` instances. `RouteDef.register` returns the
registered resource.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -274,5 +274,6 @@ Young-Ho Cha
Yuriy Shatrov
Yury Selivanov
Yusuke Tsutsumi
Zlatan Sičanica
Марк Коренберг
Семён Марьясин
7 changes: 5 additions & 2 deletions aiohttp/web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from .web_routedef import AbstractRouteDef
from .web_urldispatcher import (
AbstractResource,
AbstractRoute,
Domain,
MaskDomain,
MatchedSubAppResource,
Expand Down Expand Up @@ -250,8 +251,10 @@ def add_domain(self, domain: str,
factory = partial(MatchedSubAppResource, rule, subapp)
return self._add_subapp(factory, subapp)

def add_routes(self, routes: Iterable[AbstractRouteDef]) -> None:
self.router.add_routes(routes)
def add_routes(
self, routes: Iterable[AbstractRouteDef]
) -> List[Optional[AbstractRoute]]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional is bad here. The return type should be a strict list.

Suggested change
) -> List[Optional[AbstractRoute]]:
) -> List[AbstractRoute]:

return self.router.add_routes(routes)

@property
def on_response_prepare(self) -> _RespPrepareSignal:
Expand Down
17 changes: 10 additions & 7 deletions aiohttp/web_routedef.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
from .typedefs import PathLike

if TYPE_CHECKING: # pragma: no cover
from .web_urldispatcher import UrlDispatcher
from .web_urldispatcher import (
UrlDispatcher,
AbstractRoute
)
from .web_request import Request
from .web_response import StreamResponse
else:
Request = StreamResponse = UrlDispatcher = None
Request = StreamResponse = UrlDispatcher = AbstractRoute = None


__all__ = ('AbstractRouteDef', 'RouteDef', 'StaticDef', 'RouteTableDef',
Expand All @@ -36,7 +39,7 @@

class AbstractRouteDef(abc.ABC):
@abc.abstractmethod
def register(self, router: UrlDispatcher) -> None:
def register(self, router: UrlDispatcher) -> Optional[AbstractRoute]:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically the part I have the most questions about. So far, I've made this return value Optional (and everywhere else where its return value is propagated). The reason for this is because of the StaticDef and its register implementation. Since add_static returns an AbstractResource, do you think it would be sensible for this to be a union of AbstractRoute and AbstractResource for that reason?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StaticResource internally has self._routes which is a dict of ResourceRoute instances.
Perhaps we can extend resource.get_info() to return routes mapping; it can avoid access to private members.

pass # pragma: no cover


Expand All @@ -59,13 +62,13 @@ def __repr__(self) -> str:
"{info}>".format(method=self.method, path=self.path,
handler=self.handler, info=''.join(info)))

def register(self, router: UrlDispatcher) -> None:
def register(self, router: UrlDispatcher) -> AbstractRoute:
if self.method in hdrs.METH_ALL:
reg = getattr(router, 'add_'+self.method.lower())
reg(self.path, self.handler, **self.kwargs)
return reg(self.path, self.handler, **self.kwargs)
else:
router.add_route(self.method, self.path, self.handler,
**self.kwargs)
return router.add_route(self.method, self.path, self.handler,
**self.kwargs)


@attr.s(frozen=True, repr=False, slots=True)
Expand Down
9 changes: 6 additions & 3 deletions aiohttp/web_urldispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -1109,10 +1109,13 @@ def freeze(self) -> None:
for resource in self._resources:
resource.freeze()

def add_routes(self, routes: Iterable[AbstractRouteDef]) -> None:
def add_routes(
self, routes: Iterable[AbstractRouteDef]
) -> List[Optional[AbstractRoute]]:
"""Append routes to route table.

Parameter should be a sequence of RouteDef objects.

Returns a list of registered AbstractRoute instances.
"""
for route_def in routes:
route_def.register(self)
return [route_def.register(self) for route_def in routes]
6 changes: 6 additions & 0 deletions docs/web_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,8 @@ duplicated like one using :meth:`Application.copy`.
The table is a :class:`list` of :class:`RouteDef` items or
:class:`RouteTableDef`.

Returns a :class:`list` of registered :class:`AbstractRoute` instances.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Please use :returns: markup as in the method above.
  2. Please add .. versionchanged:: 3.7 markup, search in docs for the directive usage. The master is not ready for 4.0 release yet, I think we can publish 3.7 earlier.


The method is a shortcut for
``app.router.add_routes(routes_table)``, see also
:meth:`UrlDispatcher.add_routes`.
Expand Down Expand Up @@ -1569,6 +1571,8 @@ Router is any object that implements :class:`AbstractRouter` interface.
The table is a :class:`list` of :class:`RouteDef` items or
:class:`RouteTableDef`.

Returns a :class:`list` of registered :class:`AbstractRoute` instances.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same


.. versionadded:: 2.3

.. method:: add_get(path, handler, *, name=None, allow_head=True, **kwargs)
Expand Down Expand Up @@ -2080,6 +2084,8 @@ The definition is created by functions like :func:`get` or

Abstract method, should be overridden by subclasses.

Returns the registered resource.


.. class:: RouteDef

Expand Down