|
25 | 25 | """ |
26 | 26 | # TODOs added Oct 2014, tjr |
27 | 27 |
|
28 | | -from configparser import ConfigParser |
| 28 | +from configparser import ConfigParser, Error as ConfigParserError |
29 | 29 | import os |
30 | 30 | import sys |
31 | 31 |
|
@@ -159,6 +159,7 @@ def __init__(self, _utest=False): |
159 | 159 | self.defaultCfg = {} |
160 | 160 | self.userCfg = {} |
161 | 161 | self.cfg = {} # TODO use to select userCfg vs defaultCfg |
| 162 | + self.file_load_errors = [] # (file, error) for unparsable cfg files. |
162 | 163 |
|
163 | 164 | # See https://bugs.python.org/issue4630#msg356516 for following. |
164 | 165 | # self.blink_off_time = <first editor text>['insertofftime'] |
@@ -795,7 +796,28 @@ def LoadCfgFiles(self): |
795 | 796 | "Load all configuration files." |
796 | 797 | for key in self.defaultCfg: |
797 | 798 | self.defaultCfg[key].Load() |
798 | | - self.userCfg[key].Load() #same keys |
| 799 | + try: |
| 800 | + self.userCfg[key].Load() # same keys |
| 801 | + except ConfigParserError as err: |
| 802 | + # Move an unparsable user file aside instead of losing it |
| 803 | + # or failing to start (gh-66172). |
| 804 | + file = self.userCfg[key].file |
| 805 | + self.file_load_errors.append((file, err)) |
| 806 | + try: |
| 807 | + os.replace(file, file + '.bad') |
| 808 | + except OSError: |
| 809 | + pass |
| 810 | + |
| 811 | + def file_load_error_message(self): |
| 812 | + "Return a warning about unparsable config files, or None." |
| 813 | + if not self.file_load_errors: |
| 814 | + return None |
| 815 | + files = '\n'.join( |
| 816 | + f' {file}:\n {type(err).__name__}: {str(err).splitlines()[0]}' |
| 817 | + for file, err in self.file_load_errors) |
| 818 | + return ('The following IDLE configuration files could not be parsed. ' |
| 819 | + 'They were renamed by appending ".bad", and default settings ' |
| 820 | + 'are used instead:\n\n' + files) |
799 | 821 |
|
800 | 822 | def SaveUserCfgFiles(self): |
801 | 823 | "Write all loaded user configuration files to disk." |
|
0 commit comments