1 | """ |
---|
2 | Polling utility that returns Deferred. |
---|
3 | |
---|
4 | Ported to Python 3. |
---|
5 | """ |
---|
6 | |
---|
7 | from __future__ import annotations |
---|
8 | |
---|
9 | import time |
---|
10 | |
---|
11 | from twisted.internet import task |
---|
12 | |
---|
13 | class TimeoutError(Exception): |
---|
14 | pass |
---|
15 | |
---|
16 | class PollComplete(Exception): |
---|
17 | pass |
---|
18 | |
---|
19 | class PollMixin(object): |
---|
20 | _poll_should_ignore_these_errors : list[Exception] = [] |
---|
21 | |
---|
22 | def poll(self, check_f, pollinterval=0.01, timeout=1000): |
---|
23 | # Return a Deferred, then call check_f periodically until it returns |
---|
24 | # True, at which point the Deferred will fire.. If check_f raises an |
---|
25 | # exception, the Deferred will errback. If the check_f does not |
---|
26 | # indicate success within timeout= seconds, the Deferred will |
---|
27 | # errback. If timeout=None, no timeout will be enforced, and the loop |
---|
28 | # will poll forever (or really until Trial times out). |
---|
29 | cutoff = None |
---|
30 | if timeout is not None: |
---|
31 | cutoff = time.time() + timeout |
---|
32 | lc = task.LoopingCall(self._poll, check_f, cutoff) |
---|
33 | d = lc.start(pollinterval) |
---|
34 | def _convert_done(f): |
---|
35 | f.trap(PollComplete) |
---|
36 | return None |
---|
37 | d.addErrback(_convert_done) |
---|
38 | return d |
---|
39 | |
---|
40 | def _poll(self, check_f, cutoff): |
---|
41 | if cutoff is not None and time.time() > cutoff: |
---|
42 | raise TimeoutError("PollMixin never saw %s return True" % check_f) |
---|
43 | if check_f(): |
---|
44 | raise PollComplete() |
---|
45 | # since PollMixin is mostly used for unit tests, quit if we see any |
---|
46 | # logged errors. This should give us a nice fast failure, instead of |
---|
47 | # waiting for a timeout. Tests which use flushLoggedErrors() will |
---|
48 | # need to warn us by putting the error types they'll be ignoring in |
---|
49 | # self._poll_should_ignore_these_errors |
---|
50 | if hasattr(self, "_observer") and hasattr(self._observer, "getErrors"): |
---|
51 | errs = [] |
---|
52 | for e in self._observer.getErrors(): |
---|
53 | if not e.check(*self._poll_should_ignore_these_errors): |
---|
54 | errs.append(e) |
---|
55 | if errs: |
---|
56 | print(errs) |
---|
57 | self.fail("Errors snooped, terminating early") |
---|
58 | |
---|