twisted / twisted
Showing 1 of 3 files from the diff.

@@ -9,11 +9,15 @@
Loading
9 9
import inspect
10 10
import signal
11 11
import time
12 +
from types import FrameType
13 +
from typing import Callable, List, Optional, Tuple, Union, cast
12 14
13 15
from twisted.internet.abstract import FileDescriptor
14 16
from twisted.internet.defer import Deferred
15 17
from twisted.internet.error import ReactorAlreadyRunning, ReactorNotRestartable
16 18
from twisted.internet.test.reactormixins import ReactorBuilder
19 +
from twisted.python.failure import Failure
20 +
from twisted.trial.unittest import SynchronousTestCase
17 21
18 22
19 23
class ObjectModelIntegrationMixin:
@@ -21,7 +25,7 @@
Loading
21 25
    Helpers for tests about the object model of reactor-related objects.
22 26
    """
23 27
24 -
    def assertFullyNewStyle(self, instance):
28 +
    def assertFullyNewStyle(self, instance: object) -> None:
25 29
        """
26 30
        Assert that the given object is an instance of a new-style class and
27 31
        that there are no classic classes in the inheritance hierarchy of
@@ -30,10 +34,11 @@
Loading
30 34
        This is a beneficial condition because PyPy is better able to
31 35
        optimize attribute lookup on such classes.
32 36
        """
33 -
        self.assertIsInstance(instance, object)
37 +
        testCase = cast(SynchronousTestCase, self)
38 +
        testCase.assertIsInstance(instance, object)
34 39
        mro = inspect.getmro(type(instance))
35 40
        for subclass in mro:
36 -
            self.assertTrue(
41 +
            testCase.assertTrue(
37 42
                issubclass(subclass, object), f"{subclass!r} is not new-style"
38 43
            )
39 44
@@ -43,7 +48,7 @@
Loading
43 48
    Test details of object model integration against all reactors.
44 49
    """
45 50
46 -
    def test_newstyleReactor(self):
51 +
    def test_newstyleReactor(self) -> None:
47 52
        """
48 53
        Checks that all reactors on a platform have method resolution order
49 54
        containing only new style classes.
@@ -58,15 +63,15 @@
Loading
58 63
    and L{IReactorCore.fireSystemEvent}.
59 64
    """
60 65
61 -
    def test_stopWhenNotStarted(self):
66 +
    def test_stopWhenNotStarted(self) -> None:
62 67
        """
63 68
        C{reactor.stop()} raises L{RuntimeError} when called when the reactor
64 69
        has not been started.
65 70
        """
66 71
        reactor = self.buildReactor()
67 -
        self.assertRaises(RuntimeError, reactor.stop)
72 +
        cast(SynchronousTestCase, self).assertRaises(RuntimeError, reactor.stop)
68 73
69 -
    def test_stopWhenAlreadyStopped(self):
74 +
    def test_stopWhenAlreadyStopped(self) -> None:
70 75
        """
71 76
        C{reactor.stop()} raises L{RuntimeError} when called after the reactor
72 77
        has been stopped.
@@ -74,22 +79,22 @@
Loading
74 79
        reactor = self.buildReactor()
75 80
        reactor.callWhenRunning(reactor.stop)
76 81
        self.runReactor(reactor)
77 -
        self.assertRaises(RuntimeError, reactor.stop)
82 +
        cast(SynchronousTestCase, self).assertRaises(RuntimeError, reactor.stop)
78 83
79 -
    def test_callWhenRunningOrder(self):
84 +
    def test_callWhenRunningOrder(self) -> None:
80 85
        """
81 86
        Functions are run in the order that they were passed to
82 87
        L{reactor.callWhenRunning}.
83 88
        """
84 89
        reactor = self.buildReactor()
85 -
        events = []
90 +
        events: List[str] = []
86 91
        reactor.callWhenRunning(events.append, "first")
87 92
        reactor.callWhenRunning(events.append, "second")
88 93
        reactor.callWhenRunning(reactor.stop)
89 94
        self.runReactor(reactor)
90 -
        self.assertEqual(events, ["first", "second"])
95 +
        cast(SynchronousTestCase, self).assertEqual(events, ["first", "second"])
91 96
92 -
    def test_runningForStartupEvents(self):
97 +
    def test_runningForStartupEvents(self) -> None:
93 98
        """
94 99
        The reactor is not running when C{"before"} C{"startup"} triggers are
95 100
        called and is running when C{"during"} and C{"after"} C{"startup"}
@@ -98,54 +103,60 @@
Loading
98 103
        reactor = self.buildReactor()
99 104
        state = {}
100 105
101 -
        def beforeStartup():
106 +
        def beforeStartup() -> None:
102 107
            state["before"] = reactor.running
103 108
104 -
        def duringStartup():
109 +
        def duringStartup() -> None:
105 110
            state["during"] = reactor.running
106 111
107 -
        def afterStartup():
112 +
        def afterStartup() -> None:
108 113
            state["after"] = reactor.running
109 114
115 +
        testCase = cast(SynchronousTestCase, self)
116 +
110 117
        reactor.addSystemEventTrigger("before", "startup", beforeStartup)
111 118
        reactor.addSystemEventTrigger("during", "startup", duringStartup)
112 119
        reactor.addSystemEventTrigger("after", "startup", afterStartup)
113 120
        reactor.callWhenRunning(reactor.stop)
114 -
        self.assertEqual(state, {})
121 +
        testCase.assertEqual(state, {})
115 122
        self.runReactor(reactor)
116 -
        self.assertEqual(state, {"before": False, "during": True, "after": True})
123 +
        testCase.assertEqual(state, {"before": False, "during": True, "after": True})
117 124
118 -
    def test_signalHandlersInstalledDuringStartup(self):
125 +
    def test_signalHandlersInstalledDuringStartup(self) -> None:
119 126
        """
120 127
        Signal handlers are installed in responsed to the C{"during"}
121 128
        C{"startup"}.
122 129
        """
123 130
        reactor = self.buildReactor()
124 -
        phase = [None]
131 +
        phase: Optional[str] = None
125 132
126 -
        def beforeStartup():
127 -
            phase[0] = "before"
133 +
        def beforeStartup() -> None:
134 +
            nonlocal phase
135 +
            phase = "before"
128 136
129 -
        def afterStartup():
130 -
            phase[0] = "after"
137 +
        def afterStartup() -> None:
138 +
            nonlocal phase
139 +
            phase = "after"
131 140
132 141
        reactor.addSystemEventTrigger("before", "startup", beforeStartup)
133 142
        reactor.addSystemEventTrigger("after", "startup", afterStartup)
134 143
135 144
        sawPhase = []
136 145
137 -
        def fakeSignal(signum, action):
138 -
            sawPhase.append(phase[0])
146 +
        def fakeSignal(signum: int, action: Callable[[int, FrameType], None]) -> None:
147 +
            sawPhase.append(phase)
148 +
149 +
        testCase = cast(SynchronousTestCase, self)
139 150
140 -
        self.patch(signal, "signal", fakeSignal)
151 +
        testCase.patch(signal, "signal", fakeSignal)
141 152
        reactor.callWhenRunning(reactor.stop)
142 -
        self.assertIsNone(phase[0])
143 -
        self.assertEqual(sawPhase, [])
153 +
        testCase.assertIsNone(phase)
154 +
        testCase.assertEqual(sawPhase, [])
144 155
        self.runReactor(reactor)
145 -
        self.assertIn("before", sawPhase)
146 -
        self.assertEqual(phase[0], "after")
156 +
        testCase.assertIn("before", sawPhase)
157 +
        testCase.assertEqual(phase, "after")
147 158
148 -
    def test_stopShutDownEvents(self):
159 +
    def test_stopShutDownEvents(self) -> None:
149 160
        """
150 161
        C{reactor.stop()} fires all three phases of shutdown event triggers
151 162
        before it makes C{reactor.run()} return.
@@ -163,32 +174,34 @@
Loading
163 174
        )
164 175
        reactor.callWhenRunning(reactor.stop)
165 176
        self.runReactor(reactor)
166 -
        self.assertEqual(
177 +
        cast(SynchronousTestCase, self).assertEqual(
167 178
            events,
168 179
            [("before", "shutdown"), ("during", "shutdown"), ("after", "shutdown")],
169 180
        )
170 181
171 -
    def test_shutdownFiresTriggersAsynchronously(self):
182 +
    def test_shutdownFiresTriggersAsynchronously(self) -> None:
172 183
        """
173 184
        C{"before"} C{"shutdown"} triggers are not run synchronously from
174 185
        L{reactor.stop}.
175 186
        """
176 187
        reactor = self.buildReactor()
177 -
        events = []
188 +
        events: List[str] = []
178 189
        reactor.addSystemEventTrigger(
179 190
            "before", "shutdown", events.append, "before shutdown"
180 191
        )
181 192
182 -
        def stopIt():
193 +
        def stopIt() -> None:
183 194
            reactor.stop()
184 195
            events.append("stopped")
185 196
197 +
        testCase = cast(SynchronousTestCase, self)
198 +
186 199
        reactor.callWhenRunning(stopIt)
187 -
        self.assertEqual(events, [])
200 +
        testCase.assertEqual(events, [])
188 201
        self.runReactor(reactor)
189 -
        self.assertEqual(events, ["stopped", "before shutdown"])
202 +
        testCase.assertEqual(events, ["stopped", "before shutdown"])
190 203
191 -
    def test_shutdownDisconnectsCleanly(self):
204 +
    def test_shutdownDisconnectsCleanly(self) -> None:
192 205
        """
193 206
        A L{IFileDescriptor.connectionLost} implementation which raises an
194 207
        exception does not prevent the remaining L{IFileDescriptor}s from
@@ -198,13 +211,14 @@
Loading
198 211
199 212
        # Subclass FileDescriptor to get logPrefix
200 213
        class ProblematicFileDescriptor(FileDescriptor):
201 -
            def connectionLost(self, reason):
214 +
            def connectionLost(self, reason: Failure) -> None:
202 215
                raise RuntimeError("simulated connectionLost error")
203 216
204 217
        class OKFileDescriptor(FileDescriptor):
205 -
            def connectionLost(self, reason):
218 +
            def connectionLost(self, reason: Failure) -> None:
206 219
                lostOK[0] = True
207 220
221 +
        testCase = cast(SynchronousTestCase, self)
208 222
        reactor = self.buildReactor()
209 223
210 224
        # Unfortunately, it is necessary to patch removeAll to directly control
@@ -216,27 +230,29 @@
Loading
216 230
        reactor.removeAll = lambda: fds
217 231
        reactor.callWhenRunning(reactor.stop)
218 232
        self.runReactor(reactor)
219 -
        self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1)
220 -
        self.assertTrue(lostOK[0])
233 +
        testCase.assertEqual(len(testCase.flushLoggedErrors(RuntimeError)), 1)
234 +
        testCase.assertTrue(lostOK[0])
221 235
222 -
    def test_multipleRun(self):
236 +
    def test_multipleRun(self) -> None:
223 237
        """
224 238
        C{reactor.run()} raises L{ReactorAlreadyRunning} when called when
225 239
        the reactor is already running.
226 240
        """
227 -
        events = []
241 +
        events: List[str] = []
242 +
243 +
        testCase = cast(SynchronousTestCase, self)
228 244
229 -
        def reentrantRun():
230 -
            self.assertRaises(ReactorAlreadyRunning, reactor.run)
245 +
        def reentrantRun() -> None:
246 +
            testCase.assertRaises(ReactorAlreadyRunning, reactor.run)
231 247
            events.append("tested")
232 248
233 249
        reactor = self.buildReactor()
234 250
        reactor.callWhenRunning(reentrantRun)
235 251
        reactor.callWhenRunning(reactor.stop)
236 252
        self.runReactor(reactor)
237 -
        self.assertEqual(events, ["tested"])
253 +
        testCase.assertEqual(events, ["tested"])
238 254
239 -
    def test_runWithAsynchronousBeforeStartupTrigger(self):
255 +
    def test_runWithAsynchronousBeforeStartupTrigger(self) -> None:
240 256
        """
241 257
        When there is a C{'before'} C{'startup'} trigger which returns an
242 258
        unfired L{Deferred}, C{reactor.run()} starts the reactor and does not
@@ -244,23 +260,23 @@
Loading
244 260
        """
245 261
        events = []
246 262
247 -
        def trigger():
263 +
        def trigger() -> Deferred[object]:
248 264
            events.append("trigger")
249 -
            d = Deferred()
265 +
            d: Deferred[object] = Deferred()
250 266
            d.addCallback(callback)
251 267
            reactor.callLater(0, d.callback, None)
252 268
            return d
253 269
254 -
        def callback(ignored):
270 +
        def callback(ignored: object) -> None:
255 271
            events.append("callback")
256 272
            reactor.stop()
257 273
258 274
        reactor = self.buildReactor()
259 275
        reactor.addSystemEventTrigger("before", "startup", trigger)
260 276
        self.runReactor(reactor)
261 -
        self.assertEqual(events, ["trigger", "callback"])
277 +
        cast(SynchronousTestCase, self).assertEqual(events, ["trigger", "callback"])
262 278
263 -
    def test_iterate(self):
279 +
    def test_iterate(self) -> None:
264 280
        """
265 281
        C{reactor.iterate()} does not block.
266 282
        """
@@ -271,10 +287,10 @@
Loading
271 287
        reactor.iterate(0)  # Shouldn't block
272 288
        elapsed = time.time() - start
273 289
274 -
        self.assertTrue(elapsed < 2)
290 +
        cast(SynchronousTestCase, self).assertTrue(elapsed < 2)
275 291
        t.cancel()
276 292
277 -
    def test_crash(self):
293 +
    def test_crash(self) -> None:
278 294
        """
279 295
        C{reactor.crash()} stops the reactor and does not fire shutdown
280 296
        triggers.
@@ -286,19 +302,20 @@
Loading
286 302
        )
287 303
        reactor.callWhenRunning(reactor.callLater, 0, reactor.crash)
288 304
        self.runReactor(reactor)
289 -
        self.assertFalse(reactor.running)
290 -
        self.assertFalse(
305 +
        testCase = cast(SynchronousTestCase, self)
306 +
        testCase.assertFalse(reactor.running)
307 +
        testCase.assertFalse(
291 308
            events, "Shutdown triggers invoked but they should not have been."
292 309
        )
293 310
294 -
    def test_runAfterCrash(self):
311 +
    def test_runAfterCrash(self) -> None:
295 312
        """
296 313
        C{reactor.run()} restarts the reactor after it has been stopped by
297 314
        C{reactor.crash()}.
298 315
        """
299 -
        events = []
316 +
        events: List[Union[str, Tuple[str, bool]]] = []
300 317
301 -
        def crash():
318 +
        def crash() -> None:
302 319
            events.append("crash")
303 320
            reactor.crash()
304 321
@@ -306,30 +323,32 @@
Loading
306 323
        reactor.callWhenRunning(crash)
307 324
        self.runReactor(reactor)
308 325
309 -
        def stop():
326 +
        def stop() -> None:
310 327
            events.append(("stop", reactor.running))
311 328
            reactor.stop()
312 329
313 330
        reactor.callWhenRunning(stop)
314 331
        self.runReactor(reactor)
315 -
        self.assertEqual(events, ["crash", ("stop", True)])
332 +
        cast(SynchronousTestCase, self).assertEqual(events, ["crash", ("stop", True)])
316 333
317 -
    def test_runAfterStop(self):
334 +
    def test_runAfterStop(self) -> None:
318 335
        """
319 336
        C{reactor.run()} raises L{ReactorNotRestartable} when called when
320 337
        the reactor is being run after getting stopped priorly.
321 338
        """
322 -
        events = []
339 +
        events: List[str] = []
340 +
341 +
        testCase = cast(SynchronousTestCase, self)
323 342
324 -
        def restart():
325 -
            self.assertRaises(ReactorNotRestartable, reactor.run)
343 +
        def restart() -> None:
344 +
            testCase.assertRaises(ReactorNotRestartable, reactor.run)
326 345
            events.append("tested")
327 346
328 347
        reactor = self.buildReactor()
329 348
        reactor.callWhenRunning(reactor.stop)
330 349
        reactor.addSystemEventTrigger("after", "shutdown", restart)
331 350
        self.runReactor(reactor)
332 -
        self.assertEqual(events, ["tested"])
351 +
        testCase.assertEqual(events, ["tested"])
333 352
334 353
335 354
globals().update(SystemEventTestsBuilder.makeTestCaseClasses())
Files Coverage
src/twisted 91.31%
Project Totals (830 files) 91.31%
lnx-3.7-alldeps-withcov-posix
Build #1470623499 -
lnx-3.6-alldeps-withcov-posix-noipv6
Build #1470623499 -
lnx-3.9-alldeps-withcov-posix
Build #1470623499 -
lnx-3.6-alldeps-withcov-posix
Build #1470623499 -
lnx-pypy-3.7-alldeps-withcov-posix
Build #1470623499 -
lnx-3.6.7-nodeps-withcov-posix
Build #1470623499 -
lnx-3.10.0-rc.1-alldeps-withcov-posix
Build #1470623499 -
lnx-3.8-alldeps-withcov-posix
Build #1470623499 -
lnx-3.6.7-nodeps-withcov-posix
Build #1470623499 -
lnx-pypy-3.7-alldeps-withcov-posix
Build #1470623499 -
lnx-3.9-alldeps-withcov-posix
Build #1470623499 -
lnx-3.6-alldeps-withcov-posix
Build #1470623499 -
lnx-3.7-alldeps-withcov-posix
Build #1470623499 -
lnx-3.6-alldeps-withcov-posix-noipv6
Build #1470623499 -
lnx-3.8-alldeps-withcov-posix
Build #1470623499 -
lnx-3.10.0-rc.1-alldeps-withcov-posix
Build #1470623499 -
windows-3.7
Build #20211117.3 -
macos-3.9
Build #20211117.3 -
windows-3.6
Build #20211117.3 -
macos-3.8
Build #20211117.3 -
windows-3.9
Build #20211117.3 -
windows-3.7
Build #20211117.3 -
macos-3.6
Build #20211117.3 -
windows-3.6
Build #20211117.3 -
windows-3.8
Build #20211117.3 -
macos-3.7
Build #20211117.3 -
windows-3.9
Build #20211117.3 -
windows-3.8
Build #20211117.3 -
1
#
2
# For documentation: https://docs.codecov.io/docs/codecovyml-reference
3
# Twisted settings: https://codecov.io/gh/twisted/twisted/settings/yaml
4
#
5
# We want 100% coverage for new patches to make sure we are always increasing
6
# the coverage.
7
#
8
codecov:
9
  require_ci_to_pass: yes
10
  notify:
11
    # We have at least 10 builds in GitHub Actions and 12 in Azure
12
    # and lint + mypy + docs + ReadTheDocs
13
    after_n_builds: 15
14
    wait_for_ci: yes
15

16
coverage:
17
  precision: 2
18
  round: down
19
  status:
20
    patch:
21
      default:
22
        # New code should have 100% CI coverage as the minimum
23
        # quality assurance measurement.
24
        # If there is a good reason for new code not to have coverage,
25
        # add inline pragma comments.
26
        target: 100%
27
    project:
28
      default:
29
        # Temporary allow for a bit of slack in overall code coverage due to
30
        # swinging coverage that is not triggered by changes in a PR.
31
        # See: https://twistedmatrix.com/trac/ticket/10170
32
        threshold: 0.02%
33

34

35
# We don't want to receive general PR comments about coverage.
36
# We have the commit status checks and that should be enough.
37
# See https://docs.codecov.io/docs/pull-request-comments
38
comment: false
39

40
# See https://docs.codecov.io/docs/github-checks
41
github_checks:
42
  # We want codecov to send inline PR comments for missing coverage.
43
  annotations: true
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading