Używam ConfigParser
do odczytywania konfiguracji skryptu w czasie wykonywania.
Chciałbym mieć elastyczność polegającą na nie podawaniu nazwy sekcji (istnieją skrypty, które są dość proste; nie potrzebują „sekcji”). ConfigParser
zgłosi NoSectionError
wyjątek i nie zaakceptuje pliku.
Jak sprawić, by ConfigParser po prostu pobierał (key, value)
krotki z pliku konfiguracyjnego bez nazw sekcji?
Na przykład:
key1=val1
key2:val2
Wolałbym nie pisać do pliku konfiguracyjnego.
python
parsing
configuration-files
Escualo
źródło
źródło
Odpowiedzi:
Alex Martelli pod warunkiem rozwiązania za korzystanie
ConfigParser
analizować.properties
plików (które są najwyraźniej sekcja mniej pliki config).Jego rozwiązaniem jest opakowanie przypominające plik, które automagicznie wstawia fikcyjny nagłówek sekcji, aby spełnić
ConfigParser
wymagania.źródło
Oświecony tą odpowiedzią jterrace , wymyślam takie rozwiązanie:
ini_str = '[root]\n' + open(ini_path, 'r').read() ini_fp = StringIO.StringIO(ini_str) config = ConfigParser.RawConfigParser() config.readfp(ini_fp)
EDYCJA dla przyszłych pracowników Google: od wersji Python 3.4+
readfp
jest przestarzała iStringIO
nie jest już potrzebna. Zamiast tego możemy użyćread_string
bezpośrednio:with open('config_file') as f: file_content = '[dummy_section]\n' + f.read() config_parser = ConfigParser.RawConfigParser() config_parser.read_string(file_content)
źródło
Możesz to zrobić w jednej linii kodu.
W Pythonie 3 dołącz fałszywy nagłówek sekcji do danych pliku konfiguracyjnego i przekaż go do
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.
Możesz również użyć
itertools.chain()
do symulacji nagłówka sekcji dlaread_file()
. Może to być bardziej wydajne pod względem wykorzystania pamięci niż powyższe podejście, co może być przydatne, jeśli masz duże pliki konfiguracyjne w ograniczonym środowisku wykonawczym.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)
W Pythonie 2 dołącz fałszywy nagłówek sekcji do danych pliku konfiguracyjnego, zawiń wynik w
StringIO
obiekt i przekaż go doreadfp()
.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)
Przy każdym z tych podejść ustawienia konfiguracji będą dostępne w
parser.items('top')
.Możesz użyć StringIO również w Pythonie 3, być może ze względu na kompatybilność zarówno ze starymi, jak i nowymi interpreterami Pythona, ale pamiętaj, że teraz znajduje się w
io
pakiecie ireadfp()
jest przestarzały.Alternatywnie możesz rozważyć użycie parsera TOML zamiast ConfigParser.
źródło
Możesz to zrobić za pomocą biblioteki ConfigObj: http://www.voidspace.org.uk/python/configobj.html
Zaktualizowano: znajdź najnowszy kod tutaj .
Jeśli korzystasz z Debiana / Ubuntu, możesz zainstalować ten moduł za pomocą swojego menedżera pakietów:
Przykładowe zastosowanie:
from configobj import ConfigObj config = ConfigObj('myConfigFile.ini') config.get('key1') # You will get val1 config.get('key2') # You will get val2
źródło
Moim zdaniem najłatwiejszym sposobem jest użycie parsera CSV Pythona. Oto funkcja odczytu / zapisu demonstrująca to podejście, a także sterownik testowy. To powinno działać, pod warunkiem, że wartości nie mogą być wieloliniowe. :)
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 __name__ == '__main__': main()
źródło
csv
modułu do rozwiązywania typowychConfigParser
skarg. Łatwo uogólnione i bardziej zgodne z Pythonem 2 i 3 .Sam napotkałem ten problem i napisałem kompletny wrapper do ConfigParser (wersja w Pythonie 2), który może odczytywać i zapisywać pliki bez sekcji w sposób przejrzysty, w oparciu o podejście Alexa Martelliego połączone z zaakceptowaną odpowiedzią. Powinien zastępować dowolne użycie narzędzia ConfigParser. Publikowanie go na wypadek, gdyby ktoś potrzebujący znalazł tę stronę.
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)
źródło
Odpowiedź Blueicefield wspomniała o configobj, ale oryginalna biblioteka obsługuje tylko Python 2. Teraz ma port zgodny z Pythonem 3+:
https://github.com/DiffSK/configobj
Interfejsy API nie uległy zmianie, zobacz dokumentację .
źródło