This is an automated email from the ASF dual-hosted git repository.

junrushao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new 41d38fa3 refactor(python)!: rename `structure=` to `structural_eq=` 
(#509)
41d38fa3 is described below

commit 41d38fa32f361fd219463455e5ef061e43a85945
Author: Junru Shao <[email protected]>
AuthorDate: Mon Mar 23 07:38:54 2026 -0700

    refactor(python)!: rename `structure=` to `structural_eq=` (#509)
    
    ## Summary
    
    - Rename the `structure=` parameter to `structural_eq=` in `@py_class()`
    and `field()` to better convey that the parameter controls structural
    equality/hashing behavior
    - Update Cython layer (`type_info.pxi`) to read the new attribute name
    - Update all tests and documentation to use the new parameter name
    
    ## Breaking Change
    
    The `structure=` parameter on `@py_class()` and `field()` has been
    renamed to `structural_eq=`.
    
    **Migration**: replace all occurrences of `structure=` with
    `structural_eq=` in your `@py_class()` and `field()` calls:
    
    ```python
    # Before
    @py_class(structure="tree")
    class MyNode(Object):
        span: Object = field(structure="ignore")
    
    # After
    @py_class(structural_eq="tree")
    class MyNode(Object):
        span: Object = field(structural_eq="ignore")
    ```
    
    ## Test plan
    
    - [x] `uv pip install --force-reinstall --verbose -e .` (full C++
    rebuild required)
    - [x] `uv run pytest -vvs tests/python/test_structural_py_class.py`
    - [ ] Verify all pre-commit hooks pass (confirmed locally: all passed)
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
 docs/concepts/structural_eq_hash.rst     | 74 ++++++++++++++++----------------
 python/tvm_ffi/cython/type_info.pxi      |  2 +-
 python/tvm_ffi/dataclasses/field.py      | 35 ++++++++-------
 python/tvm_ffi/dataclasses/py_class.py   | 18 ++++----
 tests/python/test_structural_py_class.py | 52 +++++++++++-----------
 5 files changed, 92 insertions(+), 89 deletions(-)

diff --git a/docs/concepts/structural_eq_hash.rst 
b/docs/concepts/structural_eq_hash.rst
index 006114b0..63dbd4c1 100644
--- a/docs/concepts/structural_eq_hash.rst
+++ b/docs/concepts/structural_eq_hash.rst
@@ -25,9 +25,9 @@ fields — rather than by pointer identity.
 The behavior is controlled by two layers of annotation on
 :func:`~tvm_ffi.dataclasses.py_class`:
 
-1. **Type-level** ``structure=`` — what *role* does this type play in the
+1. **Type-level** ``structural_eq=`` — what *role* does this type play in the
    IR graph?
-2. **Field-level** ``structure=`` on :func:`~tvm_ffi.dataclasses.field` —
+2. **Field-level** ``structural_eq=`` on :func:`~tvm_ffi.dataclasses.field` —
    should this field be skipped, or does it introduce new variable bindings?
 
 This document explains what each annotation means, when to use it, and how
@@ -37,12 +37,12 @@ they compose.
 Type-Level Annotation
 ---------------------
 
-The ``structure`` parameter on ``@py_class`` declares how instances of the
+The ``structural_eq`` parameter on ``@py_class`` declares how instances of the
 type participate in structural equality and hashing:
 
 .. code-block:: python
 
-   @py_class(structure="tree")
+   @py_class(structural_eq="tree")
    class Expr(Object):
        ...
 
@@ -53,7 +53,7 @@ Quick reference
    :header-rows: 1
    :widths: 18 37 45
 
-   * - ``structure=``
+   * - ``structural_eq=``
      - Meaning
      - Use when...
    * - ``"tree"``
@@ -81,7 +81,7 @@ Quick reference
 
 .. code-block:: python
 
-   @py_class(structure="tree")
+   @py_class(structural_eq="tree")
    class Add(Object):
        lhs: Expr
        rhs: Expr
@@ -149,7 +149,7 @@ If sharing needs to matter, use ``"dag"`` instead.
 
 .. code-block:: python
 
-   @py_class(structure="const-tree")
+   @py_class(structural_eq="const-tree")
    class DeviceMesh(Object):
        shape: list[int]
        device_ids: list[int]
@@ -222,7 +222,7 @@ is recorded:
 
 .. code-block:: python
 
-   @py_class(structure="dag")
+   @py_class(structural_eq="dag")
    class Binding(Object):
        var: Var
        value: Expr
@@ -335,7 +335,7 @@ Full comparison: ``"tree"`` vs ``"dag"``
 
 .. code-block:: python
 
-   @py_class(structure="var")
+   @py_class(structural_eq="var")
    class Var(Object):
        name: str
 
@@ -358,8 +358,8 @@ binding position and are used in the same way.
 How it works: definition regions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-``"var"`` works together with ``field(structure="def")`` (see
-:ref:`field-annotations`). A field marked ``structure="def"`` is a
+``"var"`` works together with ``field(structural_eq="def")`` (see
+:ref:`field-annotations`). A field marked ``structural_eq="def"`` is a
 **definition region** — it's where new variable bindings are introduced.
 
 - **Inside a definition region**: encountering two different variables
@@ -376,7 +376,7 @@ The following diagram traces the comparison of two 
alpha-equivalent functions:
        participant L as lhs: fun x → x + 1
        participant R as rhs: fun y → y + 1
 
-       Note over C: Field "params" has structure="def"
+       Note over C: Field "params" has structural_eq="def"
        C->>L: get params → [x]
        C->>R: get params → [y]
        Note over C: Enter definition region
@@ -475,7 +475,7 @@ enclosing function:
 
 .. code-block:: python
 
-   @py_class(structure="singleton")
+   @py_class(structural_eq="singleton")
    class Op(Object):
        name: str
 
@@ -499,18 +499,18 @@ unequal; same pointer is always equal.
 Field-Level Annotations
 -----------------------
 
-The ``structure`` parameter on :func:`~tvm_ffi.dataclasses.field` controls
+The ``structural_eq`` parameter on :func:`~tvm_ffi.dataclasses.field` controls
 how structural equality/hashing treats that specific field.
 
-``structure="ignore"`` — Exclude a field
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``structural_eq="ignore"`` — Exclude a field
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. code-block:: python
 
-   @py_class(structure="tree")
+   @py_class(structural_eq="tree")
    class MyNode(Object):
        value: int
-       span: str = field(structure="ignore")
+       span: str = field(structural_eq="ignore")
 
 **Meaning**: "This field is not part of the node's structural identity.
 Skip it during comparison and hashing."
@@ -523,14 +523,14 @@ Use for:
   redundant to compare.
 - **Debug annotations** — names, comments, metadata for human consumption.
 
-``structure="def"`` — Definition region
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``structural_eq="def"`` — Definition region
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. code-block:: python
 
-   @py_class(structure="tree")
+   @py_class(structural_eq="tree")
    class Lambda(Object):
-       params: list[Var] = field(structure="def")
+       params: list[Var] = field(structural_eq="def")
        body: Expr
 
 **Meaning**: "This field introduces new variable bindings. When comparing
@@ -538,7 +538,7 @@ or hashing this field, allow new variable correspondences 
to be
 established."
 
 This is the counterpart to ``"var"``. A ``"var"`` type says "I am a
-variable"; ``structure="def"`` says "this field is where variables are
+variable"; ``structural_eq="def"`` says "this field is where variables are
 defined." Together they enable alpha-equivalence: comparing functions up
 to consistent variable renaming.
 
@@ -636,14 +636,14 @@ When defining a new type:
 
    graph TD
        Start["New @py_class type"] --> Q1{"Singleton?<br/>(one instance 
per<br/>logical identity)"}
-       Q1 -->|Yes| UI["structure=&quot;singleton&quot;"]
+       Q1 -->|Yes| UI["structural_eq=&quot;singleton&quot;"]
        Q1 -->|No| Q2{"Represents a<br/>variable binding?"}
-       Q2 -->|Yes| FV["structure=&quot;var&quot;"]
+       Q2 -->|Yes| FV["structural_eq=&quot;var&quot;"]
        Q2 -->|No| Q3{"Pointer sharing<br/>semantically<br/>meaningful?"}
-       Q3 -->|Yes| DN["structure=&quot;dag&quot;"]
+       Q3 -->|Yes| DN["structural_eq=&quot;dag&quot;"]
        Q3 -->|No| Q4{"Immutable AND<br/>no transitive<br/>var children?"}
-       Q4 -->|Yes| CTN["structure=&quot;const-tree&quot;"]
-       Q4 -->|No| TN["structure=&quot;tree&quot;"]
+       Q4 -->|Yes| CTN["structural_eq=&quot;const-tree&quot;"]
+       Q4 -->|No| TN["structural_eq=&quot;tree&quot;"]
 
        style UI fill:#e2e3e5
        style FV fill:#fff3cd
@@ -657,9 +657,9 @@ For fields:
 
    graph TD
        Start["field() parameter"] --> Q1{"Irrelevant to<br/>structural 
identity?<br/>(span, cache, debug)"}
-       Q1 -->|Yes| IGN["structure=&quot;ignore&quot;"]
+       Q1 -->|Yes| IGN["structural_eq=&quot;ignore&quot;"]
        Q1 -->|No| Q2{"Introduces new<br/>variable bindings?"}
-       Q2 -->|Yes| DEF["structure=&quot;def&quot;"]
+       Q2 -->|Yes| DEF["structural_eq=&quot;def&quot;"]
        Q2 -->|No| NONE["No flag needed"]
 
        style IGN fill:#f8d7da
@@ -675,17 +675,17 @@ source location:
 
 .. code-block:: python
 
-   @py_class(structure="tree")
+   @py_class(structural_eq="tree")
    class Lambda(Object):
-       params: list[Var] = field(structure="def")
+       params: list[Var] = field(structural_eq="def")
        body: Expr
-       span: str = field(structure="ignore", default="")
+       span: str = field(structural_eq="ignore", default="")
 
-   @py_class(structure="var")
+   @py_class(structural_eq="var")
    class Var(Object):
        name: str
 
-   @py_class(structure="singleton")
+   @py_class(structural_eq="singleton")
    class Op(Object):
        name: str
 
@@ -697,9 +697,9 @@ With these annotations, alpha-equivalent functions are 
structurally equal:
    fun [x] → x + 1       (span="a.py:1")
    fun [y] → y + 1       (span="b.py:5")
 
-   #  - params has structure="def" → x maps to y
+   #  - params has structural_eq="def" → x maps to y
    #  - body uses that mapping → (x + 1) ≅ (y + 1)
-   #  - span has structure="ignore" → locations don't matter
+   #  - span has structural_eq="ignore" → locations don't matter
 
 And in Python:
 
diff --git a/python/tvm_ffi/cython/type_info.pxi 
b/python/tvm_ffi/cython/type_info.pxi
index 128efa70..7a195903 100644
--- a/python/tvm_ffi/cython/type_info.pxi
+++ b/python/tvm_ffi/cython/type_info.pxi
@@ -838,7 +838,7 @@ cdef _register_one_field(
     if py_field.kw_only:
         flags |= kTVMFFIFieldFlagBitMaskKwOnly
     # Structural equality/hashing field annotations
-    cdef object field_structure = getattr(py_field, "structure", None)
+    cdef object field_structure = getattr(py_field, "structural_eq", None)
     if field_structure == "ignore":
         flags |= kTVMFFIFieldFlagBitMaskSEqHashIgnore
     elif field_structure == "def":
diff --git a/python/tvm_ffi/dataclasses/field.py 
b/python/tvm_ffi/dataclasses/field.py
index 97e8864e..3f367613 100644
--- a/python/tvm_ffi/dataclasses/field.py
+++ b/python/tvm_ffi/dataclasses/field.py
@@ -70,7 +70,7 @@ class Field:
     kw_only : bool | None
         Whether this field is keyword-only in ``__init__``.
         ``None`` means "inherit from the decorator-level *kw_only* flag".
-    structure : str | None
+    structural_eq : str | None
         Structural equality/hashing annotation for this field.  Valid
         values are:
 
@@ -96,7 +96,7 @@ class Field:
         "kw_only",
         "name",
         "repr",
-        "structure",
+        "structural_eq",
         "ty",
     )
     name: str | None
@@ -108,11 +108,13 @@ class Field:
     hash: bool | None
     compare: bool
     kw_only: bool | None
-    structure: str | None
+    structural_eq: str | None
     doc: str | None
 
-    #: Valid values for the *structure* parameter.
-    _VALID_STRUCTURE_VALUES: ClassVar[frozenset[str | None]] = 
frozenset({None, "ignore", "def"})
+    #: Valid values for the *structural_eq* parameter.
+    _VALID_STRUCTURAL_EQ_VALUES: ClassVar[frozenset[str | None]] = frozenset(
+        {None, "ignore", "def"}
+    )
 
     def __init__(  # noqa: PLR0913
         self,
@@ -126,7 +128,7 @@ class Field:
         hash: bool | None = True,
         compare: bool = False,
         kw_only: bool | None = False,
-        structure: str | None = None,
+        structural_eq: str | None = None,
         doc: str | None = None,
     ) -> None:
         # MISSING means "parameter not provided".
@@ -139,10 +141,11 @@ class Field:
                 raise TypeError(
                     f"default_factory must be a callable, got 
{type(default_factory).__name__}"
                 )
-        if structure not in Field._VALID_STRUCTURE_VALUES:
+        if structural_eq not in Field._VALID_STRUCTURAL_EQ_VALUES:
             raise ValueError(
-                f"structure must be one of 
{sorted(Field._VALID_STRUCTURE_VALUES, key=str)}, "
-                f"got {structure!r}"
+                f"structural_eq must be one of "
+                f"{sorted(Field._VALID_STRUCTURAL_EQ_VALUES, key=str)}, "
+                f"got {structural_eq!r}"
             )
         self.name = name
         self.ty = ty
@@ -153,7 +156,7 @@ class Field:
         self.hash = hash
         self.compare = compare
         self.kw_only = kw_only
-        self.structure = structure
+        self.structural_eq = structural_eq
         self.doc = doc
 
 
@@ -166,7 +169,7 @@ def field(
     hash: bool | None = None,
     compare: bool = True,
     kw_only: bool | None = None,
-    structure: str | None = None,
+    structural_eq: str | None = None,
     doc: str | None = None,
 ) -> Any:
     """Customize a field in a ``@py_class``-decorated class.
@@ -198,7 +201,7 @@ def field(
     kw_only
         Whether this field is keyword-only in ``__init__``.
         ``None`` means "inherit from the decorator-level ``kw_only`` flag".
-    structure
+    structural_eq
         Structural equality/hashing annotation. ``None`` (default) means
         the field participates normally. ``"ignore"`` excludes the field
         from structural comparison and hashing. ``"def"`` marks the field
@@ -221,11 +224,11 @@ def field(
             y: float = field(default=0.0, repr=False)
 
 
-        @py_class(structure="tree")
+        @py_class(structural_eq="tree")
         class MyFunc(Object):
-            params: Array = field(structure="def")
+            params: Array = field(structural_eq="def")
             body: Expr
-            span: Object = field(structure="ignore")
+            span: Object = field(structural_eq="ignore")
 
     """
     return Field(
@@ -236,6 +239,6 @@ def field(
         hash=hash,
         compare=compare,
         kw_only=kw_only,
-        structure=structure,
+        structural_eq=structural_eq,
         doc=doc,
     )
diff --git a/python/tvm_ffi/dataclasses/py_class.py 
b/python/tvm_ffi/dataclasses/py_class.py
index 07b6aa08..2d3d2872 100644
--- a/python/tvm_ffi/dataclasses/py_class.py
+++ b/python/tvm_ffi/dataclasses/py_class.py
@@ -251,7 +251,7 @@ def _phase2_register_fields(
     py_methods = _collect_py_methods(cls)
 
     # Register fields and type-level structural eq/hash kind with the C layer.
-    structure_kind = _STRUCTURE_KIND_MAP.get(params.get("structure"))
+    structure_kind = _STRUCTURE_KIND_MAP.get(params.get("structural_eq"))
     type_info._register_fields(own_fields, structure_kind)
     # Register user-defined dunder methods and read back system-generated ones.
     type_info._register_py_methods(py_methods)
@@ -416,7 +416,7 @@ def py_class(
     order: bool = False,
     unsafe_hash: bool = False,
     kw_only: bool = False,
-    structure: str | None = None,
+    structural_eq: str | None = None,
     slots: bool = True,
 ) -> Callable[[_T], _T] | _T:
     """Register a Python-defined FFI class with dataclass-style semantics.
@@ -443,10 +443,10 @@ def py_class(
         class Point(Object): ...
 
 
-        @py_class(structure="tree")  # structural eq/hash kind
+        @py_class(structural_eq="tree")  # structural eq/hash kind
         class MyNode(Object):
             value: int
-            span: Object = field(structure="ignore")
+            span: Object = field(structural_eq="ignore")
 
     Parameters
     ----------
@@ -469,7 +469,7 @@ def py_class(
         If True, generate ``__hash__`` (unsafe for mutable objects).
     kw_only
         If True, all fields are keyword-only in ``__init__`` by default.
-    structure
+    structural_eq
         Structural equality/hashing kind for this type.  Controls how
         instances participate in ``StructuralEqual`` and ``StructuralHash``.
         Valid values are:
@@ -496,11 +496,11 @@ def py_class(
     """
     if order and not eq:
         raise ValueError("order=True requires eq=True")
-    if structure not in _STRUCTURE_KIND_MAP:
+    if structural_eq not in _STRUCTURE_KIND_MAP:
         raise ValueError(
-            f"structure must be one of "
+            f"structural_eq must be one of "
             f"{sorted(k for k in _STRUCTURE_KIND_MAP if k is not None)}"
-            f" or None, got {structure!r}"
+            f" or None, got {structural_eq!r}"
         )
 
     effective_type_key = type_key
@@ -511,7 +511,7 @@ def py_class(
         "order": order,
         "unsafe_hash": unsafe_hash,
         "kw_only": kw_only,
-        "structure": structure,
+        "structural_eq": structural_eq,
     }
 
     def decorator(cls: _T) -> _T:
diff --git a/tests/python/test_structural_py_class.py 
b/tests/python/test_structural_py_class.py
index f280980d..d6b4585f 100644
--- a/tests/python/test_structural_py_class.py
+++ b/tests/python/test_structural_py_class.py
@@ -18,7 +18,7 @@
 
 Mirrors the C++ tests in tests/cpp/extra/test_structural_equal_hash.cc,
 porting the object-level tests (FreeVar, FuncDefAndIgnoreField, etc.)
-to Python using ``@py_class(structure=...)`` and ``field(structure=...)``.
+to Python using ``@py_class(structural_eq=...)`` and 
``field(structural_eq=...)``.
 """
 
 from __future__ import annotations
@@ -33,7 +33,7 @@ from tvm_ffi.dataclasses import field, py_class
 # ---------------------------------------------------------------------------
 
 
-@py_class("testing.py.Var", structure="var")
+@py_class("testing.py.Var", structural_eq="var")
 class TVar(tvm_ffi.Object):
     """Variable node — compared by binding position, not by name.
 
@@ -42,17 +42,17 @@ class TVar(tvm_ffi.Object):
       name field has SEqHashIgnore
     """
 
-    name: str = field(structure="ignore")
+    name: str = field(structural_eq="ignore")
 
 
-@py_class("testing.py.Int", structure="tree")
+@py_class("testing.py.Int", structural_eq="tree")
 class TInt(tvm_ffi.Object):
     """Simple integer literal node."""
 
     value: int
 
 
-@py_class("testing.py.Func", structure="tree")
+@py_class("testing.py.Func", structural_eq="tree")
 class TFunc(tvm_ffi.Object):
     """Function node with definition region and ignored comment.
 
@@ -61,19 +61,19 @@ class TFunc(tvm_ffi.Object):
       comment has SEqHashIgnore
     """
 
-    params: list = field(structure="def")
+    params: list = field(structural_eq="def")
     body: list
-    comment: str = field(structure="ignore", default="")
+    comment: str = field(structural_eq="ignore", default="")
 
 
-@py_class("testing.py.Expr", structure="tree")
+@py_class("testing.py.Expr", structural_eq="tree")
 class TExpr(tvm_ffi.Object):
     """A simple expression node for tree-comparison tests."""
 
     value: int
 
 
-@py_class("testing.py.Metadata", structure="const-tree")
+@py_class("testing.py.Metadata", structural_eq="const-tree")
 class TMetadata(tvm_ffi.Object):
     """Immutable metadata node — pointer shortcut is safe (no var children)."""
 
@@ -81,7 +81,7 @@ class TMetadata(tvm_ffi.Object):
     version: int
 
 
-@py_class("testing.py.Binding", structure="dag")
+@py_class("testing.py.Binding", structural_eq="dag")
 class TBinding(tvm_ffi.Object):
     """Binding node — sharing structure is semantically meaningful."""
 
@@ -95,7 +95,7 @@ class TBinding(tvm_ffi.Object):
 
 
 class TestFreeVar:
-    """Test structure="var" kind (C++ kTVMFFISEqHashKindFreeVar)."""
+    """Test structural_eq="var" kind (C++ kTVMFFISEqHashKindFreeVar)."""
 
     def test_free_var_equal_with_mapping(self) -> None:
         """Two different vars are equal when map_free_vars=True."""
@@ -127,7 +127,7 @@ class TestFreeVar:
         assert structural_equal(x, x)
 
     def test_free_var_name_ignored(self) -> None:
-        """The name field is structure="ignore", so it doesn't affect 
comparison."""
+        """The name field is structural_eq="ignore", so it doesn't affect 
comparison."""
         a = TVar("different_name_a")
         b = TVar("different_name_b")
         # Names differ, but with mapping they are still equal
@@ -140,7 +140,7 @@ class TestFreeVar:
 
 
 class TestFuncDefAndIgnore:
-    """Test structure="def" and structure="ignore" on fields."""
+    """Test structural_eq="def" and structural_eq="ignore" on fields."""
 
     def test_alpha_equivalent_functions(self) -> None:
         """fun(x){1, x} with comment_a == fun(y){1, y} with comment_b."""
@@ -217,7 +217,7 @@ class TestFuncDefAndIgnore:
 
 
 class TestTreeNode:
-    """Test structure="tree" kind."""
+    """Test structural_eq="tree" kind."""
 
     def test_equal_content(self) -> None:
         """Two tree nodes with identical content are structurally equal."""
@@ -249,7 +249,7 @@ class TestTreeNode:
 
 
 class TestConstTreeNode:
-    """Test structure="const-tree" kind."""
+    """Test structural_eq="const-tree" kind."""
 
     def test_equal_content(self) -> None:
         """Two const-tree nodes with identical content are structurally 
equal."""
@@ -276,7 +276,7 @@ class TestConstTreeNode:
 
 
 class TestDAGNode:
-    """Test structure="dag" kind."""
+    """Test structural_eq="dag" kind."""
 
     def test_same_dag_shape(self) -> None:
         """Two DAGs with the same sharing shape are equal."""
@@ -319,10 +319,10 @@ class TestDAGNode:
 
 
 class TestUnsupported:
-    """Test that types without structure= raise on structural comparison."""
+    """Test that types without structural_eq= raise on structural 
comparison."""
 
     def test_unsupported_raises_on_hash(self) -> None:
-        """Structural hashing raises TypeError for types without structure=."""
+        """Structural hashing raises TypeError for types without 
structural_eq=."""
 
         @py_class("testing.py.Plain")
         class Plain(tvm_ffi.Object):
@@ -332,7 +332,7 @@ class TestUnsupported:
             structural_hash(Plain(x=1))
 
     def test_unsupported_raises_on_equal(self) -> None:
-        """Structural equality raises TypeError for types without 
structure=."""
+        """Structural equality raises TypeError for types without 
structural_eq=."""
 
         @py_class("testing.py.Plain2")
         class Plain2(tvm_ffi.Object):
@@ -348,14 +348,14 @@ class TestUnsupported:
 
 
 class TestValidation:
-    """Test that invalid structure= values are rejected."""
+    """Test that invalid structural_eq= values are rejected."""
 
     def test_invalid_type_structure(self) -> None:
-        """Invalid type-level structure= value raises ValueError."""
-        with pytest.raises(ValueError, match="structure"):
-            py_class(structure="invalid")
+        """Invalid type-level structural_eq= value raises ValueError."""
+        with pytest.raises(ValueError, match="structural_eq"):
+            py_class(structural_eq="invalid")
 
     def test_invalid_field_structure(self) -> None:
-        """Invalid field-level structure= value raises ValueError."""
-        with pytest.raises(ValueError, match="structure"):
-            field(structure="bad_value")
+        """Invalid field-level structural_eq= value raises ValueError."""
+        with pytest.raises(ValueError, match="structural_eq"):
+            field(structural_eq="bad_value")

Reply via email to