]> git.llucax.com Git - software/pymin.git/blob - eventloop.py
7da492db90de7387c1fae3c48d962d2648a69df2
[software/pymin.git] / eventloop.py
1 # vim: set encoding=utf-8 et sw=4 sts=4 :
2
3 r"""
4 A simple event loop.
5
6 Please see EventLoop class documentation for more info.
7 """
8
9 from select import poll, POLLIN, POLLPRI, POLLERR
10
11 __ALL__ = ('EventLoop')
12
13 class EventLoop:
14     r"""EventLoop(file[, handler]) -> EventLoop instance
15
16     This class implements a simple event loop based on select module.
17     It "listens" to activity a single 'file' object (a file, a pipe,
18     a socket, or even a simple file descriptor) and calls a 'handler'
19     function (or the handle() method if you prefer subclassing) every
20     time the file is ready for reading (or has an error).
21
22     This is a really simple example of usage using a hanlder callable:
23
24     >>> import os 
25     >>> def handle(event_loop):
26             data = os.read(event_loop.fileno, 100)
27             os.write(1, 'Received message: %r\n' % data)
28     >>> p = EventLoop(0, handle)
29     >>> p.loop(once=True)
30
31     In this example only one event is handled (see the 'once' argument
32     of loop).
33
34     A more complex example, making a subclass and explicitly stopping
35     the loop, looks something like this:
36
37     >>> class Test(EventLoop):
38     >>>     def handle(self):
39     >>>         data = os.read(self.fileno, 100)
40     >>>         if data == 'q\n':
41     >>>             self.stop()
42     >>>         else:
43     >>>             os.write(1, 'Received message: %r\n' % data)
44     >>> p = Test(0)
45     >>> p.loop()
46
47     This example loops until the user enters a single "q", when stop()
48     is called and the event loop is exited.
49     """
50
51     def __init__(self, file, handler=None):
52         r"""Initialize the EventLoop object.
53
54         See EventLoop class documentation for more info.
55         """
56         self.poll = poll()
57         self._stop = False
58         self.__register(file)
59         self.handler = handler
60
61     def __register(self, file):
62         r"__register(file) -> None :: Register a new file for polling."
63         self._file = file
64         self.poll.register(self.fileno, POLLIN | POLLPRI | POLLERR)
65
66     def set_file(self, file):
67         r"""set_file(file) -> None :: New file object to be monitored
68
69         Unregister the previous file object being monitored and register
70         a new one.
71         """
72         self.poll.unregister(self.fileno)
73         self.__register(file)
74
75     def get_file(self):
76         r"get_file() -> file object/int :: Get the current file object/fd."
77         return self._file
78
79     file = property(get_file, set_file, doc='File object (or descriptor)')
80
81     def get_fileno(self):
82         r"get_fileno() -> int :: Get the current file descriptor"
83         if hasattr(self.file, 'fileno'):
84             return self.file.fileno()
85         return self.file
86
87     fileno = property(get_fileno, doc='File descriptor (never a file object)')
88
89     def stop(self):
90         r"""stop() -> None :: Stop the event loop.
91
92         The event loop will be interrupted as soon as the current handler
93         finishes.
94         """
95         self._stop = True
96
97     def loop(self, once=False):
98         r"""loop([once]) -> None :: Wait for events.
99
100         Wait for events and handle then when they arrive. If once is True,
101         then only 1 event is processed and then this method returns.
102         """
103         while True:
104             res = self.poll.poll()
105             if self.handler is not None:
106                 self.handler(self)
107             else:
108                 self.handle()
109             if self._stop or once:
110                 self._stop = False
111                 break
112
113     def handle(self):
114         r"handle() -> None :: Abstract method to be overriden to handle events."
115         raise NotImplementedError
116
117 if __name__ == '__main__':
118
119     import os
120
121     def handle(event_loop):
122         data = os.read(event_loop.fileno, 100)
123         os.write(1, 'Received message: %r\n' % data)
124
125     p = EventLoop(0, handle)
126
127     os.write(1, 'Say something once: ')
128     p.loop(once=True)
129     os.write(1, 'Great!\n')
130
131     class Test(EventLoop):
132         def handle(self):
133             data = os.read(self.fileno, 100)
134             if data == 'q\n':
135                 self.stop()
136             else:
137                 os.write(1, 'Received message: %r\n' % data)
138
139     p = Test(0)
140
141     os.write(1, 'Say a lot of things, then press write just "q" to stop: ')
142     p.loop()
143     os.write(1, 'Ok, bye!\n')
144