Hub Python Library documentation

厳密なデータクラス

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

厳密なデータクラス

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

< >

( accept_kwargs: bool = False )

パラメータ

  • cls — 厳密なデータクラスに変換するクラス。
  • accept_kwargs (bool, 省略可) — True の場合、__init__ で任意のキーワード引数を許可します。デフォルトは 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 -1

validate_typed_dict

TypedDictクラスで定義された型に辞書が準拠していることを検証するためのメソッドです。

これはTypedDictにおけるdataclassのバリデーションに相当する機能です。型付き辞書はインスタンス化されることがなく(静的型チェッカーによってのみ使用されるため)、バリデーションの手順は手動で呼び出す必要があります。

huggingface_hub.dataclasses.validate_typed_dict

< >

( schema: typedata: dict )

パラメータ

  • schema (type[TypedDictType]) — 期待される構造と型を定義する TypedDict クラス。
  • data (dict) — 検証対象の辞書。

例外

StrictDataclassFieldValidationError

  • StrictDataclassFieldValidationError — 辞書のいずれかのフィールドが期待される型に準拠していない場合。

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 -1

as_validated_field

validated_field を作成するためのデコレーターです。ボイラープレートコードを避けるため、バリデータが1つのみのフィールドに推奨されます。

huggingface_hub.dataclasses.as_validated_field

< >

( validator: Callable )

パラメータ

  • validator (Callable) — 値を入力として受け取り、値が無効な場合はValueError/TypeErrorを送出するメソッド。

バリデータ関数をvalidated_field(つまり、カスタムバリデータを持つdataclassフィールド)としてデコレートします。

validated_field

カスタム検証付きのdataclassフィールドを作成します。

huggingface_hub.dataclasses.validated_field

< >

( 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 )

パラメータ

  • validator (Callable または list[Callable]) — 値を入力として受け取り、値が無効な場合は ValueError/TypeError を送出するメソッドです。複数のチェックを適用するために、バリデータの一覧を指定できます。
  • **kwargs — dataclasses.field()に渡す追加の引数。

カスタムバリデータ付きのdataclassフィールドを作成します。

フィールドに複数のチェックを適用する際に便利です。ルールを1つだけ適用する場合は、as_validated_fieldデコレーターをご覧ください。

エラー

クラス huggingface_hub.errors.StrictDataclassError

< >

( )

厳密なデータクラス用のベース例外。

クラス huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

厳密なデータクラスが正しく定義されていない場合にスローされる例外。

クラス huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( 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は、パフォーマンスが重要な高負荷環境向けには設計されていません。一般的なユースケースは、モデル設定の検証(モデルの実行と比較して一度だけ行われ、無視できるほど軽微)です。これにより、コードを最小限に保つことができます。
Update on GitHub