Hub Python Library documentation
Dataclasses estrictos
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
dataclassde 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 StrictDataclassFieldValidationErrorLa 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 StrictDataclassClassValidationErrorLos campos también se validan durante la asignación:
config.hidden_size = 512 # Valid
config.hidden_size = -1 # Raises StrictDataclassFieldValidationErrorPara 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 validatorsValidadores 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 StrictDataclassFieldValidationErrorLos 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 StrictDataclassFieldValidationErrorEl método
.validate()es un nombre reservado en dataclasses estrictos. Para evitar comportamientos inesperados, se lanzará un errorStrictDataclassDefinitionErrorsi su clase ya define uno.
Referencia de la API
@strict
El decorador @strict mejora un dataclass con validación estricta.
huggingface_hub.dataclasses.strict
< source >( accept_kwargs: bool = 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 -1validate_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
< source >( schema: typedata: dict )
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 -1as_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
< source >( validator: Callable )
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
< 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 )
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
Excepción base para dataclasses estrictos.
Excepción lanzada cuando un dataclass estricto se define de forma incorrecta.
clase huggingface_hub.errors.StrictDataclassFieldValidationError
< source >( 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.
@strictno 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.