見出し画像

Python入門 (10) - YAMLの構文チェック

「YAML」の構文チェックツール「Yamale」の使い方をまとめました。

前回

1. Yamale

Yamale」は「YAML」の構文チェックツールです。

2. インストール

Pythonの仮想環境(3.6以降)で、以下のコマンドでインストールします。

$ pip install yamale

3. コマンドライン

「Yamale」は、コマンドラインから利用できます。検索対象フォルダで「YAML」を検索し、見つけたら同じフォルダにある「スキーマ」(構文定義ファイル)を使って、構文チェックを行います。

$ yamale [-h] [-s SCHEMA] [-n CPU_NUM] [-p PARSER] [--no-strict] [PATH]

PATH : YAMLの検索対象フォルダ (デフォルト:カレント)
-h, --help : ヘルプ
-s SCHEMA, --schema SCHEMA : スキーマの指定 (デフォルト:schema.yaml)
-n CPU_NUM, --cpu-num CPU_NUM : CPUの数 (デフォルト:4)
-p PARSER, --parser PARSER : YAMLライブラリ (ruamel, pyyaml(デフォルト))
--no-strict : strictモード無効

構文チェックの手順は、次のとおりです。
(1) チェック対象のYAMLの準備
・data.yaml

name: Bill
age: 26
height: 6.2
awesome: True

(2) スキーマの準備
・schema.yaml

name: str()
age: int(max=200)
height: num()
awesome: bool()

(3) 構文チェック。

$ yamale
Finding yaml files...
Found 1 yaml files.
Validating...
Validation success! 👍

5. API

「Yamale」は、APIからも利用できます。

import yamale

try:
   # スキーマの準備
   schema = yamale.make_schema('./schema.yaml')

   # チェック対象のYAMLの準備
   data = yamale.make_data('./data.yaml')

   # 構文チェック
   yamale.validate(schema, data)
except ValueError as e:
   print('Validation failed!', e)

有効なデータの場合は何も起きず、無効なデータの場合はValueErrorが投げられます。

6. スキーマ

「Yamale」を使用するには、「スキーマ」を準備する必要があります。

6-1. データ型

キーとデータ型のペアを次のように定義します。

・スキーマ

optional: str(required=False)
optional_min: int(min=1, required=False)
min: num(min=1.5)
max: int(max=100)

・有効なデータ

optional_min: 10
min: 1.6
max: 100

主なデータ型は、次のとおりです。

・str() : 文字列
・int() : 整数
・num() : 数値

主なデータ型の引数は、次のとおりです。

・required : 必須かどうか
・min : 最小
・max : 最大

6-2. インクルード

ノードの構文定義を別途定義して、インクルードで呼び出すことで、繰り返しや再帰的に利用できるようにします。従来のスキーマとノード毎の構文定義は、「---」で区切って記述します。

・スキーマ

customerA: include('customer')
customerB: include('customer')
recursion: include('recurse')
---
customer:
    name: str()
    age: int()
    custom: include('custom_type')
custom_type:
    integer: int()
recurse:
    level: int()
    again: include('recurse', required=False)

・有効なデータ

customerA:
    name: bob
    age: 900
    custom:
        integer: 1
customerB:
    name: jill
    age: 1
    custom:
        integer: 3
recursion:
    level: 1
    again:
        level: 2
        again:
            level: 3
            again:
                level: 4

6-3. リスト

リストの定義例は、次のとおりです。

・スキーマ

list_with_two_types: list(str(), include('variant'))
questions: list(include('question'))
---
variant:
    rsid: str()
    name: str()
question:
    choices: list(include('choices'))
    questions: list(include('question'), required=False)
choices:
    id: str()

・有効なデータ

list_with_two_types:
    - 'some'
    - rsid: 'rs123'
        name: 'some SNP'
    - 'thing'
    - rsid: 'rs312'
        name: 'another SNP'
questions:
    - choices:
          - id: 'id_str'
          - id: 'id_str1'
      questions:
          - choices:
              - id: 'id_str'
              - id: 'id_str1'

6-4. 最上位ノードがないリスト

最上位ノードがないリストの定義例は、次のとおりです。

・スキーマ

list(include('human'), min=2, max=2)
---
human:
    name: str()
    age: int(max=200)
    height: num()
    awesome: bool()

・有効データ

- name: Bill
    age: 26
    height: 6.2
    awesome: True
- name: Adrian
    age: 23
    height: 6.3
    awesome: True

7. データ型

データ型の引数には、必須かどうかを示すrequiredを必ず持ちます。デフォルトはTrueです。

str(required=False)

値のNoneを許さないことを示すには、noneを使用します。デフォルトはFalseです。

str(required=False, none=False)

7-1. String - str(min=int, max=int, exclude=string)

文字列。

◎ 引数

min : len(string) >= min
max : len(string) <= max
exclude : 除外すべき文字

◎ 例

str(max=10, exclude='?!')    

7-2. Regex - regex([patterns], name=string, ignore_case=False, multiline=False, dotall=False)

正規表現の文字列。

◎ 引数

[pattern] : 1 つ以上の Python 正規表現のパターン
name : パターンの説明
ignore_case : 大文字と小文字を区別しない
multiline : パターン内の^と$は、文字列全体の最初と最後での一致に加え、文字列の各行の最初と最後で一致
dotall : 「.」が、改行以外の全ての文字に一致するだけでなく、検証済み文字列内の改行文字にも一致

◎ 例

regex('^[^?!]{,10}$')
regex(r'^(\d+)(\s\1)+$', name='repeated natural')  
regex('.*^apples$', multiline=True, dotall=True)

7-3. Integer - int(min=int, max=int)

整数。

◎ 引数

min : int >= min
max : int <= max

7-4. Number - num(min=float, max=float)

数値。

◎ 引数

min : num >= min
max : num <= max

7-5. Boolean - bool()

ブーリアン値。

7-6. Null - null()

Null値の構文定義。

7-7. Enum - enum([primitives])

列挙値。

◎ 引数

primitives : 定数

◎ 例

enum('a string', 1, False)

7-8. Day - day(min=date, max=date)

年月日 (YYYY-MM-DD)。

◎ 引数

min : date >= min
max : date <= max

◎ 例

day(min='2001-01-01', max='2100-01-01')

7-9. Timestamp - timestamp(min=time, max=time)

年月日時分秒 (YYYY-MM-DD HH:MM:SS)。

◎ 引数

min : time >= min
max : time <= max

◎ 例


timestamp(min='2001-01-01 01:00:00', max='2100-01-01 23:00:00')

7-10. List - list([validators], min=int, max=int)

リスト。

◎ 引数

validators : データ型
min : len(list) >= min
max : len(list) <= max

◎ 例

list()
list(include('custom'), int(), min=4)

7-11. Map - map([validators], key=validator)

マップ。

◎ 引数

validators : データ型
key : キー

◎ 例

map()
map(str(), int())
map(str(), key=int())

7-12. IP Address - ip()

IPアドレス。

◎ 引数

version : 4 or 6

◎ 例

ip()
ip(version=4)
ip(version=6)

7-13. MAC Address - mac()

Macアドレス。

◎ 例

mac()

7-14. Any - any([validators])

共用体。

◎ 引数

validators : データ型

◎ 例

any(int(), null())
any(num(), include('vector'))
any(str(min=3, max=3),str(min=5, max=5),str(min=7, max=7))
any()

7-15. Subset - subset([validators], allow_empty=False)

サブセット。

◎ 引数

validators : データ型
allow_empty : 空を許可するかどうか

◎ 例

subset(int(), str())
subset(int(), str(), allow_empty=True)

7-16. Include - include(include_name)

インクルード。

◎ 引数

include_name : インクルード名

◎ 例

include('person')

7-17. カスタム

import yamale
import datetime
from yamale.validators import DefaultValidators, Validator

class Date(Validator):
    tag = 'date'

    def _is_valid(self, value):
        return isinstance(value, datetime.date)

validators = DefaultValidators.copy()  # This is a dictionary
validators[Date.tag] = Date
schema = yamale.make_schema('./schema.yaml', validators=validators)

次回

この記事が気に入ったらサポートをしてみませんか?