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. `AbstractRouteDef.register` (and all
subclasses) return a list of registered resources registered resource.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -276,5 +276,6 @@ Young-Ho Cha
Yuriy Shatrov
Yury Selivanov
Yusuke Tsutsumi
Zlatan Sičanica
Марк Коренберг
Семён Марьясин
6 changes: 4 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,9 @@ 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[AbstractRoute]:
return self.router.add_routes(routes)

@property
def on_response_prepare(self) -> _RespPrepareSignal:
Expand Down
23 changes: 14 additions & 9 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) -> List[AbstractRoute]:
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) -> List[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 All @@ -82,8 +85,10 @@ def __repr__(self) -> str:
"{info}>".format(prefix=self.prefix, path=self.path,
info=''.join(info)))

def register(self, router: UrlDispatcher) -> None:
router.add_static(self.prefix, self.path, **self.kwargs)
def register(self, router: UrlDispatcher) -> List[AbstractRoute]:
resource = router.add_static(self.prefix, self.path, **self.kwargs)
routes = resource.get_info().get('routes', {})
return routes.values()


def route(method: str, path: str, handler: _HandlerType,
Expand Down
12 changes: 9 additions & 3 deletions aiohttp/web_urldispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,8 @@ def _get_file_hash(byte_array: bytes) -> str:

def get_info(self) -> Dict[str, Any]:
return {'directory': self._directory,
'prefix': self._prefix}
'prefix': self._prefix,
'routes': self._routes}

def set_options_route(self, handler: _WebHandler) -> None:
if 'OPTIONS' in self._routes:
Expand Down Expand Up @@ -1109,10 +1110,15 @@ 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[AbstractRoute]:
"""Append routes to route table.

Parameter should be a sequence of RouteDef objects.

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

:returns: :class:`list` of registered :class:`AbstractRoute` instances.

The method is a shortcut for
``app.router.add_routes(routes_table)``, see also
:meth:`UrlDispatcher.add_routes`.

.. versionadded:: 3.1

.. versionchanged:: 3.7

Return value updated from ``None`` to :class:`list` of
zlatsic marked this conversation as resolved.
Show resolved Hide resolved
:class:`AbstractRoute` instances.
zlatsic marked this conversation as resolved.
Show resolved Hide resolved

.. comethod:: startup()

A :ref:`coroutine<coroutine>` that will be called along with the
Expand Down Expand Up @@ -1569,8 +1576,15 @@ Router is any object that implements :class:`AbstractRouter` interface.
The table is a :class:`list` of :class:`RouteDef` items or
:class:`RouteTableDef`.

:returns: :class:`list` of registered :class:`AbstractRoute` instances.

.. versionadded:: 2.3

.. versionchanged:: 3.7

Return value updated from ``None`` to :class:`list` of
zlatsic marked this conversation as resolved.
Show resolved Hide resolved
:class:`AbstractRoute` instances.
zlatsic marked this conversation as resolved.
Show resolved Hide resolved

.. method:: add_get(path, handler, *, name=None, allow_head=True, **kwargs)

Shortcut for adding a GET handler. Calls the :meth:`add_route` with \
Expand Down Expand Up @@ -2080,6 +2094,13 @@ The definition is created by functions like :func:`get` or

Abstract method, should be overridden by subclasses.

:returns: :class:`list` of registered :class:`AbstractRoute` objects.

.. versionchanged:: 3.7

Return value updated from ``None`` to :class:`list` of
zlatsic marked this conversation as resolved.
Show resolved Hide resolved
:class:`AbstractRoute` instances.
zlatsic marked this conversation as resolved.
Show resolved Hide resolved


.. class:: RouteDef

Expand Down
7 changes: 5 additions & 2 deletions tests/test_urldispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,8 +900,11 @@ async def test_match_info_get_info_dynamic2(router) -> None:
def test_static_resource_get_info(router) -> None:
directory = pathlib.Path(aiohttp.__file__).parent.resolve()
resource = router.add_static('/st', directory)
assert resource.get_info() == {'directory': directory,
'prefix': '/st'}
info = resource.get_info()
assert len(info) == 3
assert info['directory'] == directory
assert info['prefix'] == '/st'
assert all([type(r) is ResourceRoute for r in info['routes'].values()])


async def test_system_route_get_info(router) -> None:
Expand Down