Hub Python Library documentation

Strict Dataclasses

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Strict Dataclasses

huggingface_hub 패키지는 strict dataclass을 생성하는 유틸리티를 제공합니다. 이는 Python의 표준 dataclass에 추가적인 검증 기능이 강화된 버전입니다. Strict dataclass는 초기화 및 할당 시 모두 필드가 검증되도록 보장하여 데이터 무결성이 중요한 시나리오에 이상적입니다.

개요

Strict dataclasses는 @strict 데코레이터를 사용하여 생성됩니다. 이들은 다음과 같은 방식으로 일반 dataclasses의 기능을 확장합니다:

  • 타입 힌트에 기반한 필드 타입 검증
  • 추가 검사를 위한 사용자 정의 검증기 지원
  • 생성자에서 임의의 키워드 인수를 선택적으로 허용
  • 초기화 및 할당 시 필드 검증

장점

  • 데이터 무결성: 필드가 항상 유효한 데이터를 포함하도록 보장
  • 사용 편의성: 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})")

Fields는 초기화 중에 검증됩니다:

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

Custom 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의 문자열 표현에 나타나지만, 검증되지 않음을 강조하기 위해 * 접두사가 붙습니다.

Type Hints와의 통합

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
  • 선택 사항
  • Literal
  • 목록
  • Dict
  • Tuple
  • 설정

그리고 이러한 유형의 모든 조합도 가능합니다. 더 복잡한 유형 검증이 필요하면 사용자 정의 검증기를 통해 수행할 수 있습니다.

클래스 검증기

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 데코레이터는 dataclass에 엄격한 검증을 추가합니다.

huggingface_hub.dataclasses.strict

< >

( accept_kwargs: bool = False )

매개변수

  • cls — 엄격한 dataclass로 변환할 클래스.
  • accept_kwargs (bool, 선택 사항) — True인 경우 __init__에서 임의의 키워드 인수를 허용합니다. 기본값은 False입니다.

dataclass에 엄격한 검증을 추가하는 데코레이터

이 데코레이터는 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 검증과 동일한 기능입니다. typed dict는 인스턴스화되지 않으므로(정적 타입 체커에서만 사용됨) 검증 단계는 수동으로 호출해야 합니다.

huggingface_hub.dataclasses.validate_typed_dict

< >

( schema: typedata: dict )

매개변수

  • schema (type[TypedDictType]) — 기대되는 구조와 타입을 정의하는 TypedDict 클래스.
  • data (dict) — 검증할 사전.

다음 예외가 발생합니다

StrictDataclassFieldValidationError

  • StrictDataclassFieldValidationError — 사전의 필드 중 하나라도 예상된 타입에 부합하지 않는 경우.

TypedDict 클래스에 정의된 타입에 따라 사전이 준수하는지 검증합니다.

내부적으로 typed 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을 생성하는 데코레이터입니다. 불필요한 코드 반복을 피하기 위해 단일 검증기를 사용하는 필드에 권장됩니다.

huggingface_hub.dataclasses.as_validated_field

< >

( validator: Callable )

매개변수

  • validator (Callable) — 값을 입력으로 받아 해당 값이 유효하지 않으면 ValueError/TypeError를 발생시키는 메서드.

validated_field로(즉, 사용자 정의 검증기를 가진 dataclass 필드로) validator 함수를 장식합니다.

validated_field

custom validation을 가진 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 필드를 생성합니다.

필드에 여러 검사를 적용하는 데 유용합니다. 규칙을 하나만 적용하는 경우 as_validated_field 데코레이터를 확인해 보세요.

오류

클래스 huggingface_hub.errors.StrictDataclassError

< >

( )

엄격한 dataclass의 기본 예외입니다.

class huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

strict dataclass가 잘못 정의된 경우 발생하는 예외입니다.

class huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( field: strcause: Exception )

strict dataclass가 특정 필드에 대한 검증을 실패할 때 발생하는 예외입니다.

pydantic (또는 attrs? 또는 marshmallow_dataclass?)를 사용하지 않는 이유는 무엇인가요?

  • Pydantic을 의존성으로 추가하는 것에 대한 논의는 https://github.com/huggingface/transformers/issues/36329에서 확인하실 수 있습니다. 이는 상당한 부하를 유발하며, v1과 v2를 모두 지원하려면 신중한 로직이 필요합니다.
  • Pydantic의 대부분의 기능, 특히 자동 캐스팅, jsonschema, 직렬화, 별칭 등과 관련된 기능은 필요하지 않습니다.
  • 사전에서 클래스를 인스턴스화할 수 있는 기능은 필요하지 않습니다.
  • 데이터를 변경하지 않으려는 것입니다. @strict에서 “validation”은 “값이 유효한지 확인하는 것”을 의미합니다. Pydantic에서 “validation”은 “값을 캐스팅하고, 필요에 따라 변경한 후, 유효한지 확인하는 것”을 의미합니다.
  • 매우 빠른 검증은 필요하지 않습니다. @strict는 성능이 중요한 고부하 환경용으로 설계되지 않았습니다. 일반적인 사용 사례는 모델 구성을 검증하는 것이며(모델 실행에 비해 한 번만 수행되고 무시할 수 있을 정도로 경미함), 이를 통해 코드를 최소한으로 유지할 수 있습니다.
Update on GitHub