Hub Python Library documentation
厳密なデータクラス
厳密なデータクラス
huggingface_hub パッケージには、厳密なデータクラスを作成するためのユーティリティが提供されています。これらは、Python の標準的な dataclass の強化版であり、追加の検証機能を持っています。厳密なデータクラスは、初期化時と代入時の両方でフィールドが検証されることを保証するため、データの整合性が重要なシナリオに最適です。
概要
厳密なdataclassは@strictデコレーターを使用して作成されます。通常のdataclassの機能を以下のように拡張します:
- 型ヒントに基づいてフィールドの型を検証する
- 追加のチェック用のカスタムバリデータへの対応
- コンストラクタで任意のキーワード引数を許可するオプション
- 初期化時と代入時の両方でフィールドを検証する
メリット
- データ整合性: フィールドが常に有効なデータを含むことを保証します
- 使いやすさ: Pythonの
dataclassモジュールとシームレスに統合 - 柔軟性: 複雑な検証ロジックに対応するカスタムバリデーターをサポート
- 軽量: Pydanticやattrsなどの追加の依存関係は不要です
使用方法
基本例
from dataclasses import dataclass
from huggingface_hub.dataclasses import strict, as_validated_field
# Custom validator to ensure a value is positive
@as_validated_field
def positive_int(value: int):
if not value > 0:
raise ValueError(f"Value must be positive, got {value}")
@strict
@dataclass
class Config:
model_type: str
hidden_size: int = positive_int(default=16)
vocab_size: int = 32 # Default value
# Methods named `validate_xxx` are treated as class-wise validators
def validate_big_enough_vocab(self):
if self.vocab_size < self.hidden_size:
raise ValueError(f"vocab_size ({self.vocab_size}) must be greater than hidden_size ({self.hidden_size})")フィールドは初期化時に検証されます:
config = Config(model_type="bert", hidden_size=24) # Valid
config = Config(model_type="bert", hidden_size=-1) # Raises StrictDataclassFieldValidationError初期化時にもフィールド間の整合性が検証されます(クラス単位の検証):
# `vocab_size` too small compared to `hidden_size`
config = Config(model_type="bert", hidden_size=32, vocab_size=16) # Raises StrictDataclassClassValidationErrorフィールドは代入時にも検証されます:
config.hidden_size = 512 # Valid
config.hidden_size = -1 # Raises StrictDataclassFieldValidationError割り当て後にクラス全体の検証を再実行するには、.validateを明示的に呼び出す必要があります。
config.validate() # Runs all class validatorsカスタムバリデータ
validated_field を使用して、フィールドに複数のカスタムバリデータを追加できます。バリデータは、単一の引数を受け取り、値が無効な場合に例外を送出する呼び出し可能なオブジェクトです。
from dataclasses import dataclass
from huggingface_hub.dataclasses import strict, validated_field
def multiple_of_64(value: int):
if value % 64 != 0:
raise ValueError(f"Value must be a multiple of 64, got {value}")
@strict
@dataclass
class Config:
hidden_size: int = validated_field(validator=[positive_int, multiple_of_64])この例では、両方のバリデータがhidden_sizeフィールドに適用されます。
追加のキーワード引数
デフォルトでは、strict dataclassesはクラス内で定義されたフィールドのみを受け入れます。@strictデコレーターでaccept_kwargs=Trueを設定することで、追加のキーワード引数を許可できます。
from dataclasses import dataclass
from huggingface_hub.dataclasses import strict
@strict(accept_kwargs=True)
@dataclass
class ConfigWithKwargs:
model_type: str
vocab_size: int = 16
config = ConfigWithKwargs(model_type="bert", vocab_size=30000, extra_field="extra_value")
print(config) # ConfigWithKwargs(model_type='bert', vocab_size=30000, *extra_field='extra_value')*プレフィックスが付けられた追加のキーワード引数は、dataclassの文字列表現に表示されますが、検証されないことを示すためにこのプレフィックスが付けられています。
型ヒントとの統合
Strict dataclassesは型ヒントを尊重し、自動的に検証します。例えば:
from typing import List
from dataclasses import dataclass
from huggingface_hub.dataclasses import strict
@strict
@dataclass
class Config:
layers: List[int]
config = Config(layers=[64, 128]) # Valid
config = Config(layers="not_a_list") # Raises StrictDataclassFieldValidationErrorサポートされている型には、以下が含まれます:
- すべて
- Union
- オプション
- リテラル
- リスト
- Dict
- タプル
- セット
これらの型の任意の組み合わせも可能です。より複雑な型の検証が必要な場合は、カスタムバリデータを通じて行うことができます。
クラスバリデータ
validate_xxx という名前のメソッドは、クラスバリデータとして扱われます。これらのメソッドは、引数として self のみを指定する必要があります。クラスバリデータは初期化時に一度だけ実行され、__post_init__ の直後に呼び出されます。必要に応じて任意の数を定義でき、定義された順序で順次実行されます。
クラスバリデータは、初期化後にフィールドが更新されても自動的に再実行されません。オブジェクトを手動で再検証するには、obj.validate()を呼び出す必要があります。
from dataclasses import dataclass
from huggingface_hub.dataclasses import strict
@strict
@dataclass
class Config:
foo: str
foo_length: int
upper_case: bool = False
def validate_foo_length(self):
if len(self.foo) != self.foo_length:
raise ValueError(f"foo must be {self.foo_length} characters long, got {len(self.foo)}")
def validate_foo_casing(self):
if self.upper_case and self.foo.upper() != self.foo:
raise ValueError(f"foo must be uppercase, got {self.foo}")
config = Config(foo="bar", foo_length=3) # ok
config.upper_case = True
config.validate() # Raises StrictDataclassClassValidationError
Config(foo="abcd", foo_length=3) # Raises StrictDataclassFieldValidationError
Config(foo="Bar", foo_length=3, upper_case=True) # Raises StrictDataclassFieldValidationError
.validate()メソッドは、strict dataclass において予約名です。 予期しない動作を防ぐため、クラスがすでにこのメソッドを定義している場合、StrictDataclassDefinitionErrorエラーが発生します。
API リファレンス
@strict
@strict デコレーターは、データクラスに厳密なバリデーション機能を追加します。
huggingface_hub.dataclasses.strict
< source >( accept_kwargs: bool = False )
データクラスに厳密な検証を追加するためのデコレーター。
このデコレーターは、IDEや静的型付けツールがそのクラスをdataclassとして認識できるようにするため、@dataclassの上に使用する必要があります。
引数なしまたは引数ありで利用できます:
@strict@strict(accept_kwargs=True)
例:
>>> from dataclasses import dataclass
>>> from huggingface_hub.dataclasses import as_validated_field, strict, validated_field
>>> @as_validated_field
>>> def positive_int(value: int):
... if not value >= 0:
... raise ValueError(f"Value must be positive, got {value}")
>>> @strict(accept_kwargs=True)
... @dataclass
... class User:
... name: str
... age: int = positive_int(default=10)
# Initialize
>>> User(name="John")
User(name='John', age=10)
# Extra kwargs are accepted
>>> User(name="John", age=30, lastname="Doe")
User(name='John', age=30, *lastname='Doe')
# Invalid type => raises
>>> User(name="John", age="30")
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
TypeError: Field 'age' expected int, got str (value: '30')
# Invalid value => raises
>>> User(name="John", age=-1)
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
ValueError: Value must be positive, got -1validate_typed_dict
TypedDictクラスで定義された型に辞書が準拠していることを検証するためのメソッドです。
これはTypedDictにおけるdataclassのバリデーションに相当する機能です。型付き辞書はインスタンス化されることがなく(静的型チェッカーによってのみ使用されるため)、バリデーションの手順は手動で呼び出す必要があります。
huggingface_hub.dataclasses.validate_typed_dict
< source >( schema: typedata: dict )
TypedDictクラスで定義された型に辞書が準拠していることを検証します。
内部では、型付き dict は厳密な dataclass に変換され、@strict デコレーターを使用して検証されます。
例:
>>> from typing import Annotated, TypedDict
>>> from huggingface_hub.dataclasses import validate_typed_dict
>>> def positive_int(value: int):
... if not value >= 0:
... raise ValueError(f"Value must be positive, got {value}")
>>> class User(TypedDict):
... name: str
... age: Annotated[int, positive_int]
>>> # Valid data
>>> validate_typed_dict(User, {"name": "John", "age": 30})
>>> # Invalid type for age
>>> validate_typed_dict(User, {"name": "John", "age": "30"})
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
TypeError: Field 'age' expected int, got str (value: '30')
>>> # Invalid value for age
>>> validate_typed_dict(User, {"name": "John", "age": -1})
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
ValueError: Value must be positive, got -1as_validated_field
validated_field を作成するためのデコレーターです。ボイラープレートコードを避けるため、バリデータが1つのみのフィールドに推奨されます。
huggingface_hub.dataclasses.as_validated_field
< source >( validator: Callable )
バリデータ関数をvalidated_field(つまり、カスタムバリデータを持つdataclassフィールド)としてデコレートします。
validated_field
カスタム検証付きのdataclassフィールドを作成します。
huggingface_hub.dataclasses.validated_field
< source >( validator: list[collections.abc.Callable[[typing.Any], None]] | collections.abc.Callable[[typing.Any], None]default: typing.Any = <dataclasses._MISSING_TYPE object at 0x7f9675fda620>default_factory: typing.Any = <dataclasses._MISSING_TYPE object at 0x7f9675fda620>init: bool = Truerepr: bool = Truehash: bool | None = Nonecompare: bool = Truemetadata: dict | None = None**kwargs: typing.Any )
カスタムバリデータ付きのdataclassフィールドを作成します。
フィールドに複数のチェックを適用する際に便利です。ルールを1つだけ適用する場合は、as_validated_fieldデコレーターをご覧ください。
エラー
厳密なデータクラス用のベース例外。
厳密なデータクラスが正しく定義されていない場合にスローされる例外。
クラス huggingface_hub.errors.StrictDataclassFieldValidationError
< source >( field: strcause: Exception )
厳格なデータクラスが特定のフィールドの検証に失敗した場合にスローされる例外。
pydantic(またはattrs、marshmallow_dataclass)を使わないのはなぜですか?
- Pydanticを依存関係に追加することに関する議論は、https://github.com/huggingface/transformers/issues/36329を参照してください。これは重い追加となり、v1とv2の両方をサポートするには慎重なロジックが必要です。
- Pydanticの機能の大部分は必要ありません。特に、自動キャスト、jsonschema、シリアライズ、エイリアスなどに関連する機能は不要です。
- 辞書からクラスをインスタンス化する機能は必要ありません。
- データの破壊的変更(mutation)は行いたくありません。
@strictでは、「validation(検証)」とは「値が有効かどうかを確認すること」を意味します。一方、Pydanticでは、「validation(検証)」とは「値をキャストし、場合によっては変更を加えた上で、それが有効かどうかを確認すること」を意味します。 - 超高速な検証は必要ありません。
@strictは、パフォーマンスが重要な高負荷環境向けには設計されていません。一般的なユースケースは、モデル設定の検証(モデルの実行と比較して一度だけ行われ、無視できるほど軽微)です。これにより、コードを最小限に保つことができます。