Seite 1 von 1

Konfigurationsdatei Parsen

Verfasst: Sonntag 1. März 2009, 13:46
von PNS-Richi
Hallo,

gibt es Module für Python die das Parsen von Konfigurationsdateien erleichtern, oder habt ihr Ideen wie ich so etwas umsetzen könnte?

Beispiel:

Code: Alles auswählen

cat porn {
    domainlist /etc/...
    urllist /etc/...
    acl porn
}

acl porn {
    validtime 12:30-13:30,14:30-15:30
    redirect_url: http://www...
}
lg Richi

Verfasst: Sonntag 1. März 2009, 13:53
von hendrikS
Dauerbaustelle hat hier neulich was vorgestellt. Vielleicht hilfts.

http://www.python-forum.de/topic-17815.html

Verfasst: Sonntag 1. März 2009, 14:02
von cofi
Nun du könntest ConfigParser aus der StdLib oder ConfigObj(http://www.voidspace.org.uk/python/configobj.html) nehmen.

Aber du musst dann deine Config-Dateien im INI-Format schreiben.

Alternativ kannst du auch direkt Python-Code schreiben als Konfiguration.

Verfasst: Sonntag 1. März 2009, 14:09
von DasIch
Ich bevorzuge inzwischen json als Format für Konfigurationsdateien, dass ist mit simplejson/json imho deutlich angenehmer als ConfigParser.

Verfasst: Sonntag 1. März 2009, 14:37
von Hyperion
Noch ne Alternative:
http://www.python-forum.de/topic-17906.html

Interessant wäre schon die Frage, was das da für ein Format ist! Bleibt es so, ohne Verschachtelungen und Referenzen, dann sollte man sich relativ einfach einen eigenen Parser schreiben können. Ansonsten wirds natürlich schwieriger ...

Außerdem ist es eben fraglich, wieso man kein etabliertes Format nimmt - wenn man es dann wählen kann!

Ist das Format eine Vorgabe (evtl. durch ein anderes Programm), so könnte man immerhin gucken, ob es dafür einen Parser mitgeliefert gibt.

Verfasst: Sonntag 1. März 2009, 15:10
von PNS-Richi
Der Aufbau ist an die Konfigurationsdatei eines ähnlichen Programmes angelehnt. Verschachtelungen sind erst später von nöten, wenn überhaupt.

Theoretisch könnte ich ein anderes Format wählen, aber ich denke mit der Syntax habe ich es gut getroffen. Ich wollte nur wissen ob es schon etwas gibt was evtl. diese Syntax verwendet.

lg Richi

Verfasst: Sonntag 1. März 2009, 15:19
von Hyperion
PNS-Richi hat geschrieben:Der Aufbau ist an die Konfigurationsdatei eines ähnlichen Programmes angelehnt.
Was denn für ein ähnliches Programm? Bezogen auf "was" ähnlich?
Verschachtelungen sind erst später von nöten, wenn überhaupt.
So etwas sollte man imho schon vorher beachten ;-)
Theoretisch könnte ich ein anderes Format wählen, aber ich denke mit der Syntax habe ich es gut getroffen.
Mag sein - aber wozu das Rad neu erfinden? Ich sehe nichts, was das Format besonders machen könnte!?!
Ich wollte nur wissen ob es schon etwas gibt was evtl. diese Syntax verwendet.

lg Richi
Wenn es Deine Erfindung ist, wäre das schon ein ziemlicher Zufall ;-)

Verfasst: Sonntag 1. März 2009, 16:48
von PNS-Richi
Das Rad neu erfinden: Muss man nicht, aber Herausforderungen machen einen besser.

Was ich eigentlich meinte: Wenn es noch kein Modul zum Parsen gibt würd ichs schreiben.
Wegen der Verschachtelung bin ich noch am überlegen.

Du kannst mir gerne einen Vorschlag unterbreiten wie eine Konfigurationsdatei aussehen könnte, oder sollte :)

Verfasst: Sonntag 1. März 2009, 17:33
von Hyperion
PNS-Richi hat geschrieben: Du kannst mir gerne einen Vorschlag unterbreiten wie eine Konfigurationsdatei aussehen könnte, oder sollte :)
Dazu sind doch schon genügend Vorschläge gemacht worden!

Außerdem bin ich wenig motiviert, solange Du Fragen ignorierst und nicht beantwortest! ;-)

Verfasst: Sonntag 1. März 2009, 17:40
von DasIch
PNS-Richi hat geschrieben:Du kannst mir gerne einen Vorschlag unterbreiten wie eine Konfigurationsdatei aussehen könnte, oder sollte :)
Zum ersten sollte man nicht den Fehler machen ein eigenes Format zu erfinden wenn es schon genug gibt: json, yaml, aml, ini, xml oder zur Not auch pickle.

Verfasst: Sonntag 1. März 2009, 18:23
von sma
Eigentlich ist es einfach: 1. Sprache überlegen und Grammatik definieren. 2. Überlegen, wie man zugreifen will. 3. Scanner & Parser bauen. 4. Benutzen.

Ich kann nur raten, wie die Grammatik wäre. Leider scheint man einen Scanner mit zwei Zuständen zu benötigen, da innerhalb einer Klammer nach einem Namen beliebig viel bis zum Zeilenende kommen kann. Daher kann man nicht einen simplen RE-basierten Scanner mit einem einfachen rekursiv absteigenden Parser benutzen. Ein PEG-Parser müsste es aber können...

Grammatik bis hin zu regulären Ausdrücken:

Code: Alles auswählen

config = {group}.
group = groupname ws "{" {property} ws "}".
groupname = name {name}.
property = name value.
name = ws \w+
value = ws [^\n]*\n
ws = \s*
Mein Parserrahmenwerk:

Code: Alles auswählen

import re

def word(r):
    r = re.compile(r)
    def word(s):
        m = r.match(s)
        if m: return m.group(1), s[m.end():]
    return word

def token(t): return word("()\s*" + re.escape(t))

def seq(*ps):
    def seq(s):
        r = []
        for p in ps:
            rv = p(s)
            if not rv: return None
            if rv[0]: r.append(rv[0])
            s = rv[1]
        return r, s
    return seq

def rep(p):
    def rep(s):
        r = []
        while True:
            rv = p(s)
            if not rv: return r, s
            if rv[0]: r.append(rv[0])
            s = rv[1]
    return rep
Parser:

Code: Alles auswählen

def p_name(): return word(r"\s*(\w+)")
def p_value(): return word(r"\s*([^\n]*)\n")
def p_prop(): return seq(p_name(), p_value())
def p_groupname(): return seq(p_name(), rep(p_name()))
def p_group(): return seq(p_groupname(), word(r"\s*\{"), rep(p_prop()), word(r"\s*\}"))
def p_config(): return rep(p_group())
Ich gehe davon aus, dass der `:` hinter `redirect_url` ein Fehler ist. Dann kann der Parser `p_config` die Eingabe parsen. Statt sich selbst Parser und Parserkombinatoren zu bauen, kann man z.B. PyParsing benutzen. Wäre aber lame.

Ich will mit `config["cat porn"]["acl"]` auf die Daten zugreifen können. Wie bringe ich meinen Parser dazu, mir ein dict von dicts zu bauen? Ich definiere Aktionen, die mir die Daten umwandeln und filtere damit meine Parserergebnisse.

Jeder Parser liefert nämlich die erkannten Token zurück. `word` liefert das, was im regulären Ausdruck in Klammern steht. `token` wird ignoriert. `seq` und `rep` liefern je eine Liste. `p_name` liefert mir also einen Namen als String; dito `p_value`. `p_prop` liefert mit eine Liste mit dem Namen und dem Wert. `p_groupname` liefert mit eine zweielementige Liste mit einem Namen und einer weiteren weiteren Liste mit den weiteren Namen. Hieraus macht `a_groupname` einen String. `p_group` liefert eine zweielementige Liste mit dem Gruppennamen und einer Liste mit den Listen der Properties. Diese wandelt `a_group` in ein dict um. Und `p_config` liefert nochmal eine Liste mit den Listen der Gruppen und `a_config` macht daraus nochmal ein dict.

Code: Alles auswählen

def action(p, a):
    def action(s):
        rv = p(s)
        if rv: return a(rv[0]), rv[1]
    return action

def a_groupname(v): return " ".join(v[:1] + v[1])
def a_group(v): return v[0], dict(prop for prop in v[1])
def a_config(v): return dict(v)

def p_groupname(): return action(seq(p_name(), rep(p_name())), a_groupname)
def p_group(): return action(seq(p_groupname(), token("{"), rep(p_prop()), token("}")), a_group)
def p_config(): return action(rep(p_group()), a_config)
Jetzt funktioniert dies:

Code: Alles auswählen

print p_config()("""
cat porn {
    domainlist /etc/...
    urllist /etc/...
    acl porn
}

acl porn {
    validtime 12:30-13:30,14:30-15:30
    redirect_url http://www...
}
""")[0]
Stefan