1 # vim: set encoding=utf-8 et sw=4 sts=4 :
6 Please see EventLoop class documentation for more info.
10 from select import POLLIN, POLLPRI, POLLERR
12 __ALL__ = ('EventLoop', 'LoopInterruptedError')
14 class LoopInterruptedError(RuntimeError):
16 LoopInterruptedError(select_error) -> LoopInterruptedError instance.
18 This class is raised when the event loop is interrupted in an unexpected
19 way. It wraps a select error, which can be accessed using the 'select_error'
23 def __init__(self, select_error):
24 r"""Initialize the object.
26 See the class documentation for more info.
28 self.select_error = select_error
31 r"repr(obj) -> Object representation."
32 return 'LoopInterruptedError(select_error=%r)' % self.select_error
35 r"str(obj) -> String representation."
36 return 'Loop interrupted: %s' % self.select_error
39 r"""EventLoop(file[, handler]) -> EventLoop instance
41 This class implements a simple event loop based on select module.
42 It "listens" to activity a single 'file' object (a file, a pipe,
43 a socket, or even a simple file descriptor) and calls a 'handler'
44 function (or the handle() method if you prefer subclassing) every
45 time the file is ready for reading (or has an error).
47 This is a really simple example of usage using a hanlder callable:
50 >>> def handle(event_loop):
51 data = os.read(event_loop.fileno, 100)
52 os.write(1, 'Received message: %r\n' % data)
53 >>> p = EventLoop(0, handle)
56 In this example only one event is handled (see the 'once' argument
59 A more complex example, making a subclass and explicitly stopping
60 the loop, looks something like this:
62 >>> class Test(EventLoop):
64 >>> data = os.read(self.fileno, 100)
68 >>> os.write(1, 'Received message: %r\n' % data)
72 This example loops until the user enters a single "q", when stop()
73 is called and the event loop is exited.
76 def __init__(self, file, handler=None):
77 r"""Initialize the EventLoop object.
79 See EventLoop class documentation for more info.
81 self.poll = select.poll()
84 self.handler = handler
86 def __register(self, file):
87 r"__register(file) -> None :: Register a new file for polling."
89 self.poll.register(self.fileno, POLLIN | POLLPRI | POLLERR)
91 def set_file(self, file):
92 r"""set_file(file) -> None :: New file object to be monitored
94 Unregister the previous file object being monitored and register
97 self.poll.unregister(self.fileno)
101 r"get_file() -> file object/int :: Get the current file object/fd."
104 file = property(get_file, set_file, doc='File object (or descriptor)')
106 def get_fileno(self):
107 r"get_fileno() -> int :: Get the current file descriptor"
108 if hasattr(self.file, 'fileno'):
109 return self.file.fileno()
112 fileno = property(get_fileno, doc='File descriptor (never a file object)')
115 r"""stop() -> None :: Stop the event loop.
117 The event loop will be interrupted as soon as the current handler
122 def loop(self, once=False):
123 r"""loop([once]) -> None :: Wait for events.
125 Wait for events and handle then when they arrive. If once is True,
126 then only 1 event is processed and then this method returns.
130 res = self.poll.poll()
131 except select.error, e:
132 raise LoopInterruptedError(e)
133 if self.handler is not None:
137 if self._stop or once:
142 r"handle() -> None :: Abstract method to be overriden to handle events."
143 raise NotImplementedError
145 if __name__ == '__main__':
149 def handle(event_loop):
150 data = os.read(event_loop.fileno, 100)
151 os.write(1, 'Received message: %r\n' % data)
153 p = EventLoop(0, handle)
155 os.write(1, 'Say something once: ')
157 os.write(1, 'Great!\n')
159 class Test(EventLoop):
161 data = os.read(self.fileno, 100)
165 os.write(1, 'Received message: %r\n' % data)
169 os.write(1, 'Say a lot of things, then press write just "q" to stop: ')
171 os.write(1, 'Ok, bye!\n')