[Spambayes] Storing Options

Meyer, Tony T.A.Meyer at massey.ac.nz
Thu Mar 20 19:09:40 EST 2003

Ok, here's a draft proposal for changes to create a new way of storing  
options. I'm not going to implement any of this unless there is a       
consensus that it's a good thing, so don't panic.                       

There are four main changes, each outlined below. They can be           
implemented separately, but together makes most sense.                  

I would not change:                                                     
* The search path for options (i.e. defaults, then envar, then          
current/home directory).                                                
* Storing the defaults inside a .py file rather than having a           
'bayes.ini' file (reading the archives, the reasons behind this make    

So, here's what I do propose. Note that these are significant changes   
and would require changes (improvements ;) all over the code. The user  
would notice nothing, however. When you get a chance, please read       
through these and comment.                                              

1. Change from using getattr to get

This means using 'options["pop3proxy_servers"]' rather than             
'options.pop3proxy_servers'. This avoid the possible problems with      
conflicts with existing OptionsClass attribute names, and allows #2 and 
(more easily) #3.                                                       

2. Use the section data.

This means using 'options[("pop3proxy", "servers")]'. For backwards     
compatability 'options["pop3proxy_servers"]' would return the value of  
any option named "pop3proxy_servers", whichever section it was in.      

This is tidier, and allows neat things later on (like maybe only        
loading option sections that are relevant). For the most part it is     
already set up this way, it's just that Options currently throws away   
all the section information.                                            

3. Setting values propagates through to ConfigParser

This means that 'options.pop3proxy_add_evidence_header = True' (with    
#1 & #2, 'options[("pop3proxy", "add_evidence header")] = True')        
would not just change the Options object, but also the ConfigParser     
object that it inherits from.                                           

This *does not* mean that that any files would be changed, but *does*   
mean that they could be updated on demand, via the write() function -   
or via the update() function in UpdatableConfigParser).                 

4. Detailed options.

Each option has the following attributes:                               
* a name                                                                
* a nice name                                                           
* a default value                                                       
* explanation text                                                      
* either a tuple or a regex of allowed values                           
* the current value                                                     
* whether it should be restored on a 'return to defaults' command       

Two simple examples:

"pop3proxy_servers", "Servers", "", "These are the servers that will be
proxied blah blah...", r"\w", "pop.example.com", False

"add_evidence_header", "Clues Header", True, "This option adds a header 
with the spam clues blah blah blah", (True, False), False, True         

These would be accessed as follows:                                     
nice name: options.display_name(sect, opt)                              
default: options.default(sect, opt) - these would also be the values of 
all options prior to loading any config file                            
explanation text: options.doc(sect, opt)                                
allowed values: options.valid_input(sect, opt)                          
current value: either via options[(sect, opt)], or via                  
options.get(sect, opt)                                                  
restore on revert: options.no_restore(sect, opt)                        

Also provided would be options.is_valid(sect, opt, value) which would   
return True iff the value was valid for that option.                    

OR options[(sect, opt)] / options.get(sect, opt) returns an Option
object that has these things. This is nicer, but is more work to just
get the current value, which is what is wanted most of the time.

More information about the Spambayes mailing list