1
+ import signal
2
+ import textwrap
3
+
1
4
import pytest
2
5
3
6
@@ -214,38 +217,6 @@ def pytest_configure(config):
214
217
assert result .ret == 0
215
218
216
219
217
- def test_pytest_collection_modifyitems (testdir , xdist_args ):
218
- """
219
- Verify that collected files which are removed in a
220
- pytest_collection_modifyitems implementation are not
221
- checked by mypy.
222
-
223
- This would also fail if a MypyStatusItem were injected
224
- despite there being no MypyFileItems.
225
- """
226
- testdir .makepyfile (conftest = '''
227
- def pytest_collection_modifyitems(session, config, items):
228
- plugin = config.pluginmanager.getplugin('mypy')
229
- for mypy_item_i in reversed([
230
- i
231
- for i, item in enumerate(items)
232
- if isinstance(item, plugin.MypyFileItem)
233
- ]):
234
- items.pop(mypy_item_i)
235
- ''' )
236
- testdir .makepyfile ('''
237
- def pyfunc(x: int) -> str:
238
- return x * 2
239
-
240
- def test_pass():
241
- pass
242
- ''' )
243
- result = testdir .runpytest_subprocess ('--mypy' , * xdist_args )
244
- test_count = 1
245
- result .assert_outcomes (passed = test_count )
246
- assert result .ret == 0
247
-
248
-
249
220
def test_mypy_indirect (testdir , xdist_args ):
250
221
"""Verify that uncollected files checked by mypy cause a failure."""
251
222
testdir .makepyfile (bad = '''
@@ -259,38 +230,6 @@ def pyfunc(x: int) -> str:
259
230
assert result .ret != 0
260
231
261
232
262
- def test_mypy_indirect_inject (testdir , xdist_args ):
263
- """
264
- Verify that uncollected files checked by mypy because of a MypyFileItem
265
- injected in pytest_collection_modifyitems cause a failure.
266
- """
267
- testdir .makepyfile (bad = '''
268
- def pyfunc(x: int) -> str:
269
- return x * 2
270
- ''' )
271
- testdir .makepyfile (good = '''
272
- import bad
273
- ''' )
274
- testdir .makepyfile (conftest = '''
275
- import py
276
- import pytest
277
-
278
- @pytest.hookimpl(trylast=True) # Inject as late as possible.
279
- def pytest_collection_modifyitems(session, config, items):
280
- plugin = config.pluginmanager.getplugin('mypy')
281
- items.append(
282
- plugin.MypyFileItem.from_parent(
283
- parent=session,
284
- name=str(py.path.local('good.py')),
285
- ),
286
- )
287
- ''' )
288
- name = 'empty'
289
- testdir .mkdir (name )
290
- result = testdir .runpytest_subprocess ('--mypy' , * xdist_args , name )
291
- assert result .ret != 0
292
-
293
-
294
233
def test_api_error_formatter (testdir , xdist_args ):
295
234
"""Ensure that the plugin can be configured in a conftest.py."""
296
235
testdir .makepyfile (bad = '''
@@ -333,3 +272,87 @@ def pyfunc(x):
333
272
'1: error: Function is missing a type annotation' ,
334
273
])
335
274
assert result .ret != 0
275
+
276
+
277
+ def test_looponfail (testdir ):
278
+ """Ensure that the plugin works with --looponfail."""
279
+
280
+ pass_source = textwrap .dedent (
281
+ """\
282
+ def pyfunc(x: int) -> int:
283
+ return x * 2
284
+ """ ,
285
+ )
286
+ fail_source = textwrap .dedent (
287
+ """\
288
+ def pyfunc(x: int) -> str:
289
+ return x * 2
290
+ """ ,
291
+ )
292
+ pyfile = testdir .makepyfile (fail_source )
293
+ looponfailroot = testdir .mkdir ("looponfailroot" )
294
+ looponfailroot_pyfile = looponfailroot .join (pyfile .basename )
295
+ pyfile .move (looponfailroot_pyfile )
296
+ pyfile = looponfailroot_pyfile
297
+ testdir .makeini (
298
+ textwrap .dedent (
299
+ """\
300
+ [pytest]
301
+ looponfailroots = {looponfailroots}
302
+ """ .format (
303
+ looponfailroots = looponfailroot ,
304
+ ),
305
+ ),
306
+ )
307
+
308
+ child = testdir .spawn_pytest (
309
+ "--mypy --looponfail " + str (pyfile ),
310
+ expect_timeout = 30.0 ,
311
+ )
312
+
313
+ def _expect_session ():
314
+ child .expect ("==== test session starts ====" )
315
+
316
+ def _expect_failure ():
317
+ _expect_session ()
318
+ child .expect ("==== FAILURES ====" )
319
+ child .expect (pyfile .basename + " ____" )
320
+ child .expect ("2: error: Incompatible return value" )
321
+ # These only show with mypy>=0.730:
322
+ # child.expect("==== mypy ====")
323
+ # child.expect("Found 1 error in 1 file (checked 1 source file)")
324
+ child .expect ("2 failed" )
325
+ child .expect ("#### LOOPONFAILING ####" )
326
+ _expect_waiting ()
327
+
328
+ def _expect_waiting ():
329
+ child .expect ("#### waiting for changes ####" )
330
+ child .expect ("Watching" )
331
+
332
+ def _fix ():
333
+ pyfile .write (pass_source )
334
+ _expect_changed ()
335
+ _expect_success ()
336
+
337
+ def _expect_changed ():
338
+ child .expect ("MODIFIED " + str (pyfile ))
339
+
340
+ def _expect_success ():
341
+ for _ in range (2 ):
342
+ _expect_session ()
343
+ # These only show with mypy>=0.730:
344
+ # child.expect("==== mypy ====")
345
+ # child.expect("Success: no issues found in 1 source file")
346
+ child .expect ("2 passed" )
347
+ _expect_waiting ()
348
+
349
+ def _break ():
350
+ pyfile .write (fail_source )
351
+ _expect_changed ()
352
+ _expect_failure ()
353
+
354
+ _expect_failure ()
355
+ _fix ()
356
+ _break ()
357
+ _fix ()
358
+ child .kill (signal .SIGTERM )
0 commit comments