开发者

Userfriendly way of handling config files in python?

I want to write a program that sends an e-mail to one or more specified recipients when a certain event occurs. For this I need the user to write the parameters for the mail server into a config. Possible values are for example: serveradress, ports, ssl(true/false) and a list of desired recipients.

Whats the user-friendliest/best-practice way to do this?

I could of course use a python file with the correct parameters and the user has to fill it out, but I wouldn't consider this user friendly. I also read about the 'config' module in python, but it seems to me that it's made f开发者_JAVA百科or creating config files on its own, and not to have users fill the files out themselves.


Are you saying that the fact that the config file would need to be valid Python makes it unfriendly? It seems like having lines in a file like:

 server = 'mail.domain.com'
 port = 25

...etc would be intuitive enough while still being valid Python. If you don't want the user to have to know that they have to quote strings, though, you might go the YAML route. I use YAML pretty much exclusively for config files and find it very intuitive, and it would also be intuitive for an end user I think (though it requires a third-party module - PyYAML):

 server: mail.domain.com
 port: 25

Having pyyaml load it is simple:

>>> import yaml
>>> yaml.load("""a: 1
... b: foo
... """)
{'a': 1, 'b': 'foo'}

With a file it's easy too.

>>> with open('myconfig.yaml', 'r') as cfile:
...    config = yaml.load(cfile)
... 

config now contains all of the parameters.


I doesn't matter technically proficient your users are; you can count on them to screw up editing a text file. (They'll save it in the wrong place. They'll use MS Word to edit a text file. They'll make typos.) I suggest making a gui that validates the input and creates the configuration file in the correct format and location. A simple gui created in Tkinter would probably fit your needs.


I've been using ConfigParser. It's designed to read .ini style files that have:

[section]
option = value

It's quite easy to use and the documentation is pretty easy to read. Basically you just load the whole file into a ConfigParser object:

import ConfigParser    

config = ConfigParser.ConfigParser()
config.read('configfile.txt')

Then you can make sure the users haven't messed anything up by checking the options. I do so with a list:

OPTIONS = 
    ['section,option,defaultvalue',
     .
     .
     .
    ]

for opt in OPTIONS:
    section,option,defaultval = opt.split(',')
    if not config.has_option(section,option):
        print "Missing option %s in section %s" % (option,section)

Getting the values out is easy too.

val = config.get('section','option')

And I also wrote a function that creates a sample config file using that OPTIONS list.

    new_config = ConfigParser.ConfigParser()
    for opt in OPTIONS:
        section,option,defaultval = opt.split(',')
        if not new_config.has_section(section):
            new_config.add_section(section)
        new_config.set(section, option, defaultval)
    with open("sample_configfile.txt", 'wb') as newconfigfile:
        new_config.write(newconfigfile)
    print "Generated file: sample_configfile.txt"


What are the drawbacks of such a solution:

ch = 'serveradress = %s\nport = %s\nssl = %s'

a = raw_input("Enter the server's address : ")

b = 'a'
bla = "\nEnter the port : "
while not all(x.isdigit() for x in b):
    b = raw_input(bla)
    bla = "Take care: you must enter digits exclusively\n"\
          +"  Re-enter the port (digits only) : "

c = ''
bla = "\nChoose the ssl option (t or f) : "
while c not in ('t','f'):
    c = raw_input(bla)
    bla = "Take care: you must type f or t exclusively\n"\
          +"  Re-choose the ssl option : "


with open('configfile.txt','w') as f:
    f.write(ch % (a,b,c))

.

PS

I've read in the jonesy's post that the value in a config file may have to be quoted. If so, and you want the user not to have to write him/her-self the quotes, you simply add

a = a.join('""')
b = b.join('""')
c = c.join('""')

.

EDIT

ch = 'serveradress = %s\nport = %s\nssl = %s'

d = {0:('',
        "Enter the server's address : "),
     1:("Take care: you must enter digits exclusively",
        "Enter the port : "),
     2:("Take care: you must type f or t exclusively",
        "Choose the ssl option (t or f) : ")  }

def func(i,x):
    if x is None:
        return False
    if i==0:
        return True
    elif i==1:
        try:
            ess = int(x)
            return True
        except:
            return False
    elif i==2:
        if x in ('t','f'):
            return True
        else:
            return False


li = len(d)*[None]
L = range(len(d))

while True:

    for n in sorted(L):
        bla = d[n][1]
        val = None
        while not func(n,val):
            val = raw_input(bla)
            bla = '\n  '.join(d[n])
        li[n] = val.join('""')

    decision = ''
    disp = "\n====== If you choose to process, =============="\
           +"\n    the content of the file will be :\n\n" \
           + ch % tuple(li) \
           + "\n==============================================="\
           + "\n\nDo you want to process (type y) or to correct (type c) : "
    while decision not in ('y','c'):
        decision = raw_input(disp)
        disp = "Do you want to process (type y) or to correct (type c) ? : "

    if decision=='y':
        break
    else:
        diag = False
        while not diag:
            vi = '\nWhat lines do you want to correct ?\n'\
                 +'\n'.join(str(j)+' - '+line for j,line in enumerate((ch % tuple(li)).splitlines()))\
                 +'\nType numbers of lines belonging to range(0,'+str(len(d))+') separated by spaces) :\n'
            to_modify = raw_input(vi)
            try:
                diag = all(int(entry) in xrange(len(d)) for entry in to_modify.split())
                L = [int(entry) for entry in to_modify.split()]
            except:
                diag = False


with open('configfile.txt','w') as f:
    f.write(ch % tuple(li))

print '-*-  Recording of the config file : done  -*-'
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜