| 401 | |
| 402 | |
| 403 | class RouteHandler: |
| 404 | def __init__( |
| 405 | self, |
| 406 | base_url: Optional[str], |
| 407 | url: URLMatch, |
| 408 | handler: RouteHandlerCallback, |
| 409 | is_sync: bool, |
| 410 | times: Optional[int] = None, |
| 411 | ): |
| 412 | self._base_url = base_url |
| 413 | self.url = url |
| 414 | self.handler = handler |
| 415 | self._times = times if times else math.inf |
| 416 | self._handled_count = 0 |
| 417 | self._is_sync = is_sync |
| 418 | self._ignore_exception = False |
| 419 | self._active_invocations: Set[RouteHandlerInvocation] = set() |
| 420 | |
| 421 | def matches(self, request_url: str) -> bool: |
| 422 | return url_matches(self._base_url, request_url, self.url) |
| 423 | |
| 424 | async def handle(self, route: "Route") -> bool: |
| 425 | handler_invocation = RouteHandlerInvocation( |
| 426 | asyncio.get_running_loop().create_future(), route |
| 427 | ) |
| 428 | self._active_invocations.add(handler_invocation) |
| 429 | try: |
| 430 | return await self._handle_internal(route) |
| 431 | except Exception as e: |
| 432 | # If the handler was stopped (without waiting for completion), we ignore all exceptions. |
| 433 | if self._ignore_exception: |
| 434 | return False |
| 435 | if is_target_closed_error(e): |
| 436 | # We are failing in the handler because the target has closed. |
| 437 | # Give user a hint! |
| 438 | optional_async_prefix = "await " if not self._is_sync else "" |
| 439 | raise rewrite_error( |
| 440 | e, |
| 441 | f"\"{str(e)}\" while running route callback.\nConsider awaiting `{optional_async_prefix}page.unroute_all(behavior='ignoreErrors')`\nbefore the end of the test to ignore remaining routes in flight.", |
| 442 | ) |
| 443 | raise e |
| 444 | finally: |
| 445 | handler_invocation.complete.set_result(None) |
| 446 | self._active_invocations.remove(handler_invocation) |
| 447 | |
| 448 | async def _handle_internal(self, route: "Route") -> bool: |
| 449 | handled_future = route._start_handling() |
| 450 | |
| 451 | self._handled_count += 1 |
| 452 | if self._is_sync: |
| 453 | handler_finished_future = route._loop.create_future() |
| 454 | |
| 455 | def _handler() -> None: |
| 456 | try: |
| 457 | self.handler(route, route.request) # type: ignore |
| 458 | handler_finished_future.set_result(None) |
| 459 | except Exception as e: |
| 460 | handler_finished_future.set_exception(e) |