configparser - Lavora con i File di Configurazione
Scopo: Leggere/scrivere file di configurazione simili ai file INI di Windows
Il modulo configparser si usa per gestire dei file di configurazione per un'applicazione che siano modificabili dall'utente. Il contenuto dei file di configurazione può essere organizzato in gruppi, e sono supportate parecchie opzioni di tipi di valore, inclusi interi, valori a virgola mobile e booleani. I valori delle opzioni possono essere combinati usando le stringhe di formattazione di Python, per costruire valori più grandi tipo URL da parti degli stessi tipo nomi host e numeri di porte.
Formato del File di Configurazione
Il formato di file usato da configparser è simile a quello usato dalle vecchie versioni di Microsoft Windows. Consiste in una o più sezioni nominative, ognuna delle quali può contenere opzioni individuali con nomi e valori.
Le sezioni del file di configurazione sono identificate cercando delle righe che iniziano con [
e finiscono con ]
. Il valore racchiuso tra le parentesi quadre è il nome della sezione, e può contenere qualsiasi carattere ad eccezione delle parentesi quadre.
Le opzioni sono elencate una per riga all'interno di una sezione. La riga inizia con il nome dell'opzione, la quale è separata dal valore dai due punti (:
) oppure dall'uguale (=
). I caratteri whitespace (spazi, tabulazioni ecc.) attorno al separatore vengono ignorati mentre il file viene elaborato.
Il seguente è un file di configurazione di esempio con una sezione chiamata bug_tracker
, con tre opzioni: url
, username
e password
.
# Questo è un semplice esempio con commenti [bug_tracker] url = http://localhost:8080/bugs/ username = dhellmann ; Non si dovrebbero memorizzare password in chiaro nei file ; di configurazione. password = SEGRETO
Leggere i File di Configurazione
L'uso più comune per un file di configurazione è quello di avere un utente od un amministratore di sistema che lo modifichi con un normale editor di testi per impostare i comportamenti predefiniti dell'applicazione, quindi il file vien fatto leggere dall'applicazione, che lo elabora ed agisce in base al suo contenuto. Per leggere il file di configurazione si usi il metodo read()
di ConfigParser
.
# configparser_read.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('semplice.ini')
print(parser.get('bug_tracker', 'url'))
Il programma legge il file simple.ini
visto qui sopra e stampa il valore dell'opzione url
dalla sezione bug_tracker
.
$ python3 configparser_read.py http://localhost:8080/bugs/
Il metodo read()
accetta anche un elenco di nomi di file. Ciascun nome viene scorso a turno, e se il file esiste viene aperto e letto.
# configparser_read_many.py
from configparser import ConfigParser
import glob
parser = ConfigParser()
candidates = ['non_esiste.ini', 'anche_questo_non_esiste.ini',
'semplice.ini', 'multisezione.ini']
found = parser.read(candidates)
missing = set(candidates) - set(found)
print('File configurazione trovati:', sorted(found))
print('File mancanti :', sorted(missing))
read()
restituisce un elenco che contiene i nomi dei file caricati con successo, in modo che il programma possa scoprire quali file di configurazione sono mancanti e decidere se ignorarli oppure se trattare questa condizione come un errore.
$ python3 configparser_read_many.py File configurazione trovati: ['multisezione.ini', 'semplice.ini'] File mancanti : ['anche_questo_non_esiste.ini', 'non_esiste.ini']
Dati Unicode in Configurazione
I file di configurazione che contengono dati Unicode dovrebbero essere letti usando il valore di codifica appropriato. Nel file di esempio seguente è stato modificato il valore della password originale inserendovi caratteri Unicode, poi il file è stato codificato usando UTF-8.
# unicode.ini [bug_tracker] url = http://localhost:8080/bugs/ username = dhellmann password = ßéç®é†
Il file viene aperto con il decodificatore appropriato, convertendo i dati UTF-8 nelle stringhe Unicode native.
# configparser_unicode.py
from configparser import ConfigParser
parser = ConfigParser()
# Apertura del file con la codifica corretta
parser.read('unicode.ini', encoding='utf-8')
password = parser.get('bug_tracker', 'password')
print('Password:', password.encode('utf-8'))
print('Tipe :', type(password))
print('repr() :', repr(password))
Il valore restituito da get()
è una stringa Unicode
, quindi per stamparlo in sicurezza deve essere ricodificato come UTF-8.
$ python3 configparser_unicode.py Password: b'\xc3\x9f\xc3\xa9\xc3\xa7\xc2\xae\xc3\xa9\xe2\x80\xa0' Tipo : <class 'str'> repr() : 'ßéç®é†'
Accedere alle Impostazioni di Configurazione
ConfigParser
comprende metodi per esaminare la struttura della configurazione elaborata, compreso l'elenco delle sezioni ed opzioni, ed il recupero dei loro valori. Questo file di configurazione include due sezioni per servizi web separati.
[bug_tracker] url = http://localhost:8080/bugs/ username = dhellmann password = SECRET [wiki] url = http://localhost:8080/wiki/ username = dhellmann password = SECRET
Questo semplice programma applica alcuni dei metodi per cercare i dati di configurazione, inclusi sections()
, options()
ed items()
.
# configparser_structure.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('multisezione.ini')
for section_name in parser.sections():
print('Sezione:', section_name)
print(' Opzioni:', parser.options(section_name))
for name, value in parser.items(section_name):
print(' {} = {}'.format(name, value))
print()
Sia sections()
che options()
ritornano liste di stringhe, mentre items()
ritorna una lista di tuple che contengono coppie di nomi-valori.
$ python3 configparser_structure.py Sezione: bug_tracker Opzioni: ['url', 'username', 'password'] url = http://localhost:8080/bugs/ username = dhellmann password = SECRET Sezione: wiki Opzioni: ['url', 'username', 'password'] url = http://localhost:8080/wiki/ username = dhellmann password = SECRET
ConfigParser
supporta anche la stessa API di mappatura dei dizionari, ConfigParser
funge infatti da dizionario che contiene dizionari separati per ogni sezione.
# configparser_structure_dict.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('multisezione.ini')
for section_name in parser:
print('Sezione:', section_name)
section = parser[section_name]
print(' Opzioni:', list(section.keys()))
for name in section:
print(' {} = {}'.format(name, section[name]))
print()
Usando l'API di mappatura per accedere allo stesso file di configurazione si ottiene lo stesso output.
$ python3 configparser_structure_dict.py Sezione: DEFAULT Opzioni: [] Sezione: bug_tracker Opzioni: ['url', 'username', 'password'] url = http://localhost:8080/bugs/ username = dhellmann password = SECRET Sezione: wiki Opzioni: ['url', 'username', 'password'] url = http://localhost:8080/wiki/ username = dhellmann password = SECRET
Verificare Se Sono Presenti Valori
Per verificare se una sezione esiste, si usi has_section()
passando il nome della sezione.
# configparser_has_section.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('multisezione.ini')
for candidate in ['wiki', 'bug_tracker', 'dvcs']:
print('{:<12}: {}'.format(
candidate, parser.has_section(candidate)))
Se si verifica se una sezione esiste prima di chiamare get()
si evitano le eccezioni per dati mancanti.
$ python3 configparser_has_section.py wiki : True bug_tracker : True dvcs : False
Si usi has_option()
per verificare se una opzione esiste all'interno di una sezione.
# configparser_has_option.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('multisezione.ini')
SECTIONS = ['wiki', 'none']
OPTIONS = ['username', 'password', 'url', 'descrizione']
for section in SECTIONS:
has_section = parser.has_section(section)
print('{} sezione esiste: {}'.format(section, has_section))
for candidate in OPTIONS:
has_option = parser.has_option(section, candidate)
print('{}.{:<12} : {}'.format(
section, candidate, has_option))
print()
Se la sezione non esiste, has_section()
ritorna False
.
$ python3 configparser_has_option.py wiki sezione esiste: True wiki.username : True wiki.password : True wiki.url : True wiki.descrizione : False none sezione esiste: False none.username : False none.password : False none.url : False none.descrizione : False
Tipi di Valore
Tutti i nomi di sezione ed opzione sono trattati come stringhe, ma i valori delle opzioni possono essere stringhe, interi, valori a virgola mobile, booleani. Vi è un intervallo di possibili valori booleani che possono essere convertiti a vero o falso. Il file di esempio seguente ne include uno per tipo.
# types.ini [interi] positive = 1 negative = -5 [virgola mobile] positive = 0.2 negative = -3.14 [booleani] 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
non effettua alcun tentativo di comprendere il tipo dell'opzione. Spetta all'applicazione di utilizzare il metodo corretto per recuperare il valore nel tipo desiderato. get()
ritorna sempre una stringa. Si usi getint()
per gli interi, getfloat()
per i valori a virgola mobile e getboolean()
per i valori booleani.
# configparser_value_types.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('tipi.ini')
print('Interi:')
for name in parser.options('interi'):
string_value = parser.get('interi', name)
value = parser.getint('interi', name)
print(' {:<12} : {!r:<7} -> {}'.format(
name, string_value, value))
print('\nVirgola Mobile:')
for name in parser.options('virgola_mobile'):
string_value = parser.get('virgola_mobile', name)
value = parser.getfloat('virgola_mobile', name)
print(' {:<12} : {!r:<7} -> {:0.2f}'.format(
name, string_value, value))
print('\nBooleani:')
for name in parser.options('booleani'):
string_value = parser.get('booleani', name)
value = parser.getboolean('booleani', name)
print(' {:<12} : {!r:<7} -> {}'.format(
name, string_value, value))
L'esecuzione di questo programma con l'input di esempio produce il seguente risultato.
$ python3 configparser_value_types.py Interi: positivo : '1' -> 1 negativo : '-5' -> -5 Virgola Mobile: positivo : '0.2' -> 0.20 negativo : '-3.14' -> -3.14 Booleani: numero_vero : '1' -> True numero_falso : '0' -> False sino_vero : 'yes' -> True sino_false : 'no' -> False verofalso_vero : 'true' -> True verofalso_false : 'false' -> False accesospento_vero : 'on' -> True accesospento_false : 'false' -> False
E' possibile aggiungere convertitori di tipo personalizzati passando le funzioni di conversione tramite l'argomento converters
di ConfigParser
. Ogni convertitore riceve un singolo valore in input e dovrebbe trasformare quel valore nell'appropriato tipo di valore da ritornare.
# 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('tipi_personalizzati.ini')
string_value = parser['dataora']['data_scadenza']
value = parser.getdatetime('dataora', 'data_scadenza')
print('data_scadenza : {!r} -> {!r}'.format(string_value, value))
L'aggiunta di un convertitore fa sì che ConfigParser
crei automaticamente un metodo per quel tipo, usando il nome del tipo come specificato in converters
. In questo esempio il convertitore 'datetime'
provoca l'aggiunta di un nuovo metodo getdatetime()
.
$ python3 configparser_custom_types.py parse_iso_datetime('2015-11-08T11:30:05.905898') data_scadenza : '2015-11-08T11:30:05.905898' -> datetime.datetime(2015, 11, 8, 11, 30, 5, 905898)
E' anche possibile aggiungere metodi di conversione direttamente ad una sottoclasse di ConfigParser
.
Opzioni com Flag
In genere il parser richiede un valore esplicito per ogni opzione, tuttavia impostando il parametro dell'argomento allow_no_value
a True
di ConfigParser
una opzione può presentarsi a se stante in una riga nel file di configurazione ed essere usata come flag.
# configparser_allow_no_value.py
import configparser
# Richiede valori
try:
parser = configparser.ConfigParser()
parser.read('consenti_no_valori.ini')
except configparser.ParsingError as err:
print('Non posso elaborare:', err)
# Consente nomi di opzioni a se stanti
print('\nRiprovo con allow_no_value=True')
parser = configparser.ConfigParser(allow_no_value=True)
parser.read('consenti_no_valori.ini')
for flag in ['abilita_caratteristica_attivata',
'abilita_altra_caratteristica_attivata']:
print('\n', flag)
exists = parser.has_option('flags', flag)
print(' has_option:', exists)
if exists:
print(' get:', parser.get('flags', flag))
Quando una opzione non ha uno specifico valore, has_option()
riporta che l'opzione esiste e get()
ritorna None
.
$ python3 configparser_allow_no_value.py Non posso elaborare: Source contains parsing errors: 'consenti_no_valori.ini' [line 4]: 'abilita_caratteristica_attivata\n' Riprovo con allow_no_value=True abilita_caratteristica_attivata has_option: True get: None abilita_altra_caratteristica_attivata has_option: False
Stringhe Multiriga
I valori stringa possono essere espressi su più righe, se le righe sottostanti sono indentate.
# multiriga.ini [esempio] messaggio = Questa è una stringa multiriga. Con due paragrafi. Essi sono separati da una riga vuota.
# configparser_multiline.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('multiriga.ini')
print(parser.get('esempio', 'messaggio'))
All'interno di valori multiriga indentati, la righe vuote sono trattate come parte del valore e preservate.
$ python3 configparser_multiline.py Questa è una stringa multiriga. Con due paragrafi. Essi sono separati da una riga vuota.
Modificare le Impostazioni
Sebbene ConfigParser
sia principalmente concepito per la lettura di impostazioni da file, è anche possibile popolare le impostazioni chiamando add_section()
per creare una nuova sezione, e set()
per aggiungere o modificare un'opzione.
# configparser_populate.py
import configparser
parser = configparser.SafeConfigParser()
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))
Tutte le opzioni devono essere impostate come stringhe, anche se poi saranno recuperate come interi, valori a virgola mobile o booleani.
$ python3 configparser_populate.py bug_tracker url = 'http://localhost:8080/bugs' username = 'dhellmann' password = 'secret'
Sezioni ed opzioni possono essere rimosse da un oggetto ConfigParser
rispettivamente con remove_section()
e remove_option()
.
# configparser_remove.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('multisezione.ini')
print('Lettura valori:\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('\nModifica valori:\n')
for section in parser.sections():
print(section)
for name, value in parser.items(section):
print(' {} = {!r}'.format(name, value))
La rimozione di una sezione comporta l'eliminazione di tutte le opzioni in essa contenute.
$ python3 configparser_remove.py Lettura valori: bug_tracker url = 'http://localhost:8080/bugs/' username = 'dhellmann' password = 'SECRET' wiki url = 'http://localhost:8080/wiki/' username = 'dhellmann' password = 'SECRET' Modifica valori: bug_tracker url = 'http://localhost:8080/bugs/' username = 'dhellmann'
Salvare File di Configurazione
Una volta che ConfigParser
è stato popolato con i dati desiderati, può essere salvato ad un file chiamando il metodo write()
. Questo rende possibile fornire una interfaccia utente per la modifica delle impostazioni di configurazione, senza dover scrivere altro codice per gestire il file.
# 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)
Il metodo write()
riceve un oggetto di tipo file come argomento. Scrive i dati nel formato INI in modo che possano essere nuovamente elaborati da ConfigParser
.
$ python3 configparser_write.py [bug_tracker] url = http://localhost:8080/bugs username = dhellmann password = secret
Percorso per la Ricerca delle Opzioni
ConfigParser
usa un processo di ricerca a fasi multiple quando cerca una opzione.
Prima di iniziare la ricerca di una opzione, viene verificato il nome della sezione. Se la sezione non esiste, ed il nome non è il valore speciale DEFAULT
, viene sollevata l'eccezione NoSectionError
.
- Se il nome opzione appare nel dizionario
vars
passato aget()
, viene ritornato il valore davars
. - Se il nome opzione appare nella sezione specificata, viene ritornato il valore da quella sezione.
- Se il nome opzione appare nella sezione
DEFAULT
viene ritornato quel valore. - Se il nome opzione appare nel dizionario
defaults
passato al costruttore, viene ritornato quel valore.
Se il nome non viene trovato in alcuna delle locazioni sopra citate, viene sollevata una eccezione NoOptionError
.
Il comportamento del percorso di ricerca può essere verificato usando questo file di configurazione.
# with-defaults.ini [DEFAULT] file-only = valore dalla sezione DEFAULT init-and-file = valore dalla sezione DEFAULT from-section = valore dalla sezione DEFAULT from-vars = valore dalla sezione DEFAULT [sect] section-only = valore dalla sezione nel file from-section = valore dalla sezione nel file from-vars = valore dalla sezione nel file
Il programma di esempio include impostazioni predefinite per le opzioni non specificate nel file di configurazione, e sovrascrive alcuni valori che sono definiti nel file.
# configparser_defaults.py
import configparser
# Definisce i nomi delle opzioni
option_names = [
'from-default',
'from-section', 'section-only',
'file-only', 'init-only', 'init-and-file',
'from-vars',
]
# Inizializza il parser con qualche valore di default
DEFAULTS = {
'from-default': 'valore da DEFAULTS passato ad init',
'init-only': 'valore da DEFAULTS passato ad init',
'init-and-file': 'valore da DEFAULTS passato ad init',
'from-section': 'valore da DEFAULTS passato ad init',
'from-vars': 'valore da DEFAULTS passato ad init',
}
parser = configparser.ConfigParser(defaults=DEFAULTS)
print('Default prima di caricare il file:')
defaults = parser.defaults()
for name in option_names:
if name in defaults:
print(' {:<15} = {!r}'.format(name, defaults[name]))
# Carica il file di configurazione
parser.read('with-defaults.ini')
print('\nDefault dopo il caricamento del file:')
defaults = parser.defaults()
for name in option_names:
if name in defaults:
print(' {:<15} = {!r}'.format(name, defaults[name]))
# Definisce alcuni valori locali da sovrascriver
vars = {'from-vars': 'valori da vars'}
# Mostra i valori di tutte le opzioni
print('\nRicerca opzioni:')
for name in option_names:
value = parser.get('sect', name, vars=vars)
print(' {:<15} = {!r}'.format(name, value))
# Mostra messaggi di errore per opzioni che non esistono
print('\nCasi di errore:')
try:
print('Opzione non esiste :', parser.get('sect', 'no-option'))
except configparser.NoOptionError as err:
print(err)
try:
print('Sezione non esiste:', parser.get('no-sect', 'no-option'))
except configparser.NoSectionError as err:
print(err)
Il risultato mostra le origini del valore per ciascuna opzione ed illustra il modo nel quale impostazioni predefinite da sorgenti diverse sovrascrivano valori esistenti.
$ python3 configparser_defaults.py Default prima di caricare il file: from-default = 'valore da DEFAULTS passato ad init' from-section = 'valore da DEFAULTS passato ad init' init-only = 'valore da DEFAULTS passato ad init' init-and-file = 'valore da DEFAULTS passato ad init' from-vars = 'valore da DEFAULTS passato ad init' Default dopo il caricamento del file: from-default = 'valore da DEFAULTS passato ad init' from-section = 'valore dalla sezione DEFAULT' file-only = 'valore dalla sezione DEFAULT' init-only = 'valore da DEFAULTS passato ad init' init-and-file = 'valore dalla sezione DEFAULT' from-vars = 'valore dalla sezione DEFAULT' Ricerca opzioni: from-default = 'valore da DEFAULTS passato ad init' from-section = 'valore dalla sezione nel file' section-only = 'valore dalla sezione nel file' file-only = 'valore dalla sezione DEFAULT' init-only = 'valore da DEFAULTS passato ad init' init-and-file = 'valore dalla sezione DEFAULT' from-vars = 'valori da vars' Casi di errore: No option 'no-option' in section: 'sect' No section: 'no-sect'
Combinare Valori con Interpolazione
ConfigParser
fornisce una caratteristica chiamata interpolazione che può essere usata per combinare valori insieme. Valori che contengono stringhe di formattazione standard Python attivano l'interpolazione quando sono recuperati. Nomi di opzione espressi all'interno del valore che si sta acquisendo sono sostituiti con i loro valori, uno per uno, fino a che non sono più necessarie altre sostituzioni.
Gli esempi di URL dal file INI mostrati in precedenza possono essere riscritti usando l'interpolazione in modo che sia più facile modificarne solo una parte del valore. Ad esempio, in questo file di configurazione il protocollo, il nome host e la porta di un URL vengono espressi come opzioni separate.
# interpolazione.ini [bug_tracker] protocol = http server = localhost port = 8080 url = %(protocol)s://%(server)s:%(port)s/bugs/ username = dhellmann password = SECRET
L'interpolazione viene eseguita in modalità predefinita ogni volta che viene chiamato get()
. Si passi True
come parametro per l'argomento raw
per ottenere il valore originale, senza interpolazione.
# configparser_interpolation.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('interpolazione.ini')
print('Valore originale :', parser.get('bug_tracker', 'url'))
parser.set('bug_tracker', 'port', '9090')
print('Valore porta modificato:', parser.get('bug_tracker', 'url'))
print('Senza interpolazione :', parser.get('bug_tracker', 'url',
raw=True))
Visto che il valore viene calcolato da get()
, la modifica di una delle impostazioni utilizzate per il valore url
modificherà il valore ritornato.
$ python3 configparser_interpolation.py Valore originale : http://localhost:8080/bugs/ Valore porta modificato: http://localhost:9090/bugs/ Senza interpolazione : %(protocol)s://%(server)s:%(port)s/bugs/
Usare Opzioni Predefinite
I valori per l'interpolazione non devono apparire nella stessa sezione dell'opzione originale. Le opzioni predefinite possono essere mescolate a valori sovrascritti.
# interpolazione_predefiniti.ini [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
Con questa configurazione, il valore per url
proviene dalla sezione DEFAULT
, e il processo di sostituzione inizia cercando in bug_tracker
poi arriva a DEFAULT
per le parti che non trova.
# configparser_interpolation_defaults.py
from configparser import ConfigParser
parser = ConfigParser()
parser.read('interpolazione_predefiniti.ini')
print('URL:', parser.get('bug_tracker', 'url'))
I valori del nome dell'host e della porta provengono dalla sezione bug_tracker
, ma protocol
proviene da DEFAULT
.
$ python3 configparser_interpolation_defaults.py URL: http://localhost:8080/bugs/
Errori in Sostituzione
Le sostituzioni si interrompono dopo il numero di passi definito in MAX_INTERPOLATION_DEPTH
per evitare problemi dovuti a riferimenti ricorsivi.
# 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('ERRORE:', err)
Una eccezione InterpolationDepthError
viene sollevata se ci sono troppi passi di sostituzione.
$ python3 configparser_interpolation_recursion.py ERRORE: Recursion limit exceeded in value substitution: option 'opt' in section 'sect' contains an interpolation key which cannot be substituted in 10 steps. Raw value: '%(opt)s'
Valori mancanti danno luogo ad una eccezione 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('ERRORE:', err)
Visto che non è stato definito alcun valore server
, url
non può essere costruito.
$ python3 configparser_interpolation_error.py ERRORE: 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'
Caratteri Speciali
Visto che %
fa partire le istruzioni di interpolazione, se è necessario un %
nel valore dell'opzione occorre farlo precedere da un altro carattere di percentuale (%%
).
# escape.ini [escape] value = un %% nel valore ritornato si esprime raddoppiandolo
Leggere il valore non richiede altre considerazioni particolari.
# configparser_escape.py
from configparser import ConfigParser
import os
filename = 'escape.ini'
config = ConfigParser()
config.read([filename])
value = config.get('escape', 'value')
print(value)
Quando viene letto il valore, %%
viene automaticamente convertito in %
.
$ python3 configparser_escape.py un % nel valore ritornato si esprime raddoppiandolo
Interpolazione Estesa
ConfigParser
supporta implementazioni alternative di interpolazione. Passando un oggetto che supporta l'API definita da Interpolation
nel parametro interpolation
. Ad esempio, usando ExtendedInterpolation
in luogo della predefinita BasicInterpolation
si ha accesso a diverse sintassi usando ${}
come indicatore di variabile.
# configparser_extendedinterpolation.py
from configparser import ConfigParser, ExtendedInterpolation
parser = ConfigParser(interpolation=ExtendedInterpolation())
parser.read('interpolazione_estesa.ini')
print('Valore originale :', parser.get('bug_tracker', 'url'))
parser.set('intranet', 'port', '9090')
print('Valore porta alterato:', parser.get('bug_tracker', 'url'))
print('Senza interpolazione :', parser.get('bug_tracker', 'url',
raw=True))
L'interpolazione estesa supporta l'accesso a valori da altri sezioni del file di configurazione prefissando il nome della variabile dal nome della sezione e dal simbolo dei due punti (:).
# interpolazione_estesa.ini [intranet] server = localhost port = 8080 [bug_tracker] url = http://${intranet:server}:${intranet:port}/bugs/ username = dhellmann password = SECRET
Facendo riferimento a valori in altre sezioni del file rende possibile condividere una gerarchia di valori, senza piazzare tutti quelli predefiniti nella sezione DEFAULTS
.
$ python3 configparser_extendedinterpolation.py Valore originale : http://localhost:8080/bugs/ Valore porta alterato: http://localhost:9090/bugs/ Senza interpolazione : http://${intranet:server}:${intranet:port}/bugs/
Disabilitare l'Interpolazione
Per disabilitare l'interpolazione, si passi None
in luogo di un oggetto Interpolation
.
# configparser_nointerpolation.py
from configparser import ConfigParser
parser = ConfigParser(interpolation=None)
parser.read('interpolazione.ini')
print('Senza interpolazione:', parser.get('bug_tracker', 'url'))
Questo fa sì che qualsiasi sintassi che possa essere elaborata dall'oggetto di interpolazione venga ignorata in sicurezza.
$ python3 configparser_nointerpolation.py Senza interpolazione: %(protocol)s://%(server)s:%(port)s/bugs/
Vedere anche:
- configparser
- La documentazione della libreria standard per questo modulo.
- ConfigObj
- Un avanzato elaboratore di file di configurazione con supporto di caratteristiche tipo la validazione del contenuto.
- Note di portabilità per configparser.