mirror of
https://github.com/avitoras/telegram-tui.git
synced 2026-02-04 11:56:25 +00:00
179 lines
5.4 KiB
Python
179 lines
5.4 KiB
Python
# Urwid main loop code
|
|
# Copyright (C) 2004-2012 Ian Ward
|
|
# Copyright (C) 2008 Walter Mundt
|
|
# Copyright (C) 2009 Andrew Psaltis
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Urwid web site: https://urwid.org/
|
|
|
|
"""Abstract shared code for urwid EventLoop implementation."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import abc
|
|
import logging
|
|
import signal
|
|
import typing
|
|
|
|
if typing.TYPE_CHECKING:
|
|
import asyncio
|
|
from collections.abc import Callable
|
|
from concurrent.futures import Executor, Future
|
|
from types import FrameType
|
|
|
|
from typing_extensions import ParamSpec
|
|
|
|
_T = typing.TypeVar("_T")
|
|
_Spec = ParamSpec("_Spec")
|
|
|
|
__all__ = ("EventLoop", "ExitMainLoop")
|
|
|
|
|
|
class ExitMainLoop(Exception):
|
|
"""
|
|
When this exception is raised within a main loop the main loop
|
|
will exit cleanly.
|
|
"""
|
|
|
|
|
|
class EventLoop(abc.ABC):
|
|
"""
|
|
Abstract class representing an event loop to be used by :class:`MainLoop`.
|
|
"""
|
|
|
|
__slots__ = ("logger",)
|
|
|
|
def __init__(self) -> None:
|
|
self.logger = logging.getLogger(__name__).getChild(self.__class__.__name__)
|
|
|
|
def run_in_executor(
|
|
self,
|
|
executor: Executor,
|
|
func: Callable[_Spec, _T],
|
|
*args: _Spec.args,
|
|
**kwargs: _Spec.kwargs,
|
|
) -> Future[_T] | asyncio.Future[_T]:
|
|
"""Run callable in executor if supported.
|
|
|
|
:param executor: Executor to use for running the function
|
|
:type executor: concurrent.futures.Executor
|
|
:param func: function to call
|
|
:type func: Callable
|
|
:param args: arguments to function (positional only)
|
|
:type args: object
|
|
:param kwargs: keyword arguments to function (keyword only)
|
|
:type kwargs: object
|
|
:return: future object for the function call outcome.
|
|
(exact future type depends on the event loop type)
|
|
:rtype: concurrent.futures.Future | asyncio.Future
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@abc.abstractmethod
|
|
def alarm(self, seconds: float, callback: Callable[[], typing.Any]) -> typing.Any:
|
|
"""
|
|
Call callback() a given time from now. No parameters are
|
|
passed to callback.
|
|
|
|
This method has no default implementation.
|
|
|
|
Returns a handle that may be passed to remove_alarm()
|
|
|
|
seconds -- floating point time to wait before calling callback
|
|
callback -- function to call from event loop
|
|
"""
|
|
|
|
@abc.abstractmethod
|
|
def enter_idle(self, callback):
|
|
"""
|
|
Add a callback for entering idle.
|
|
|
|
This method has no default implementation.
|
|
|
|
Returns a handle that may be passed to remove_idle()
|
|
"""
|
|
|
|
@abc.abstractmethod
|
|
def remove_alarm(self, handle) -> bool:
|
|
"""
|
|
Remove an alarm.
|
|
|
|
This method has no default implementation.
|
|
|
|
Returns True if the alarm exists, False otherwise
|
|
"""
|
|
|
|
@abc.abstractmethod
|
|
def remove_enter_idle(self, handle) -> bool:
|
|
"""
|
|
Remove an idle callback.
|
|
|
|
This method has no default implementation.
|
|
|
|
Returns True if the handle was removed.
|
|
"""
|
|
|
|
@abc.abstractmethod
|
|
def remove_watch_file(self, handle) -> bool:
|
|
"""
|
|
Remove an input file.
|
|
|
|
This method has no default implementation.
|
|
|
|
Returns True if the input file exists, False otherwise
|
|
"""
|
|
|
|
@abc.abstractmethod
|
|
def run(self) -> None:
|
|
"""
|
|
Start the event loop. Exit the loop when any callback raises
|
|
an exception. If ExitMainLoop is raised, exit cleanly.
|
|
|
|
This method has no default implementation.
|
|
"""
|
|
|
|
@abc.abstractmethod
|
|
def watch_file(self, fd: int, callback: Callable[[], typing.Any]):
|
|
"""
|
|
Call callback() when fd has some data to read. No parameters
|
|
are passed to callback.
|
|
|
|
This method has no default implementation.
|
|
|
|
Returns a handle that may be passed to remove_watch_file()
|
|
|
|
fd -- file descriptor to watch for input
|
|
callback -- function to call when input is available
|
|
"""
|
|
|
|
def set_signal_handler(
|
|
self,
|
|
signum: int,
|
|
handler: Callable[[int, FrameType | None], typing.Any] | int | signal.Handlers,
|
|
) -> Callable[[int, FrameType | None], typing.Any] | int | signal.Handlers | None:
|
|
"""
|
|
Sets the signal handler for signal signum.
|
|
|
|
The default implementation of :meth:`set_signal_handler`
|
|
is simply a proxy function that calls :func:`signal.signal()`
|
|
and returns the resulting value.
|
|
|
|
signum -- signal number
|
|
handler -- function (taking signum as its single argument),
|
|
or `signal.SIG_IGN`, or `signal.SIG_DFL`
|
|
"""
|
|
return signal.signal(signum, handler)
|