11import argparse
22import configparser
33import glob as fileglob
4+ from io import StringIO
45import os
56import re
67import sys
@@ -116,18 +117,16 @@ def parse_config_file(options: Options, filename: Optional[str],
116117 print ("%s: No [mypy] section in config file" % file_read , file = stderr )
117118 else :
118119 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 )
122122 for k , v in updates .items ():
123123 setattr (options , k , v )
124124 options .report_dirs .update (report_dirs )
125125
126126 for name , section in parser .items ():
127127 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 )
131130 if report_dirs :
132131 print ("%s: Per-module sections should not specify reports (%s)" %
133132 (prefix , ', ' .join (s + '_report' for s in sorted (report_dirs ))),
@@ -156,7 +155,6 @@ def parse_config_file(options: Options, filename: Optional[str],
156155
157156def parse_section (prefix : str , template : Options ,
158157 section : Mapping [str , str ],
159- stdout : TextIO = sys .stdout ,
160158 stderr : TextIO = sys .stderr
161159 ) -> Tuple [Dict [str , object ], Dict [str , str ]]:
162160 """Parse one section of a config file.
@@ -176,17 +174,17 @@ def parse_section(prefix: str, template: Options,
176174 if report_type in defaults .REPORTER_NAMES :
177175 report_dirs [report_type ] = section [key ]
178176 else :
179- print ("%s: Unrecognized report type: %s" % (prefix , key ),
177+ print ("%sUnrecognized report type: %s" % (prefix , key ),
180178 file = stderr )
181179 continue
182180 if key .startswith ('x_' ):
183181 continue # Don't complain about `x_blah` flags
184182 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 "
186184 "individual flags instead (see 'mypy -h' for the list of flags enabled "
187185 "in strict mode)" % prefix , file = stderr )
188186 else :
189- print ("%s: Unrecognized option: %s = %s" % (prefix , key , section [key ]),
187+ print ("%sUnrecognized option: %s = %s" % (prefix , key , section [key ]),
190188 file = stderr )
191189 continue
192190 ct = type (dv )
@@ -198,29 +196,75 @@ def parse_section(prefix: str, template: Options,
198196 try :
199197 v = ct (section .get (key ))
200198 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 )
202200 continue
203201 else :
204202 print ("%s: Don't know what type %s should have" % (prefix , key ), file = stderr )
205203 continue
206204 except ValueError as err :
207- print ("%s: %s: %s" % (prefix , key , err ), file = stderr )
205+ print ("%s%s: %s" % (prefix , key , err ), file = stderr )
208206 continue
209207 if key == 'cache_dir' :
210208 v = os .path .expanduser (v )
211209 if key == 'silent_imports' :
212- print ("%s: silent_imports has been replaced by "
210+ print ("%ssilent_imports has been replaced by "
213211 "ignore_missing_imports=True; follow_imports=skip" % prefix , file = stderr )
214212 if v :
215213 if 'ignore_missing_imports' not in results :
216214 results ['ignore_missing_imports' ] = True
217215 if 'follow_imports' not in results :
218216 results ['follow_imports' ] = 'skip'
219217 if key == 'almost_silent' :
220- print ("%s: almost_silent has been replaced by "
218+ print ("%salmost_silent has been replaced by "
221219 "follow_imports=error" % prefix , file = stderr )
222220 if v :
223221 if 'follow_imports' not in results :
224222 results ['follow_imports' ] = 'error'
225223 results [key ] = v
226224 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