Hub Python Library documentation

Dataclasses strictes

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v2.4.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Dataclasses strictes

Le package huggingface_hub fournit un utilitaire pour créer des dataclasses strictes. Il s’agit de versions améliorées des dataclass standard de Python, dotées de fonctionnalités de validation supplémentaires. Les dataclasses strictes garantissent que les champs sont validés à la fois lors de l’initialisation et de l’assignation, ce qui les rend idéales pour les scénarios où l’intégrité des données est cruciale.

Aperçu

Les dataclasses stricts sont créés à l'aide du décorateur @strict. Ils étendent la fonctionnalité des dataclasses classiques en :

  • Validation des types de champs en fonction des annotations de type
  • Prise en charge de validateurs personnalisés pour des vérifications supplémentaires
  • Autoriser facultativement des arguments de mot-clé arbitraires dans le constructeur
  • Validation des champs à l'initialisation et lors de l'assignation

Avantages

  • Intégrité des données : Garantit que les champs contiennent toujours des données valides
  • Facilité d'utilisation : Intégration transparente avec le module dataclass de Python
  • Flexibilité : prend en charge des validateurs personnalisés pour une logique de validation complexe
  • Léger : N'exige aucune dépendance supplémentaire telle que Pydantic, attrs ou des bibliothèques similaires

Utilisation

Exemple de base

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

Les champs sont validés lors de l'initialisation :

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

La cohérence entre les champs est également validée lors de l’initialisation (validation par classe) :

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

Les champs sont également validés lors de l'assignation :

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

Pour relancer la validation de la classe après l’attribution, vous devez appeler explicitement .validate :

config.validate()  # Runs all class validators

Validateurs personnalisés

Vous pouvez attacher plusieurs validateurs personnalisés à des champs à l’aide de validated_field. Un validateur est un objet appelable qui prend un seul argument et lève une exception si la valeur est invalide.

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

Dans cet exemple, les deux validateurs sont appliqués au champ hidden_size.

Arguments de mot-clé supplémentaires

Par défaut, les dataclasses strictes n'acceptent que les champs définis dans la classe. Vous pouvez autoriser des arguments de mot-clé supplémentaires en définissant accept_kwargs=True dans le décorateur @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')

Les arguments de mot-clé supplémentaires apparaissent dans la représentation en chaîne de la dataclass, mais sont préfixés par * pour souligner qu’ils ne sont pas validés.

Intégration avec les Type Hints

Les dataclasses strictes respectent les annotations de type et les valident automatiquement. Par exemple :

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

Les types pris en charge incluent :

  • Tous
  • Union
  • Facultatif
  • Littéral
  • Liste
  • Dict
  • Tuple
  • Ensemble

Et toute combinaison de ces types. Si vous avez besoin d'une validation de type plus complexe, vous pouvez le faire à l'aide d'un validateur personnalisé.

Validateurs de classes

Les méthodes nommées validate_xxx sont traitées comme des validateurs de classe. Ces méthodes ne doivent prendre que self comme argument. Les validateurs de classe sont exécutés une seule fois lors de l’initialisation, juste après __post_init__. Vous pouvez en définir autant que nécessaire : ils seront exécutés séquentiellement dans l’ordre où ils apparaissent.

Notez que les validateurs de classe ne sont pas relancés automatiquement lorsqu'un champ est mis à jour après l'initialisation. Pour revalider manuellement l'objet, vous devez appeler 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

La méthode .validate() est un nom réservé pour les dataclasses strictes. Afin d'éviter tout comportement inattendu, une erreur StrictDataclassDefinitionError sera levée si votre classe en définit déjà une.

Référence de l'API

@strict

Le décorateur @strict renforce une dataclass avec une validation stricte.

huggingface_hub.dataclasses.strict

< >

( accept_kwargs: bool = False )

Paramètres

  • cls — La classe à convertir en dataclass stricte.
  • accept_kwargs (bool, facultatif) — Si True, autorise des arguments de mots-clés arbitraires dans __init__. Valeur par défaut : False.

Décorateur pour ajouter une validation stricte à une dataclass.

Ce décorateur doit être utilisé au-dessus de @dataclass pour s’assurer que les IDE et les outils de typage statique reconnaissent la classe comme un dataclass.

Peut être utilisé avec ou sans arguments :

  • @strict
  • @strict(accept_kwargs=True)

Exemple :

>>> 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éthode permettant de vérifier qu'un dictionnaire est conforme aux types définis dans une classe TypedDict.

C'est l'équivalent de la validation de dataclass, mais pour les TypedDict. Comme les typed dicts ne sont jamais instanciés (ils ne sont utilisés que par les vérificateurs de types statiques), l'étape de validation doit être appelée manuellement.

huggingface_hub.dataclasses.validate_typed_dict

< >

( schema: typedata: dict )

Paramètres

  • schema (type[TypedDictType]) — La classe TypedDict définissant la structure et les types attendus.
  • data (dict) — Le dictionnaire à valider.

Lève

StrictDataclassFieldValidationError

  • StrictDataclassFieldValidationError — Si un champ du dictionnaire ne respecte pas le type attendu.

Valider qu'un dictionnaire est conforme aux types définis dans une classe TypedDict.

Sous le capot, le dictionnaire typé est converti en dataclass stricte et validé à l'aide du décorateur @strict.

Exemple :

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

Décorateur pour créer un validated_field. Recommandé pour les champs avec un seul validateur afin d'éviter le code répétitif.

huggingface_hub.dataclasses.as_validated_field

< >

( validator: Callable )

Paramètres

  • validator (Callable) — Méthode qui prend une valeur en entrée et lève ValueError/TypeError si la valeur est invalide.

Décore une fonction de validation en tant que validated_field (c’est-à-dire un champ de dataclass avec un validateur personnalisé).

validated_field

Crée un champ de dataclass avec une validation personnalisée.

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 0x7fabedd4e6b0>default_factory: typing.Any = <dataclasses._MISSING_TYPE object at 0x7fabedd4e6b0>init: bool = Truerepr: bool = Truehash: bool | None = Nonecompare: bool = Truemetadata: dict | None = None**kwargs: typing.Any )

Paramètres

  • validator (Callable ou list[Callable]) — Une méthode qui prend une valeur en entrée et lève ValueError/TypeError si la valeur est invalide. Peut être une liste de validateurs pour appliquer plusieurs vérifications.
  • **kwargs — Arguments supplémentaires à passer à dataclasses.field().

Créer un champ de dataclass avec un validateur personnalisé.

Utile pour appliquer plusieurs vérifications à un champ. Si vous n'appliquez qu'une seule règle, consultez le décorateur as_validated_field.

Erreurs

classe huggingface_hub.errors.StrictDataclassError

< >

( )

Exception de base pour les dataclasses strictes.

classe huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

Exception levée lorsqu'une dataclass stricte est définie de manière incorrecte.

classe huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( field: strcause: Exception )

Exception levée lorsqu'une dataclass stricte échoue à la validation pour un champ donné.

Pourquoi ne pas utiliser pydantic ? (ou attrs ? ou marshmallow_dataclass ?)

  • Voir la discussion dans https://github.com/huggingface/transformers/issues/36329 concernant l’ajout de Pydantic en tant que dépendance. Il s’agirait d’une dépendance lourde et nécessiterait une logique rigoureuse pour prendre en charge à la fois les versions v1 et v2.
  • Nous n’avons pas besoin de la plupart des fonctionnalités de Pydantic, en particulier celles liées au cast automatique, à jsonschema, à la sérialisation, aux alias, etc.
  • Nous n’avons pas besoin de la capacité d’instantier une classe à partir d’un dictionnaire.
  • Nous ne souhaitons pas muter les données. Dans @strict, « validation » signifie « vérifier si une valeur est valide ». Dans Pydantic, « validation » signifie « convertir une valeur, éventuellement en la modifiant, puis vérifier si elle est valide ».
  • Nous n’avons pas besoin d’une validation ultra-rapide. @strict n’est pas conçu pour des charges lourdes où les performances sont critiques. Les cas d’usage courants consistent à valider la configuration d’un modèle (opération effectuée une seule fois et négligeable par rapport à l’exécution d’un modèle). Cela nous permet de garder le code minimal.
Update on GitHub