ominfra 0.0.0.dev76__py3-none-any.whl → 0.0.0.dev78__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,232 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import abc
3
+ import errno
4
+ import logging
5
+ import select
6
+ import typing as ta
7
+
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ class BasePoller(abc.ABC):
13
+
14
+ def __init__(self) -> None:
15
+ super().__init__()
16
+
17
+ @abc.abstractmethod
18
+ def register_readable(self, fd: int) -> None:
19
+ raise NotImplementedError
20
+
21
+ @abc.abstractmethod
22
+ def register_writable(self, fd: int) -> None:
23
+ raise NotImplementedError
24
+
25
+ @abc.abstractmethod
26
+ def unregister_readable(self, fd: int) -> None:
27
+ raise NotImplementedError
28
+
29
+ @abc.abstractmethod
30
+ def unregister_writable(self, fd: int) -> None:
31
+ raise NotImplementedError
32
+
33
+ @abc.abstractmethod
34
+ def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[int], ta.List[int]]:
35
+ raise NotImplementedError
36
+
37
+ def before_daemonize(self) -> None: # noqa
38
+ pass
39
+
40
+ def after_daemonize(self) -> None: # noqa
41
+ pass
42
+
43
+ def close(self) -> None: # noqa
44
+ pass
45
+
46
+
47
+ class SelectPoller(BasePoller):
48
+
49
+ def __init__(self) -> None:
50
+ super().__init__()
51
+
52
+ self._readables: ta.Set[int] = set()
53
+ self._writables: ta.Set[int] = set()
54
+
55
+ def register_readable(self, fd: int) -> None:
56
+ self._readables.add(fd)
57
+
58
+ def register_writable(self, fd: int) -> None:
59
+ self._writables.add(fd)
60
+
61
+ def unregister_readable(self, fd: int) -> None:
62
+ self._readables.discard(fd)
63
+
64
+ def unregister_writable(self, fd: int) -> None:
65
+ self._writables.discard(fd)
66
+
67
+ def unregister_all(self) -> None:
68
+ self._readables.clear()
69
+ self._writables.clear()
70
+
71
+ def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[int], ta.List[int]]:
72
+ try:
73
+ r, w, x = select.select(
74
+ self._readables,
75
+ self._writables,
76
+ [], timeout,
77
+ )
78
+ except OSError as err:
79
+ if err.args[0] == errno.EINTR:
80
+ log.debug('EINTR encountered in poll')
81
+ return [], []
82
+ if err.args[0] == errno.EBADF:
83
+ log.debug('EBADF encountered in poll')
84
+ self.unregister_all()
85
+ return [], []
86
+ raise
87
+ return r, w
88
+
89
+
90
+ class PollPoller(BasePoller):
91
+ _READ = select.POLLIN | select.POLLPRI | select.POLLHUP
92
+ _WRITE = select.POLLOUT
93
+
94
+ def __init__(self) -> None:
95
+ super().__init__()
96
+
97
+ self._poller = select.poll()
98
+ self._readables: set[int] = set()
99
+ self._writables: set[int] = set()
100
+
101
+ def register_readable(self, fd: int) -> None:
102
+ self._poller.register(fd, self._READ)
103
+ self._readables.add(fd)
104
+
105
+ def register_writable(self, fd: int) -> None:
106
+ self._poller.register(fd, self._WRITE)
107
+ self._writables.add(fd)
108
+
109
+ def unregister_readable(self, fd: int) -> None:
110
+ self._readables.discard(fd)
111
+ self._poller.unregister(fd)
112
+ if fd in self._writables:
113
+ self._poller.register(fd, self._WRITE)
114
+
115
+ def unregister_writable(self, fd: int) -> None:
116
+ self._writables.discard(fd)
117
+ self._poller.unregister(fd)
118
+ if fd in self._readables:
119
+ self._poller.register(fd, self._READ)
120
+
121
+ def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[int], ta.List[int]]:
122
+ fds = self._poll_fds(timeout) # type: ignore
123
+ readables, writables = [], []
124
+ for fd, eventmask in fds:
125
+ if self._ignore_invalid(fd, eventmask):
126
+ continue
127
+ if eventmask & self._READ:
128
+ readables.append(fd)
129
+ if eventmask & self._WRITE:
130
+ writables.append(fd)
131
+ return readables, writables
132
+
133
+ def _poll_fds(self, timeout: float) -> ta.List[ta.Tuple[int, int]]:
134
+ try:
135
+ return self._poller.poll(timeout * 1000)
136
+ except OSError as err:
137
+ if err.args[0] == errno.EINTR:
138
+ log.debug('EINTR encountered in poll')
139
+ return []
140
+ raise
141
+
142
+ def _ignore_invalid(self, fd: int, eventmask: int) -> bool:
143
+ if eventmask & select.POLLNVAL:
144
+ # POLLNVAL means `fd` value is invalid, not open. When a process quits it's `fd`s are closed so there is no
145
+ # more reason to keep this `fd` registered If the process restarts it's `fd`s are registered again.
146
+ self._poller.unregister(fd)
147
+ self._readables.discard(fd)
148
+ self._writables.discard(fd)
149
+ return True
150
+ return False
151
+
152
+
153
+ class KqueuePoller(BasePoller):
154
+ max_events = 1000
155
+
156
+ def __init__(self) -> None:
157
+ super().__init__()
158
+
159
+ self._kqueue: ta.Optional[ta.Any] = select.kqueue()
160
+ self._readables: set[int] = set()
161
+ self._writables: set[int] = set()
162
+
163
+ def register_readable(self, fd: int) -> None:
164
+ self._readables.add(fd)
165
+ kevent = select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)
166
+ self._kqueue_control(fd, kevent)
167
+
168
+ def register_writable(self, fd: int) -> None:
169
+ self._writables.add(fd)
170
+ kevent = select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)
171
+ self._kqueue_control(fd, kevent)
172
+
173
+ def unregister_readable(self, fd: int) -> None:
174
+ kevent = select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)
175
+ self._readables.discard(fd)
176
+ self._kqueue_control(fd, kevent)
177
+
178
+ def unregister_writable(self, fd: int) -> None:
179
+ kevent = select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)
180
+ self._writables.discard(fd)
181
+ self._kqueue_control(fd, kevent)
182
+
183
+ def _kqueue_control(self, fd: int, kevent: 'select.kevent') -> None:
184
+ try:
185
+ self._kqueue.control([kevent], 0) # type: ignore
186
+ except OSError as error:
187
+ if error.errno == errno.EBADF:
188
+ log.debug('EBADF encountered in kqueue. Invalid file descriptor %s', fd)
189
+ else:
190
+ raise
191
+
192
+ def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[int], ta.List[int]]:
193
+ readables, writables = [], [] # type: ignore
194
+
195
+ try:
196
+ kevents = self._kqueue.control(None, self.max_events, timeout) # type: ignore
197
+ except OSError as error:
198
+ if error.errno == errno.EINTR:
199
+ log.debug('EINTR encountered in poll')
200
+ return readables, writables
201
+ raise
202
+
203
+ for kevent in kevents:
204
+ if kevent.filter == select.KQ_FILTER_READ:
205
+ readables.append(kevent.ident)
206
+ if kevent.filter == select.KQ_FILTER_WRITE:
207
+ writables.append(kevent.ident)
208
+
209
+ return readables, writables
210
+
211
+ def before_daemonize(self) -> None:
212
+ self.close()
213
+
214
+ def after_daemonize(self) -> None:
215
+ self._kqueue = select.kqueue()
216
+ for fd in self._readables:
217
+ self.register_readable(fd)
218
+ for fd in self._writables:
219
+ self.register_writable(fd)
220
+
221
+ def close(self) -> None:
222
+ self._kqueue.close() # type: ignore
223
+ self._kqueue = None
224
+
225
+
226
+ Poller: ta.Type[BasePoller]
227
+ if hasattr(select, 'kqueue'):
228
+ Poller = KqueuePoller
229
+ elif hasattr(select, 'poll'):
230
+ Poller = PollPoller
231
+ else:
232
+ Poller = SelectPoller