Hub Python Library documentation

严格数据类

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

严格数据类

huggingface_hub 包提供了一个用于创建严格数据类的工具。这些是 Python 标准 dataclass 的增强版本,具备额外的验证功能。严格数据类确保字段在初始化和赋值时均经过验证,使其非常适合数据完整性至关重要的场景。

概述

严格 dataclass 使用 @strict 装饰器创建。它们通过以下方式扩展了常规 dataclass 的功能:

  • 基于类型提示验证字段类型
  • 支持自定义验证器以进行额外检查
  • 在构造函数中可选地允许任意关键字参数
  • 在初始化和赋值时验证字段

优势

  • 数据完整性:确保字段始终包含有效数据
  • 易用性:与 Python 的 dataclass 模块无缝集成
  • 灵活性:支持自定义验证器以处理复杂的验证逻辑
  • 轻量级:无需 Pydantic、attrs 或类似库等额外依赖

用法

基础示例

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

字段在初始化期间经过验证:

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

在初始化期间(按类验证)也会验证字段之间的一致性:

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

在赋值时,字段也会经过验证:

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

要在分配后重新运行整个类的验证,必须显式调用 .validate:

config.validate()  # Runs all class validators

自定义验证器

您可以使用 validated_field 为字段附加多个自定义验证器。验证器是一个可调用对象,它接受单个参数,并在值无效时引发异常。

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

在此示例中,两个验证器都应用于hidden_size字段。

其他关键字参数

默认情况下,strict dataclasses 仅接受在类中定义的字段。您可以在 @strict 装饰器中设置 accept_kwargs=True 来允许额外的关键字参数。

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

数据类的字符串表示中会包含额外的关键字参数,但会以 * 作为前缀,以突出显示这些参数未经验证。

与类型提示的集成

严格 dataclass 会遵循类型提示并自动进行验证。例如:

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

支持的类型包括:

  • 任意
  • Union
  • 可选
  • 字面量
  • 列表
  • Dict
  • 元组
  • 设置

以及这些类型的任意组合。如果您需要更复杂的类型验证,可以通过自定义验证器来实现。

类验证器

名为 validate_xxx 的方法被视为类验证器。这些方法只能接受 self 作为参数。类验证器在初始化期间运行一次,紧随 __post_init__ 之后。您可以定义任意数量的类验证器——它们将按照出现的顺序依次执行。

请注意,在初始化后更新字段时,类验证器不会自动重新运行。若要手动重新验证对象,需要调用 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

.validate() 方法是严格数据类上的保留名称。 为防止出现意外行为,如果您的类已经定义了该方法,则会引发 StrictDataclassDefinitionError 错误。

API 参考

@strict

@strict 装饰器为数据类增强了严格验证功能。

huggingface_hub.dataclasses.strict

< >

( accept_kwargs: bool = False )

参数

  • cls — 要转换为严格数据类的类。
  • accept_kwargs (bool, 可选) — 如果为 True,则允许在 __init__ 中使用任意关键字参数。默认为 False。

用于为 dataclass 添加严格验证的装饰器。

此装饰器必须位于 @dataclass 之上,以确保 IDE 和静态类型检查工具将该类识别为 dataclass。

可以带参数或不带参数使用:

  • @strict
  • @strict(accept_kwargs=True)

示例:

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

用于验证字典是否符合 TypedDict 类中定义的类型的方法。

这是针对 TypedDict 的 dataclass 验证等效操作。由于类型化字典永远不会被实例化(仅由静态类型检查器使用),因此必须手动调用验证步骤。

huggingface_hub.dataclasses.validate_typed_dict

< >

( schema: typedata: dict )

参数

  • schema (type[TypedDictType]) — 定义预期结构和类型的 TypedDict 类。
  • data (dict) — 要验证的字典。

引发

StrictDataclassFieldValidationError

  • StrictDataclassFieldValidationError — 如果字典中的任何字段不符合预期的类型。

验证字典是否符合 TypedDict 类中定义的类型。

在底层,类型化字典会被转换为严格的数据类,并使用 @strict 装饰器进行验证。

示例:

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

用于创建 validated_field 的装饰器。对于仅包含单个验证器的字段,推荐使用此装饰器以避免样板代码。

huggingface_hub.dataclasses.as_validated_field

< >

( validator: Callable )

参数

  • validator (Callable) — 一个接收值作为输入的方法,如果该值无效,则抛出 ValueError/TypeError。

将验证器函数装饰为validated_field(即带有自定义验证器的 dataclass 字段)。

validated_field

创建一个带有自定义验证的数据类字段。

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 )

参数

  • validator (Callable 或 list[Callable]) — 一个接收值作为输入的方法,如果该值无效则引发 ValueError/TypeError。 可以是验证器的列表,以应用多项检查。
  • **kwargs — 传递给 dataclasses.field() 的额外参数。

创建一个带有自定义验证器的 dataclass 字段。

适用于对字段应用多项检查。如果只应用一条规则,请查看 as_validated_field 装饰器。

错误

类 huggingface_hub.errors.StrictDataclassError

< >

( )

严格数据类的基类异常。

类 huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

当严格 dataclass 定义不正确时抛出的异常。

类 huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( field: strcause: Exception )

当严格数据类在验证某个字段时失败,会抛出此异常。

为什么不用 pydantic?(或者 attrs?或者 marshmallow_dataclass?)

  • 请参阅 https://github.com/huggingface/transformers/issues/36329 中关于将 Pydantic 添加为依赖项的讨论。这将是一个较重的添加,并且需要谨慎的逻辑来同时支持 v1 和 v2。
  • 我们并不需要 Pydantic 的大部分功能,尤其是那些与自动类型转换、jsonschema、序列化、别名等相关的功能。
  • 我们不需要从字典实例化类的能力。
  • 我们不想修改数据。在 @strict 中,“validation” 指的是“检查值是否有效”。而在 Pydantic 中,“validation” 指的是“对值进行类型转换(可能会修改该值),然后检查其是否有效”。
  • 我们不需要极快的验证速度。@strict 并非为性能至关重要的重负载场景而设计。常见用例包括验证模型配置(仅执行一次,与运行模型相比开销可忽略不计)。这让我们能够保持代码的极简。
Update on GitHub