diff options
| author | Andrew Dunai <andunai@gmail.com> | 2018-01-10 14:56:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-01-10 14:56:32 +0200 |
| commit | a2919015de2f016339cc7c5face9aecdc97cdb40 (patch) | |
| tree | 71a031ea6ac36e9a9058c67c676418c13225023b | |
| parent | 1704e374ba55e6fdfe8d68870bd1781ce8afedcd (diff) | |
| parent | b309279e6e3bf17a7f742d8d6e81d22c2a8169cd (diff) | |
| download | urwid-a2919015de2f016339cc7c5face9aecdc97cdb40.tar.gz | |
Merge pull request #271 from federicotdn/master
Create the EventLoop abstract class, add documentation for signal handling
| -rw-r--r-- | .gitignore | 108 | ||||
| -rwxr-xr-x | urwid/main_loop.py | 149 |
2 files changed, 215 insertions, 42 deletions
@@ -1,16 +1,104 @@ -.DS_Store +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class -*.pyc -*.pyo +# C extensions +*.so -*.egg-info -_build -build -dist +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg MANIFEST +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ .coverage -coverage -htmlcov +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +.static_storage/ +.media/ +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site -_trial_temp +# mypy +.mypy_cache/
\ No newline at end of file diff --git a/urwid/main_loop.py b/urwid/main_loop.py index 3d18c52..c043e47 100755 --- a/urwid/main_loop.py +++ b/urwid/main_loop.py @@ -587,7 +587,103 @@ class MainLoop(object): self.screen.draw_screen(self.screen_size, canvas) -class SelectEventLoop(object): +class EventLoop(object): + """ + Abstract class representing an event loop to be used by :class:`MainLoop`. + """ + + def alarm(self, seconds, callback): + """ + 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 + """ + raise NotImplementedError() + + 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() + """ + raise NotImplementedError() + + def remove_alarm(self, handle): + """ + Remove an alarm. + + This method has no default implementation. + + Returns True if the alarm exists, False otherwise + """ + raise NotImplementedError() + + def remove_enter_idle(self, handle): + """ + Remove an idle callback. + + This method has no default implementation. + + Returns True if the handle was removed. + """ + raise NotImplementedError() + + def remove_watch_file(self, handle): + """ + Remove an input file. + + This method has no default implementation. + + Returns True if the input file exists, False otherwise + """ + raise NotImplementedError() + + def run(self): + """ + 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. + """ + raise NotImplementedError() + + def watch_file(self, fd, callback): + """ + 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 + """ + raise NotImplementedError() + + def set_signal_handler(self, signum, handler): + """ + 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) + +class SelectEventLoop(EventLoop): """ Event loop based on :func:`select.select` """ @@ -651,12 +747,6 @@ class SelectEventLoop(object): return True return False - def set_signal_handler(self, signum, handler): - """ - Proxy function to signal.signal() - """ - return signal.signal(signum, handler) - def enter_idle(self, callback): """ Add a callback for entering idle. @@ -736,7 +826,7 @@ class SelectEventLoop(object): self._did_something = True -class GLibEventLoop(object): +class GLibEventLoop(EventLoop): """ Event loop based on GLib.MainLoop """ @@ -775,9 +865,22 @@ class GLibEventLoop(object): def set_signal_handler(self, signum, handler): """ - Sets a handler for a specified signal. This method's behaviour - method tries to imitate the signal() function from the signal - module. + Sets the signal handler for signal signum. + + .. WARNING:: + Because this method uses the `GLib`-specific `unix_signal_add` + function, its behaviour is different than `signal.signal().` + + If `signum` is not `SIGHUP`, `SIGINT`, `SIGTERM`, `SIGUSR1`, + `SIGUSR2` or `SIGWINCH`, this method performs no actions and + immediately returns None. + + Returns None in all cases (unlike :func:`signal.signal()`). + .. + + signum -- signal number + handler -- function (taking signum as its single argument), + or `signal.SIG_IGN`, or `signal.SIG_DFL` """ glib_signals = [ signal.SIGHUP, @@ -924,7 +1027,7 @@ class GLibEventLoop(object): return wrapper -class TornadoEventLoop(object): +class TornadoEventLoop(EventLoop): """ This is an Urwid-specific event loop to plug into its MainLoop. It acts as an adaptor for Tornado's IOLoop which does all heavy lifting except idle-callbacks. @@ -1034,12 +1137,6 @@ class TornadoEventLoop(object): self._ioloop.remove_handler(fd) return True - def set_signal_handler(self, signum, handler): - """ - Proxy function to signal.signal() - """ - return signal.signal(signum, handler) - def enter_idle(self, callback): self._max_idle_handle += 1 handle = self._max_idle_handle @@ -1090,7 +1187,7 @@ class TwistedInputDescriptor(FileDescriptor): return self.cb() -class TwistedEventLoop(object): +class TwistedEventLoop(EventLoop): """ Event loop based on Twisted_ """ @@ -1185,12 +1282,6 @@ class TwistedEventLoop(object): return True return False - def set_signal_handler(self, signum, handler): - """ - Proxy function to signal.signal() - """ - return signal.signal(signum, handler) - def enter_idle(self, callback): """ Add a callback for entering idle. @@ -1276,7 +1367,7 @@ class TwistedEventLoop(object): return wrapper -class AsyncioEventLoop(object): +class AsyncioEventLoop(EventLoop): """ Event loop based on the standard library ``asyncio`` module. @@ -1338,12 +1429,6 @@ class AsyncioEventLoop(object): """ return self._loop.remove_reader(handle) - def set_signal_handler(self, signum, handler): - """ - Proxy function to signal.signal() - """ - return signal.signal(signum, handler) - def enter_idle(self, callback): """ Add a callback for entering idle. |
