| 385 | return getattr(self._base_app, "routes", []) |
| 386 | |
| 387 | def matches(self, scope: Scope) -> tuple[Match, Scope]: |
| 388 | path_params: dict[str, Any] |
| 389 | if scope["type"] in ("http", "websocket"): # pragma: no branch |
| 390 | root_path = scope.get("root_path", "") |
| 391 | route_path = get_route_path(scope) |
| 392 | match = self.path_regex.match(route_path) |
| 393 | if match: |
| 394 | matched_params = match.groupdict() |
| 395 | for key, value in matched_params.items(): |
| 396 | matched_params[key] = self.param_convertors[key].convert(value) |
| 397 | remaining_path = "/" + matched_params.pop("path") |
| 398 | matched_path = route_path[: -len(remaining_path)] |
| 399 | path_params = dict(scope.get("path_params", {})) |
| 400 | path_params.update(matched_params) |
| 401 | child_scope = { |
| 402 | "path_params": path_params, |
| 403 | # app_root_path will only be set at the top level scope, |
| 404 | # initialized with the (optional) value of a root_path |
| 405 | # set above/before Starlette. And even though any |
| 406 | # mount will have its own child scope with its own respective |
| 407 | # root_path, the app_root_path will always be available in all |
| 408 | # the child scopes with the same top level value because it's |
| 409 | # set only once here with a default, any other child scope will |
| 410 | # just inherit that app_root_path default value stored in the |
| 411 | # scope. All this is needed to support Request.url_for(), as it |
| 412 | # uses the app_root_path to build the URL path. |
| 413 | "app_root_path": scope.get("app_root_path", root_path), |
| 414 | "root_path": root_path + matched_path, |
| 415 | "endpoint": self.app, |
| 416 | } |
| 417 | return Match.FULL, child_scope |
| 418 | return Match.NONE, {} |
| 419 | |
| 420 | def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: |
| 421 | if self.name is not None and name == self.name and "path" in path_params: |