我想编写一个程序,在发生特定事件时向一个或多个指定的收件人发送电子邮件。为此,我需要用户将邮件服务器的参数写入配置。可能的值例如是:serveradress,ports,ssl(true / false)和所需收件人列表。
用户最友好/最佳实践的方法是什么?
我当然可以使用带有正确参数的python文件,用户必须填写它,但我不认为这个用户友好。我也读过python中的'config'模块,但在我看来,它是为自己创建配置文件而制作的,而不是让用户自己填充文件。
答案 0 :(得分:4)
你是说配置文件需要有效的Python这一事实使它不友好吗?它似乎在文件中包含行:
server = 'mail.domain.com'
port = 25
...等足够直观,同时仍然是有效的Python。但是,如果您不希望用户必须知道他们必须引用字符串,那么您可能会使用YAML路由。我几乎只使用YAML配置文件并发现它非常直观,而且我认为它对于最终用户来说也很直观(虽然它需要第三方模块 - PyYAML):
server: mail.domain.com
port: 25
加载pyyaml很简单:
>>> import yaml
>>> yaml.load("""a: 1
... b: foo
... """)
{'a': 1, 'b': 'foo'}
使用文件也很容易。
>>> with open('myconfig.yaml', 'r') as cfile:
... config = yaml.load(cfile)
...
config现在包含所有参数。
答案 1 :(得分:2)
我的用户技术熟练并不重要;你可以指望它们搞砸了编辑文本文件。 (他们会将它保存在错误的地方。他们将使用MS Word编辑文本文件。他们会打字错误。)我建议制作一个验证输入的gui并以正确的格式和位置创建配置文件。在Tkinter创建的简单gui可能符合您的需求。
答案 2 :(得分:1)
这种解决方案的缺点是什么:
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
我在jonesy的帖子中读到可能必须引用配置文件中的值。如果是这样,并且您希望用户不必为他/她自己写引号,则只需添加
即可a = a.join('""')
b = b.join('""')
c = c.join('""')
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 -*-'
答案 3 :(得分:1)
我一直在使用ConfigParser。它旨在读取具有以下内容的 .ini 样式文件。
[section]
option = value
它非常易于使用,文档非常易于阅读。基本上你只需将整个文件加载到ConfigParser对象中:
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('configfile.txt')
然后,您可以通过选中选项确保用户没有搞砸任何事情。我这样做有一个清单:
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)
获取价值也很容易。
val = config.get('section','option')
我还编写了一个使用 OPTIONS 列表创建示例配置文件的函数。
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"