@@ -44,7 +44,7 @@ def __init__(self, cfgFile, cfgDefaults=None):
44
44
"""
45
45
cfgFile - string, fully specified configuration file name
46
46
"""
47
- self .file = cfgFile
47
+ self .file = cfgFile # This is currently '' when testing.
48
48
ConfigParser .__init__ (self , defaults = cfgDefaults , strict = False )
49
49
50
50
def Get (self , section , option , type = None , default = None , raw = False ):
@@ -73,7 +73,8 @@ def GetOptionList(self, section):
73
73
74
74
def Load (self ):
75
75
"Load the configuration file from disk."
76
- self .read (self .file )
76
+ if self .file :
77
+ self .read (self .file )
77
78
78
79
class IdleUserConfParser (IdleConfParser ):
79
80
"""
@@ -130,21 +131,22 @@ def RemoveFile(self):
130
131
def Save (self ):
131
132
"""Update user configuration file.
132
133
133
- Remove empty sections. If resulting config isn't empty, write the file
134
- to disk. If config is empty , remove the file from disk if it exists.
134
+ If self not empty after removing empty sections , write the file
135
+ to disk. Otherwise , remove the file from disk if it exists.
135
136
136
137
"""
137
- if not self .IsEmpty ():
138
- fname = self .file
139
- try :
140
- cfgFile = open (fname , 'w' )
141
- except OSError :
142
- os .unlink (fname )
143
- cfgFile = open (fname , 'w' )
144
- with cfgFile :
145
- self .write (cfgFile )
146
- else :
147
- self .RemoveFile ()
138
+ fname = self .file
139
+ if fname :
140
+ if not self .IsEmpty ():
141
+ try :
142
+ cfgFile = open (fname , 'w' )
143
+ except OSError :
144
+ os .unlink (fname )
145
+ cfgFile = open (fname , 'w' )
146
+ with cfgFile :
147
+ self .write (cfgFile )
148
+ else :
149
+ self .RemoveFile ()
148
150
149
151
class IdleConf :
150
152
"""Hold config parsers for all idle config files in singleton instance.
@@ -158,7 +160,7 @@ class IdleConf:
158
160
(user home dir)/.idlerc/config-{config-type}.cfg
159
161
"""
160
162
def __init__ (self ):
161
- self .config_types = ('main' , 'extensions ' , 'highlight ' , 'keys ' )
163
+ self .config_types = ('main' , 'highlight ' , 'keys ' , 'extensions ' )
162
164
self .defaultCfg = {}
163
165
self .userCfg = {}
164
166
self .cfg = {} # TODO use to select userCfg vs defaultCfg
@@ -766,7 +768,6 @@ def SaveUserCfgFiles(self):
766
768
767
769
idleConf = IdleConf ()
768
770
769
-
770
771
_warned = set ()
771
772
def _warn (msg , * key ):
772
773
key = (msg ,) + key
@@ -778,9 +779,100 @@ def _warn(msg, *key):
778
779
_warned .add (key )
779
780
780
781
782
+ class ConfigChanges (dict ):
783
+ """Manage a user's proposed configuration option changes.
784
+
785
+ Names used across multiple methods:
786
+ page -- one of the 4 top-level dicts representing a
787
+ .idlerc/config-x.cfg file.
788
+ config_type -- name of a page.
789
+ section -- a section within a page/file.
790
+ option -- name of an option within a section.
791
+ value -- value for the option.
792
+
793
+ Methods
794
+ add_option: Add option and value to changes.
795
+ save_option: Save option and value to config parser.
796
+ save_all: Save all the changes to the config parser and file.
797
+ delete_section: Delete section if it exists.
798
+ clear: Clear all changes by clearing each page.
799
+ """
800
+ def __init__ (self ):
801
+ "Create a page for each configuration file"
802
+ self .pages = [] # List of unhashable dicts.
803
+ for config_type in idleConf .config_types :
804
+ self [config_type ] = {}
805
+ self .pages .append (self [config_type ])
806
+
807
+ def add_option (self , config_type , section , item , value ):
808
+ "Add item/value pair for config_type and section."
809
+ page = self [config_type ]
810
+ value = str (value ) # Make sure we use a string.
811
+ if section not in page :
812
+ page [section ] = {}
813
+ page [section ][item ] = value
814
+
815
+ @staticmethod
816
+ def save_option (config_type , section , item , value ):
817
+ """Return True if the configuration value was added or changed.
818
+
819
+ Helper for save_all.
820
+ """
821
+ if idleConf .defaultCfg [config_type ].has_option (section , item ):
822
+ if idleConf .defaultCfg [config_type ].Get (section , item ) == value :
823
+ # The setting equals a default setting, remove it from user cfg.
824
+ return idleConf .userCfg [config_type ].RemoveOption (section , item )
825
+ # If we got here, set the option.
826
+ return idleConf .userCfg [config_type ].SetOption (section , item , value )
827
+
828
+ def save_all (self ):
829
+ """Save configuration changes to the user config file.
830
+
831
+ Then clear self in preparation for additional changes.
832
+ """
833
+ idleConf .userCfg ['main' ].Save ()
834
+ for config_type in self :
835
+ cfg_type_changed = False
836
+ page = self [config_type ]
837
+ for section in page :
838
+ if section == 'HelpFiles' : # Remove it for replacement.
839
+ idleConf .userCfg ['main' ].remove_section ('HelpFiles' )
840
+ cfg_type_changed = True
841
+ for item , value in page [section ].items ():
842
+ if self .save_option (config_type , section , item , value ):
843
+ cfg_type_changed = True
844
+ if cfg_type_changed :
845
+ idleConf .userCfg [config_type ].Save ()
846
+ for config_type in ['keys' , 'highlight' ]:
847
+ # Save these even if unchanged!
848
+ idleConf .userCfg [config_type ].Save ()
849
+ self .clear ()
850
+ # ConfigDialog caller must add the following call
851
+ # self.save_all_changed_extensions() # Uses a different mechanism.
852
+
853
+ def delete_section (self , config_type , section ):
854
+ """Delete a section from self, userCfg, and file.
855
+
856
+ Used to delete custom themes and keysets.
857
+ """
858
+ if section in self [config_type ]:
859
+ del self [config_type ][section ]
860
+ configpage = idleConf .userCfg [config_type ]
861
+ configpage .remove_section (section )
862
+ configpage .Save ()
863
+
864
+ def clear (self ):
865
+ """Clear all 4 pages.
866
+
867
+ Called in save_all after saving to idleConf.
868
+ XXX Mark window *title* when there are changes; unmark here.
869
+ """
870
+ for page in self .pages :
871
+ page .clear ()
872
+
873
+
781
874
# TODO Revise test output, write expanded unittest
782
- #
783
- if __name__ == '__main__' :
875
+ def _dump (): # htest # (not really, but ignore in coverage)
784
876
from zlib import crc32
785
877
line , crc = 0 , 0
786
878
@@ -790,10 +882,10 @@ def sprint(obj):
790
882
line += 1
791
883
crc = crc32 (txt .encode (encoding = 'utf-8' ), crc )
792
884
print (txt )
793
- #print('***', line, crc, '***') # uncomment for diagnosis
885
+ #print('***', line, crc, '***') # Uncomment for diagnosis.
794
886
795
887
def dumpCfg (cfg ):
796
- print ('\n ' , cfg , '\n ' ) # has variable '0xnnnnnnnn' addresses
888
+ print ('\n ' , cfg , '\n ' ) # Cfg has variable '0xnnnnnnnn' address.
797
889
for key in sorted (cfg .keys ()):
798
890
sections = cfg [key ].sections ()
799
891
sprint (key )
@@ -808,3 +900,9 @@ def dumpCfg(cfg):
808
900
dumpCfg (idleConf .defaultCfg )
809
901
dumpCfg (idleConf .userCfg )
810
902
print ('\n lines = ' , line , ', crc = ' , crc , sep = '' )
903
+
904
+ if __name__ == '__main__' :
905
+ import unittest
906
+ unittest .main ('idlelib.idle_test.test_config' ,
907
+ verbosity = 2 , exit = False )
908
+ #_dump()
0 commit comments