Hub Python Library documentation

Dataclasses estritas

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Dataclasses estritas

O pacote huggingface_hub fornece um utilitário para criar dataclasses estritas. Estas são versões aprimoradas do dataclass padrão do Python, com recursos adicionais de validação. As dataclasses estritas garantem que os campos sejam validados tanto durante a inicialização quanto na atribuição, tornando-as ideais para cenários em que a integridade dos dados é crítica.

Visão geral

Dataclasses estritas são criadas usando o decorador @strict. Elas estendem a funcionalidade de dataclasses regulares por:

  • Validando tipos de campo com base em type hints
  • Suporte a validadores personalizados para verificações adicionais
  • Permitir opcionalmente argumentos de palavra-chave arbitrários no construtor
  • Validando campos tanto na inicialização quanto durante a atribuição

Benefícios

  • Integridade dos dados: Garante que os campos contenham sempre dados válidos
  • Facilidade de uso: Integração perfeita com o módulo dataclass do Python
  • Flexibilidade: Suporta validadores personalizados para lógica de validação complexa
  • Leve: Não requer dependências adicionais, como Pydantic, attrs ou bibliotecas semelhantes

Uso

Exemplo Básico

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})")

Os campos são validados durante a inicialização:

config = Config(model_type="bert", hidden_size=24)   # Valid
config = Config(model_type="bert", hidden_size=-1)   # Raises StrictDataclassFieldValidationError

A consistência entre os campos também é validada durante a inicialização (validação por classe):

# `vocab_size` too small compared to `hidden_size`
config = Config(model_type="bert", hidden_size=32, vocab_size=16)   # Raises StrictDataclassClassValidationError

Os campos também são validados durante a atribuição:

config.hidden_size = 512  # Valid
config.hidden_size = -1   # Raises StrictDataclassFieldValidationError

Para reexecutar a validação de toda a classe após a atribuição, você deve chamar explicitamente .validate:

config.validate()  # Runs all class validators

Validadores Personalizados

Você pode anexar vários validadores personalizados a campos usando validated_field. Um validador é um objeto chamável que recebe um único argumento e levanta uma exceção se o valor for inválido.

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

Neste exemplo, ambos os validadores são aplicados ao campo hidden_size.

Argumentos de palavra-chave adicionais

Por padrão, dataclasses estritas aceitam apenas campos definidos na classe. Você pode permitir argumentos de palavra-chave adicionais definindo accept_kwargs=True no decorador @strict.

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

Argumentos de palavra-chave adicionais aparecem na representação em string do dataclass, mas são prefixados com * para destacar que não são validados.

Integração com Type Hints

Dataclasses estritas respeitam as anotações de tipo e as validam automaticamente. Por exemplo:

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

Os tipos suportados incluem:

  • Qualquer
  • União
  • Opcional
  • Literal
  • Lista
  • Dict
  • Tuple
  • Conjunto

E qualquer combinação desses tipos. Se você precisar de validação de tipos mais complexa, pode fazê-la por meio de um validador personalizado.

Validadores de classe

Métodos nomeados validate_xxx são tratados como validadores de classe. Esses métodos devem receber apenas self como argumento. Os validadores de classe são executados uma vez durante a inicialização, logo após __post_init__. Você pode definir quantos deles precisar — eles serão executados sequencialmente na ordem em que aparecem.

Observe que os validadores de classe não são executados automaticamente novamente quando um campo é atualizado após a inicialização. Para revalidar o objeto manualmente, é necessário chamar 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

O método .validate() é um nome reservado em dataclasses estritas. Para evitar comportamentos inesperados, um erro StrictDataclassDefinitionError será lançado se a sua classe já definir um.

Referência da API

@strict

O decorador @strict aprimora uma dataclass com validação estrita.

huggingface_hub.dataclasses.strict

< >

( accept_kwargs: bool = False )

Parâmetros

  • cls — A classe a ser convertida em um dataclass estrito.
  • accept_kwargs (bool, opcional) — Se True, permite argumentos de palavra-chave arbitrários em __init__. O padrão é False.

Decorator para adicionar validação estrita a uma dataclass.

Este decorador deve ser usado acima de @dataclass para garantir que as IDEs e as ferramentas de tipagem estática reconheçam a classe como um dataclass.

Pode ser usado com ou sem argumentos:

  • @strict
  • @strict(accept_kwargs=True)

Exemplo:

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

Método para validar que um dicionário está em conformidade com os tipos definidos em uma classe TypedDict.

Esta é a equivalente à validação de dataclass, mas para TypedDicts. Como dicts tipados nunca são instanciados (são usados apenas por verificadores de tipo estáticos), a etapa de validação deve ser chamada manualmente.

huggingface_hub.dataclasses.validate_typed_dict

< >

( schema: typedata: dict )

Parâmetros

  • schema (type[TypedDictType]) — A classe TypedDict que define a estrutura e os tipos esperados.
  • data (dict) — O dicionário a ser validado.

Exceções

StrictDataclassFieldValidationError

  • StrictDataclassFieldValidationError — Se algum campo no dicionário não estiver em conformidade com o tipo esperado.

Valide se um dicionário está em conformidade com os tipos definidos em uma classe TypedDict.

Por baixo dos panos, o typed dict é convertido em uma dataclass estrita e validado usando o decorador @strict.

Exemplo:

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

Decorador para criar um validated_field. Recomendado para campos com um único validador para evitar código repetitivo.

huggingface_hub.dataclasses.as_validated_field

< >

( validator: Callable )

Parâmetros

  • validator (Callable) — Um método que recebe um valor como entrada e levanta ValueError/TypeError se o valor for inválido.

Decora uma função validadora como um validated_field (ou seja, um campo de dataclass com um validador personalizado).

validated_field

Cria um campo de dataclass com validação personalizada.

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 )

Parâmetros

  • validator (Callable ou list[Callable]) — Um método que recebe um valor como entrada e levanta ValueError/TypeError se o valor for inválido. Pode ser uma lista de validadores para aplicar múltiplas verificações.
  • **kwargs — Argumentos adicionais para passar para dataclasses.field().

Crie um campo de dataclass com um validador personalizado.

Útil para aplicar várias verificações a um campo. Se for aplicar apenas uma regra, confira o decorador as_validated_field.

Erros

classe huggingface_hub.errors.StrictDataclassError

< >

( )

Exceção base para dataclasses estritas.

classe huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

Exceção lançada quando uma dataclass estrita é definida incorretamente.

classe huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( field: strcause: Exception )

Exceção lançada quando um dataclass estrito falha na validação de um campo específico.

Por que não usar pydantic? (ou attrs? ou marshmallow_dataclass?)

  • Veja a discussão em https://github.com/huggingface/transformers/issues/36329 sobre a adição do Pydantic como dependência. Seria uma adição pesada e exigiria uma lógica cuidadosa para suportar tanto a v1 quanto a v2.
  • Não precisamos da maioria dos recursos do Pydantic, especialmente aqueles relacionados a conversão automática, jsonschema, serialização, aliases, etc.
  • Não precisamos da capacidade de instanciar uma classe a partir de um dicionário.
  • Não queremos mutar dados. Em @strict, “validação” significa “verificar se um valor é válido”. No Pydantic, “validação” significa “converter um valor, possivelmente mutando-o, e então verificar se ele é válido”.
  • Não precisamos de validação extremamente rápida. @strict não foi projetado para cargas pesadas em que o desempenho é crítico. Os casos de uso comuns envolvem a validação de uma configuração de modelo (executada uma única vez e insignificante em comparação com a execução de um modelo). Isso nos permite manter o código minimalista.
Update on GitHub