4
4
Depends on mypy and pytype being installed.
5
5
6
6
If pytype is installed:
7
- 1. For every pyi, run "pytd <foo.pyi>" in a separate process
7
+ 1. For every pyi, do nothing if it is in pytype_blacklist.txt.
8
+ 2. If the blacklist line has a "# parse only" comment run
9
+ "pytd <foo.pyi>" in a separate process.
10
+ 3. If the file is not in the blacklist run
11
+ "pytype --typeshed-location=typeshed_location --module-name=foo \
12
+ --convert-to-pickle=tmp_file <foo.pyi>.
13
+ Option two will parse the file, mostly syntactical correctness. Option three
14
+ will load the file and all the builtins, typeshed dependencies. This will
15
+ also discover incorrect usage of imported modules.
8
16
"""
9
17
10
18
import os
@@ -25,32 +33,44 @@ def main():
25
33
code , runs = pytype_test (args )
26
34
27
35
if code :
28
- print (" --- exit status %d ---" % code )
36
+ print (' --- exit status %d ---' % code )
29
37
sys .exit (code )
30
38
if not runs :
31
- print (" --- nothing to do; exit 1 ---" )
39
+ print (' --- nothing to do; exit 1 ---' )
32
40
sys .exit (1 )
33
41
34
42
35
43
def load_blacklist ():
36
44
filename = os .path .join (os .path .dirname (__file__ ), "pytype_blacklist.txt" )
37
- regex = r"^\s*([^\s#]+)\s*(?:#.*)?$"
45
+ skip_re = re .compile (r'^\s*([^\s#]+)\s*(?:#.*)?$' )
46
+ parse_only_re = re .compile (r'^\s*([^\s#]+)\s*#\s*parse only\s*' )
47
+ skip = []
48
+ parse_only = []
38
49
39
50
with open (filename ) as f :
40
- return re .findall (regex , f .read (), flags = re .M )
51
+ for line in f :
52
+ parse_only_match = parse_only_re .match (line )
53
+ skip_match = skip_re .match (line )
54
+ if parse_only_match :
55
+ parse_only .append (parse_only_match .group (1 ))
56
+ elif skip_match :
57
+ skip .append (skip_match .group (1 ))
41
58
59
+ return skip , parse_only
42
60
43
- class PytdRun (object ):
61
+
62
+ class BinaryRun (object ):
44
63
def __init__ (self , args , dry_run = False ):
45
64
self .args = args
65
+
46
66
self .dry_run = dry_run
47
67
self .results = None
48
68
49
69
if dry_run :
50
- self .results = (0 , "" , "" )
70
+ self .results = (0 , '' , '' )
51
71
else :
52
72
self .proc = subprocess .Popen (
53
- [ "pytd" ] + args ,
73
+ self . args ,
54
74
stdout = subprocess .PIPE ,
55
75
stderr = subprocess .PIPE )
56
76
@@ -63,29 +83,54 @@ def communicate(self):
63
83
return self .results
64
84
65
85
86
+ def _get_module_name (filename ):
87
+ """Converts a filename stdblib/m.n/module/foo to module.foo."""
88
+ return '.' .join (filename .split (os .path .sep )[2 :]).replace (
89
+ '.pyi' , '' ).replace ('.__init__' , '' )
90
+
91
+
66
92
def pytype_test (args ):
67
93
try :
68
- PytdRun ([ "-h" ]).communicate ()
94
+ BinaryRun ([ 'pytd' , '-h' ]).communicate ()
69
95
except OSError :
70
- print (" Cannot run pytd. Did you install pytype?" )
96
+ print (' Cannot run pytd. Did you install pytype?' )
71
97
return 0 , 0
72
98
73
- wanted = re .compile (r"stdlib/.*\.pyi$" )
74
- skipped = re .compile ("(%s)$" % "|" .join (load_blacklist ()))
75
- files = []
99
+ skip , parse_only = load_blacklist ()
100
+ wanted = re .compile (r'stdlib/.*\.pyi$' )
101
+ skipped = re .compile ('(%s)$' % '|' .join (skip ))
102
+ parse_only = re .compile ('(%s)$' % '|' .join (parse_only ))
103
+
104
+ pytype_run = []
105
+ pytd_run = []
76
106
77
- for root , _ , filenames in os .walk (" stdlib" ):
107
+ for root , _ , filenames in os .walk (' stdlib' ):
78
108
for f in sorted (filenames ):
79
109
f = os .path .join (root , f )
80
- if wanted .search (f ) and not skipped .search (f ):
81
- files .append (f )
110
+ if wanted .search (f ):
111
+ if parse_only .search (f ):
112
+ pytd_run .append (f )
113
+ elif not skipped .search (f ):
114
+ pytype_run .append (f )
82
115
83
116
running_tests = collections .deque ()
84
117
max_code , runs , errors = 0 , 0 , 0
85
- print ( "Running pytype tests..." )
118
+ files = pytype_run + pytd_run
86
119
while 1 :
87
120
while files and len (running_tests ) < args .num_parallel :
88
- test_run = PytdRun ([files .pop ()], dry_run = args .dry_run )
121
+ f = files .pop ()
122
+ if f in pytype_run :
123
+ test_run = BinaryRun (
124
+ ['pytype' ,
125
+ '--typeshed-location=%s' % os .getcwd (),
126
+ '--module-name=%s' % _get_module_name (f ),
127
+ '--convert-to-pickle=%s' % os .devnull ,
128
+ f ],
129
+ dry_run = args .dry_run )
130
+ elif f in pytd_run :
131
+ test_run = BinaryRun (['pytd' , f ], dry_run = args .dry_run )
132
+ else :
133
+ raise ValueError ('Unknown action for file: %s' % f )
89
134
running_tests .append (test_run )
90
135
91
136
if not running_tests :
@@ -97,13 +142,11 @@ def pytype_test(args):
97
142
runs += 1
98
143
99
144
if code :
100
- print ("pytd error processing \" %s\" :" % test_run .args [0 ])
101
145
print (stderr )
102
146
errors += 1
103
147
104
- print (" Ran pytype with %d pyis, got %d errors." % (runs , errors ))
148
+ print (' Ran pytype with %d pyis, got %d errors.' % (runs , errors ))
105
149
return max_code , runs
106
150
107
-
108
151
if __name__ == '__main__' :
109
152
main ()
0 commit comments