2017-07-17 25 views
1

YAMLに設定を保存するプロジェクトがあります(設定ファイルは、スクリプトによって生成されます)。今はpyyamlを使ってYAML形式を解析し、設定を検証するためにmarshmallowを使用しています。私はYAMLに設定を保存することにかなり満足していますが、marshmellowは私が必要とするツールではないと思っています(スキーマは読みにくいですが、設定のためにシリアライズする必要はなく、xsdのようなものが必要です)。では、プロジェクトの設定を検証するベストプラクティスは何か、おそらく言語に依存しない方法がありますか?独自の構文とあなたが学ばなければならないの特異性と、YAML設定ファイルを解析して検証する最良の方法

successive: 
    worker: 
    cds_process_number: 0 # positive integer or zero 
    spider_interval: 10 # positive integer 
    run_worker_sh: /home/lmakeev/CDS/releases/master/scripts/run_worker.sh # OS path 
    allow: 
     - "*" # regular expression 
    deny: 
     - "^[A-Z]{3}_.+$" # regular expression 
+0

PyYAMLで同じ結果を得ることができます。なぜマシュマロは正しい道具ではないと思いますか?今は非常に開放的です。 – Grimmy

+0

非常に複雑な構造体スキーマのために読みにくいですが、設定のためのシリアライゼーションは必要ありません。xsdのようなものが必要です – Helvdan

+0

何かがこれですか?:https://github.com/Julian/jsonschema – Grimmy

答えて

1

スキーマの記述は、独自の言語である:

YAMLの設定を(我々は、Python 2.7を使用しています)。また、要件が変更された場合にYAMLが検証される「プログラム」を維持する必要があります。

すでにYAMLを使用していて、Pythonに精通している場合は、YAMLのタグ機能を使用して解析時にオブジェクトをチェックできます。

ファイルinput.yamlを持っていると仮定すると:

successive: 
    worker: 
    cds_process_number: !nonneg 0 
    spider_interval: !pos 10 
    run_worker_sh: !path /home/lmakeev/CDS/releases/master/scripts/run_worker.sh 
    allow: 
     - !regex "*" 
    deny: 
     - !regex "^[A-Z]{3}_.+$" 

、あなたが作成し、次のprogram¹使用して値を確認してください4つのクラスに登録することができます(削除され、タグが挿入されたコメントをあなたの例のファイル):

import sys 
import os 
import re 
import ruamel.yaml 
import pathlib 

class NonNeg: 
    yaml_tag = u"!nonneg" 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = int(node.value) # this creates/returns an int 
     assert val >= 0 
     return val 

class Pos(int): 
    yaml_tag = u"!pos" 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = cls(node.value) # this creates/return a Pos() 
     assert val > 0 
     return val 

class Path: 
    yaml_tag = u"!path" 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = pathlib.Path(node.value) 
     assert os.path.exists(val) 
     return val 


class Regex: 
    yaml_tag = u"!regex" 
    def __init__(self, val, comp): 
     # store original string and compile() of that string 
     self._val = val 
     self._compiled = comp 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = str(node.value) 
     try: 
      comp = re.compile(val) 
     except Exception as e: 
      comp = None 
      print("Incorrect regex", node.start_mark) 
      print(" ", node.tag, node.value) 
     return cls(val, comp) 


yaml = ruamel.yaml.YAML(typ="safe") 
yaml.register_class(NonNeg) 
yaml.register_class(Pos) 
yaml.register_class(Path) 
yaml.register_class(Regex) 

data = yaml.load(pathlib.Path('input.yaml')) 

個々のfrom_yamlクラスメソッドの実際のチェックは、ニーズに合わせて調整する必要があります(そのファイルがないため、パスのアサーションを削除する必要がありました)。

あなたはそれを印刷していることに注意しましょう上で実行する場合:

Incorrect regex in "input.yaml", line 7, column 9 
    !regex * 

"*"が有効な正規表現ではないために。あなたは:".*"を意味しましたか?


は、これは私が著者だそのruamel.yaml、YAML 1.2パーサーを使用して行われたを¹しました。 ObjectDictをサブクラス化する(デフォルトでは安全ではないので、コード内で正しいことを確認してください)

関連する問題