Skip to content

Commit

Permalink
🐛 Allow Flama applications to mount other Flama applications
Browse files Browse the repository at this point in the history
  • Loading branch information
perdy committed Mar 1, 2023
1 parent 053cb7a commit 2e770c2
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 4 deletions.
8 changes: 8 additions & 0 deletions flama/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@ def resolve_url(self, name: str, **path_params: t.Any) -> url.URL:
"""
return self.router.resolve_url(name, **path_params)

def resolve_route(self, scope: types.Scope) -> t.Tuple[BaseRoute, types.Scope]:
"""Look for a route that matches given ASGI scope.
:param scope: ASGI scope.
:return: Route and its scope.
"""
return self.router.resolve_route(scope)

get = functools.partialmethod(route, methods=["GET"])
head = functools.partialmethod(route, methods=["HEAD"])
post = functools.partialmethod(route, methods=["POST"])
Expand Down
7 changes: 5 additions & 2 deletions flama/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,8 +752,11 @@ def resolve_route(self, scope: types.Scope) -> t.Tuple[BaseRoute, types.Scope]:
if m == Match.full:
route_scope = types.Scope({**scope, **route.route_scope(scope)})

if isinstance(route, Mount) and isinstance(route.app, Router):
return route.app.resolve_route(route_scope)
if isinstance(route, Mount):
try:
return route.app.resolve_route(route_scope) # type: ignore[no-any-return,union-attr]
except AttributeError:
...

return route, route_scope
elif m == Match.partial:
Expand Down
25 changes: 23 additions & 2 deletions tests/test_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,28 @@ async def foo():
assert route_scope["root_path"] == ""
assert route_scope["endpoint"] == foo

def test_resolve_route_mount_view(self, app, router, asgi_scope):
def test_resolve_route_mount_app(self, app, asgi_scope):
nested = Flama()

@nested.route("/foo/")
async def foo():
return "foo"

app.mount("/router", app=nested)

asgi_scope["path"] = "/router/foo/"
asgi_scope["method"] = "GET"

route, route_scope = app.router.resolve_route(scope=asgi_scope)

assert route.endpoint == foo
assert route.path == "/foo/"
assert route_scope is not None
assert route_scope["path"] == "/foo/"
assert route_scope["root_path"] == "/router"
assert route_scope["endpoint"] == foo

def test_resolve_route_mount_router(self, app, router, asgi_scope):
@router.route("/foo/")
async def foo():
return "foo"
Expand All @@ -776,7 +797,7 @@ async def foo():
assert route_scope["root_path"] == "/router"
assert route_scope["endpoint"] == foo

def test_resolve_route_nested_mount_view(self, app, router, asgi_scope):
def test_resolve_route_nested_mount_router(self, app, router, asgi_scope):
@router.route("/foo/")
async def foo():
return "foo"
Expand Down

0 comments on commit 2e770c2

Please sign in to comment.