1212
1313
1414mypy_argv = []
15- nodeid_name = ' mypy'
15+ nodeid_name = " mypy"
1616
1717
1818def default_file_error_formatter (item , results , errors ):
1919 """Create a string to be displayed when mypy finds errors in a file."""
20- return ' \n ' .join (errors )
20+ return " \n " .join (errors )
2121
2222
2323file_error_formatter = default_file_error_formatter
2424
2525
2626def pytest_addoption (parser ):
2727 """Add options for enabling and running mypy."""
28- group = parser .getgroup ('mypy' )
28+ group = parser .getgroup ("mypy" )
29+ group .addoption ("--mypy" , action = "store_true" , help = "run mypy on .py files" )
2930 group .addoption (
30- '--mypy' , action = 'store_true' ,
31- help = 'run mypy on .py files' )
32- group .addoption (
33- '--mypy-ignore-missing-imports' , action = 'store_true' ,
34- help = "suppresses error messages about imports that cannot be resolved" )
31+ "--mypy-ignore-missing-imports" ,
32+ action = "store_true" ,
33+ help = "suppresses error messages about imports that cannot be resolved" ,
34+ )
3535
3636
3737XDIST_WORKERINPUT_ATTRIBUTE_NAMES = (
38- ' workerinput' ,
38+ " workerinput" ,
3939 # xdist < 2.0.0:
40- ' slaveinput' ,
40+ " slaveinput" ,
4141)
4242
4343
@@ -76,38 +76,38 @@ def pytest_configure(config):
7676
7777 # If xdist is enabled, then the results path should be exposed to
7878 # the workers so that they know where to read parsed results from.
79- if config .pluginmanager .getplugin ('xdist' ):
79+ if config .pluginmanager .getplugin ("xdist" ):
80+
8081 class _MypyXdistPlugin :
8182 def pytest_configure_node (self , node ): # xdist hook
8283 """Pass config._mypy_results_path to workers."""
83- _get_xdist_workerinput (node )['_mypy_results_path' ] = \
84- node .config ._mypy_results_path
84+ _get_xdist_workerinput (node )[
85+ "_mypy_results_path"
86+ ] = node .config ._mypy_results_path
87+
8588 config .pluginmanager .register (_MypyXdistPlugin ())
8689
8790 # pytest_terminal_summary cannot accept config before pytest 4.2.
8891 global _pytest_terminal_summary_config
8992 _pytest_terminal_summary_config = config
9093
9194 config .addinivalue_line (
92- 'markers' ,
93- '{marker}: mark tests to be checked by mypy.' .format (
94- marker = MypyItem .MARKER ,
95- ),
95+ "markers" ,
96+ "{marker}: mark tests to be checked by mypy." .format (marker = MypyItem .MARKER ),
9697 )
97- if config .getoption (' --mypy-ignore-missing-imports' ):
98- mypy_argv .append (' --ignore-missing-imports' )
98+ if config .getoption (" --mypy-ignore-missing-imports" ):
99+ mypy_argv .append (" --ignore-missing-imports" )
99100
100101
101102def pytest_collect_file (path , parent ):
102103 """Create a MypyFileItem for every file mypy should run on."""
103- if path .ext in {'.py' , '.pyi' } and any ([
104- parent .config .option .mypy ,
105- parent .config .option .mypy_ignore_missing_imports ,
106- ]):
104+ if path .ext in {".py" , ".pyi" } and any (
105+ [parent .config .option .mypy , parent .config .option .mypy_ignore_missing_imports ],
106+ ):
107107 # Do not create MypyFile instance for a .py file if a
108108 # .pyi file with the same name already exists;
109109 # pytest will complain about duplicate modules otherwise
110- if path .ext == ' .pyi' or not path .new (ext = ' .pyi' ).isfile ():
110+ if path .ext == " .pyi" or not path .new (ext = " .pyi" ).isfile ():
111111 return MypyFile .from_parent (parent = parent , fspath = path )
112112 return None
113113
@@ -120,17 +120,15 @@ class MypyFile(pytest.File):
120120 def from_parent (cls , * args , ** kwargs ):
121121 """Override from_parent for compatibility."""
122122 # pytest.File.from_parent did not exist before pytest 5.4.
123- return getattr (super (), ' from_parent' , cls )(* args , ** kwargs )
123+ return getattr (super (), " from_parent" , cls )(* args , ** kwargs )
124124
125125 def collect (self ):
126126 """Create a MypyFileItem for the File."""
127127 yield MypyFileItem .from_parent (parent = self , name = nodeid_name )
128128 # Since mypy might check files that were not collected,
129129 # pytest could pass even though mypy failed!
130130 # To prevent that, add an explicit check for the mypy exit status.
131- if not any (
132- isinstance (item , MypyStatusItem ) for item in self .session .items
133- ):
131+ if not any (isinstance (item , MypyStatusItem ) for item in self .session .items ):
134132 yield MypyStatusItem .from_parent (
135133 parent = self ,
136134 name = nodeid_name + "-status" ,
@@ -141,7 +139,7 @@ class MypyItem(pytest.Item):
141139
142140 """A Mypy-related test Item."""
143141
144- MARKER = ' mypy'
142+ MARKER = " mypy"
145143
146144 def __init__ (self , * args , ** kwargs ):
147145 super ().__init__ (* args , ** kwargs )
@@ -151,7 +149,7 @@ def __init__(self, *args, **kwargs):
151149 def from_parent (cls , * args , ** kwargs ):
152150 """Override from_parent for compatibility."""
153151 # pytest.Item.from_parent did not exist before pytest 5.4.
154- return getattr (super (), ' from_parent' , cls )(* args , ** kwargs )
152+ return getattr (super (), " from_parent" , cls )(* args , ** kwargs )
155153
156154 def repr_failure (self , excinfo ):
157155 """
@@ -193,7 +191,7 @@ def runtest(self):
193191 results = MypyResults .from_session (self .session )
194192 if results .status :
195193 raise MypyError (
196- ' mypy exited with status {status}.' .format (
194+ " mypy exited with status {status}." .format (
197195 status = results .status ,
198196 ),
199197 )
@@ -218,33 +216,32 @@ def dump(self, results_f: TextIO) -> None:
218216 return json .dump (vars (self ), results_f )
219217
220218 @classmethod
221- def load (cls , results_f : TextIO ) -> ' MypyResults' :
219+ def load (cls , results_f : TextIO ) -> " MypyResults" :
222220 """Get results cached by dump()."""
223221 return cls (** json .load (results_f ))
224222
225223 @classmethod
226224 def from_mypy (
227- cls ,
228- items : List [MypyFileItem ],
229- * ,
230- opts : Optional [List [str ]] = None
231- ) -> ' MypyResults' :
225+ cls ,
226+ items : List [MypyFileItem ],
227+ * ,
228+ opts : Optional [List [str ]] = None # noqa: C816
229+ ) -> " MypyResults" :
232230 """Generate results from mypy."""
233231
234232 if opts is None :
235233 opts = mypy_argv [:]
236234 abspath_errors = {
237- os .path .abspath (str (item .fspath )): []
238- for item in items
235+ os .path .abspath (str (item .fspath )): [] for item in items
239236 } # type: MypyResults._abspath_errors_type
240237
241238 stdout , stderr , status = mypy .api .run (opts + list (abspath_errors ))
242239
243240 unmatched_lines = []
244- for line in stdout .split (' \n ' ):
241+ for line in stdout .split (" \n " ):
245242 if not line :
246243 continue
247- path , _ , error = line .partition (':' )
244+ path , _ , error = line .partition (":" )
248245 abspath = os .path .abspath (path )
249246 try :
250247 abspath_errors [abspath ].append (error )
@@ -257,27 +254,26 @@ def from_mypy(
257254 stderr = stderr ,
258255 status = status ,
259256 abspath_errors = abspath_errors ,
260- unmatched_stdout = ' \n ' .join (unmatched_lines ),
257+ unmatched_stdout = " \n " .join (unmatched_lines ),
261258 )
262259
263260 @classmethod
264- def from_session (cls , session ) -> ' MypyResults' :
261+ def from_session (cls , session ) -> " MypyResults" :
265262 """Load (or generate) cached mypy results for a pytest session."""
266263 results_path = (
267264 session .config ._mypy_results_path
268- if _is_master (session .config ) else
269- _get_xdist_workerinput (session .config )[' _mypy_results_path' ]
265+ if _is_master (session .config )
266+ else _get_xdist_workerinput (session .config )[" _mypy_results_path" ]
270267 )
271- with FileLock (results_path + ' .lock' ):
268+ with FileLock (results_path + " .lock" ):
272269 try :
273- with open (results_path , mode = 'r' ) as results_f :
270+ with open (results_path , mode = "r" ) as results_f :
274271 results = cls .load (results_f )
275272 except FileNotFoundError :
276- results = cls .from_mypy ([
277- item for item in session .items
278- if isinstance (item , MypyFileItem )
279- ])
280- with open (results_path , mode = 'w' ) as results_f :
273+ results = cls .from_mypy (
274+ [item for item in session .items if isinstance (item , MypyFileItem )],
275+ )
276+ with open (results_path , mode = "w" ) as results_f :
281277 results .dump (results_f )
282278 return results
283279
@@ -293,15 +289,15 @@ def pytest_terminal_summary(terminalreporter):
293289 """Report stderr and unrecognized lines from stdout."""
294290 config = _pytest_terminal_summary_config
295291 try :
296- with open (config ._mypy_results_path , mode = 'r' ) as results_f :
292+ with open (config ._mypy_results_path , mode = "r" ) as results_f :
297293 results = MypyResults .load (results_f )
298294 except FileNotFoundError :
299295 # No MypyItems executed.
300296 return
301297 if results .unmatched_stdout or results .stderr :
302- terminalreporter .section (' mypy' )
298+ terminalreporter .section (" mypy" )
303299 if results .unmatched_stdout :
304- color = {' red' : True } if results .status else {' green' : True }
300+ color = {" red" : True } if results .status else {" green" : True }
305301 terminalreporter .write_line (results .unmatched_stdout , ** color )
306302 if results .stderr :
307303 terminalreporter .write_line (results .stderr , yellow = True )
0 commit comments