#python #configuration
#python #конфигурация
Вопрос:
Я хочу написать программу, которая отправляет электронное письмо одному или нескольким указанным получателям при возникновении определенного события. Для этого мне нужно, чтобы пользователь записал параметры для почтового сервера в конфигурацию. Возможными значениями являются, например: адрес сервера, порты, ssl (true / false) и список желаемых получателей.
Какой самый удобный для пользователя способ сделать это?
Я мог бы, конечно, использовать файл python с правильными параметрами, и пользователь должен заполнить его, но я бы не счел это удобным для пользователя. Я также читал о модуле ‘config’ в python, но мне кажется, что он создан для самостоятельного создания конфигурационных файлов, а не для того, чтобы пользователи сами заполняли файлы.
Комментарии:
1. Вы должны проверить docs.python.org/library/configparser.html
2. Я не понимаю. Пользователю придется записывать параметры каждый раз, когда будет отправлено электронное письмо? Зачем в этом случае записывать параметры в конфигурационный файл? Разве данных, содержащихся в строке, созданной с параметрами, заданными пользователем, было бы недостаточно?
3. @eyquem Пользователь должен ввести данные один раз в конфигурационный файл. После этого программа всегда считывает его из файла.
Ответ №1:
Вы хотите сказать, что тот факт, что файл конфигурации должен быть действительным в Python, делает его недружественным? Похоже, что в файле есть строки, подобные:
server = 'mail.domain.com'
port = 25
…etc был бы достаточно интуитивно понятным, оставаясь при этом действительным 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)
...
конфигурация теперь содержит все параметры.
Комментарии:
1. Спасибо за ваш ответ. Я боюсь, что python может быть неудобен для пользователя из-за необходимости заключать строки в кавычки (как вы упомянули) и из-за отступов. Yaml звучит великолепно, в Ubuntu даже есть пакет python-yaml для него.
2. yaml действительно великолепен, я часто использую его для файлов конфигурации
3. @Basil: Большинство людей могут без труда найти ключи «в кавычках» и сопоставить «апострофам». Для англоязычных пользователей это стандартно, и все они знают, как это сделать. Ваши пользователи не владеют английским языком?
4. @S.Лотт Я не хотел подразумевать, что пользователи не смогут это понять. Просто отсутствие необходимости заботиться о кавычках и отступах упрощает задачу.
5. @Basil: В файле конфигурации никогда не должно быть никаких отступов и только самые простые правила цитирования. Вы обнаружите, что соответствующее подмножество Python часто намного проще , чем все другие варианты синтаксиса.
Ответ №2:
Не имеет значения, насколько технически опытны ваши пользователи; вы можете рассчитывать на то, что они облажаются при редактировании текстового файла. (Они сохранят его не в том месте. Они будут использовать MS Word для редактирования текстового файла. Они будут делать опечатки.) Я предлагаю создать графический интерфейс, который проверяет входные данные и создает файл конфигурации в правильном формате и расположении. Простой графический интерфейс, созданный в Tkinter, вероятно, соответствовал бы вашим потребностям.
Комментарии:
1. Я согласен с вами. Но на данный момент программа доступна только из командной строки, и в таком виде она останется на некоторое время.
2. Вы все еще можете создать программу, которая запрашивает параметры конфигурации и сохраняет их корректно с помощью
raw_input
. Если вам необходимо, чтобы ваши пользователи редактировали файл напрямую, я бы согласился сyaml
ответом joesy.
Ответ №3:
Я использовал 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')
И я также написал функцию, которая создает пример конфигурационного файла, используя этот список ОПЦИЙ.
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"
Ответ №4:
Каковы недостатки такого решения:
ch = 'serveradress = %snport = %snssl = %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 exclusivelyn"
" 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 exclusivelyn"
" Re-choose the ssl option : "
with open('configfile.txt','w') as f:
f.write(ch % (a,b,c))
.
PS
Я прочитал в сообщении jonesy’s, что значение в файле конфигурации, возможно, придется заключать в кавычки. Если это так, и вы хотите, чтобы пользователю не приходилось самому писать кавычки, вы просто добавляете
a = a.join('""')
b = b.join('""')
c = c.join('""')
.
Редактировать
ch = 'serveradress = %snport = %snssl = %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 :nn"
ch % tuple(li)
"n==============================================="
"nnDo 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 -*-'
Комментарии:
1. Я думаю, что в целом это хорошая идея. Единственная проблема, которую я вижу в этом, заключается в том, что если вы допустите опечатку, вам придется вводить все заново. Но я думаю, что добавлю комментарии вроде вашего («.. вы должны вводить исключительно цифры») к файлу.
2. @Basil Ну, это можно исправить. Дайте мне немного времени, и я предложу вам улучшение.