1
1
import signal
2
+ import sys
2
3
import textwrap
3
4
4
5
import mypy .version
5
6
from packaging .version import Version
6
7
import pexpect
7
8
import pytest
8
9
10
+ import pytest_mypy
11
+
9
12
10
13
MYPY_VERSION = Version (mypy .version .__version__ )
11
14
PYTEST_VERSION = Version (pytest .__version__ )
15
+ PYTHON_VERSION = Version (
16
+ "." .join (
17
+ str (token )
18
+ for token in [
19
+ sys .version_info .major ,
20
+ sys .version_info .minor ,
21
+ sys .version_info .micro ,
22
+ ]
23
+ )
24
+ )
12
25
13
26
14
27
@pytest .fixture (
@@ -100,7 +113,7 @@ def pyfunc(x: int) -> str:
100
113
assert "_mypy_results_path" not in result .stderr .str ()
101
114
102
115
103
- def test_mypy_annotation_unchecked (testdir , xdist_args ):
116
+ def test_mypy_annotation_unchecked (testdir , xdist_args , tmp_path , monkeypatch ):
104
117
"""Verify that annotation-unchecked warnings do not manifest as an error."""
105
118
testdir .makepyfile (
106
119
"""
@@ -109,6 +122,29 @@ def pyfunc(x):
109
122
return x * y
110
123
""" ,
111
124
)
125
+ min_mypy_version = Version ("0.990" )
126
+ if MYPY_VERSION < min_mypy_version :
127
+ # mypy doesn't emit annotation-unchecked warnings until 0.990:
128
+ fake_mypy_path = tmp_path / "mypy"
129
+ fake_mypy_path .mkdir ()
130
+ (fake_mypy_path / "__init__.py" ).touch ()
131
+ (fake_mypy_path / "api.py" ).write_text (
132
+ textwrap .dedent (
133
+ """
134
+ def run(*args, **kwargs):
135
+ return (
136
+ "test_mypy_annotation_unchecked.py:2:"
137
+ " note: By default the bodies of untyped functions"
138
+ " are not checked, consider using --check-untyped-defs"
139
+ " [annotation-unchecked]\\ nSuccess: no issues found in"
140
+ " 1 source file\\ n",
141
+ "",
142
+ 0,
143
+ )
144
+ """
145
+ )
146
+ )
147
+ monkeypatch .setenv ("PYTHONPATH" , str (tmp_path ))
112
148
result = testdir .runpytest_subprocess (* xdist_args )
113
149
result .assert_outcomes ()
114
150
result = testdir .runpytest_subprocess ("--mypy" , * xdist_args )
@@ -552,3 +588,68 @@ def test_mypy_item_collect(request):
552
588
mypy_status_check = 1
553
589
result .assert_outcomes (passed = test_count + mypy_file_checks + mypy_status_check )
554
590
assert result .ret == 0
591
+
592
+
593
+ @pytest .mark .xfail (
594
+ MYPY_VERSION < Version ("0.750" ),
595
+ raises = AssertionError ,
596
+ reason = "https://github.com/python/mypy/issues/7800" ,
597
+ )
598
+ def test_mypy_results_from_mypy_with_opts ():
599
+ """MypyResults.from_mypy respects passed options."""
600
+ mypy_results = pytest_mypy .MypyResults .from_mypy ([], opts = ["--version" ])
601
+ assert mypy_results .status == 0
602
+ assert mypy_results .abspath_errors == {}
603
+ assert str (MYPY_VERSION ) in mypy_results .stdout
604
+
605
+
606
+ @pytest .mark .xfail (
607
+ Version ("3.7" ) < PYTHON_VERSION < Version ("3.9" )
608
+ and Version ("0.710" ) <= MYPY_VERSION < Version ("0.720" ),
609
+ raises = AssertionError ,
610
+ reason = "Mypy crashes for some reason." ,
611
+ )
612
+ def test_mypy_no_output (testdir , xdist_args ):
613
+ """No terminal summary is shown if there is no output from mypy."""
614
+ type_ignore = (
615
+ "# type: ignore"
616
+ if (
617
+ PYTEST_VERSION
618
+ < Version ("6.0" ) # Pytest didn't add type annotations until 6.0.
619
+ or MYPY_VERSION < Version ("0.710" )
620
+ )
621
+ else ""
622
+ )
623
+ testdir .makepyfile (
624
+ # Mypy prints a success message to stderr by default:
625
+ # "Success: no issues found in 1 source file"
626
+ # Clear stderr and unmatched_stdout to simulate mypy having no output:
627
+ conftest = f"""
628
+ import pytest { type_ignore }
629
+
630
+ @pytest.hookimpl(hookwrapper=True)
631
+ def pytest_terminal_summary(config):
632
+ mypy_results_path = getattr(config, "_mypy_results_path", None)
633
+ if not mypy_results_path:
634
+ # xdist worker
635
+ return
636
+ pytest_mypy = config.pluginmanager.getplugin("mypy")
637
+ with open(mypy_results_path, mode="w") as results_f:
638
+ pytest_mypy.MypyResults(
639
+ opts=[],
640
+ stdout="",
641
+ stderr="",
642
+ status=0,
643
+ abspath_errors={{}},
644
+ unmatched_stdout="",
645
+ ).dump(results_f)
646
+ yield
647
+ """ ,
648
+ )
649
+ result = testdir .runpytest_subprocess ("--mypy" , * xdist_args )
650
+ mypy_file_checks = 1
651
+ mypy_status_check = 1
652
+ mypy_checks = mypy_file_checks + mypy_status_check
653
+ result .assert_outcomes (passed = mypy_checks )
654
+ assert result .ret == 0
655
+ assert f"= { pytest_mypy .terminal_summary_title } =" not in str (result .stdout )
0 commit comments