Hub Python Library documentation
Dataclasses estritas
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
dataclassdo 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 StrictDataclassFieldValidationErrorA 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 StrictDataclassClassValidationErrorOs campos também são validados durante a atribuição:
config.hidden_size = 512 # Valid
config.hidden_size = -1 # Raises StrictDataclassFieldValidationErrorPara reexecutar a validação de toda a classe após a atribuição, você deve chamar explicitamente .validate:
config.validate() # Runs all class validatorsValidadores 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 StrictDataclassFieldValidationErrorOs 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 StrictDataclassFieldValidationErrorO método
.validate()é um nome reservado em dataclasses estritas. Para evitar comportamentos inesperados, um erroStrictDataclassDefinitionErrorserá 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
< source >( accept_kwargs: bool = 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 -1validate_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
< source >( 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 -1as_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
< source >( validator: Callable )
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
< 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 )
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
Exceção base para dataclasses estritas.
Exceção lançada quando uma dataclass estrita é definida incorretamente.
classe huggingface_hub.errors.StrictDataclassFieldValidationError
< source >( 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.
@strictnã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.