16
16
import os
17
17
import re
18
18
import sys
19
- import toml
20
19
import tempfile
21
20
from glob import glob
22
21
from pathlib import Path
23
22
from typing import Dict , NamedTuple
24
23
25
- parser = argparse . ArgumentParser (
26
- description = "Test runner for typeshed. Patterns are unanchored regexps on the full path."
27
- )
24
+ import toml
25
+
26
+ parser = argparse . ArgumentParser ( description = "Test runner for typeshed. Patterns are unanchored regexps on the full path." )
28
27
parser .add_argument ("-v" , "--verbose" , action = "count" , default = 0 , help = "More output" )
29
28
parser .add_argument ("-n" , "--dry-run" , action = "store_true" , help = "Don't actually run mypy" )
30
29
parser .add_argument ("-x" , "--exclude" , type = str , nargs = "*" , help = "Exclude pattern" )
@@ -123,10 +122,7 @@ def add_files(files, seen, root, name, args, exclude_list):
123
122
if match (full , args , exclude_list ):
124
123
seen .add (mod )
125
124
files .append (full )
126
- elif (
127
- os .path .isfile (os .path .join (full , "__init__.pyi" )) or
128
- os .path .isfile (os .path .join (full , "__init__.py" ))
129
- ):
125
+ elif os .path .isfile (os .path .join (full , "__init__.pyi" )) or os .path .isfile (os .path .join (full , "__init__.py" )):
130
126
for r , ds , fs in os .walk (full ):
131
127
ds .sort ()
132
128
fs .sort ()
@@ -143,6 +139,7 @@ class MypyDistConf(NamedTuple):
143
139
module_name : str
144
140
values : Dict
145
141
142
+
146
143
# The configuration section in the metadata file looks like the following, with multiple module sections possible
147
144
# [mypy-tests]
148
145
# [mypy-tests.yaml]
@@ -179,18 +176,61 @@ def add_configuration(configurations, seen_dist_configs, distribution):
179
176
seen_dist_configs .add (distribution )
180
177
181
178
182
- def main ():
183
- args = parser .parse_args ()
184
-
185
- with open (os .path .join (os .path .dirname (__file__ ), "mypy_exclude_list.txt" )) as f :
186
- exclude_list = re .compile ("(%s)$" % "|" .join (re .findall (r"^\s*([^\s#]+)\s*(?:#.*)?$" , f .read (), flags = re .M )))
187
-
179
+ def run_mypy (args , configurations , major , minor , files , * , custom_typeshed = False ):
188
180
try :
189
181
from mypy .main import main as mypy_main
190
182
except ImportError :
191
183
print ("Cannot import mypy. Did you install it?" )
192
184
sys .exit (1 )
193
185
186
+ with tempfile .NamedTemporaryFile ("w+" ) as temp :
187
+ temp .write ("[mypy]\n " )
188
+ for dist_conf in configurations :
189
+ temp .write ("[mypy-%s]\n " % dist_conf .module_name )
190
+ for k , v in dist_conf .values .items ():
191
+ temp .write ("{} = {}\n " .format (k , v ))
192
+ temp .flush ()
193
+
194
+ flags = [
195
+ "--python-version" ,
196
+ "%d.%d" % (major , minor ),
197
+ "--config-file" ,
198
+ temp .name ,
199
+ "--strict-optional" ,
200
+ "--no-site-packages" ,
201
+ "--show-traceback" ,
202
+ "--no-implicit-optional" ,
203
+ "--disallow-any-generics" ,
204
+ "--disallow-subclassing-any" ,
205
+ "--warn-incomplete-stub" ,
206
+ ]
207
+ if custom_typeshed :
208
+ # Setting custom typeshed dir prevents mypy from falling back to its bundled
209
+ # typeshed in case of stub deletions
210
+ flags .extend (["--custom-typeshed-dir" , os .path .dirname (os .path .dirname (__file__ ))])
211
+ if args .warn_unused_ignores :
212
+ flags .append ("--warn-unused-ignores" )
213
+ if args .platform :
214
+ flags .extend (["--platform" , args .platform ])
215
+ sys .argv = ["mypy" ] + flags + files
216
+ if args .verbose :
217
+ print ("running" , " " .join (sys .argv ))
218
+ else :
219
+ print ("running mypy" , " " .join (flags ), "# with" , len (files ), "files" )
220
+ if not args .dry_run :
221
+ try :
222
+ mypy_main ("" , sys .stdout , sys .stderr )
223
+ except SystemExit as err :
224
+ return err .code
225
+ return 0
226
+
227
+
228
+ def main ():
229
+ args = parser .parse_args ()
230
+
231
+ with open (os .path .join (os .path .dirname (__file__ ), "mypy_exclude_list.txt" )) as f :
232
+ exclude_list = re .compile ("(%s)$" % "|" .join (re .findall (r"^\s*([^\s#]+)\s*(?:#.*)?$" , f .read (), flags = re .M )))
233
+
194
234
versions = [(3 , 10 ), (3 , 9 ), (3 , 8 ), (3 , 7 ), (3 , 6 ), (2 , 7 )]
195
235
if args .python_version :
196
236
versions = [v for v in versions if any (("%d.%d" % v ).startswith (av ) for av in args .python_version )]
@@ -201,12 +241,12 @@ def main():
201
241
code = 0
202
242
runs = 0
203
243
for major , minor in versions :
204
- files = []
205
244
seen = {"__builtin__" , "builtins" , "typing" } # Always ignore these.
206
245
configurations = []
207
246
seen_dist_configs = set ()
208
247
209
- # First add standard library files.
248
+ # Test standard library files.
249
+ files = []
210
250
if major == 2 :
211
251
root = os .path .join ("stdlib" , "@python2" )
212
252
for name in os .listdir (root ):
@@ -224,7 +264,13 @@ def main():
224
264
if supported_versions [mod ][0 ] <= (major , minor ) <= supported_versions [mod ][1 ]:
225
265
add_files (files , seen , root , name , args , exclude_list )
226
266
227
- # Next add files for all third party distributions.
267
+ if files :
268
+ this_code = run_mypy (args , configurations , major , minor , files , custom_typeshed = True )
269
+ code = max (code , this_code )
270
+ runs += 1
271
+
272
+ # Test files of all third party distributions.
273
+ files = []
228
274
for distribution in os .listdir ("stubs" ):
229
275
if not is_supported (distribution , major ):
230
276
continue
@@ -242,46 +288,11 @@ def main():
242
288
add_configuration (configurations , seen_dist_configs , distribution )
243
289
244
290
if files :
245
- with tempfile .NamedTemporaryFile ("w+" , delete = False ) as temp :
246
- temp .write ("[mypy]\n " )
247
-
248
- for dist_conf in configurations :
249
- temp .write ("[mypy-%s]\n " % dist_conf .module_name )
250
- for k , v in dist_conf .values .items ():
251
- temp .write ("{} = {}\n " .format (k , v ))
252
-
253
- config_file_name = temp .name
291
+ # TODO: remove custom_typeshed after mypy 0.920 is released
292
+ this_code = run_mypy (args , configurations , major , minor , files , custom_typeshed = True )
293
+ code = max (code , this_code )
254
294
runs += 1
255
- flags = [
256
- "--python-version" , "%d.%d" % (major , minor ),
257
- "--config-file" , config_file_name ,
258
- "--strict-optional" ,
259
- "--no-site-packages" ,
260
- "--show-traceback" ,
261
- "--no-implicit-optional" ,
262
- "--disallow-any-generics" ,
263
- "--disallow-subclassing-any" ,
264
- "--warn-incomplete-stub" ,
265
- # Setting custom typeshed dir prevents mypy from falling back to its bundled
266
- # typeshed in case of stub deletions
267
- "--custom-typeshed-dir" , os .path .dirname (os .path .dirname (__file__ )),
268
- ]
269
- if args .warn_unused_ignores :
270
- flags .append ("--warn-unused-ignores" )
271
- if args .platform :
272
- flags .extend (["--platform" , args .platform ])
273
- sys .argv = ["mypy" ] + flags + files
274
- if args .verbose :
275
- print ("running" , " " .join (sys .argv ))
276
- else :
277
- print ("running mypy" , " " .join (flags ), "# with" , len (files ), "files" )
278
- try :
279
- if not args .dry_run :
280
- mypy_main ("" , sys .stdout , sys .stderr )
281
- except SystemExit as err :
282
- code = max (code , err .code )
283
- finally :
284
- os .remove (config_file_name )
295
+
285
296
if code :
286
297
print ("--- exit status" , code , "---" )
287
298
sys .exit (code )
0 commit comments