J'utilise ConfigParser pour lire la configuration d'exécution d'un script.
Je voudrais avoir la flexibilité de ne pas fournir de nom de section (il y a des scripts qui sont assez simples; ils n'ont pas besoin d'une "section"). ConfigParser lèvera l'exception NoSectionError
et n'acceptera pas le fichier.
Comment puis-je faire en sorte que ConfigParser récupère simplement le (key, value)
tuples d'un fichier de configuration sans noms de section? Par exemple:
key1=val1
key2:val2
Je préfère ne pas écrire dans le fichier de configuration.
Alex Martelli a fourni une solution pour utiliser ConfigParser
pour analyser .properties
fichiers (qui sont apparemment des fichiers de configuration sans section).
Sa solution est un wrapper de type fichier qui insère automatiquement un en-tête de section factice pour satisfaire les exigences de ConfigParser
.
Éclairé par cette réponse de jterrace , je trouve cette solution:
ini_str = '[root]\n' + open(ini_path, 'r').read()
ini_fp = StringIO.StringIO(ini_str)
config = ConfigParser.RawConfigParser()
config.readfp(ini_fp)
[~ # ~] éditez [~ # ~] pour les futurs googleurs: à partir de Python 3.4+ readfp
est obsolète et StringIO
n'est plus nécessaire. Au lieu de cela, nous pouvons utiliser read_string
directement:
with open('config_file') as f:
file_content = '[dummy_section]\n' + f.read()
config_parser = RawConfigParser()
config_parser.read_string(file_content)
Vous pouvez le faire dans une seule ligne de code.
Dans python 3, ajoutez un faux en-tête de section à vos données de fichier de configuration et passez-le à read_string()
.
from configparser import ConfigParser
parser = ConfigParser()
with open("foo.conf") as stream:
parser.read_string("[top]\n" + stream.read()) # This line does the trick.
Vous pouvez également utiliser itertools.chain()
pour simuler un en-tête de section pour read_file()
. Cela peut être plus efficace en mémoire que l'approche ci-dessus, ce qui peut être utile si vous avez de gros fichiers de configuration dans un environnement d'exécution contraint.
from configparser import ConfigParser
from itertools import chain
parser = ConfigParser()
with open("foo.conf") as lines:
lines = chain(("[top]",), lines) # This line does the trick.
parser.read_file(lines)
Dans python 2, ajoutez un faux en-tête de section aux données de votre fichier de configuration, enveloppez le résultat dans un objet StringIO
et transmettez-le à - readfp()
.
from ConfigParser import ConfigParser
from StringIO import StringIO
parser = ConfigParser()
with open("foo.conf") as stream:
stream = StringIO("[top]\n" + stream.read()) # This line does the trick.
parser.readfp(stream)
Avec l'une de ces approches, vos paramètres de configuration seront disponibles dans parser.items('top')
.
Vous pouvez également utiliser StringIO dans python 3 également, peut-être pour la compatibilité avec les anciens et les nouveaux python interprètes, mais notez qu'il vit maintenant dans le io
package et readfp()
est désormais obsolète.
Vous pouvez également envisager d'utiliser un analyseur TOML au lieu de ConfigParser.
Vous pouvez utiliser la bibliothèque ConfigObj pour le faire simplement: http://www.voidspace.org.uk/python/configobj.html
Mise à jour: Trouvez le dernier code ici .
Si vous êtes sous Debian/Ubuntu, vous pouvez installer ce module en utilisant votre gestionnaire de paquets:
apt-get install python-configobj
Un exemple d'utilisation:
from configobj import ConfigObj
config = ConfigObj('myConfigFile.ini')
config.get('key1') # You will get val1
config.get('key2') # You will get val2
À mon avis, la façon la plus simple de le faire est d'utiliser l'analyseur CSV de python. Voici une fonction de lecture/écriture illustrant cette approche ainsi qu'un pilote de test. Cela devrait fonctionner à condition que les valeurs ne soient pas autorisées sur plusieurs lignes. :)
import csv
import operator
def read_properties(filename):
""" Reads a given properties file with each line of the format key=value. Returns a dictionary containing the pairs.
Keyword arguments:
filename -- the name of the file to be read
"""
result={ }
with open(filename, "rb") as csvfile:
reader = csv.reader(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
for row in reader:
if len(row) != 2:
raise csv.Error("Too many fields on row with contents: "+str(row))
result[row[0]] = row[1]
return result
def write_properties(filename,dictionary):
""" Writes the provided dictionary in key-sorted order to a properties file with each line of the format key=value
Keyword arguments:
filename -- the name of the file to be written
dictionary -- a dictionary containing the key/value pairs.
"""
with open(filename, "wb") as csvfile:
writer = csv.writer(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
for key, value in sorted(dictionary.items(), key=operator.itemgetter(0)):
writer.writerow([ key, value])
def main():
data={
"Hello": "5+5=10",
"World": "Snausage",
"Awesome": "Possum"
}
filename="test.properties"
write_properties(filename,data)
newdata=read_properties(filename)
print "Read in: "
print newdata
print
contents=""
with open(filename, 'rb') as propfile:
contents=propfile.read()
print "File contents:"
print contents
print ["Failure!", "Success!"][data == newdata]
return
if __== '__main__':
main()
Ayant moi-même rencontré ce problème, j'ai écrit un wrapper complet à ConfigParser (la version en Python 2) qui peut lire et écrire des fichiers sans sections de manière transparente, basé sur l'approche d'Alex Martelli liée à la réponse acceptée . Il devrait être un remplacement sans rendez-vous pour toute utilisation de ConfigParser. L'afficher au cas où quelqu'un qui en aurait besoin trouverait cette page.
import ConfigParser
import StringIO
class SectionlessConfigParser(ConfigParser.RawConfigParser):
"""
Extends ConfigParser to allow files without sections.
This is done by wrapping read files and prepending them with a placeholder
section, which defaults to '__config__'
"""
def __init__(self, *args, **kwargs):
default_section = kwargs.pop('default_section', None)
ConfigParser.RawConfigParser.__init__(self, *args, **kwargs)
self._default_section = None
self.set_default_section(default_section or '__config__')
def get_default_section(self):
return self._default_section
def set_default_section(self, section):
self.add_section(section)
# move all values from the previous default section to the new one
try:
default_section_items = self.items(self._default_section)
self.remove_section(self._default_section)
except ConfigParser.NoSectionError:
pass
else:
for (key, value) in default_section_items:
self.set(section, key, value)
self._default_section = section
def read(self, filenames):
if isinstance(filenames, basestring):
filenames = [filenames]
read_ok = []
for filename in filenames:
try:
with open(filename) as fp:
self.readfp(fp)
except IOError:
continue
else:
read_ok.append(filename)
return read_ok
def readfp(self, fp, *args, **kwargs):
stream = StringIO()
try:
stream.name = fp.name
except AttributeError:
pass
stream.write('[' + self._default_section + ']\n')
stream.write(fp.read())
stream.seek(0, 0)
return ConfigParser.RawConfigParser.readfp(self, stream, *args,
**kwargs)
def write(self, fp):
# Write the items from the default section manually and then remove them
# from the data. They'll be re-added later.
try:
default_section_items = self.items(self._default_section)
self.remove_section(self._default_section)
for (key, value) in default_section_items:
fp.write("{0} = {1}\n".format(key, value))
fp.write("\n")
except ConfigParser.NoSectionError:
pass
ConfigParser.RawConfigParser.write(self, fp)
self.add_section(self._default_section)
for (key, value) in default_section_items:
self.set(self._default_section, key, value)
La réponse de Blueicefield mentionnait configobj, mais la bibliothèque d'origine ne prend en charge que Python 2. Elle a maintenant un Python 3+ port compatible:
https://github.com/DiffSK/configobj
Les API n'ont pas changé, voyez c'est doc .