Рубрики
Без рубрики

configparser – Работа с файлами конфигурации

Автор оригинала: Doug Hellmann.

Цель:

Чтение/запись файлов конфигурации, аналогичных файлам Windows INI

Используйте модуль configparser для управления редактируемыми пользователем файлами конфигурации приложения. Содержимое файлов конфигурации может быть организовано в группы, и поддерживается несколько типов значений параметров, включая целые числа, значения с плавающей запятой и логические значения. Значения параметров можно комбинировать с использованием строк форматирования Python для построения более длинных значений, таких как URL-адреса, из более коротких значений, таких как имена хостов и номера портов.

Формат файла конфигурации

Формат файла, используемый configparser , аналогичен формату, используемому в более старых версиях Microsoft Windows. Он состоит из одного или нескольких именованных разделов , каждый из которых может содержать отдельные параметры с именами и значениями.

Разделы файла конфигурации идентифицируются поиском строк, начинающихся с [ и заканчивающихся ] . Значение в квадратных скобках представляет собой имя раздела и может содержать любые символы, кроме квадратных скобок.

Параметры перечислены по одной в каждой строке в разделе. Строка начинается с имени параметра, которое отделяется от значения двоеточием (: ) или знаком равенства ( ). Пробелы вокруг разделителя игнорируются при анализе файла.

Строки, начинающиеся с точки с запятой (; ) или octothorpe ( # ), обрабатываются как комментарии и не отображаются при программном доступе к содержимому файла конфигурации.

В этом образце файла конфигурации есть раздел с именем bug_tracker с тремя параметрами: url , имя пользователя и пароль .

# This is a simple example with comments.
[bug_tracker]
url  http://localhost:8080/bugs/
username  dhellmann
; You should not store passwords in plain text
; configuration files.
password  SECRET

Чтение файлов конфигурации

Чаще всего файл конфигурации используется для того, чтобы пользователь или системный администратор отредактировал файл с помощью обычного текстового редактора, чтобы установить параметры поведения приложения по умолчанию, а затем попросить приложение прочитать файл, проанализировать его и действовать на основе его содержимого. Используйте метод read () в ConfigParser , чтобы прочитать файл конфигурации.

configparser_read.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('simple.ini')

print(parser.get('bug_tracker', 'url'))

Эта программа считывает файл simple.ini из предыдущего раздела и печатает значение параметра url из раздела bug_tracker .

$ python3 configparser_read.py

http://localhost:8080/bugs/

Метод read () также принимает список имен файлов. Каждое имя по очереди сканируется, и если файл существует, он открывается и читается.

configparser_read_many.py

from configparser import ConfigParser
import glob

parser  ConfigParser()

candidates  ['does_not_exist.ini', 'also-does-not-exist.ini',
              'simple.ini', 'multisection.ini']

found  parser.read(candidates)

missing  set(candidates) - set(found)

print('Found config files:', sorted(found))
print('Missing files     :', sorted(missing))

read () возвращает список, содержащий имена успешно загруженных файлов, поэтому программа может обнаружить, какие файлы конфигурации отсутствуют, и решить, игнорировать ли их или рассматривать условие как ошибку.

$ python3 configparser_read_many.py

Found config files: ['multisection.ini', 'simple.ini']
Missing files     : ['also-does-not-exist.ini',
'does_not_exist.ini']

Данные конфигурации Unicode

Файлы конфигурации, содержащие данные Unicode, следует читать с использованием правильного значения кодировки. В следующем примере файл изменяет значение пароля исходного ввода, чтобы он содержал символы Юникода и кодируется с использованием UTF-8.

unicode.ini

[bug_tracker]
url = http://localhost:8080/bugs/
username = dhellmann
password = ßéç®é†

Файл открывается с помощью соответствующего декодера, преобразующего данные UTF-8 в собственные строки Unicode.

configparser_unicode.py

from configparser import ConfigParser
import codecs

parser  ConfigParser()
# Open the file with the correct encoding
parser.read('unicode.ini', encoding'utf-8')

password  parser.get('bug_tracker', 'password')

print('Password:', password.encode('utf-8'))
print('Type    :', type(password))
print('repr()  :', repr(password))

Значение, возвращаемое функцией get () , является строкой Unicode, поэтому для ее безопасной печати ее необходимо перекодировать в UTF-8.

$ python3 configparser_unicode.py

Password: b'\xc3\x9f\xc3\xa9\xc3\xa7\xc2\xae\xc3\xa9\xe2\x80\xa0
'
Type    : 
repr()  : 'ßéç®é†'

Доступ к настройкам конфигурации

ConfigParser включает методы для изучения структуры проанализированной конфигурации, включая перечисление разделов и параметров и получение их значений. Этот файл конфигурации включает два раздела для отдельных веб-служб.

[bug_tracker]
url  http://localhost:8080/bugs/
username  dhellmann
password  SECRET

[wiki]
url  http://localhost:8080/wiki/
username  dhellmann
password  SECRET

В этом примере программы используются некоторые методы для просмотра данных конфигурации, включая section () , options () и items () .

configparser_structure.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('multisection.ini')

for section_name in parser.sections():
    print('Section:', section_name)
    print('  Options:', parser.options(section_name))
    for name, value in parser.items(section_name):
        print('  {} = {}'.format(name, value))
    print()

И section () , и options () возвращают списки строк, а items () возвращает список кортежей, содержащих пары имя-значение.

$ python3 configparser_structure.py

Section: bug_tracker
  Options: ['url', 'username', 'password']
  url = http://localhost:8080/bugs/
  username = dhellmann
  password = SECRET

Section: wiki
  Options: ['url', 'username', 'password']
  url = http://localhost:8080/wiki/
  username = dhellmann
  password = SECRET

ConfigParser также поддерживает тот же API сопоставления, что и dict , при этом ConfigParser действует как один словарь, содержащий отдельные словари для каждого раздела.

configparser_structure_dict.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('multisection.ini')

for section_name in parser:
    print('Section:', section_name)
    section  parser[section_name]
    print('  Options:', list(section.keys()))
    for name in section:
        print('  {} = {}'.format(name, section[name]))
    print()

Использование API сопоставления для доступа к одному и тому же файлу конфигурации дает тот же результат.

$ python3 configparser_structure_dict.py

Section: DEFAULT
  Options: []

Section: bug_tracker
  Options: ['url', 'username', 'password']
  url = http://localhost:8080/bugs/
  username = dhellmann
  password = SECRET

Section: wiki
  Options: ['url', 'username', 'password']
  url = http://localhost:8080/wiki/
  username = dhellmann
  password = SECRET

Проверка наличия ценностей

Чтобы проверить, существует ли раздел, используйте has_section () , передав имя раздела.

configparser_has_section.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('multisection.ini')

for candidate in ['wiki', 'bug_tracker', 'dvcs']:
    print('{:<12}: {}'.format(
        candidate, parser.has_section(candidate)))

Проверка наличия раздела перед вызовом get () позволяет избежать исключений для отсутствующих данных.

$ python3 configparser_has_section.py

wiki        : True
bug_tracker : True
dvcs        : False

Используйте has_option () , чтобы проверить, существует ли параметр в разделе.

configparser_has_option.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('multisection.ini')

SECTIONS  ['wiki', 'none']
OPTIONS  ['username', 'password', 'url', 'description']

for section in SECTIONS:
    has_section  parser.has_section(section)
    print('{} section exists: {}'.format(section, has_section))
    for candidate in OPTIONS:
        has_option  parser.has_option(section, candidate)
        print('{}.{:<12}  : {}'.format(
            section, candidate, has_option))
    print()

Если раздел не существует, has_option () возвращает False .

$ python3 configparser_has_option.py

wiki section exists: True
wiki.username      : True
wiki.password      : True
wiki.url           : True
wiki.description   : False

none section exists: False
none.username      : False
none.password      : False
none.url           : False
none.description   : False

Типы значений

Все имена разделов и параметров обрабатываются как строки, но значения параметров могут быть строками, целыми числами, числами с плавающей запятой или логическими значениями. Существует ряд возможных логических значений, которые преобразуются в истинное или ложное. В следующем примере файла есть по одному.

types.ini

[ints]
positive  1
negative  -5

[floats]
positive  0.2
negative  -3.14

[booleans]
number_true  1
number_false  0
yn_true  yes
yn_false  no
tf_true  true
tf_false  false
onoff_true  on
onoff_false  false

ConfigParser не пытается понять тип параметра. Ожидается, что приложение будет использовать правильный метод для получения значения желаемого типа. get () всегда возвращает строку. Используйте getint () для целых чисел, getfloat () для чисел с плавающей запятой и getboolean () для логических значений.

configparser_value_types.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('types.ini')

print('Integers:')
for name in parser.options('ints'):
    string_value  parser.get('ints', name)
    value  parser.getint('ints', name)
    print('  {:<12} : {!r:<7} -> {}'.format(
        name, string_value, value))

print('\nFloats:')
for name in parser.options('floats'):
    string_value  parser.get('floats', name)
    value  parser.getfloat('floats', name)
    print('  {:<12} : {!r:<7} -> {:0.2f}'.format(
        name, string_value, value))

print('\nBooleans:')
for name in parser.options('booleans'):
    string_value  parser.get('booleans', name)
    value  parser.getboolean('booleans', name)
    print('  {:<12} : {!r:<7} -> {}'.format(
        name, string_value, value))

Запуск этой программы с примером ввода дает следующий результат.

$ python3 configparser_value_types.py

Integers:
  positive     : '1'     -> 1
  negative     : '-5'    -> -5

Floats:
  positive     : '0.2'   -> 0.20
  negative     : '-3.14' -> -3.14

Booleans:
  number_true  : '1'     -> True
  number_false : '0'     -> False
  yn_true      : 'yes'   -> True
  yn_false     : 'no'    -> False
  tf_true      : 'true'  -> True
  tf_false     : 'false' -> False
  onoff_true   : 'on'    -> True
  onoff_false  : 'false' -> False

Конвертеры пользовательских типов можно добавить, передав функции преобразования в аргументе converters в ConfigParser . Каждый преобразователь получает одно входное значение и должен преобразовать это значение в соответствующий тип возврата.

configparser_custom_types.py

from configparser import ConfigParser
import datetime


def parse_iso_datetime(s):
    print('parse_iso_datetime({!r})'.format(s))
    return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')


parser  ConfigParser(
    converters{
        'datetime': parse_iso_datetime,
    }
)
parser.read('custom_types.ini')

string_value  parser['datetimes']['due_date']
value  parser.getdatetime('datetimes', 'due_date')
print('due_date : {!r} -> {!r}'.format(string_value, value))

Добавление преобразователя приводит к тому, что ConfigParser автоматически создает метод извлечения для этого типа с использованием имени типа, указанного в преобразователях . В этом примере преобразователь 'datetime' вызывает добавление нового метода getdatetime () .

$ python3 configparser_custom_types.py

parse_iso_datetime('2015-11-08T11:30:05.905898')
due_date : '2015-11-08T11:30:05.905898' -> datetime.datetime(201
5, 11, 8, 11, 30, 5, 905898)

Также возможно добавить методы конвертера непосредственно в подкласс ConfigParser .

Параметры как флаги

Обычно синтаксическому анализатору требуется явное значение для каждого параметра, но если для параметра ConfigParser allow_no_value установлено значение True , параметр может появляться сам по себе в строку во входном файле и использовать ее как флаг.

configparser_allow_no_value.py

import configparser

# Require values
try:
    parser  configparser.ConfigParser()
    parser.read('allow_no_value.ini')
except configparser.ParsingError as err:
    print('Could not parse:', err)

# Allow stand-alone option names
print('\nTrying again with)
parser  configparser.ConfigParser(allow_no_valueTrue)
parser.read('allow_no_value.ini')
for flag in ['turn_feature_on', 'turn_other_feature_on']:
    print('\n', flag)
    exists  parser.has_option('flags', flag)
    print('  has_option:', exists)
    if exists:
        print('         get:', parser.get('flags', flag))

Если параметр не имеет явного значения, has_option () сообщает, что параметр существует, а get () возвращает None .

$ python3 configparser_allow_no_value.py

Could not parse: Source contains parsing errors:
'allow_no_value.ini'
        [line  2]: 'turn_feature_on\n'

Trying again with

 turn_feature_on
  has_option: True
         get: None

 turn_other_feature_on
  has_option: False

Многострочные струны

Строковые значения могут занимать несколько строк, если последующие строки имеют отступ.

[example]
message  This is a multi-line string.
  With two paragraphs.

  They are separated by a completely empty line.

В многострочных значениях с отступом пустые строки рассматриваются как часть значения и сохраняются.

$ python3 configparser_multiline.py

This is a multi-line string.
With two paragraphs.

They are separated by a completely empty line.

Изменение настроек

Хотя ConfigParser в первую очередь предназначен для настройки путем чтения параметров из файлов, параметры также можно заполнить, вызвав add_section () для создания нового раздела и set ( ) , чтобы добавить или изменить параметр.

configparser_populate.py

import configparser

parser  configparser.ConfigParser()

parser.add_section('bug_tracker')
parser.set('bug_tracker', 'url', 'http://localhost:8080/bugs')
parser.set('bug_tracker', 'username', 'dhellmann')
parser.set('bug_tracker', 'password', 'secret')

for section in parser.sections():
    print(section)
    for name, value in parser.items(section):
        print('  {} = {!r}'.format(name, value))

Все параметры должны быть заданы как строки, даже если они будут извлечены как целые числа, значения с плавающей запятой или логические значения.

$ python3 configparser_populate.py

bug_tracker
  url = 'http://localhost:8080/bugs'
  username = 'dhellmann'
  password = 'secret'

Разделы и параметры можно удалить из ConfigParser с помощью remove_section () и remove_option () .

configparser_remove.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('multisection.ini')

print('Read values:\n')
for section in parser.sections():
    print(section)
    for name, value in parser.items(section):
        print('  {} = {!r}'.format(name, value))

parser.remove_option('bug_tracker', 'password')
parser.remove_section('wiki')

print('\nModified values:\n')
for section in parser.sections():
    print(section)
    for name, value in parser.items(section):
        print('  {} = {!r}'.format(name, value))

При удалении раздела удаляются все содержащиеся в нем параметры.

$ python3 configparser_remove.py

Read values:

bug_tracker
  url = 'http://localhost:8080/bugs/'
  username = 'dhellmann'
  password = 'SECRET'
wiki
  url = 'http://localhost:8080/wiki/'
  username = 'dhellmann'
  password = 'SECRET'

Modified values:

bug_tracker
  url = 'http://localhost:8080/bugs/'
  username = 'dhellmann'

Сохранение файлов конфигурации

После заполнения ConfigParser необходимыми данными его можно сохранить в файл, вызвав метод write () . Это позволяет предоставить пользовательский интерфейс для редактирования параметров конфигурации без необходимости писать какой-либо код для управления файлом.

configparser_write.py

import configparser
import sys

parser  configparser.ConfigParser()

parser.add_section('bug_tracker')
parser.set('bug_tracker', 'url', 'http://localhost:8080/bugs')
parser.set('bug_tracker', 'username', 'dhellmann')
parser.set('bug_tracker', 'password', 'secret')

parser.write(sys.stdout)

Метод write () принимает в качестве аргумента файловый объект. Он записывает данные в формате INI, чтобы их можно было снова проанализировать с помощью ConfigParser .

$ python3 configparser_write.py

[bug_tracker]
url = http://localhost:8080/bugs
username = dhellmann
password = secret

Предупреждение

Комментарии в исходном файле конфигурации не сохраняются при чтении, изменении и перезаписи файла конфигурации.

Путь поиска вариантов

ConfigParser использует многоэтапный процесс поиска при поиске варианта.

Перед запуском поиска опции проверяется название раздела. Если раздел не существует и имя не является специальным значением DEFAULT , возникает ошибка NoSectionError .

  1. Е
  2. с
  3. л
  4. и
  5. и
  6. м
  7. я
  8. п
  9. а
  10. р
  11. а
  12. м
  13. е
  14. т
  15. р
  16. а
  17. п
  18. о
  19. я
  20. в
  21. л
  22. я
  23. е
  24. т
  25. с
  26. я
  27. в
  28. с
  29. л
  30. о
  31. в
  32. а
  33. р
  34. е
  35. <
  36. c
  37. o
  38. d
  39. e
  40. >
  41. v
  42. a
  43. r
  44. s
  45. <
  46. /
  47. c
  48. o
  49. d
  50. e
  51. >
  52. ,
  53. п
  54. е
  55. р
  56. е
  57. д
  58. а
  59. н
  60. н
  61. о
  62. м
  63. в
  64. <
  65. c
  66. o
  67. d
  68. e
  69. >
  70. g
  71. e
  72. t
  73. (
  74. )
  75. <
  76. /
  77. c
  78. o
  79. d
  80. e
  81. >
  82. ,
  83. в
  84. о
  85. з
  86. в
  87. р
  88. а
  89. щ
  90. а
  91. е
  92. т
  93. с
  94. я
  95. з
  96. н
  97. а
  98. ч
  99. е
  100. н
  101. и
  102. е
  103. и
  104. з
  105. <
  106. c
  107. o
  108. d
  109. e
  110. >
  111. v
  112. a
  113. r
  114. s
  115. <
  116. /
  117. c
  118. o
  119. d
  120. e
  121. >
  122. .
  123. Е
  124. с
  125. л
  126. и
  127. и
  128. м
  129. я
  130. п
  131. а
  132. р
  133. а
  134. м
  135. е
  136. т
  137. р
  138. а
  139. п
  140. о
  141. я
  142. в
  143. л
  144. я
  145. е
  146. т
  147. с
  148. я
  149. в
  150. у
  151. к
  152. а
  153. з
  154. а
  155. н
  156. н
  157. о
  158. м
  159. р
  160. а
  161. з
  162. д
  163. е
  164. л
  165. е
  166. ,
  167. в
  168. о
  169. з
  170. в
  171. р
  172. а
  173. щ
  174. а
  175. е
  176. т
  177. с
  178. я
  179. з
  180. н
  181. а
  182. ч
  183. е
  184. н
  185. и
  186. е
  187. и
  188. з
  189. э
  190. т
  191. о
  192. г
  193. о
  194. р
  195. а
  196. з
  197. д
  198. е
  199. л
  200. а
  201. .
  202. Е
  203. с
  204. л
  205. и
  206. и
  207. м
  208. я
  209. п
  210. а
  211. р
  212. а
  213. м
  214. е
  215. т
  216. р
  217. а
  218. о
  219. т
  220. о
  221. б
  222. р
  223. а
  224. ж
  225. а
  226. е
  227. т
  228. с
  229. я
  230. в
  231. р
  232. а
  233. з
  234. д
  235. е
  236. л
  237. е
  238. <
  239. c
  240. o
  241. d
  242. e
  243. >
  244. D
  245. E
  246. F
  247. A
  248. U
  249. L
  250. T
  251. <
  252. /
  253. c
  254. o
  255. d
  256. e
  257. >
  258. ,
  259. в
  260. о
  261. з
  262. в
  263. р
  264. а
  265. щ
  266. а
  267. е
  268. т
  269. с
  270. я
  271. э
  272. т
  273. о
  274. з
  275. н
  276. а
  277. ч
  278. е
  279. н
  280. и
  281. е
  282. .
  283. Е
  284. с
  285. л
  286. и
  287. и
  288. м
  289. я
  290. п
  291. а
  292. р
  293. а
  294. м
  295. е
  296. т
  297. р
  298. а
  299. о
  300. т
  301. о
  302. б
  303. р
  304. а
  305. ж
  306. а
  307. е
  308. т
  309. с
  310. я
  311. в
  312. с
  313. л
  314. о
  315. в
  316. а
  317. р
  318. е
  319. <
  320. c
  321. o
  322. d
  323. e
  324. >
  325. d
  326. e
  327. f
  328. a
  329. u
  330. l
  331. t
  332. s
  333. <
  334. /
  335. c
  336. o
  337. d
  338. e
  339. >
  340. ,
  341. п
  342. е
  343. р
  344. е
  345. д
  346. а
  347. н
  348. н
  349. о
  350. м
  351. к
  352. о
  353. н
  354. с
  355. т
  356. р
  357. у
  358. к
  359. т
  360. о
  361. р
  362. у
  363. ,
  364. в
  365. о
  366. з
  367. в
  368. р
  369. а
  370. щ
  371. а
  372. е
  373. т
  374. с
  375. я
  376. э
  377. т
  378. о
  379. з
  380. н
  381. а
  382. ч
  383. е
  384. н
  385. и
  386. е
  387. .

Если имя не найдено ни в одном из этих расположений, возникает ошибка NoOptionError .

С помощью этого файла конфигурации можно продемонстрировать поведение пути поиска.

[DEFAULT]
file-only  value from DEFAULT section
init-and-file  value from DEFAULT section
from-section  value from DEFAULT section
from-vars  value from DEFAULT section

[sect]
section-only  value from section in file
from-section  value from section in file
from-vars  value from section in file

Эта тестовая программа включает настройки по умолчанию для параметров, не указанных в файле конфигурации, и отменяет некоторые значения, определенные в файле.

configparser_defaults.py

import configparser

# Define the names of the options
option_names  [
    'from-default',
    'from-section', 'section-only',
    'file-only', 'init-only', 'init-and-file',
    'from-vars',
]

# Initialize the parser with some defaults
DEFAULTS  {
    'from-default': 'value from defaults passed to init',
    'init-only': 'value from defaults passed to init',
    'init-and-file': 'value from defaults passed to init',
    'from-section': 'value from defaults passed to init',
    'from-vars': 'value from defaults passed to init',
}
parser  configparser.ConfigParser(defaultsDEFAULTS)

print('Defaults before loading file:')
defaults  parser.defaults()
for name in option_names:
    if name in defaults:
        print('  {:<15} = {!r}'.format(name, defaults[name]))

# Load the configuration file
parser.read('with-defaults.ini')

print('\nDefaults after loading file:')
defaults  parser.defaults()
for name in option_names:
    if name in defaults:
        print('  {:<15} = {!r}'.format(name, defaults[name]))

# Define some local overrides
vars  {'from-vars': 'value from vars'}

# Show the values of all the options
print('\nOption lookup:')
for name in option_names:
    value  parser.get('sect', name, varsvars)
    print('  {:<15} = {!r}'.format(name, value))

# Show error messages for options that do not exist
print('\nError cases:')
try:
    print('No such option :', parser.get('sect', 'no-option'))
except configparser.NoOptionError as err:
    print(err)

try:
    print('No such section:', parser.get('no-sect', 'no-option'))
except configparser.NoSectionError as err:
    print(err)

В выходных данных показано происхождение значения каждой опции и показано, как значения по умолчанию из разных источников переопределяют существующие значения.

$ python3 configparser_defaults.py

Defaults before loading file:
  from-default    = 'value from defaults passed to init'
  from-section    = 'value from defaults passed to init'
  init-only       = 'value from defaults passed to init'
  init-and-file   = 'value from defaults passed to init'
  from-vars       = 'value from defaults passed to init'

Defaults after loading file:
  from-default    = 'value from defaults passed to init'
  from-section    = 'value from DEFAULT section'
  file-only       = 'value from DEFAULT section'
  init-only       = 'value from defaults passed to init'
  init-and-file   = 'value from DEFAULT section'
  from-vars       = 'value from DEFAULT section'

Option lookup:
  from-default    = 'value from defaults passed to init'
  from-section    = 'value from section in file'
  section-only    = 'value from section in file'
  file-only       = 'value from DEFAULT section'
  init-only       = 'value from defaults passed to init'
  init-and-file   = 'value from DEFAULT section'
  from-vars       = 'value from vars'

Error cases:
No option 'no-option' in section: 'sect'
No section: 'no-sect'

Комбинирование значений с интерполяцией

ConfigParser предоставляет функцию, называемую интерполяцией , которую можно использовать для объединения значений вместе. Значения, содержащие строки стандартного формата Python, запускают функцию интерполяции при их извлечении. Параметры, названные в пределах извлекаемого значения, по очереди заменяются своими значениями до тех пор, пока подстановка не отпадет.

Примеры URL, приведенные ранее в этом разделе, можно переписать, чтобы использовать интерполяцию, чтобы упростить изменение только части значения. Например, этот файл конфигурации отделяет протокол, имя хоста и порт от URL-адреса как отдельные параметры.

[bug_tracker]
protocol  http
server  localhost
port  8080
url  %(protocol)s://%(server)s:%(port)s/bugs/
username  dhellmann
password  SECRET

По умолчанию интерполяция выполняется каждый раз при вызове get () . Передайте истинное значение в аргументе raw , чтобы получить исходное значение без интерполяции.

configparser_interpolation.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('interpolation.ini')

print('Original value       :', parser.get('bug_tracker', 'url'))

parser.set('bug_tracker', 'port', '9090')
print('Altered port value   :', parser.get('bug_tracker', 'url'))

print('Without interpolation:', parser.get('bug_tracker', 'url',
                                           rawTrue))

Поскольку значение вычисляется с помощью get () , изменение одной из настроек, используемых значением url , изменяет возвращаемое значение.

$ python3 configparser_interpolation.py

Original value       : http://localhost:8080/bugs/
Altered port value   : http://localhost:9090/bugs/
Without interpolation: %(protocol)s://%(server)s:%(port)s/bugs/

Использование значений по умолчанию

Значения для интерполяции не обязательно должны появляться в том же разделе, что и исходный вариант. Значения по умолчанию можно смешивать со значениями переопределения.

[DEFAULT]
url  %(protocol)s://%(server)s:%(port)s/bugs/
protocol  http
server  bugs.example.com
port  80

[bug_tracker]
server  localhost
port  8080
username  dhellmann
password  SECRET

В этой конфигурации значение для url поступает из раздела DEFAULT , и подстановка начинается с просмотра bug_tracker и возврата к ПО УМОЛЧАНИЮ для частей, которые не найдены.

configparser_interpolation_defaults.py

from configparser import ConfigParser

parser  ConfigParser()
parser.read('interpolation_defaults.ini')

print('URL:', parser.get('bug_tracker', 'url'))

Значения hostname и port взяты из раздела bug_tracker , а protocol – из DEFAULT .

$ python3 configparser_interpolation_defaults.py

URL: http://localhost:8080/bugs/

Ошибки замены

Замена прекращается после шагов MAX_INTERPOLATION_DEPTH , чтобы избежать проблем из-за рекурсивных ссылок.

configparser_interpolation_recursion.py

import configparser

parser  configparser.ConfigParser()

parser.add_section('sect')
parser.set('sect', 'opt', '%(opt)s')

try:
    print(parser.get('sect', 'opt'))
except configparser.InterpolationDepthError as err:
    print('ERROR:', err)

Исключение InterpolationDepthError возникает, если шагов подстановки слишком много.

$ python3 configparser_interpolation_recursion.py

ERROR: Recursion limit exceeded in value substitution: option 'o
pt' in section 'sect' contains an interpolation key which cannot
 be substituted in 10 steps. Raw value: '%(opt)s'

Отсутствующие значения приводят к исключению InterpolationMissingOptionError .

configparser_interpolation_error.py

import configparser

parser  configparser.ConfigParser()

parser.add_section('bug_tracker')
parser.set('bug_tracker', 'url',
           'http://%(server)s:%(port)s/bugs')

try:
    print(parser.get('bug_tracker', 'url'))
except configparser.InterpolationMissingOptionError as err:
    print('ERROR:', err)

Поскольку значение server не определено, url не может быть создан.

$ python3 configparser_interpolation_error.py

ERROR: Bad value substitution: option 'url' in section
'bug_tracker' contains an interpolation key 'server' which is
not a valid option name. Raw value:
'http://%(server)s:%(port)s/bugs'

Экранирование специальных символов

Поскольку % запускает инструкции интерполяции, буквальный % в значении должен быть экранирован как %% .

[escape]
value  a literal %% must be escaped

Считывание значения не требует особого внимания.

configparser_escape.py

from configparser import ConfigParser
import os

filename  'escape.ini'
config  ConfigParser()
config.read([filename])

value  config.get('escape', 'value')

print(value)

Когда значение считывается, %% автоматически преобразуется в % .

$ python3 configparser_escape.py

a literal % must be escaped

Расширенная интерполяция

ConfigParser поддерживает альтернативные реализации интерполяции. Передача объекта, который поддерживает API, определенный параметром Interpolation , в параметр interpolation . Например, использование ExtendedInterpolation вместо BasicInterpolation по умолчанию позволяет использовать другой синтаксис с использованием $ {} для указания переменных.

configparser_extendedinterpolation.py

from configparser import ConfigParser, ExtendedInterpolation

parser  ConfigParser(interpolationExtendedInterpolation())
parser.read('extended_interpolation.ini')

print('Original value       :', parser.get('bug_tracker', 'url'))

parser.set('intranet', 'port', '9090')
print('Altered port value   :', parser.get('bug_tracker', 'url'))

print('Without interpolation:', parser.get('bug_tracker', 'url',
                                           rawTrue))

Расширенная интерполяция поддерживает доступ к значениям из других разделов файла конфигурации путем добавления к имени переменной префикса имени раздела и двоеточия (: ).

[intranet]
server = localhost
port = 8080

[bug_tracker]
url = http://${intranet:server}:${intranet:port}/bugs/
username = dhellmann
password = SECRET

Обращение к значениям в других разделах файла позволяет совместно использовать иерархию значений, не помещая все значения по умолчанию в раздел DEFAULTS .

$ python3 configparser_extendedinterpolation.py

Original value       : http://localhost:8080/bugs/
Altered port value   : http://localhost:9090/bugs/
Without interpolation: http://${intranet:server}:${intranet:port
}/bugs/

Отключение интерполяции

Чтобы отключить интерполяцию, передайте None вместо объекта Interpolation .

configparser_nointerpolation.py

from configparser import ConfigParser

parser  ConfigParser(interpolationNone)
parser.read('interpolation.ini')

print('Without interpolation:', parser.get('bug_tracker', 'url'))

Это позволяет безопасно игнорировать любой синтаксис, который мог быть обработан объектом интерполяции.

$ python3 configparser_nointerpolation.py

Without interpolation: %(protocol)s://%(server)s:%(port)s/bugs/

Смотрите также