CodeSampleX

示例

attrs 26.1.0: Programmatically generate classes, resolve string forward-reference type annotations, introspect fields, and enforce attribute-level immutability in attrs 26.1.0

已验证示例 — pypi attrs 26.1.0: Programmatically generate classes, resolve string forward-reference type annotations, introspect fields, and enforce…

sha256:ea93dd9601fe1fb4d4cc69b1d1c649e3133c54d0a3ece0a5f1ef9912bb9b343d

本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。 提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。 MIT-0

执行证据

声明的环境与签名的运行分开呈现,你可以看到这个样本究竟运行了什么、在哪里运行。

证据依据
签名契约通过
验证回执
2
构建过它的签名密钥
2
声明的环境 python linux x64 python python pip

验证运行环境

环境 契约 阶段 运行日期
python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-17
python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-18

案例

HOW
目标
Programmatically generate classes, resolve string forward-reference type annotations, introspect fields, and enforce attribute-level immutability in attrs 26.1.0
包
符号
  • attrs.resolve_types
  • attrs.make_class
  • attrs.fields_dict
  • attrs.fields
  • attrs.has
  • attrs.validate
  • attrs.astuple
  • attrs.filters.exclude
  • attrs.setters.frozen
  • attrs.exceptions.FrozenAttributeError
  • attrs.exceptions.FrozenInstanceError
  • attrs.exceptions.NotAnAttrsClassError
环境
python
创建时间
2026-08-17T13:04:07Z

契约

  1. attrs.resolve_types evaluates string forward references on attrs classes into resolved Python types in place on Attribute.type, while raising NotAnAttrsClassError on non-attrs classes
  2. assert attrs.make_class dynamically constructs slotted, frozen, and validated attrs classes with full field definition support
  3. assert attrs.fields_dict requires a class and raises TypeError on instances, whereas attrs.fields accepts both classes and instances
  4. assert attrs.has returns True for attrs classes and instances and False for standard Python objects
  5. assert on_setattr=setters.frozen raises FrozenAttributeError on field mutation while @frozen raises FrozenInstanceError
  6. assert attrs.validate manually re-evaluates all field validators against current instance state on demand
  7. assert attrs.astuple recursively serializes nested attrs instances and supports attribute filtering via attrs.filters.exclude
  8. assert initialization lifecycle sequence executes __attrs_pre_init__, converters, validators with converted values, and __attrs_post_init__ deterministically

文件

  • NOTES.md
  • csx.json
  • requirements.txt
  • src/__init__.py
  • src/models.py
  • test/__init__.py
  • test/contract.py

下载源代码构件 (tar.gz)

源代码

NOTES.md
# Notes on attrs 26.1.0 Behavior

## Search Results
Calling `search_known_solution` returned existing samples:
- `sha256:89a1110228934559fed8711f85b6f59e237474ccaa0a73797a4d02be4b9d4404` (evaluating validator disabling contexts and field transformer aliases)
- `sha256:a94157e4aed7876259ed8efef84afdec66ce469f4a0e2d632e81d3e9fe282e43` (evaluating equality comparisons and keyword-only inheritance)
- `sha256:04534868bcf83a1c9437d56575f5b38eea5b61ac3a126103d53fa34f2fbd7310` (evaluating authoring custom validators and converters)

This sample tests a distinct set of programmatic generation, type resolution, inspection, and lifecycle behaviors in `attrs 26.1.0`.

## Pinned Release
- Package: `attrs`
- Release: `26.1.0` (pinned in `requirements.txt`)

## Observed Behaviors
1. **Type Annotation Resolution (`attrs.resolve_types`)**:
   - Under deferred evaluation (e.g. `from __future__ import annotations`), field type hints initially remain raw strings.
   - `attrs.resolve_types(cls)` resolves string forward references in place on `Attribute.type` and returns the class.
   - Passing a non-attrs class raises `attrs.exceptions.NotAnAttrsClassError`.
   - Forward references unresolvable in the global/local namespace raise `NameError` unless supplied via `localns`.

2. **Programmatic Class Creation (`attrs.make_class`)**:
   - `attrs.make_class` dynamically produces attrs classes with full support for field definitions, validators, defaults, slots, and frozen immutability.

3. **Field Introspection Discrepancy (`attrs.fields` vs `attrs.fields_dict`)**:
   - `attrs.fields` accepts both class objects and instances directly.
   - `attrs.fields_dict` requires a class object and raises `TypeError: Passed object must be a class` when passed an instance.

4. **Class and Instance Introspection (`attrs.has`)**:
   - `attrs.has` returns `True` for both attrs classes and attrs instances, and `False` for standard Python classes or primitive instances.

5. **Field Immutability vs Class Immutability**:
   - `on_setattr=attrs.setters.frozen` locks individual fields on otherwise mutable classes, raising `attrs.exceptions.FrozenAttributeError` on mutation attempts.
   - Whole-class `@frozen` (or `@define(frozen=True)`) locks the entire instance and raises `attrs.exceptions.FrozenInstanceError`.

6. **On-Demand Validation (`attrs.validate`)**:
   - `attrs.validate(instance)` re-runs all field validators against the current instance state, catching invalid values that bypassed standard attribute setters.

7. **Tuple Serialization and Filtering (`attrs.astuple`)**:
   - `attrs.astuple` recursively transforms nested attrs instances into nested tuples while supporting attribute filtering through `attrs.filters.exclude`.

8. **Deterministic Lifecycle Ordering**:
   - Initialization executes deterministically in the following order: `__attrs_pre_init__` (with raw constructor arguments) -> default factories -> converters (transforming raw inputs) -> validators (receiving converted values) -> `__attrs_post_init__`.
csx.json
{"case":{"caseId":"case:sha256:80908c224518a738fc7350008feba23150a2c2088f52df4ffa3a903ba9737fc5","contract":["attrs.resolve_types evaluates string forward references on attrs classes into resolved Python types in place on Attribute.type, while raising NotAnAttrsClassError on non-attrs classes","assert attrs.make_class dynamically constructs slotted, frozen, and validated attrs classes with full field definition support","assert attrs.fields_dict requires a class and raises TypeError on instances, whereas attrs.fields accepts both classes and instances","assert attrs.has returns True for attrs classes and instances and False for standard Python objects","assert on_setattr=setters.frozen raises FrozenAttributeError on field mutation while @frozen raises FrozenInstanceError","assert attrs.validate manually re-evaluates all field validators against current instance state on demand","assert attrs.astuple recursively serializes nested attrs instances and supports attribute filtering via attrs.filters.exclude","assert initialization lifecycle sequence executes __attrs_pre_init__, converters, validators with converted values, and __attrs_post_init__ deterministically"],"goal":"Programmatically generate classes, resolve string forward-reference type annotations, introspect fields, and enforce attribute-level immutability in attrs 26.1.0","kind":"HOW","packages":["pkg:pypi/attrs@26.1.0"],"schemaVersion":1,"symbols":["attrs.resolve_types","attrs.make_class","attrs.fields_dict","attrs.fields","attrs.has","attrs.validate","attrs.astuple","attrs.filters.exclude","attrs.setters.frozen","attrs.exceptions.FrozenAttributeError","attrs.exceptions.FrozenInstanceError","attrs.exceptions.NotAnAttrsClassError"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/attrs@26.1.0"],"schemaVersion":1,"symbols":["attrs.resolve_types","attrs.make_class","attrs.fields_dict","attrs.fields","attrs.has","attrs.validate","attrs.astuple","attrs.filters.exclude","attrs.setters.frozen","attrs.exceptions.FrozenAttributeError","attrs.exceptions.FrozenInstanceError","attrs.exceptions.NotAnAttrsClassError"],"verifierAdapter":"python@1"}
requirements.txt
attrs==26.1.0
src/__init__.py
"""attrs behavioral contracts package."""
src/models.py
from __future__ import annotations

from typing import Any, List, Optional
import attrs
from attrs import define, field, frozen, setters, validators

LIFECYCLE_STEPS: List[str] = []


def record_converter(val: int) -> int:
    LIFECYCLE_STEPS.append(f"converter:{val}")
    return val * 2


def record_validator(inst: Any, attr: attrs.Attribute, val: int) -> None:
    LIFECYCLE_STEPS.append(f"validator:{val}")
    if val <= 0:
        raise ValueError(f"{attr.name} must be positive")


@define
class LifecycleTracker:
    """Demonstrates attrs initialization sequence and hook execution order."""

    value: int = field(
        converter=record_converter,
        validator=record_validator,
    )

    def __attrs_pre_init__(self, value: int) -> None:
        LIFECYCLE_STEPS.append(f"pre_init:{value}")

    def __attrs_post_init__(self) -> None:
        LIFECYCLE_STEPS.append(f"post_init:{self.value}")


@define
class GraphNode:
    """Demonstrates type annotation forward references resolved via attrs.resolve_types."""

    name: str
    parent: Optional[GraphNode] = None
    neighbors: List[GraphNode] = field(factory=list)


@define
class AuditRecord:
    """Demonstrates field-level immutability using on_setattr=setters.frozen."""

    record_id: str = field(on_setattr=setters.frozen)
    status: str = "pending"


@frozen
class ImmutableConfig:
    """Demonstrates whole-class immutability with @frozen."""

    key: str
    value: str


@define
class ValidatedRange:
    """Demonstrates on-demand manual validation with attrs.validate()."""

    lower: int = field(validator=validators.ge(0))
    upper: int = field(validator=validators.ge(0))


@define
class NestedCoordinate:
    """Demonstrates nested data extraction with attrs.astuple."""

    x: int
    y: int


@define
class LocationMarker:
    """Demonstrates nested composite models serialized via attrs.astuple."""

    label: str
    coords: NestedCoordinate
    internal_tag: str = "internal"
test/__init__.py
"""attrs behavioral contract tests."""
test/contract.py
import importlib.metadata
import sys
from pathlib import Path
from typing import List, Optional

# Add project root to sys.path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

import attrs
from attrs import exceptions, filters, validators
from src.models import (
    LIFECYCLE_STEPS,
    AuditRecord,
    GraphNode,
    ImmutableConfig,
    LifecycleTracker,
    LocationMarker,
    NestedCoordinate,
    ValidatedRange,
)


def test_resolve_types_forward_references():
    """Verify attrs.resolve_types evaluates string forward references on attrs classes."""
    # Before resolve_types, annotations remain strings under postponed evaluation
    fields_before = attrs.fields(GraphNode)
    assert fields_before.name.type == "str"
    assert fields_before.parent.type == "Optional[GraphNode]"
    assert fields_before.neighbors.type == "List[GraphNode]"

    # resolve_types returns the class and resolves Attribute.type in place
    ret = attrs.resolve_types(GraphNode)
    assert ret is GraphNode

    fields_after = attrs.fields(GraphNode)
    assert fields_after.name.type is str
    assert fields_after.parent.type == Optional[GraphNode]
    assert fields_after.neighbors.type == List[GraphNode]

    # Calling resolve_types on a non-attrs class raises NotAnAttrsClassError
    class OrdinaryClass:
        x: int

    try:
        attrs.resolve_types(OrdinaryClass)
        raise AssertionError("resolve_types on non-attrs class should raise NotAnAttrsClassError")
    except exceptions.NotAnAttrsClassError as exc:
        assert "is not an attrs-decorated class" in str(exc)

    # Calling resolve_types with unresolved forward references raises NameError without localns
    @attrs.define
    class CustomLookupNode:
        data: "UndefinedExternalType"

    try:
        attrs.resolve_types(CustomLookupNode)
        raise AssertionError("Undefined annotation without localns should raise NameError")
    except NameError as exc:
        assert "UndefinedExternalType" in str(exc)

    # Supplying localns allows resolving custom types explicitly
    class UndefinedExternalType:
        pass

    attrs.resolve_types(CustomLookupNode, localns={"UndefinedExternalType": UndefinedExternalType})
    assert attrs.fields(CustomLookupNode).data.type is UndefinedExternalType


def test_make_class_programmatic_generation():
    """Verify attrs.make_class dynamically constructs slotted, frozen, and validated classes."""
    DynamicPoint = attrs.make_class(
        "DynamicPoint",
        {
            "x": attrs.field(validator=validators.instance_of(int)),
            "y": attrs.field(validator=validators.instance_of(int), default=0),
        },
        frozen=True,
        slots=True,
    )

    pt = DynamicPoint(10, 20)
    assert pt.x == 10
    assert pt.y == 20
    assert attrs.has(DynamicPoint) is True
    assert attrs.has(pt) is True

    # Default value works as expected
    pt_default = DynamicPoint(5)
    assert pt_default.x == 5
    assert pt_default.y == 0

    # Validator runs on dynamic class constructor
    try:
        DynamicPoint("invalid", 10)  # type: ignore[arg-type]
        raise AssertionError("make_class with invalid type should fail validation")
    except TypeError as exc:
        assert "must be <class 'int'>" in str(exc)

    # Frozen behavior enforced on dynamic class
    try:
        pt.x = 99
        raise AssertionError("Modifying frozen dynamic class instance should raise FrozenInstanceError")
    except exceptions.FrozenInstanceError as exc:
        assert "can't set attribute" in str(exc)


def test_fields_dict_vs_fields_inspection():
    """Verify attrs.fields_dict requires a class while attrs.fields accepts instances."""
    node = GraphNode(name="root")

    # attrs.fields accepts both class and instance
    fields_from_cls = attrs.fields(GraphNode)
    fields_from_inst = attrs.fields(node)
    assert fields_from_cls == fields_from_inst
    assert [f.name for f in fields_from_cls] == ["name", "parent", "neighbors"]

    # attrs.fields_dict returns a name-to-Attribute mapping for classes
    field_map = attrs.fields_dict(GraphNode)
    assert list(field_map.keys()) == ["name", "parent", "neighbors"]
    assert field_map["name"] == fields_from_cls.name

    # attrs.fields_dict strictly rejects instances with TypeError
    try:
        attrs.fields_dict(node)  # type: ignore[arg-type]
        raise AssertionError("fields_dict(instance) should raise TypeError")
    except TypeError as exc:
        assert "Passed object must be a class" in str(exc)


def test_has_introspection():
    """Verify attrs.has distinguishes attrs classes and instances from standard objects."""
    class PlainPythonClass:
        pass

    plain_inst = PlainPythonClass()
    node = GraphNode(name="test")

    assert attrs.has(GraphNode) is True
    assert attrs.has(node) is True
    assert attrs.has(PlainPythonClass) is False
    assert attrs.has(plain_inst) is False
    assert attrs.has(int) is False
    assert attrs.has(123) is False


def test_frozen_field_vs_frozen_instance():
    """Verify on_setattr=setters.frozen raises FrozenAttributeError while @frozen raises FrozenInstanceError."""
    # Field-level frozen allows mutating other fields but blocks frozen field modification
    record = AuditRecord(record_id="REC-001", status="pending")
    assert record.record_id == "REC-001"
    assert record.status == "pending"

    record.status = "processed"
    assert record.status == "processed"

    try:
        record.record_id = "REC-002"
        raise AssertionError("Modifying field with on_setattr=setters.frozen should raise FrozenAttributeError")
    except exceptions.FrozenAttributeError as exc:
        assert "can't set attribute" in str(exc)

    # Class-level frozen blocks any attribute modification
    cfg = ImmutableConfig(key="timeout", value="30s")
    try:
        cfg.value = "60s"
        raise AssertionError("Modifying @frozen class attribute should raise FrozenInstanceError")
    except exceptions.FrozenInstanceError as exc:
        assert "can't set attribute" in str(exc)


def test_manual_validation():
    """Verify attrs.validate runs all field validators on demand to catch out-of-band mutations."""
    rng = ValidatedRange(lower=5, upper=10)
    assert rng.lower == 5
    assert rng.upper == 10

    # Mutate attribute out-of-band bypassing setter hooks
    object.__setattr__(rng, "lower", -10)
    assert rng.lower == -10

    # attrs.validate detects the invalid state
    try:
        attrs.validate(rng)
        raise AssertionError("validate() should fail when field invariant is violated")
    except ValueError as exc:
        assert "'lower' must be >= 0: -10" in str(exc)


def test_astuple_serialization_and_filtering():
    """Verify attrs.astuple recursively serializes nested attrs instances into tuples with filtering."""
    marker = LocationMarker(
        label="central",
        coords=NestedCoordinate(x=100, y=200),
        internal_tag="debug_meta",
    )

    # Full recursive extraction
    tup = attrs.astuple(marker)
    assert tup == ("central", (100, 200), "debug_meta")
    assert isinstance(tup[1], tuple)

    # Filtered extraction omitting internal_tag
    filtered_tup = attrs.astuple(
        marker,
        filter=filters.exclude(attrs.fields(LocationMarker).internal_tag),
    )
    assert filtered_tup == ("central", (100, 200))


def test_initialization_lifecycle_sequence():
    """Verify deterministic execution order of pre_init, converters, validators, and post_init."""
    LIFECYCLE_STEPS.clear()
    tracker = LifecycleTracker(value=7)

    assert tracker.value == 14
    # Execution order:
    # 1. __attrs_pre_init__ runs with raw constructor arguments
    # 2. converter runs with raw argument and transforms it (7 -> 14)
    # 3. validator runs with converted value (14)
    # 4. __attrs_post_init__ runs after all attributes are set on self
    assert LIFECYCLE_STEPS == [
        "pre_init:7",
        "converter:7",
        "validator:14",
        "post_init:14",
    ]


if __name__ == "__main__":
    test_resolve_types_forward_references()
    test_make_class_programmatic_generation()
    test_fields_dict_vs_fields_inspection()
    test_has_introspection()
    test_frozen_field_vs_frozen_instance()
    test_manual_validation()
    test_astuple_serialization_and_filtering()
    test_initialization_lifecycle_sequence()
    print("contract ok:", importlib.metadata.version("attrs"))

原始种子者

csx-seed