| 194 | |
| 195 | |
| 196 | class Route(BaseRoute): |
| 197 | def __init__( |
| 198 | self, |
| 199 | path: str, |
| 200 | endpoint: Callable[..., Any], |
| 201 | *, |
| 202 | methods: Collection[str] | None = None, |
| 203 | name: str | None = None, |
| 204 | include_in_schema: bool = True, |
| 205 | middleware: Sequence[Middleware] | None = None, |
| 206 | ) -> None: |
| 207 | assert path.startswith("/"), "Routed paths must start with '/'" |
| 208 | self.path = path |
| 209 | self.endpoint = endpoint |
| 210 | self.name = get_name(endpoint) if name is None else name |
| 211 | self.include_in_schema = include_in_schema |
| 212 | |
| 213 | endpoint_handler = endpoint |
| 214 | while isinstance(endpoint_handler, functools.partial): |
| 215 | endpoint_handler = endpoint_handler.func |
| 216 | if inspect.isfunction(endpoint_handler) or inspect.ismethod(endpoint_handler): |
| 217 | # Endpoint is function or method. Treat it as `func(request) -> response`. |
| 218 | self.app = request_response(endpoint) |
| 219 | if methods is None: |
| 220 | methods = ["GET"] |
| 221 | else: |
| 222 | # Endpoint is a class. Treat it as ASGI. |
| 223 | self.app = endpoint |
| 224 | |
| 225 | if middleware is not None: |
| 226 | for cls, args, kwargs in reversed(middleware): |
| 227 | self.app = cls(self.app, *args, **kwargs) |
| 228 | |
| 229 | if methods is None: |
| 230 | self.methods = None |
| 231 | else: |
| 232 | self.methods = {method.upper() for method in methods} |
| 233 | if "GET" in self.methods: |
| 234 | self.methods.add("HEAD") |
| 235 | |
| 236 | self.path_regex, self.path_format, self.param_convertors = compile_path(path) |
| 237 | |
| 238 | def matches(self, scope: Scope) -> tuple[Match, Scope]: |
| 239 | path_params: dict[str, Any] |
| 240 | if scope["type"] == "http": |
| 241 | route_path = get_route_path(scope) |
| 242 | match = self.path_regex.match(route_path) |
| 243 | if match: |
| 244 | matched_params = match.groupdict() |
| 245 | for key, value in matched_params.items(): |
| 246 | matched_params[key] = self.param_convertors[key].convert(value) |
| 247 | path_params = dict(scope.get("path_params", {})) |
| 248 | path_params.update(matched_params) |
| 249 | child_scope = {"endpoint": self.endpoint, "path_params": path_params} |
| 250 | if self.methods and scope["method"] not in self.methods: |
| 251 | return Match.PARTIAL, child_scope |
| 252 | else: |
| 253 | return Match.FULL, child_scope |
no outgoing calls