1
1
import argparse
2
2
import configparser
3
3
import glob as fileglob
4
+ from io import StringIO
4
5
import os
5
6
import re
6
7
import sys
@@ -116,24 +117,22 @@ def parse_config_file(options: Options, filename: Optional[str],
116
117
print ("%s: No [mypy] section in config file" % file_read , file = stderr )
117
118
else :
118
119
section = parser ['mypy' ]
119
- prefix = '%s: [%s]' % (file_read , 'mypy' )
120
- updates , report_dirs = parse_section (prefix , options , section ,
121
- stdout , stderr )
120
+ prefix = '%s: [%s]: ' % (file_read , 'mypy' )
121
+ updates , report_dirs = parse_section (prefix , options , section , stderr )
122
122
for k , v in updates .items ():
123
123
setattr (options , k , v )
124
124
options .report_dirs .update (report_dirs )
125
125
126
126
for name , section in parser .items ():
127
127
if name .startswith ('mypy-' ):
128
- prefix = '%s: [%s]' % (file_read , name )
129
- updates , report_dirs = parse_section (prefix , options , section ,
130
- stdout , stderr )
128
+ prefix = '%s: [%s]: ' % (file_read , name )
129
+ updates , report_dirs = parse_section (prefix , options , section , stderr )
131
130
if report_dirs :
132
- print ("%s: Per -module sections should not specify reports (%s)" %
131
+ print ("%sPer -module sections should not specify reports (%s)" %
133
132
(prefix , ', ' .join (s + '_report' for s in sorted (report_dirs ))),
134
133
file = stderr )
135
134
if set (updates ) - PER_MODULE_OPTIONS :
136
- print ("%s: Per -module sections should only specify per-module flags (%s)" %
135
+ print ("%sPer -module sections should only specify per-module flags (%s)" %
137
136
(prefix , ', ' .join (sorted (set (updates ) - PER_MODULE_OPTIONS ))),
138
137
file = stderr )
139
138
updates = {k : v for k , v in updates .items () if k in PER_MODULE_OPTIONS }
@@ -146,7 +145,7 @@ def parse_config_file(options: Options, filename: Optional[str],
146
145
147
146
if (any (c in glob for c in '?[]!' ) or
148
147
any ('*' in x and x != '*' for x in glob .split ('.' ))):
149
- print ("%s: Patterns must be fully-qualified module names, optionally "
148
+ print ("%sPatterns must be fully-qualified module names, optionally "
150
149
"with '*' in some components (e.g spam.*.eggs.*)"
151
150
% prefix ,
152
151
file = stderr )
@@ -156,7 +155,6 @@ def parse_config_file(options: Options, filename: Optional[str],
156
155
157
156
def parse_section (prefix : str , template : Options ,
158
157
section : Mapping [str , str ],
159
- stdout : TextIO = sys .stdout ,
160
158
stderr : TextIO = sys .stderr
161
159
) -> Tuple [Dict [str , object ], Dict [str , str ]]:
162
160
"""Parse one section of a config file.
@@ -176,17 +174,17 @@ def parse_section(prefix: str, template: Options,
176
174
if report_type in defaults .REPORTER_NAMES :
177
175
report_dirs [report_type ] = section [key ]
178
176
else :
179
- print ("%s: Unrecognized report type: %s" % (prefix , key ),
177
+ print ("%sUnrecognized report type: %s" % (prefix , key ),
180
178
file = stderr )
181
179
continue
182
180
if key .startswith ('x_' ):
183
181
continue # Don't complain about `x_blah` flags
184
182
elif key == 'strict' :
185
- print ("%s: Strict mode is not supported in configuration files: specify "
183
+ print ("%sStrict mode is not supported in configuration files: specify "
186
184
"individual flags instead (see 'mypy -h' for the list of flags enabled "
187
185
"in strict mode)" % prefix , file = stderr )
188
186
else :
189
- print ("%s: Unrecognized option: %s = %s" % (prefix , key , section [key ]),
187
+ print ("%sUnrecognized option: %s = %s" % (prefix , key , section [key ]),
190
188
file = stderr )
191
189
continue
192
190
ct = type (dv )
@@ -198,29 +196,75 @@ def parse_section(prefix: str, template: Options,
198
196
try :
199
197
v = ct (section .get (key ))
200
198
except argparse .ArgumentTypeError as err :
201
- print ("%s: %s: %s" % (prefix , key , err ), file = stderr )
199
+ print ("%s%s: %s" % (prefix , key , err ), file = stderr )
202
200
continue
203
201
else :
204
- print ("%s: Don 't know what type %s should have" % (prefix , key ), file = stderr )
202
+ print ("%sDon 't know what type %s should have" % (prefix , key ), file = stderr )
205
203
continue
206
204
except ValueError as err :
207
- print ("%s: %s: %s" % (prefix , key , err ), file = stderr )
205
+ print ("%s%s: %s" % (prefix , key , err ), file = stderr )
208
206
continue
209
207
if key == 'cache_dir' :
210
208
v = os .path .expanduser (v )
211
209
if key == 'silent_imports' :
212
- print ("%s: silent_imports has been replaced by "
210
+ print ("%ssilent_imports has been replaced by "
213
211
"ignore_missing_imports=True; follow_imports=skip" % prefix , file = stderr )
214
212
if v :
215
213
if 'ignore_missing_imports' not in results :
216
214
results ['ignore_missing_imports' ] = True
217
215
if 'follow_imports' not in results :
218
216
results ['follow_imports' ] = 'skip'
219
217
if key == 'almost_silent' :
220
- print ("%s: almost_silent has been replaced by "
218
+ print ("%salmost_silent has been replaced by "
221
219
"follow_imports=error" % prefix , file = stderr )
222
220
if v :
223
221
if 'follow_imports' not in results :
224
222
results ['follow_imports' ] = 'error'
225
223
results [key ] = v
226
224
return results , report_dirs
225
+
226
+
227
+ def mypy_comments_to_config_map (args : List [str ], template : Options ) -> Dict [str , str ]:
228
+ """Rewrite the mypy comment syntax into ini file syntax"""
229
+ options = {}
230
+ for line in args :
231
+ for entry in line .split (', ' ):
232
+ if '=' not in entry :
233
+ name = entry
234
+ value = None
235
+ else :
236
+ name , value = entry .split ('=' , 1 )
237
+
238
+ name = name .replace ('-' , '_' )
239
+ if value is None :
240
+ if name .startswith ('no_' ) and not hasattr (template , name ):
241
+ name = name [3 :]
242
+ value = 'False'
243
+ else :
244
+ value = 'True'
245
+ options [name ] = value
246
+
247
+ return options
248
+
249
+
250
+ def parse_mypy_comments (
251
+ args : List [str ], template : Options ) -> Tuple [Dict [str , object ], List [str ]]:
252
+ """Parse a collection of inline mypy: configuration comments.
253
+
254
+ Returns a dictionary of options to be applied and a list of error messages
255
+ generated.
256
+ """
257
+
258
+ # In order to easily match the behavior for bools, we abuse configparser.
259
+ # Oddly, the only way to get the SectionProxy object with the getboolean
260
+ # method is to create a config parser.
261
+ parser = configparser .RawConfigParser ()
262
+ parser ['dummy' ] = mypy_comments_to_config_map (args , template )
263
+
264
+ stderr = StringIO ()
265
+ sections , reports = parse_section ('' , template , parser ['dummy' ], stderr = stderr )
266
+ errors = [x for x in stderr .getvalue ().strip ().split ('\n ' ) if x ]
267
+ if reports :
268
+ errors .append ("Reports not supported in inline configuration" )
269
+
270
+ return sections , errors
0 commit comments