11import signal
22import textwrap
33
4+ import pexpect
45import pytest
56
67
8+ PYTEST_VERSION = tuple (int (v ) for v in pytest .__version__ .split ("." )[:2 ])
9+
10+
711@pytest .fixture (
812 params = [
913 True , # xdist enabled, active
@@ -309,7 +313,8 @@ def pyfunc(x):
309313 assert result .ret != 0
310314
311315
312- def test_looponfail (testdir ):
316+ @pytest .mark .parametrize ("module_name" , ["__init__" , "test_demo" ])
317+ def test_looponfail (testdir , module_name ):
313318 """Ensure that the plugin works with --looponfail."""
314319
315320 pass_source = textwrap .dedent (
@@ -324,7 +329,7 @@ def pyfunc(x: int) -> str:
324329 return x * 2
325330 """ ,
326331 )
327- pyfile = testdir .makepyfile (fail_source )
332+ pyfile = testdir .makepyfile (** { module_name : fail_source } )
328333 looponfailroot = testdir .mkdir ("looponfailroot" )
329334 looponfailroot_pyfile = looponfailroot .join (pyfile .basename )
330335 pyfile .move (looponfailroot_pyfile )
@@ -345,6 +350,17 @@ def pyfunc(x: int) -> str:
345350 expect_timeout = 30.0 ,
346351 )
347352
353+ num_tests = 2
354+ if module_name == "__init__" and (3 , 10 ) <= PYTEST_VERSION < (6 , 2 ):
355+ # https://github.com/pytest-dev/pytest/issues/8016
356+ # Pytest had a bug where it assumed only Packages would have a
357+ # basepath of __init__.py, but in this test, the MypyItems do too!
358+ # A MypyItem is not a Collector, so this originally led to an
359+ # AttributeError. As a workaround, MypyItem implements collect()
360+ # by yielding itself. That gets past the AttributeError, but
361+ # the bug takes a branch that only allows one Item to be collected.
362+ num_tests = 1
363+
348364 def _expect_session ():
349365 child .expect ("==== test session starts ====" )
350366
@@ -356,7 +372,7 @@ def _expect_failure():
356372 # These only show with mypy>=0.730:
357373 # child.expect("==== mypy ====")
358374 # child.expect("Found 1 error in 1 file (checked 1 source file)")
359- child .expect ("2 failed" )
375+ child .expect (str ( num_tests ) + " failed" )
360376 child .expect ("#### LOOPONFAILING ####" )
361377 _expect_waiting ()
362378
@@ -378,7 +394,18 @@ def _expect_success():
378394 # These only show with mypy>=0.730:
379395 # child.expect("==== mypy ====")
380396 # child.expect("Success: no issues found in 1 source file")
381- child .expect ("2 passed" )
397+ try :
398+ child .expect (str (num_tests ) + " passed" )
399+ except pexpect .exceptions .TIMEOUT :
400+ if module_name == "__init__" and (6 , 0 ) <= PYTEST_VERSION < (6 , 2 ):
401+ # Mypy probably noticed the __init__.py problem during the
402+ # development of Pytest 6.0, but the error was addressed
403+ # with an isinstance assertion, breaking the MypyItem
404+ # workaround. Here, we hit that assertion:
405+ child .expect ("AssertionError" )
406+ child .expect ("1 error" )
407+ pytest .xfail ("https://github.com/pytest-dev/pytest/issues/8016" )
408+ raise
382409 _expect_waiting ()
383410
384411 def _break ():
@@ -391,3 +418,27 @@ def _break():
391418 _break ()
392419 _fix ()
393420 child .kill (signal .SIGTERM )
421+
422+
423+ def test_mypy_item_collect (testdir , xdist_args ):
424+ """Ensure coverage for a 3.10<=pytest<6.0 workaround."""
425+ testdir .makepyfile (
426+ """
427+ def test_mypy_item_collect(request):
428+ plugin = request.config.pluginmanager.getplugin("mypy")
429+ mypy_items = [
430+ item
431+ for item in request.session.items
432+ if isinstance(item, plugin.MypyItem)
433+ ]
434+ assert mypy_items
435+ for mypy_item in mypy_items:
436+ assert all(item is mypy_item for item in mypy_item.collect())
437+ """ ,
438+ )
439+ result = testdir .runpytest_subprocess ("--mypy" , * xdist_args )
440+ test_count = 1
441+ mypy_file_checks = 1
442+ mypy_status_check = 1
443+ result .assert_outcomes (passed = test_count + mypy_file_checks + mypy_status_check )
444+ assert result .ret == 0
0 commit comments