@@ -216,6 +216,73 @@ def split_commas(value: str) -> list[str]:
216216 }
217217)
218218
219+ def _maybe_parse_individual_file (
220+ config_file : str , stderr : TextIO | None = None ,
221+ ) -> tuple [MutableMapping [str , Any ], dict [str , _INI_PARSER_CALLABLE ], str ] | None :
222+
223+ if not os .path .exists (config_file ):
224+ return None
225+
226+ config_parser = configparser .RawConfigParser ()
227+ parser : MutableMapping [str , Any ]
228+ try :
229+ if is_toml (config_file ):
230+ with open (config_file , "rb" ) as f :
231+ toml_data = tomllib .load (f )
232+ # Filter down to just mypy relevant toml keys
233+ toml_data = toml_data .get ("tool" , {})
234+ if "mypy" not in toml_data :
235+ return None
236+ toml_data = {"mypy" : toml_data ["mypy" ]}
237+ parser = destructure_overrides (toml_data )
238+ config_types = toml_config_types
239+ else :
240+ config_parser .read (config_file )
241+ parser = config_parser
242+ config_types = ini_config_types
243+
244+ except (tomllib .TOMLDecodeError , configparser .Error , ConfigTOMLValueError ) as err :
245+ print (f"{ config_file } : { err } " , file = stderr )
246+ return None
247+
248+ if os .path .basename (config_file ) in defaults .SHARED_CONFIG_NAMES and "mypy" not in parser :
249+ return None
250+
251+ return parser , config_types , config_file
252+
253+
254+ def _find_config_file (
255+ stderr : TextIO | None = None ,
256+ ) -> tuple [MutableMapping [str , Any ], dict [str , _INI_PARSER_CALLABLE ], str ] | None :
257+
258+ current_dir = os .path .abspath (os .getcwd ())
259+
260+ while True :
261+ for name in defaults .CONFIG_NAMES + defaults .SHARED_CONFIG_NAMES :
262+ config_file = os .path .relpath (os .path .join (current_dir , name ))
263+ ret = _maybe_parse_individual_file (config_file , stderr )
264+ if ret is None :
265+ continue
266+ return ret
267+
268+ if any (
269+ os .path .exists (os .path .join (current_dir , cvs_root ))
270+ for cvs_root in (".git" , ".hg" )
271+ ):
272+ break
273+ parent_dir = os .path .dirname (current_dir )
274+ if parent_dir == current_dir :
275+ break
276+ current_dir = parent_dir
277+
278+ for config_file in defaults .USER_CONFIG_FILES :
279+ ret = _maybe_parse_individual_file (config_file , stderr )
280+ if ret is None :
281+ continue
282+ return ret
283+
284+ return None
285+
219286
220287def parse_config_file (
221288 options : Options ,
@@ -234,46 +301,21 @@ def parse_config_file(
234301 stderr = stderr or sys .stderr
235302
236303 if filename is not None :
237- config_files : tuple [str , ...] = (filename ,)
238- else :
239- config_files_iter : Iterable [str ] = map (os .path .expanduser , defaults .CONFIG_FILES )
240- config_files = tuple (config_files_iter )
241-
242- config_parser = configparser .RawConfigParser ()
243-
244- for config_file in config_files :
245- if not os .path .exists (config_file ):
246- continue
247- try :
248- if is_toml (config_file ):
249- with open (config_file , "rb" ) as f :
250- toml_data = tomllib .load (f )
251- # Filter down to just mypy relevant toml keys
252- toml_data = toml_data .get ("tool" , {})
253- if "mypy" not in toml_data :
254- continue
255- toml_data = {"mypy" : toml_data ["mypy" ]}
256- parser : MutableMapping [str , Any ] = destructure_overrides (toml_data )
257- config_types = toml_config_types
258- else :
259- config_parser .read (config_file )
260- parser = config_parser
261- config_types = ini_config_types
262- except (tomllib .TOMLDecodeError , configparser .Error , ConfigTOMLValueError ) as err :
263- print (f"{ config_file } : { err } " , file = stderr )
264- else :
265- if config_file in defaults .SHARED_CONFIG_FILES and "mypy" not in parser :
266- continue
267- file_read = config_file
268- options .config_file = file_read
269- break
304+ ret = _maybe_parse_individual_file (filename , stderr )
305+ if ret is None :
306+ return
307+ parser , config_types , file_read = ret
270308 else :
271- return
309+ ret = _find_config_file (stderr )
310+ if ret is None :
311+ return
312+ parser , config_types , file_read = ret
272313
273- os .environ ["MYPY_CONFIG_FILE_DIR" ] = os .path .dirname (os .path .abspath (config_file ))
314+ options .config_file = file_read
315+ os .environ ["MYPY_CONFIG_FILE_DIR" ] = os .path .dirname (os .path .abspath (file_read ))
274316
275317 if "mypy" not in parser :
276- if filename or file_read not in defaults .SHARED_CONFIG_FILES :
318+ if filename or os . path . basename ( file_read ) not in defaults .SHARED_CONFIG_NAMES :
277319 print (f"{ file_read } : No [mypy] section in config file" , file = stderr )
278320 else :
279321 section = parser ["mypy" ]
0 commit comments