Hub Python Library documentation

Dataclasses estrictos

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Dataclasses estrictos

El paquete huggingface_hub ofrece una utilidad para crear dataclasses estrictos. Son versiones mejoradas de los dataclass estándar de Python con funciones de validación adicionales. Los dataclasses estrictos garantizan que los campos se validen tanto durante la inicialización como durante la asignación, lo que los hace ideales para escenarios donde la integridad de los datos es crítica.

Resumen

Los dataclasses estrictos se crean usando el decorador @strict. Extienden la funcionalidad de los dataclasses regulares mediante:

  • Validación de tipos de campos basándose en las indicaciones de tipo
  • Soporte para validadores personalizados para comprobaciones adicionales
  • Permitir opcionalmente argumentos de palabra clave arbitrarios en el constructor
  • Validar campos tanto en la inicialización como durante la asignación

Ventajas

  • Integridad de los datos: Garantiza que los campos contengan siempre datos válidos
  • Facilidad de uso: Se integra de forma transparente con el módulo dataclass de Python
  • Flexibilidad: Admite validadores personalizados para lógica de validación compleja
  • Ligero: No requiere dependencias adicionales como Pydantic, attrs o bibliotecas similares

Uso

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

Los campos se validan durante la inicialización:

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

La coherencia entre campos también se valida durante la inicialización (validación a nivel de clase):

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

Los campos también se validan durante la asignación:

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

Para volver a ejecutar la validación de toda la clase después de la asignación, debe llamar explícitamente a .validate:

config.validate()  # Runs all class validators

Validadores personalizados

Puede adjuntar varios validadores personalizados a campos usando validated_field. Un validador es un objeto invocable que toma un único argumento y lanza una excepción si el valor no es vá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])

En este ejemplo, ambos validadores se aplican al campo hidden_size.

Argumentos de palabra clave adicionales

Por defecto, los dataclasses estrictos solo aceptan campos definidos en la clase. Puedes permitir argumentos de palabra clave adicionales estableciendo accept_kwargs=True en el 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')

Los argumentos de palabra clave adicionales aparecen en la representación en cadena del dataclass, pero se prefijan con * para destacar que no se validan.

Integración con Type Hints

Los dataclasses estrictos respetan las anotaciones de tipo y las validan automáticamente. Por ejemplo:

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

Los tipos admitidos incluyen:

  • Cualquiera
  • Unión
  • Opcional
  • Literal
  • Lista
  • Dict
  • Tuple
  • Set

Y cualquier combinación de estos tipos. Si necesitas una validación de tipos más compleja, puedes realizarla a través de un validador personalizado.

Validadores de clase

Los métodos con nombre validate_xxx se tratan como validadores de clase. Estos métodos deben aceptar únicamente self como argumento. Los validadores de clase se ejecutan una vez durante la inicialización, justo después de __post_init__. Puede definir tantos como necesite; se ejecutarán de forma secuencial en el orden en que aparecen.

Tenga en cuenta que los validadores de clase no se ejecutan automáticamente de nuevo cuando un campo se actualiza después de la inicialización. Para revalidar el objeto manualmente, debe llamar a 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

El método .validate() es un nombre reservado en dataclasses estrictos. Para evitar comportamientos inesperados, se lanzará un error StrictDataclassDefinitionError si su clase ya define uno.

Referencia de la API

@strict

El decorador @strict mejora un dataclass con validación estricta.

huggingface_hub.dataclasses.strict

< >

( accept_kwargs: bool = False )

Parámetros

  • cls — La clase que se convertirá en un dataclass estricto.
  • accept_kwargs (bool, opcional) — Si es True, permite argumentos de palabras clave arbitrarios en __init__. El valor predeterminado es False.

Decorador para añadir validación estricta a un dataclass.

Este decorador debe usarse sobre @dataclass para garantizar que las IDE y las herramientas de tipado estático reconozcan la clase como un dataclass.

Puede usarse con o sin argumentos:

  • @strict
  • @strict(accept_kwargs=True)

Ejemplo:

>>> 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 un diccionario cumple con los tipos definidos en una clase TypedDict.

Esto es equivalente a la validación de dataclass, pero para TypedDict. Dado que los typed dicts nunca se instancian (solo se usan por los verificadores de tipos estáticos), el paso de validación debe llamarse manualmente.

huggingface_hub.dataclasses.validate_typed_dict

< >

( schema: typedata: dict )

Parámetros

  • schema (type[TypedDictType]) — La clase TypedDict que define la estructura y los tipos esperados.
  • data (dict) — El diccionario a validar.

Lanza

StrictDataclassFieldValidationError

  • StrictDataclassFieldValidationError — Si algún campo del diccionario no cumple con el tipo esperado.

Validar que un diccionario cumpla con los tipos definidos en una clase TypedDict.

Por debajo, el diccionario tipado se convierte en una dataclass estricta y se valida mediante el decorador @strict.

Ejemplo:

>>> 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 crear un validated_field. Recomendado para campos con un único validador para evitar código repetitivo.

huggingface_hub.dataclasses.as_validated_field

< >

( validator: Callable )

Parámetros

  • validator (Callable) — Un método que toma un valor como entrada y lanza ValueError/TypeError si el valor no es válido.

Decora una función validadora como un validated_field (es decir, un campo de dataclass con un validador personalizado).

validated_field

Crea un campo de dataclass con validación 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 o list[Callable]) — Un método que toma un valor como entrada y lanza ValueError/TypeError si el valor no es válido. Puede ser una lista de validadores para aplicar varias comprobaciones.
  • **kwargs — Argumentos adicionales para pasar a dataclasses.field().

Crea un campo de dataclass con un validador personalizado.

Útil para aplicar varias comprobaciones a un campo. Si solo se aplica una regla, consulte el decorador as_validated_field.

Errores

clase huggingface_hub.errors.StrictDataclassError

< >

( )

Excepción base para dataclasses estrictos.

clase huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

Excepción lanzada cuando un dataclass estricto se define de forma incorrecta.

clase huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( field: strcause: Exception )

Excepción lanzada cuando un dataclass estricto no supera la validación para un campo determinado.

¿Por qué no usar pydantic? (o attrs? o marshmallow_dataclass?)

  • Véase la discusión en https://github.com/huggingface/transformers/issues/36329 sobre la adición de Pydantic como dependencia. Sería una adición pesada y requeriría una lógica cuidadosa para soportar tanto v1 como v2.
  • No necesitamos la mayoría de las funciones de Pydantic, especialmente las relacionadas con el casteo automático, jsonschema, serialización, alias, etc.
  • No necesitamos la capacidad de instanciar una clase a partir de un diccionario.
  • No queremos mutar los datos. En @strict, “validation” significa “comprobar si un valor es válido”. En Pydantic, “validation” significa “convertir un valor, posiblemente mutándolo, y luego comprobar si es válido”.
  • No necesitamos una validación ultrarrápida. @strict no está diseñado para cargas pesadas donde el rendimiento es crítico. Los casos de uso habituales implican validar la configuración de un modelo (se realiza una sola vez y es despreciable en comparación con la ejecución de un modelo). Esto nos permite mantener el código al mínimo.
Update on GitHub