[PYTHON] Ich möchte die Einstellungsdatei erhalten und prüfen, ob die von jinja2 generierte JSON-Datei eine gültige JSON ist

Die JSON-Datei, die die Einstellungsdatei empfängt und von jinja2 generiert wird, wird bei der Bereitstellung verwendet. Ich möchte überprüfen, ob diese generierte JSON-Datei ein gültiger JSON ist.

Befehl verwendet

Ein Bild wie j2cli.

Verwenden Sie die folgenden zwei Dateien.

Zum Beispiel, wenn die Einstellungsdatei wie folgt lautet

{
  "name": "staging"
}

Verwenden Sie eine solche Vorlage.

{
  "app-name": "{{name}}-app",
  "batch-name": "{{name}}-batch"
}

Infolgedessen wird der folgende JSON ausgegeben. Dies wird als eigentliche Konfigurationsdatei verwendet.

{
  "app-name": "staging-app",
  "batch-name": "staging-batch"
}

Bei dev-ähnlichen Einstellungen kann die Ausgabe wie folgt aussehen.

{
  "app-name": "dev-app",
  "batch-name": "dev-batch"
}

Problem

Der generierte JSON ist möglicherweise ungültig. Es scheint, dass Sie es endlich bemerken werden, wenn es in der Produktion bereitgestellt wird. Ich möchte im Voraus überprüfen.

Dinge die zu tun sind

Die Richtlinie lautet wie folgt.

  1. Vorlage mit jinja2 ausgeben
  2. Json lädt den ausgegebenen JSON erneut
  3. Wenn ein Fehler auftritt, sollte JSON ungültig sein

Im Python-Code sieht es so aus.

import jinja2
import json


env = jinja2.Environment(loader=jinja2.FileSystemLoader(["."]), undefined=jinja2.StrictUndefined)
t = env.get_or_select_template(template_path)
json.loads(t.render(**config))  #Fehler, wenn ungültig

Es gibt jedoch einige Einschränkungen.

Hinweis 1 Wenn der erwartete Wert nicht in der Einstellungsdatei enthalten ist

{"foo": "foo-{{name}}"}

Wenn Sie mit jinja2 ausgeben, ohne etwas in einer solchen Vorlage festzulegen, tritt Folgendes auf, es tritt jedoch kein Fehler auf.

{"foo": "foo-"}

Dies kann durch Ändern der undefinierten Einstellung von jinja2 erkannt werden. Wenn Sie "undefined = jinja2.StrictUndefined" hinzufügen, tritt "UndefinedError" auf.

Hinweis 2 Wenn die Vorlage zu viel "}" enthält

Es ist schlecht, wenn die Vorlage fehlerhaft ist und zu viel "}" enthält. Obwohl der generierte JSON als JSON gültig ist. Nicht die erwartete Ausgabe.

Wenn Sie versehentlich die folgende Vorlage schreiben.

{
  "app-name": "{{name}}}-app"
}

Das Folgende ist ein gültiger JSON. Nicht die erwartete Ausgabe.

{
  "app-name": "staging}-app"
}

Vorerst sollten Sie auch den Wert von dict überprüfen.

Ein Skript, das prüft, ob das Ergebnis der Ausgabe mit jinja2 ein gültiger JSON ist

Basierend auf dem oben Gesagten habe ich ein Skript erstellt, das prüft, ob das Ergebnis der Ausgabe mit jinja2 ein gültiger JSON ist. Verwenden Sie es so. Wenn die variable Umgebung nicht vorhanden ist, tritt ein Fehler auf, wie unten gezeigt. Ein Beispiel für die Verwendung ist ein Fehler, wenn zwei Einstellungen mit dem Namen "Umgebung" nicht in der Einstellungsdatei vorhanden sind.

$ python check.py --conf-dir conf/ --template-dir template/ || echo ng
template/back.json.j2(conf/master.json): UndefinedError 'environ' is undefined
template/back.json.j2(conf/production.json): UndefinedError 'environ' is undefined
template/back.json.j2(conf/rook.json): UndefinedError 'environ' is undefined
ng

Die Implementierung ist wie folgt.

import sys
import os.path
import argparse
import jinja2
import json


def validate_conf(d, path=None):
    path = path or []
    if hasattr(d, "items"):
        for k, v in d.items():
            path.append(k)
            validate_conf(v, path=path)
            path.pop()
    elif isinstance(d, (list, tuple)):
        for i, x in enumerate(d):
            path.append(i)
            validate_conf(x, path=path)
            path.pop()
    elif isinstance(d, str):
        v = d
        if "{" in v:
            raise ValueError("invalid value: '{{' is included. path={}".format(path))
        if "}" in v:
            raise ValueError("invalid value: '}}' is included. path={}".format(path))
    return d


def check(env, config, template_path):
    t = env.get_or_select_template(template_path)
    data = json.loads(t.render(**config))
    return validate_conf(data)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--conf-dir", required=True)
    parser.add_argument("--template-dir", required=True)
    args = parser.parse_args()

    env = jinja2.Environment(loader=jinja2.FileSystemLoader(["."]), undefined=jinja2.StrictUndefined)
    status = 0
    for root, _, conf_files in os.walk(args.conf_dir):
        for conf_file in conf_files:
            try:
                confpath = os.path.join(root, conf_file)
                with open(confpath) as rf:
                    conf = json.load(rf)
            except Exception as e:
                sys.stderr.write("{confpath}: {e.__class__.__name__} {e}\n".format(confpath=confpath, e=e))
                status = 1
                continue

            for root2, _, template_files in os.walk(args.template_dir):
                for template_file in template_files:
                    try:
                        filepath = os.path.join(root2, template_file)
                        check(env, conf, filepath)
                    except Exception as e:
                        sys.stderr.write("{filepath}({confpath}): {e.__class__.__name__} {e}\n".format(
                            confpath=confpath, filepath=filepath, e=e)
                        )
                        status = 1
    sys.exit(status)


if __name__ == "__main__":
    main()

Recommended Posts

Ich möchte die Einstellungsdatei erhalten und prüfen, ob die von jinja2 generierte JSON-Datei eine gültige JSON ist
Ich habe ein Skript erstellt, um zu überprüfen, ob an der angegebenen Position der JSON-Datei in Python Englisch eingegeben wird.
Ich möchte Robomaster S1 ① Rooting und Dateikonfigurationsprüfung hacken
Ich möchte gleichzeitig einen Musik-Player erstellen und Musik ablegen
Ich möchte ein Element mit numpy in eine Datei schreiben und es überprüfen.
Erstellen Sie ein Python-Skript, um zu überprüfen, ob der Link unter der angegebenen URL gültig ist
[Django] Test zum Senden einer Datei per POST und Überprüfen des zurückgegebenen Kontexts [TDD]
Ich möchte initialisieren, wenn der Wert leer ist (Python)
Ich möchte die Ausführungszeit aufzeichnen und ein Protokoll führen.
[Blender] Skript zum Überprüfen, ob es sich bei dem ausgewählten um ein Netz handelt
Überprüfen Sie, ob die Einstellungsdatei leicht verständlich gelesen wird
Was tun, wenn Sie eine Binärdatei katzen oder verfolgen und das Terminal verstümmelt ist?
Ich habe eine Funktion erstellt, um zu überprüfen, ob der Webhook vorerst in Lambda empfangen wird
Ich möchte Tag-Informationen (Titel und Künstler) einer Musikdatei (flac, wav) extrahieren.
Ich habe ein Programm erstellt, um die Größe einer Datei mit Python zu überprüfen
Überprüfen Sie, ob die ausführbare Datei und ihre abhängigen Bibliotheken ein bestimmtes Symbol enthalten (vereinfachte Version).
Ich möchte den Pfad des Verzeichnisses abrufen, in dem die laufende Datei gespeichert ist.
Wie auch immer, ich möchte JSON-Daten einfach überprüfen
Ich möchte eine Datei auf tkinter ablegen und ihren Pfad abrufen [Tkinter DnD2]
Ich möchte dem Anfang einer WAV-Datei 1 Sekunde lang Stille hinzufügen
Ich habe ein Tool zum Generieren von Markdown aus der exportierten Scrapbox-JSON-Datei erstellt
Ich möchte den Dateinamen, die Zeilennummer und den Funktionsnamen in Python 3.4 erhalten
Ich möchte mit Python in eine Datei schreiben
Ich möchte die Variablen in der Python-Vorlagendatei ersetzen und in einer anderen Datei in Massenproduktion herstellen
So überprüfen Sie in Python, ob sich eines der Elemente einer Liste in einer anderen Liste befindet
Ich möchte den Dateinamen von DataLoader sehen
Überprüfen Sie, ob die Zeichenfolge eine Zahl in Python ist
Ich möchte eine Datei mit Python zufällig testen
Ich möchte gewinnen, wenn es den nutzlosesten Grand Prix für Visualisierung der Welt gibt. Lernen Sie Visualisierung, indem Sie die OP-Funktion weiterentwickeln
Ich möchte den Schnittpunkt einer Bezier-Kurve und einer geraden Linie finden (Bezier-Clipping-Methode)
Ich möchte eine Karaoke-Klangquelle erstellen, indem ich Instrumente und Gesang mit Python trenne
Ich möchte die von LINE an S3 gesendeten Fotos speichern
So wechseln Sie die Konfigurationsdatei, die von Python gelesen werden soll
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
Ich möchte die Natur von Python und Pip kennenlernen
Ich möchte den EDINET-Code und die Wertpapiernummer zuordnen
Ich möchte, dass Sphinx bequem ist und von allen benutzt wird
Ich möchte vorerst eine Docker-Datei erstellen.
Ich möchte Informationen von fstab am ssh-Verbindungsziel abrufen und den Befehl ausführen
Ich möchte ein Histogramm erstellen und die Normalverteilungskurve darauf überlagern. matplotlib edition
Ich möchte die Frage nach der Methode "__init__" und dem Argument "self" der Python-Klasse klären.
Ich möchte eine Datei, die keine bestimmte Zeichenfolge ist, als logrotate Ziel angeben, aber ist es unmöglich?
Überprüfen Sie, ob der von PHP generierte Passwort-Hash in Python übereinstimmt
So erstellen Sie einen Befehl zum Lesen der Einstellungsdatei mit Pyramide
LINEbot-Entwicklung möchte ich den Betrieb in der lokalen Umgebung überprüfen
Ich möchte ein System erstellen, um zu verhindern, dass vergessen wird, den Schlüssel 1 festzuziehen
Holz kratzen und essen - ich möchte ein gutes Restaurant finden! ~ (Arbeit)
Ich möchte eine Pipfile erstellen und im Docker wiedergeben
Ich möchte die Position meines Gesichts mit OpenCV überprüfen!
[Golang] Überprüfen Sie, ob eine bestimmte Zeichenfolge in der Zeichenfolge enthalten ist
Wenn Sie von Mia Nanasawas Bild geheilt werden möchten, klicken Sie auf die Twitter-API ♪
Django super Einführung von Python-Anfängern! Teil 3 Ich habe versucht, die Vererbungsfunktion für Vorlagendateien zu verwenden
Ich möchte die legendäre Nintendo-Kombination wiederbeleben, indem ich AI und HR Tech voll ausnütze!
Ich möchte komplizierte vier Regeln in der IF-Anweisung der Django-Vorlage verwenden! → Verwenden Sie eine benutzerdefinierte Vorlage
[Golang] Ich möchte dem json-Tag des int-Typ-Felds der Struktur omitempty hinzufügen, damit es ignoriert wird, wenn 0 eingegeben wird.
Ich möchte die Farbe ändern, indem ich auf den Streupunkt in matplotlib klicke
[Python Kivy] So erhalten Sie den Dateipfad durch Ziehen und Ablegen
Ich habe versucht, das Bild durch Klicken mit der rechten und linken Maustaste in den angegebenen Ordner zu verschieben