Schema
ライブラリ
Schema
概要
Schemaは「Schema validation just got Pythonic」をキャッチフレーズに開発された、シンプルで軽量なPythonデータ構造バリデーションライブラリです。設定ファイル、フォーム、外部サービス、コマンドライン引数など、JSON/YAMLから変換されたPythonデータ型の検証に特化しています。Vladimir Keleshevによって開発され、Pythonらしい直感的なAPI設計と最小限の依存関係が特徴。複雑な機能を排除し、シンプルさと使いやすさを追求したバリデーションライブラリです。
詳細
Schemaは型チェック、callableバリデータ、論理演算子(And/Or)、Optional、Use、Regexなどの基本的なバリデーション機能を提供します。優先度ベースのディスパッチメカニズムにより、様々なデータ型と検証ルールを柔軟に処理できます。単一のschema.pyファイルで構成される自己完結型の実装で、プロジェクトに簡単に組み込めます。Python 2.6から3.9まで幅広いバージョンをサポートし、draft-07 JSON Schema生成機能も備えています。
主な特徴
- 極めてシンプルなAPI: Pythonicな記法による直感的な使用感
- 軽量実装: 単一ファイル(schema.py)のみで動作
- 柔軟な型チェック: Python型、callable、正規表現による検証
- 論理演算子サポート: And/Orによる複雑な条件の組み合わせ
- JSON Schema生成: 標準的なdraft-07形式のスキーマ出力
- 詳細なエラー報告: SchemaErrorによる明確なエラーメッセージ
メリット・デメリット
メリット
- 学習コストが極めて低い(シンプルなAPI)
- 依存関係なし(単一ファイルで完結)
- 軽量で高速な動作
- Pythonらしい直感的な記法
- 幅広いPythonバージョンサポート(2.6〜3.9)
- MITライセンスによる自由な利用
デメリット
- 高度なバリデーション機能の不足
- 型変換機能が限定的
- エコシステムが小規模
- 大規模プロジェクトには機能不足
- パフォーマンス最適化されていない
- 非同期処理未対応
参考ページ
書き方の例
インストールと基本セットアップ
# pipでインストール
pip install schema
# または単一ファイルをプロジェクトにコピー
wget https://raw.githubusercontent.com/keleshev/schema/master/schema.py
基本的な型チェック
from schema import Schema
# 単純な型チェック
Schema(int).validate(123) # 成功: 123を返す
Schema(str).validate("hello") # 成功: "hello"を返す
# 型が一致しない場合
try:
Schema(int).validate("123") # SchemaError発生
except SchemaError as e:
print(f"エラー: {e}")
# is_validで検証のみ行う
if Schema(int).is_valid(123):
print("有効なデータです")
辞書の検証
from schema import Schema, And, Use, Optional
# ユーザー情報の検証スキーマ
user_schema = Schema({
'name': And(str, len), # 空でない文字列
'age': And(Use(int), lambda n: 18 <= n <= 99), # 文字列を整数に変換して範囲チェック
Optional('email'): And(str, lambda s: '@' in s), # オプショナルなメールアドレス
Optional('gender'): And(str, Use(str.lower), lambda s: s in ('male', 'female'))
})
# データの検証
data = {
'name': 'Taro Yamada',
'age': '25', # 文字列で渡されても整数に変換
'email': '[email protected]'
}
validated = user_schema.validate(data)
print(validated) # {'name': 'Taro Yamada', 'age': 25, 'email': '[email protected]'}
リストとネストした構造の検証
from schema import Schema, And, Use
# 商品リストの検証
products_schema = Schema([{
'id': And(int, lambda n: n > 0),
'name': And(str, len),
'price': And(Use(float), lambda p: p > 0),
'tags': [str], # 文字列のリスト
'stock': {
'quantity': int,
'warehouse': str
}
}])
# データの検証
products = [{
'id': 1,
'name': 'ノートPC',
'price': '89800', # 文字列から浮動小数点に変換
'tags': ['電子機器', 'コンピュータ'],
'stock': {
'quantity': 15,
'warehouse': '東京倉庫'
}
}]
validated = products_schema.validate(products)
callableバリデータとカスタムエラー
from schema import Schema, Use, SchemaError
# カスタムバリデータ関数
def validate_email(email):
import re
pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
if not re.match(pattern, email):
raise SchemaError(f'無効なメールアドレス: {email}')
return email
# パスワード強度チェック
def strong_password(password):
if len(password) < 8:
return False
if not any(c.isupper() for c in password):
return False
if not any(c.isdigit() for c in password):
return False
return True
# スキーマ定義
account_schema = Schema({
'username': And(str, lambda s: 3 <= len(s) <= 20),
'email': Use(validate_email),
'password': And(str, strong_password, error='パスワードは8文字以上で、大文字と数字を含む必要があります')
})
# 検証実行
try:
account_schema.validate({
'username': 'user123',
'email': '[email protected]',
'password': 'weak' # エラーになる
})
except SchemaError as e:
print(f"バリデーションエラー: {e}")
OrとForbiddenの使用
from schema import Schema, Or, Forbidden
# 認証方法の選択(emailまたはusernameのいずれか一つ)
auth_schema = Schema({
Or('email', 'username', only_one=True): str,
'password': str,
Forbidden('admin'): object # adminフィールドは禁止
})
# 有効なデータ
auth_schema.validate({'email': '[email protected]', 'password': 'Pass123!'})
auth_schema.validate({'username': 'user123', 'password': 'Pass123!'})
# エラーケース
try:
# 両方指定するとエラー
auth_schema.validate({
'email': '[email protected]',
'username': 'user123',
'password': 'Pass123!'
})
except SchemaError as e:
print(f"エラー: {e}")
JSON Schema生成
from schema import Schema, Optional, Literal
import json
# スキーマ定義(説明付き)
api_schema = Schema(
{
Literal("name", description="ユーザーの表示名"): str,
Literal("age", description="年齢(18歳以上)"): And(int, lambda n: n >= 18),
Optional(Literal("bio", description="自己紹介文")): str
},
description="ユーザープロファイルAPI"
)
# JSON Schema生成
json_schema = api_schema.json_schema("https://example.com/user-profile.json")
print(json.dumps(json_schema, indent=2, ensure_ascii=False))