| 564 | |
| 565 | |
| 566 | class Router: |
| 567 | def __init__( |
| 568 | self, |
| 569 | routes: Sequence[BaseRoute] | None = None, |
| 570 | redirect_slashes: bool = True, |
| 571 | default: ASGIApp | None = None, |
| 572 | # the generic to Lifespan[AppType] is the type of the top level application |
| 573 | # which the router cannot know statically, so we use Any |
| 574 | lifespan: Lifespan[Any] | None = None, |
| 575 | *, |
| 576 | middleware: Sequence[Middleware] | None = None, |
| 577 | ) -> None: |
| 578 | self.routes = [] if routes is None else list(routes) |
| 579 | self.redirect_slashes = redirect_slashes |
| 580 | self.default = self.not_found if default is None else default |
| 581 | |
| 582 | if lifespan is None: |
| 583 | self.lifespan_context: Lifespan[Any] = _DefaultLifespan(self) |
| 584 | |
| 585 | elif inspect.isasyncgenfunction(lifespan): |
| 586 | warnings.warn( |
| 587 | "async generator function lifespans are deprecated, " |
| 588 | "use an @contextlib.asynccontextmanager function instead", |
| 589 | StarletteDeprecationWarning, |
| 590 | ) |
| 591 | self.lifespan_context = asynccontextmanager(lifespan) |
| 592 | elif inspect.isgeneratorfunction(lifespan): |
| 593 | warnings.warn( |
| 594 | "generator function lifespans are deprecated, use an @contextlib.asynccontextmanager function instead", |
| 595 | StarletteDeprecationWarning, |
| 596 | ) |
| 597 | self.lifespan_context = _wrap_gen_lifespan_context(lifespan) |
| 598 | else: |
| 599 | self.lifespan_context = lifespan |
| 600 | |
| 601 | self.middleware_stack = self.app |
| 602 | if middleware: |
| 603 | for cls, args, kwargs in reversed(middleware): |
| 604 | self.middleware_stack = cls(self.middleware_stack, *args, **kwargs) |
| 605 | |
| 606 | async def not_found(self, scope: Scope, receive: Receive, send: Send) -> None: |
| 607 | if scope["type"] == "websocket": |
| 608 | websocket_close = WebSocketClose() |
| 609 | await websocket_close(scope, receive, send) |
| 610 | return |
| 611 | |
| 612 | # If we're running inside a starlette application then raise an |
| 613 | # exception, so that the configurable exception handler can deal with |
| 614 | # returning the response. For plain ASGI apps, just return the response. |
| 615 | if "app" in scope: |
| 616 | raise HTTPException(status_code=404) |
| 617 | else: |
| 618 | response = PlainTextResponse("Not Found", status_code=404) |
| 619 | await response(scope, receive, send) |
| 620 | |
| 621 | def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: |
| 622 | for route in self.routes: |
| 623 | try: |
no outgoing calls