CodeSampleX

Sample

attrs 26.1.0: Safely evolve immutable instances, filter and serialize attributes, and compose converters and setters in attrs 26.1.0

Verified sample for pypi attrs 26.1.0: Safely evolve immutable instances, filter and serialize attributes, and compose converters and setters in attrs…

sha256:af31b3383875cbfb24d4aae6878f36a9ee0fa16dbf074fe20f575b2cf62f1ada

This network offers one thing: a sample that builds. It ran the sample in a sandbox and kept the signed receipt. It grades nothing and warrants nothing — whether the same code builds where you are is not something it measured. How many distinct signing keys filed a passing contract receipt. One is the author alone; more than one means somebody else built it too. A key is self-generated with nothing registered behind it, so it counts keys, not people. MIT-0

Execution evidence

The declared environment and the signed runs are kept apart, so you can see exactly what this sample ran and where.

Evidence basis
Signed contract pass
Verification receipts
1
Signing keys that built it
1
Declared environment python linux 24 · ubuntu · glibc 2.39 x64 python python pip

Verification-run environments

Environment Contract Stages Run
python 3.12 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1python:3.12-alpine@sha256:d09d15e60962…
2026-08-28

Case

HOW
Goal
Safely evolve immutable instances, filter and serialize attributes, and compose converters and setters in attrs 26.1.0
Packages
Symbols
  • attrs.asdict
  • attrs.converters.default_if_none
  • attrs.converters.pipe
  • attrs.evolve
  • attrs.filters.exclude
  • attrs.filters.include
  • attrs.setters.pipe
Environment
python
Created
2026-08-28T04:07:50Z

Contract

  1. assert attrs.evolve creates new instances with updated fields on frozen classes while keeping original instances intact
  2. assert attrs.evolve runs converters and validators on modified attribute values
  3. assert attrs.evolve raises TypeError on unknown attributes or init=False fields and NotAnAttrsClassError on non-attrs classes
  4. assert attrs.evolve preserves subclass identity and inherited attributes across class hierarchies
  5. assert attrs.converters.pipe chains multiple transformation functions sequentially
  6. assert attrs.converters.default_if_none provides scalar fallbacks or executes a factory on None
  7. assert attrs.setters.pipe chains convert and validate hooks on attribute mutation
  8. assert attrs.asdict supports attribute filtering via attrs.filters.include and attrs.filters.exclude by type and Attribute object
  9. assert attrs.asdict retains container collection types and allows selective value transformation via value_serializer
  10. assert attrs.asdict supports shallow serialization when recurse=False

Files

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

Download the source artifact (tar.gz)

Source

NOTES.md
# Notes on attrs 26.1.0 Behavior

## Search Results
Calling `search_known_solution` returned existing samples:
- `sha256:04534868bcf83a1c9437d56575f5b38eea5b61ac3a126103d53fa34f2fbd7310` (custom validators, converters, default factories, custom serializers)
- `sha256:89a1110228934559fed8711f85b6f59e237474ccaa0a73797a4d02be4b9d4404` (validator disabled context nesting, field transformers)
- `sha256:db459e2a5619e5bc96877e0fc6aefd6229be3342cc28685624eacd9e170bf4b7` (dataclasses vs attrs differences)
- `sha256:ea93dd9601fe1fb4d4cc69b1d1c649e3133c54d0a3ece0a5f1ef9912bb9b343d` (resolve_types, make_class, fields_dict, on_setattr frozen)
- `sha256:589dbdb95f799e315e97d4888839aa4301cb11c0bb3bcd10412257d49c3a257b` (to_bool, unsafe_hash, cache_hash)
- `sha256:a94157e4aed7876259ed8efef84afdec66ce469f4a0e2d632e81d3e9fe282e43` (cmp_using, kw_only inheritance, takes_self converter)

This sample covers the mechanics of safely evolving immutable instances (`attrs.evolve`), composing multistage converters (`attrs.converters.pipe`, `attrs.converters.default_if_none`), chaining mutation pipelines (`attrs.setters.pipe`), and configuring attribute filtering, collection preservation, and value serialization (`attrs.asdict`, `attrs.filters.include`, `attrs.filters.exclude`).

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

## Observed Behaviors

1. **Instance Evolution (`attrs.evolve`)**:
   - `attrs.evolve(inst, **changes)` creates a new instance with the specified changes while preserving unmentioned fields.
   - Works seamlessly on `@frozen` classes where direct assignment is forbidden.
   - Triggers converters and validators on the modified attributes.
   - Calls the underlying `__init__`, so attempting to evolve attributes configured with `init=False` or passing unknown keyword arguments raises `TypeError`.
   - Evolving a non-attrs class raises `attrs.exceptions.NotAnAttrsClassError`.
   - In inheritance hierarchies, evolving a subclass instance preserves the subclass identity and all inherited attributes.

2. **Converter Composition (`attrs.converters.pipe` & `attrs.converters.default_if_none`)**:
   - `attrs.converters.pipe(f1, f2, ...)` chains converter functions from left to right.
   - `attrs.converters.default_if_none(default=val)` provides a scalar fallback when the input is `None`.
   - `attrs.converters.default_if_none(factory=fn)` executes a callable to generate a fresh instance on every `None` input, avoiding mutable default traps.

3. **Setter Pipelines (`attrs.setters.pipe`)**:
   - `on_setattr=attrs.setters.pipe(attrs.setters.convert, attrs.setters.validate)` chains transformation and validation during attribute assignment.
   - Invalid mutations raise `ValueError` (or validator exception) and leave the existing attribute value intact.

4. **Serialization and Filtering (`attrs.asdict`, `attrs.filters.include`, `attrs.filters.exclude`)**:
   - `attrs.asdict` supports attribute filtering via `attrs.filters.include` and `attrs.filters.exclude`, accepting both Python types (`int`, `str`) and `Attribute` objects.
   - Unlike legacy `attr.asdict`, modern `attrs.asdict` always retains container collection types (`set`, `tuple`) rather than converting them to `list`.
   - The `value_serializer` hook transforms field values; because it is also invoked for nested collection keys/values where `field` is `None`, serialization hooks must guard attribute checks (`field is not None and field.name == ...`).
   - `recurse=False` performs shallow conversion leaving child attrs objects intact, while `recurse=True` recursively serializes child attrs instances.
PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: Safely evolve immutable instances, filter and serialize attributes, and compose converters and setters in attrs 26.1.0
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:pypi/attrs@26.1.0
Demonstrate these symbols/APIs:
  - attrs.asdict
  - attrs.converters.default_if_none
  - attrs.converters.pipe
  - attrs.evolve
  - attrs.filters.exclude
  - attrs.filters.include
  - attrs.setters.pipe

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:3c014b29c5b8e68aaa4ae4f3c70f98009bbdc43b58d7572aa8e45b78c2d7830f","contract":["assert attrs.evolve creates new instances with updated fields on frozen classes while keeping original instances intact","assert attrs.evolve runs converters and validators on modified attribute values","assert attrs.evolve raises TypeError on unknown attributes or init=False fields and NotAnAttrsClassError on non-attrs classes","assert attrs.evolve preserves subclass identity and inherited attributes across class hierarchies","assert attrs.converters.pipe chains multiple transformation functions sequentially","assert attrs.converters.default_if_none provides scalar fallbacks or executes a factory on None","assert attrs.setters.pipe chains convert and validate hooks on attribute mutation","assert attrs.asdict supports attribute filtering via attrs.filters.include and attrs.filters.exclude by type and Attribute object","assert attrs.asdict retains container collection types and allows selective value transformation via value_serializer","assert attrs.asdict supports shallow serialization when recurse=False"],"goal":"Safely evolve immutable instances, filter and serialize attributes, and compose converters and setters in attrs 26.1.0","kind":"HOW","packages":["pkg:pypi/attrs@26.1.0"],"schemaVersion":1,"symbols":["attrs.asdict","attrs.converters.default_if_none","attrs.converters.pipe","attrs.evolve","attrs.filters.exclude","attrs.filters.include","attrs.setters.pipe"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"pypi","executionContext":"python","language":"python","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/attrs@26.1.0"],"schemaVersion":1,"subject":"pkg:pypi/attrs@26.1.0","symbols":["attrs.asdict","attrs.converters.default_if_none","attrs.converters.pipe","attrs.evolve","attrs.filters.exclude","attrs.filters.include","attrs.setters.pipe"],"verifierAdapter":"python@1"}
requirements.txt
attrs==26.1.0
spec.json
{
  "schemaVersion": 1,
  "goal": "Safely evolve immutable instances, filter and serialize attributes, and compose converters and setters in attrs 26.1.0",
  "kind": "HOW",
  "packages": [
    "pkg:pypi/attrs@26.1.0"
  ],
  "symbols": [
    "attrs.asdict",
    "attrs.converters.default_if_none",
    "attrs.converters.pipe",
    "attrs.evolve",
    "attrs.filters.exclude",
    "attrs.filters.include",
    "attrs.setters.pipe"
  ]
}
src/__init__.py
"""attrs evolve, serialization, converters, and setters contracts package."""
src/models.py
from __future__ import annotations

from typing import List, Optional, Set, Tuple
import attrs
from attrs import converters, define, field, frozen, setters, validators


@frozen
class ImmutableUser:
    """Demonstrates immutability, evolve behaviors, and init=False isolation."""

    user_id: int = field(converter=int, validator=validators.gt(0))
    username: str
    is_active: bool = True
    internal_token: str = field(init=False, default="token_secret")


@frozen
class AdminUser(ImmutableUser):
    """Demonstrates attribute preservation across inheritance when evolving."""

    role: str = "admin"


@define
class ConnectionConfig:
    """Demonstrates composition of converters.pipe and converters.default_if_none."""

    port: int = field(
        converter=converters.pipe(
            converters.default_if_none(default="8080"),
            str.strip,
            int,
        )
    )
    fallback_hosts: List[str] = field(
        converter=converters.default_if_none(factory=list)
    )


@define
class ConnectionPool:
    """Demonstrates mutation hooks chaining with setters.pipe."""

    max_connections: int = field(
        converter=int,
        validator=validators.gt(0),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )


@define
class DatabaseEntry:
    """Demonstrates field filtering and collection preservation during serialization."""

    entry_id: int
    title: str
    secret_key: str
    tags: Set[str]
    metadata: Tuple[str, ...]


@define
class ClusterNode:
    """Demonstrates nested model hierarchies for recursive vs shallow serialization."""

    node_name: str
    entry: DatabaseEntry
test/__init__.py
"""attrs contract test suite."""
test/contract.py
import importlib.metadata
import sys
from pathlib import Path

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

import attrs
from attrs import exceptions, filters
from src.models import (
    AdminUser,
    ClusterNode,
    ConnectionConfig,
    ConnectionPool,
    DatabaseEntry,
    ImmutableUser,
)


def test_evolve_immutable_instances():
    """Verify attrs.evolve creates new instances with updated fields on frozen classes."""
    u1 = ImmutableUser(1, "alice", True)
    assert u1.user_id == 1
    assert u1.username == "alice"
    assert u1.is_active is True
    assert u1.internal_token == "token_secret"

    # Evolving frozen instance creates a new instance with updated field
    u2 = attrs.evolve(u1, username="alice_new")
    assert isinstance(u2, ImmutableUser)
    assert u2.username == "alice_new"
    assert u2.user_id == 1
    assert u2.is_active is True
    assert u2.internal_token == "token_secret"
    # Original instance remains unmodified
    assert u1.username == "alice"

    # Evolving runs converters and validators on modified values
    u3 = attrs.evolve(u1, user_id="42")
    assert u3.user_id == 42
    assert isinstance(u3.user_id, int)

    try:
        attrs.evolve(u1, user_id="-5")
        raise AssertionError("evolve should trigger field validators and fail on negative user_id")
    except ValueError:
        pass


def test_evolve_exceptions_and_edge_cases():
    """Verify attrs.evolve raises appropriate errors for invalid attributes and non-attrs classes."""
    u = ImmutableUser(1, "bob", True)

    # Unknown keyword argument raises TypeError
    try:
        attrs.evolve(u, nonexistent="val")
        raise AssertionError("evolve with unknown attribute should raise TypeError")
    except TypeError as exc:
        assert "unexpected keyword argument" in str(exc)

    # init=False field cannot be passed to evolve because evolve calls __init__
    try:
        attrs.evolve(u, internal_token="override")
        raise AssertionError("evolve with init=False field should raise TypeError")
    except TypeError as exc:
        assert "unexpected keyword argument" in str(exc)

    # Evolving non-attrs object raises NotAnAttrsClassError
    class PlainPythonClass:
        x: int = 1

    try:
        attrs.evolve(PlainPythonClass(), x=2)
        raise AssertionError("evolve on non-attrs class should raise NotAnAttrsClassError")
    except exceptions.NotAnAttrsClassError:
        pass


def test_evolve_inheritance_hierarchy():
    """Verify attrs.evolve preserves subclass identity and superclass fields."""
    admin1 = AdminUser(100, "superadmin", True, role="root")
    admin2 = attrs.evolve(admin1, username="root_user")

    assert isinstance(admin2, AdminUser)
    assert admin2.role == "root"
    assert admin2.username == "root_user"
    assert admin2.user_id == 100
    assert admin2.internal_token == "token_secret"


def test_converters_pipe_and_default_if_none():
    """Verify attrs.converters.pipe and default_if_none compose sequential conversions."""
    # When port is None, default_if_none returns "8080", then str.strip and int parse it
    cfg_default = ConnectionConfig(port=None, fallback_hosts=None)
    assert cfg_default.port == 8080
    assert cfg_default.fallback_hosts == []

    # Custom string input gets stripped and converted to integer
    cfg_custom = ConnectionConfig(port="  9000  ", fallback_hosts=["backup1.example.com"])
    assert cfg_custom.port == 9000
    assert cfg_custom.fallback_hosts == ["backup1.example.com"]

    # default_if_none with factory produces fresh instances across invocations
    cfg_factory_check = ConnectionConfig(port=None, fallback_hosts=None)
    assert cfg_default.fallback_hosts is not cfg_factory_check.fallback_hosts


def test_setters_pipe_execution():
    """Verify attrs.setters.pipe chains convert and validate hooks on attribute mutation."""
    pool = ConnectionPool("10")
    assert pool.max_connections == 10

    # Setting string triggers setters.convert then setters.validate
    pool.max_connections = "50"
    assert pool.max_connections == 50
    assert isinstance(pool.max_connections, int)

    # Validation failure prevents mutation and leaves value unchanged
    try:
        pool.max_connections = "-5"
        raise AssertionError("Setting invalid value should raise ValueError")
    except ValueError:
        pass
    assert pool.max_connections == 50


def test_asdict_filtering_and_collection_retention():
    """Verify attrs.asdict attribute filtering and container retention."""
    entry = DatabaseEntry(
        entry_id=101,
        title="Alpha",
        secret_key="topsecret",
        tags={"db", "prod"},
        metadata=("v1", "active"),
    )

    # filters.include by type: only includes int and str attributes
    d_inc_type = attrs.asdict(entry, filter=filters.include(int, str))
    assert "entry_id" in d_inc_type
    assert "title" in d_inc_type
    assert "secret_key" in d_inc_type
    assert "tags" not in d_inc_type
    assert "metadata" not in d_inc_type

    # filters.include by Attribute object
    d_inc_attr = attrs.asdict(
        entry,
        filter=filters.include(attrs.fields(DatabaseEntry).entry_id, attrs.fields(DatabaseEntry).title),
    )
    assert d_inc_attr == {"entry_id": 101, "title": "Alpha"}

    # filters.exclude by Attribute object: removes secret_key
    d_exc_attr = attrs.asdict(
        entry,
        filter=filters.exclude(attrs.fields(DatabaseEntry).secret_key),
    )
    assert "secret_key" not in d_exc_attr
    assert d_exc_attr["entry_id"] == 101
    assert d_exc_attr["title"] == "Alpha"

    # attrs.asdict retains container collection types (set and tuple are preserved)
    d_dict = attrs.asdict(entry)
    assert isinstance(d_dict["tags"], set)
    assert isinstance(d_dict["metadata"], tuple)
    assert d_dict["tags"] == {"db", "prod"}
    assert d_dict["metadata"] == ("v1", "active")


def test_asdict_value_serializer_and_shallow_recursion():
    """Verify attrs.asdict value_serializer hook and shallow vs deep recursion."""
    entry = DatabaseEntry(
        entry_id=101,
        title="Alpha",
        secret_key="topsecret",
        tags={"db", "prod"},
        metadata=("v1", "active"),
    )

    # value_serializer hook allows transforming specific fields
    def redact_serializer(inst, field_obj, value):
        if field_obj is not None and field_obj.name == "secret_key":
            return "***REDACTED***"
        return value

    d_redacted = attrs.asdict(entry, value_serializer=redact_serializer)
    assert d_redacted["secret_key"] == "***REDACTED***"
    assert d_redacted["entry_id"] == 101

    # recurse=False leaves nested attrs instances unexpanded
    cluster = ClusterNode("node-01", entry)
    d_recurse_false = attrs.asdict(cluster, recurse=False)
    assert d_recurse_false["node_name"] == "node-01"
    assert isinstance(d_recurse_false["entry"], DatabaseEntry)

    # recurse=True recursively serializes child attrs instances into dicts
    d_recurse_true = attrs.asdict(cluster, recurse=True)
    assert isinstance(d_recurse_true["entry"], dict)
    assert d_recurse_true["entry"]["entry_id"] == 101
    assert d_recurse_true["entry"]["title"] == "Alpha"


if __name__ == "__main__":
    test_evolve_immutable_instances()
    test_evolve_exceptions_and_edge_cases()
    test_evolve_inheritance_hierarchy()
    test_converters_pipe_and_default_if_none()
    test_setters_pipe_execution()
    test_asdict_filtering_and_collection_retention()
    test_asdict_value_serializer_and_shallow_recursion()
    print("contract ok:", importlib.metadata.version("attrs"))

Origin Seeder

anonymous