[PYTHON] Je souhaite recevoir le fichier de configuration et vérifier si le fichier JSON généré par jinja2 est un JSON valide

Le fichier JSON qui reçoit le fichier de paramètres et est généré par jinja2 est utilisé lors du déploiement. Je veux vérifier si ce fichier JSON généré est un JSON valide.

Commande utilisée

Une image comme j2cli.

Utilisez les deux fichiers suivants.

--Fichier de configuration (.json)

Par exemple, lorsque le fichier de paramètres est le suivant

{
  "name": "staging"
}

Utilisez un modèle comme celui-ci.

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

Par conséquent, le JSON suivant est généré. Ceci est utilisé comme fichier de configuration réel.

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

Dans le cas de paramètres de type dev, la sortie peut être la suivante.

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

problème

Le JSON généré est peut-être invalide. Il semble que vous le remarquerez enfin lorsqu'il sera déployé en production. Je veux vérifier à l'avance.

Choses à faire

La politique est la suivante.

  1. Emettre un modèle avec jinja2
  2. Json.loads le JSON émis à nouveau
  3. Si une erreur se produit, il doit s'agir d'un JSON non valide

Cela ressemble à ceci dans le code python.

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))  #Erreur si invalide

Cependant, il y a quelques mises en garde.

Remarque 1 Lorsque la valeur attendue n'est pas incluse dans le fichier de paramètres

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

Si vous émettez avec jinja2 sans rien définir dans un tel modèle, ce qui suit se produira, mais aucune erreur ne se produira.

{"foo": "foo-"}

Cela peut être détecté en modifiant le paramètre non défini de jinja2. Si vous ajoutez ʻundefined = jinja2.StrictUndefined, ʻUndefinedError se produira.

Remarque 2 Lorsque le modèle contient une quantité excessive de "}"

C'est mauvais si le modèle est défectueux et contient une quantité excessive de "}". Bien que le JSON généré soit valide en tant que JSON. Pas le résultat attendu.

Si vous écrivez accidentellement le modèle suivant.

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

Ce qui suit est un JSON valide. Pas le résultat attendu.

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

Pour le moment, vous devriez également vérifier la valeur de dict.

Un script qui vérifie si le résultat de l'émission avec jinja2 est un JSON valide

Sur la base de ce qui précède, j'ai créé un script qui vérifie si le résultat de l'émission avec jinja2 est un JSON valide. Utilisez-le comme ça. Si la variable environ n'existe pas, une erreur se produira comme indiqué ci-dessous. Un exemple d'utilisation de ceci est une erreur lorsque deux paramètres nommés ʻenviron` n'existent pas dans le fichier de paramètres.

$ 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

La mise en œuvre est la suivante.

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

Je souhaite recevoir le fichier de configuration et vérifier si le fichier JSON généré par jinja2 est un JSON valide
J'ai créé un script pour vérifier si l'anglais est entré dans la position spécifiée du fichier JSON en Python.
Je veux pirater Robomaster S1 ① Vérification de l'enracinement et de la configuration des fichiers
Je veux créer un lecteur de musique et enregistrer de la musique en même temps
Je veux écrire un élément dans un fichier avec numpy et le vérifier.
Créez un script python pour vérifier si le lien à l'URL spécifiée est valide
[Django] Test pour envoyer un fichier par POST et vérifier le contexte retourné [TDD]
Je veux initialiser si la valeur est vide (python)
Je souhaite enregistrer l'heure d'exécution et conserver un journal.
[Blender] Script pour vérifier si celui sélectionné est un mesh
Vérifiez si le fichier de paramètres est lu de manière simple à comprendre
Que faire si vous chattez ou suivez un fichier binaire et que le terminal est brouillé
J'ai créé une fonction pour vérifier si le webhook est reçu dans Lambda pour le moment
Je souhaite extraire les informations d'étiquette (titre et artiste) d'un fichier de musique (flac, wav).
J'ai fait un programme pour vérifier la taille d'un fichier avec Python
Vérifier s'il y a un symbole spécifique dans le fichier exécutable et ses bibliothèques dépendantes (version simplifiée)
Je veux obtenir le chemin du répertoire où le fichier en cours d'exécution est stocké.
Quoi qu'il en soit, je veux vérifier facilement les données JSON
Je veux déposer un fichier sur tkinter et obtenir son chemin [Tkinter DnD2]
Je veux ajouter du silence pendant 1 seconde au début d'un fichier wav
J'ai créé un outil pour générer du Markdown à partir du fichier JSON Scrapbox exporté
Je veux obtenir le nom du fichier, le numéro de ligne et le nom de la fonction dans Python 3.4
Je veux écrire dans un fichier avec Python
Je veux remplacer les variables dans le fichier de modèle python et le produire en masse dans un autre fichier
Comment vérifier en Python si l'un des éléments d'une liste est dans une autre liste
Je veux voir le nom de fichier de DataLoader
Vérifiez si la chaîne est un nombre en python
Je veux échantillonner au hasard un fichier avec Python
Je veux gagner s'il y a le grand prix de visualisation le plus inutile au monde ・ Apprenez la visualisation en faisant évoluer la fonction OP
Je veux trouver l'intersection d'une courbe de Bézier et d'une ligne droite (méthode de découpage de Bézier)
Je souhaite créer une source sonore de karaoké en séparant les instruments et les voix en utilisant Python
Je souhaite enregistrer les photos envoyées par LINE vers S3
Comment changer le fichier de configuration pour qu'il soit lu par Python
J'ai fait une fonction pour vérifier le modèle de DCGAN
Je veux connaître la nature de Python et pip
Je souhaite mapper le code EDINET et le numéro de valeur
Je veux que Sphinx soit pratique et utilisé par tout le monde
Je veux créer un Dockerfile pour le moment.
Je veux obtenir des informations de fstab à la destination de la connexion ssh et exécuter la commande
Je veux créer un histogramme et superposer la courbe de distribution normale dessus. édition matplotlib
Je veux clarifier la question de la méthode "__init__" et de l'argument "self" de la classe Python.
Je souhaite spécifier un fichier qui n'est pas une certaine chaîne de caractères comme cible logrotate, mais est-ce impossible?
Vérifiez si le hachage de mot de passe généré par PHP correspond en Python
Comment faire une commande pour lire le fichier de paramètres avec pyramide
Développement LINEbot, je souhaite vérifier le fonctionnement dans l'environnement local
Je veux créer un système pour éviter d'oublier de serrer la clé 1
Gratter et manger des bûches - je veux trouver un bon restaurant! ~ (Travail)
Je veux créer un fichier pip et le refléter dans le menu fixe
Je veux vérifier la position de mon visage avec OpenCV!
[Golang] Vérifiez si une chaîne de caractères spécifique est incluse dans la chaîne de caractères
Si vous voulez être guéri par l'image de Mia Nanasawa, appuyez sur l'API Twitter ♪
Django super introduction par les débutants Python! Partie 3 J'ai essayé d'utiliser la fonction d'héritage de fichier de modèle
Je veux faire revivre la légendaire combinaison Nintendo en utilisant pleinement l'IA et la technologie RH!
Je veux utiliser quatre règles compliquées dans l'instruction IF du modèle Django! → Utilisez un modèle personnalisé
[Golang] Je veux ajouter omitempty à la balise json du champ de type int de la structure afin qu'il soit ignoré si 0 est entré.
Je veux changer la couleur en cliquant sur le point de dispersion dans matplotlib
[Python Kivy] Comment obtenir le chemin du fichier par glisser-déposer
J'ai essayé de déplacer l'image vers le dossier spécifié en faisant un clic droit et un clic gauche