From 4cf126dc42f7a822bc1413a5fc80f41dd6f1795e Mon Sep 17 00:00:00 2001 From: zlatan Date: Fri, 4 Oct 2019 15:42:02 +0200 Subject: [PATCH 01/12] UrlDispatcher - add_routes returns a list of AbstractRoutes --- CHANGES/3866.feature | 3 +++ aiohttp/web_app.py | 7 +++++-- aiohttp/web_routedef.py | 17 ++++++++++------- aiohttp/web_urldispatcher.py | 9 ++++++--- docs/web_reference.rst | 6 ++++++ 5 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 CHANGES/3866.feature diff --git a/CHANGES/3866.feature b/CHANGES/3866.feature new file mode 100644 index 00000000000..f74330930ba --- /dev/null +++ b/CHANGES/3866.feature @@ -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. diff --git a/aiohttp/web_app.py b/aiohttp/web_app.py index a70ff506fd0..0e58b1e4c28 100644 --- a/aiohttp/web_app.py +++ b/aiohttp/web_app.py @@ -34,6 +34,7 @@ from .web_routedef import AbstractRouteDef from .web_urldispatcher import ( AbstractResource, + AbstractRoute, Domain, MaskDomain, MatchedSubAppResource, @@ -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]]: + return self.router.add_routes(routes) @property def on_response_prepare(self) -> _RespPrepareSignal: diff --git a/aiohttp/web_routedef.py b/aiohttp/web_routedef.py index 91b5ef0fee8..2b7f558c969 100644 --- a/aiohttp/web_routedef.py +++ b/aiohttp/web_routedef.py @@ -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', @@ -36,7 +39,7 @@ class AbstractRouteDef(abc.ABC): @abc.abstractmethod - def register(self, router: UrlDispatcher) -> None: + def register(self, router: UrlDispatcher) -> Optional[AbstractRoute]: pass # pragma: no cover @@ -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) diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index 0a6b199b369..e1e7f25999e 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -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] diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 5df154104d7..9afb83cff7a 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -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. + The method is a shortcut for ``app.router.add_routes(routes_table)``, see also :meth:`UrlDispatcher.add_routes`. @@ -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. + .. versionadded:: 2.3 .. method:: add_get(path, handler, *, name=None, allow_head=True, **kwargs) @@ -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 From 1920bd66ba679b881f2fe36f9a4903613bdb2daf Mon Sep 17 00:00:00 2001 From: zlatan Date: Fri, 4 Oct 2019 15:48:55 +0200 Subject: [PATCH 02/12] add myself to the contributors --- CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index d126b74eb47..1222ca291e6 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -274,5 +274,6 @@ Young-Ho Cha Yuriy Shatrov Yury Selivanov Yusuke Tsutsumi +Zlatan Sičanica Марк Коренберг Семён Марьясин From 3d1d6b24d19ec625869fcefa761ba503afdc0e39 Mon Sep 17 00:00:00 2001 From: zlatan Date: Fri, 11 Oct 2019 10:52:44 +0200 Subject: [PATCH 03/12] AbstractRouteDef.register returns a list of registered AbstractRoutes --- CHANGES/3866.feature | 4 ++-- aiohttp/web_app.py | 5 ++--- aiohttp/web_routedef.py | 18 +++++++++++------- aiohttp/web_urldispatcher.py | 13 ++++++++----- docs/web_reference.rst | 2 +- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/CHANGES/3866.feature b/CHANGES/3866.feature index f74330930ba..ede67ac7420 100644 --- a/CHANGES/3866.feature +++ b/CHANGES/3866.feature @@ -1,3 +1,3 @@ `web.UrlDispatcher.add_routes` and `web.Application.add_routes` return a list -of registered `AbstractRoute` instances. `RouteDef.register` returns the -registered resource. +of registered `AbstractRoute` instances. `AbstractRouteDef.register` (and all +subclasses) return a list of registered resources registered resource. diff --git a/aiohttp/web_app.py b/aiohttp/web_app.py index 0e58b1e4c28..1d122bb02e5 100644 --- a/aiohttp/web_app.py +++ b/aiohttp/web_app.py @@ -251,9 +251,8 @@ def add_domain(self, domain: str, factory = partial(MatchedSubAppResource, rule, subapp) return self._add_subapp(factory, subapp) - def add_routes( - self, routes: Iterable[AbstractRouteDef] - ) -> List[Optional[AbstractRoute]]: + def add_routes(self, + routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: return self.router.add_routes(routes) @property diff --git a/aiohttp/web_routedef.py b/aiohttp/web_routedef.py index 2b7f558c969..b0f414776ea 100644 --- a/aiohttp/web_routedef.py +++ b/aiohttp/web_routedef.py @@ -39,7 +39,7 @@ class AbstractRouteDef(abc.ABC): @abc.abstractmethod - def register(self, router: UrlDispatcher) -> Optional[AbstractRoute]: + def register(self, router: UrlDispatcher) -> List[AbstractRoute]: pass # pragma: no cover @@ -62,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) -> AbstractRoute: + def register(self, router: UrlDispatcher) -> List[AbstractRoute]: if self.method in hdrs.METH_ALL: reg = getattr(router, 'add_'+self.method.lower()) - return reg(self.path, self.handler, **self.kwargs) + return [reg(self.path, self.handler, **self.kwargs)] else: - return 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) @@ -85,8 +85,12 @@ 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') + if routes is not None: + return [routes['GET'], routes['HEAD']] + return [] def route(method: str, path: str, handler: _HandlerType, diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index e1e7f25999e..92904aabfea 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -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: @@ -1109,13 +1110,15 @@ def freeze(self) -> None: for resource in self._resources: resource.freeze() - def add_routes( - self, routes: Iterable[AbstractRouteDef] - ) -> List[Optional[AbstractRoute]]: + 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. """ - return [route_def.register(self) for route_def in routes] + registered_routes = [] + for route_def in routes: + registered_routes.extend(route_def.register(self)) + return registered_routes diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 9afb83cff7a..11d1b7038ab 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -2084,7 +2084,7 @@ The definition is created by functions like :func:`get` or Abstract method, should be overridden by subclasses. - Returns the registered resource. + Returns a list of registered `AbstractRoute` objects. .. class:: RouteDef From a0694c33a6703e1e209d54df6dd38e563b958c63 Mon Sep 17 00:00:00 2001 From: zlatan Date: Fri, 11 Oct 2019 10:58:18 +0200 Subject: [PATCH 04/12] test_urldispatch - update get_info test according to new changes --- tests/test_urldispatch.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py index 3cf8d1f7e1a..a68af341c82 100644 --- a/tests/test_urldispatch.py +++ b/tests/test_urldispatch.py @@ -904,8 +904,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: From ecb12487a22323b6d4f86a2ac6f311edf2855d06 Mon Sep 17 00:00:00 2001 From: zlatan Date: Fri, 11 Oct 2019 14:35:02 +0200 Subject: [PATCH 05/12] web_routedef: cov fix --- aiohttp/web_routedef.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aiohttp/web_routedef.py b/aiohttp/web_routedef.py index b0f414776ea..7fbc848d702 100644 --- a/aiohttp/web_routedef.py +++ b/aiohttp/web_routedef.py @@ -87,10 +87,8 @@ def __repr__(self) -> str: def register(self, router: UrlDispatcher) -> List[AbstractRoute]: resource = router.add_static(self.prefix, self.path, **self.kwargs) - routes = resource.get_info().get('routes') - if routes is not None: - return [routes['GET'], routes['HEAD']] - return [] + routes = resource.get_info().get('routes', {}) + return routes.values() def route(method: str, path: str, handler: _HandlerType, From f046d425d3f8c1b34077e196a7a7624a7160e187 Mon Sep 17 00:00:00 2001 From: zlatan Date: Wed, 16 Oct 2019 13:23:15 +0200 Subject: [PATCH 06/12] docs: update add_routes and registers so they use proper markdown --- docs/web_reference.rst | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 11d1b7038ab..65ebfc2a786 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -1413,7 +1413,7 @@ 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. + :returns: :class:`list` of registered :class:`AbstractRoute` instances. The method is a shortcut for ``app.router.add_routes(routes_table)``, see also @@ -1421,6 +1421,11 @@ duplicated like one using :meth:`Application.copy`. .. versionadded:: 3.1 + .. versionchanged:: 3.7 + + Return value updated from ``None`` to :class:`list` of + :class:`AbstractRoute` instances. + .. comethod:: startup() A :ref:`coroutine` that will be called along with the @@ -1571,10 +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 a :class:`list` of registered :class:`AbstractRoute` instances. + :returns: :class:`list` of registered :class:`AbstractRoute` instances. .. versionadded:: 2.3 + .. versionchanged:: 3.7 + + Return value updated from ``None`` to :class:`list` of + :class:`AbstractRoute` instances. + .. method:: add_get(path, handler, *, name=None, allow_head=True, **kwargs) Shortcut for adding a GET handler. Calls the :meth:`add_route` with \ @@ -2084,7 +2094,12 @@ The definition is created by functions like :func:`get` or Abstract method, should be overridden by subclasses. - Returns a list of registered `AbstractRoute` objects. + :returns: :class:`list` of registered :class:`AbstractRoute` objects. + + .. versionchanged:: 3.7 + + Return value updated from ``None`` to :class:`list` of + :class:`AbstractRoute` instances. .. class:: RouteDef From 1fdb1699d3da4a5e9ede4524740ff74c5baacb0b Mon Sep 17 00:00:00 2001 From: Zlatan Date: Fri, 18 Oct 2019 17:37:56 +0200 Subject: [PATCH 07/12] Update docs/web_reference.rst Co-Authored-By: Andrew Svetlov --- docs/web_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 65ebfc2a786..e4d1c882977 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -2099,7 +2099,7 @@ The definition is created by functions like :func:`get` or .. versionchanged:: 3.7 Return value updated from ``None`` to :class:`list` of - :class:`AbstractRoute` instances. + :class:`AbstractRoute` instances. .. class:: RouteDef From 43fe35d4987c03983a29e12e97052a50bb60863e Mon Sep 17 00:00:00 2001 From: Zlatan Date: Fri, 18 Oct 2019 17:38:07 +0200 Subject: [PATCH 08/12] Update docs/web_reference.rst Co-Authored-By: Andrew Svetlov --- docs/web_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index e4d1c882977..37bb35ded7b 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -2098,7 +2098,7 @@ The definition is created by functions like :func:`get` or .. versionchanged:: 3.7 - Return value updated from ``None`` to :class:`list` of + Return value updated from ``None`` to :class:`list` of :class:`AbstractRoute` instances. From 2846b45b030ca9a5edb9a5bc7d10047083691155 Mon Sep 17 00:00:00 2001 From: Zlatan Date: Fri, 18 Oct 2019 17:38:18 +0200 Subject: [PATCH 09/12] Update docs/web_reference.rst Co-Authored-By: Andrew Svetlov --- docs/web_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 37bb35ded7b..cf34586c35a 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -1583,7 +1583,7 @@ Router is any object that implements :class:`AbstractRouter` interface. .. versionchanged:: 3.7 Return value updated from ``None`` to :class:`list` of - :class:`AbstractRoute` instances. + :class:`AbstractRoute` instances. .. method:: add_get(path, handler, *, name=None, allow_head=True, **kwargs) From bfa97eee5eff1b223626f82a232e36aef604b213 Mon Sep 17 00:00:00 2001 From: Zlatan Date: Fri, 18 Oct 2019 17:38:27 +0200 Subject: [PATCH 10/12] Update docs/web_reference.rst Co-Authored-By: Andrew Svetlov --- docs/web_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index cf34586c35a..9458c6169e9 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -1582,7 +1582,7 @@ Router is any object that implements :class:`AbstractRouter` interface. .. versionchanged:: 3.7 - Return value updated from ``None`` to :class:`list` of + Return value updated from ``None`` to :class:`list` of :class:`AbstractRoute` instances. .. method:: add_get(path, handler, *, name=None, allow_head=True, **kwargs) From 16ead654733338f5f411cb400868b688a83bfffa Mon Sep 17 00:00:00 2001 From: Zlatan Date: Fri, 18 Oct 2019 17:38:33 +0200 Subject: [PATCH 11/12] Update docs/web_reference.rst Co-Authored-By: Andrew Svetlov --- docs/web_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 9458c6169e9..966c4356745 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -1424,7 +1424,7 @@ duplicated like one using :meth:`Application.copy`. .. versionchanged:: 3.7 Return value updated from ``None`` to :class:`list` of - :class:`AbstractRoute` instances. + :class:`AbstractRoute` instances. .. comethod:: startup() From dcc9b806ec45817135f7e635a90b3a59eba655d5 Mon Sep 17 00:00:00 2001 From: Zlatan Date: Fri, 18 Oct 2019 17:38:39 +0200 Subject: [PATCH 12/12] Update docs/web_reference.rst Co-Authored-By: Andrew Svetlov --- docs/web_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 966c4356745..f2dd9f62b77 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -1423,7 +1423,7 @@ duplicated like one using :meth:`Application.copy`. .. versionchanged:: 3.7 - Return value updated from ``None`` to :class:`list` of + Return value updated from ``None`` to :class:`list` of :class:`AbstractRoute` instances. .. comethod:: startup()