Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
timeouts.py183 linesDownload Raw Back to asyncio
1import enum2 3from types import TracebackType4 5from . import events6from . import exceptions7from . import tasks8 9 10__all__ = (11    "Timeout",12    "timeout",13    "timeout_at",14)15 16 17class _State(enum.Enum):18    CREATED = "created"19    ENTERED = "active"20    EXPIRING = "expiring"21    EXPIRED = "expired"22    EXITED = "finished"23 24 25class Timeout:26    """Asynchronous context manager for cancelling overdue coroutines.27 28    Use `timeout()` or `timeout_at()` rather than instantiating this class directly.29    """30 31    def __init__(self, when: float | None) -> None:32        """Schedule a timeout that will trigger at a given loop time.33 34        - If `when` is `None`, the timeout will never trigger.35        - If `when < loop.time()`, the timeout will trigger on the next36          iteration of the event loop.37        """38        self._state = _State.CREATED39 40        self._timeout_handler: events.TimerHandle | None = None41        self._task: tasks.Task | None = None42        self._when = when43 44    def when(self) -> float | None:45        """Return the current deadline."""46        return self._when47 48    def reschedule(self, when: float | None) -> None:49        """Reschedule the timeout."""50        if self._state is not _State.ENTERED:51            if self._state is _State.CREATED:52                raise RuntimeError("Timeout has not been entered")53            raise RuntimeError(54                f"Cannot change state of {self._state.value} Timeout",55            )56 57        self._when = when58 59        if self._timeout_handler is not None:60            self._timeout_handler.cancel()61 62        if when is None:63            self._timeout_handler = None64        else:65            loop = events.get_running_loop()66            if when <= loop.time():67                self._timeout_handler = loop.call_soon(self._on_timeout)68            else:69                self._timeout_handler = loop.call_at(when, self._on_timeout)70 71    def expired(self) -> bool:72        """Is timeout expired during execution?"""73        return self._state in (_State.EXPIRING, _State.EXPIRED)74 75    def __repr__(self) -> str:76        info = ['']77        if self._state is _State.ENTERED:78            when = round(self._when, 3) if self._when is not None else None79            info.append(f"when={when}")80        info_str = ' '.join(info)81        return f"<Timeout [{self._state.value}]{info_str}>"82 83    async def __aenter__(self) -> "Timeout":84        if self._state is not _State.CREATED:85            raise RuntimeError("Timeout has already been entered")86        task = tasks.current_task()87        if task is None:88            raise RuntimeError("Timeout should be used inside a task")89        self._state = _State.ENTERED90        self._task = task91        self._cancelling = self._task.cancelling()92        self.reschedule(self._when)93        return self94 95    async def __aexit__(96        self,97        exc_type: type[BaseException] | None,98        exc_val: BaseException | None,99        exc_tb: TracebackType | None,100    ) -> bool | None:101        assert self._state in (_State.ENTERED, _State.EXPIRING)102 103        if self._timeout_handler is not None:104            self._timeout_handler.cancel()105            self._timeout_handler = None106 107        if self._state is _State.EXPIRING:108            self._state = _State.EXPIRED109 110            if self._task.uncancel() <= self._cancelling and exc_type is not None:111                # Since there are no new cancel requests, we're112                # handling this.113                if issubclass(exc_type, exceptions.CancelledError):114                    raise TimeoutError from exc_val115                elif exc_val is not None:116                    self._insert_timeout_error(exc_val)117                    if isinstance(exc_val, ExceptionGroup):118                        for exc in exc_val.exceptions:119                            self._insert_timeout_error(exc)120        elif self._state is _State.ENTERED:121            self._state = _State.EXITED122 123        return None124 125    def _on_timeout(self) -> None:126        assert self._state is _State.ENTERED127        self._task.cancel()128        self._state = _State.EXPIRING129        # drop the reference early130        self._timeout_handler = None131 132    @staticmethod133    def _insert_timeout_error(exc_val: BaseException) -> None:134        while exc_val.__context__ is not None:135            if isinstance(exc_val.__context__, exceptions.CancelledError):136                te = TimeoutError()137                te.__context__ = te.__cause__ = exc_val.__context__138                exc_val.__context__ = te139                break140            exc_val = exc_val.__context__141 142 143def timeout(delay: float | None) -> Timeout:144    """Timeout async context manager.145 146    Useful in cases when you want to apply timeout logic around block147    of code or in cases when asyncio.wait_for is not suitable. For example:148 149    >>> async with asyncio.timeout(10):  # 10 seconds timeout150    ...     await long_running_task()151 152 153    delay - value in seconds or None to disable timeout logic154 155    long_running_task() is interrupted by raising asyncio.CancelledError,156    the top-most affected timeout() context manager converts CancelledError157    into TimeoutError.158    """159    loop = events.get_running_loop()160    return Timeout(loop.time() + delay if delay is not None else None)161 162 163def timeout_at(when: float | None) -> Timeout:164    """Schedule the timeout at absolute time.165 166    Like timeout() but argument gives absolute time in the same clock system167    as loop.time().168 169    Please note: it is not POSIX time but a time with170    undefined starting base, e.g. the time of the system power on.171 172    >>> async with asyncio.timeout_at(loop.time() + 10):173    ...     await long_running_task()174 175 176    when - a deadline when timeout occurs or None to disable timeout logic177 178    long_running_task() is interrupted by raising asyncio.CancelledError,179    the top-most affected timeout() context manager converts CancelledError180    into TimeoutError.181    """182    return Timeout(when)183 
codekingpro/portable-devtools · Team Ai