Skip to content

Commit

Permalink
Create the EventLoop abstract class, add documentation for signal han…
Browse files Browse the repository at this point in the history
…dling, use Python .gitignore provided by GitHub
  • Loading branch information
federicotdn committed Jan 8, 2018
1 parent 1704e37 commit b309279
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 42 deletions.
108 changes: 98 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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/
149 changes: 117 additions & 32 deletions urwid/main_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,103 @@ def draw_screen(self):
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`
"""
Expand Down Expand Up @@ -651,12 +747,6 @@ def remove_watch_file(self, handle):
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.
Expand Down Expand Up @@ -736,7 +826,7 @@ def _loop(self):
self._did_something = True


class GLibEventLoop(object):
class GLibEventLoop(EventLoop):
"""
Event loop based on GLib.MainLoop
"""
Expand Down Expand Up @@ -775,9 +865,22 @@ def ret_false():

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,
Expand Down Expand Up @@ -924,7 +1027,7 @@ def wrapper(*args,**kargs):
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.
Expand Down Expand Up @@ -1034,12 +1137,6 @@ def remove_watch_file(self, handle):
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
Expand Down Expand Up @@ -1090,7 +1187,7 @@ def doRead(self):
return self.cb()


class TwistedEventLoop(object):
class TwistedEventLoop(EventLoop):
"""
Event loop based on Twisted_
"""
Expand Down Expand Up @@ -1185,12 +1282,6 @@ def remove_watch_file(self, handle):
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.
Expand Down Expand Up @@ -1276,7 +1367,7 @@ def wrapper(*args,**kargs):
return wrapper


class AsyncioEventLoop(object):
class AsyncioEventLoop(EventLoop):
"""
Event loop based on the standard library ``asyncio`` module.
Expand Down Expand Up @@ -1338,12 +1429,6 @@ def remove_watch_file(self, handle):
"""
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.
Expand Down

0 comments on commit b309279

Please sign in to comment.