Skip to content

feat(python): add structural equality/hashing support to py_class and field#507

Merged
junrushao merged 1 commit intoapache:mainfrom
junrushao:junrushao/2026-03-21/py-class-equality
Mar 22, 2026
Merged

feat(python): add structural equality/hashing support to py_class and field#507
junrushao merged 1 commit intoapache:mainfrom
junrushao:junrushao/2026-03-21/py-class-equality

Conversation

@junrushao
Copy link
Member

@junrushao junrushao commented Mar 22, 2026

Summary

  • Add structure= parameter to @py_class() and field() controlling structural equality/hashing behavior. Class-level values: "var", "tree", "const-tree", "dag". Field-level values: "ignore", "def". Dispatched via Cython-accelerated _ffi_seq_hash_kind and _ffi_field_info_seq_hash attributes, mapping to C++ TVMFFISEqHashKind and SEqHashIgnore/SEqHashDef field flags.
  • Expand py_class test coverage with 349 tests ported from mlc-python (field parsing, defaults, inheritance, JSON serialization, nested structures, edge cases).
  • Add docs/concepts/structural_eq_hash.rst documenting the structural equality/hashing design.
  • Pin astral-sh/setup-uv to v7.3.1 and pypa/cibuildwheel to v3.3.1 (Apache-approved SHAs), fixing CI permission failures in https://github.com/apache/tvm-ffi/actions/runs/23389552989.

Test plan

  • uv run pytest -vvs tests/python/test_dataclass_py_class.py tests/python/test_structural_py_class.py — 349 passed
  • All pre-commit hooks pass

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust structural equality and hashing mechanism for Python classes defined using py_class. This enhancement allows for content-based comparison and hashing of complex object graphs, crucial for IR nodes and dataflow structures, moving beyond simple pointer identity. It also addresses a critical CI issue by updating GitHub Actions dependencies to approved versions, ensuring build stability.

Highlights

  • Structural Equality and Hashing: Added structural equality and hashing support for py_class and field based on field-level annotations, enabling content-based comparison and hashing for complex object graphs.
  • Expanded Test Coverage: Expanded py_class test coverage with 349 new tests for various scenarios including field parsing, inheritance, container types, and nested structures, ensuring robustness of the new features.
  • CI Action Fix: Fixed GitHub Actions wheel build permissions by pinning specific, Apache infrastructure-approved versions of setup-uv and cibuildwheel to resolve previous failures.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces structural equality and hashing for py_class objects, controlled by a new structure parameter on the @py_class decorator and field helper. The implementation is robust, spanning Python and Cython layers, and is accompanied by excellent, comprehensive documentation that clearly explains the new concepts. The PR also includes a substantial expansion of the test suite, adding hundreds of new tests that cover a wide range of py_class functionality, significantly improving the project's test coverage and maintainability. A minor CI fix is also included. The changes are of high quality, and I have no further feedback.

…nd `field` (#53)

Add a `structure=` parameter to `@py_class()` and `field()` that
controls structural equality and hashing behavior for Python-defined
FFI dataclasses.

Class-level `structure=` accepts: "var" (default, identity semantics),
"tree", "const-tree", "dag". Field-level `structure=` accepts:
"ignore" and "def". These map to the C++ `TVMFFISEqHashKind` enum and
`SEqHashIgnore`/`SEqHashDef` field flags, dispatched through
Cython-accelerated `_ffi_seq_hash_kind` and `_ffi_field_info_seq_hash`
attributes on object types.

Additional changes in this squash:

- Expand `py_class` test coverage with 349 tests ported from
  mlc-python covering field parsing, defaults, inheritance, JSON
  serialization, nested structures, and edge cases.
- Add `docs/concepts/structural_eq_hash.rst` documenting the
  structural equality/hashing design.
- Pin `astral-sh/setup-uv` to v7.3.1 (`5a095e7a`) and
  `pypa/cibuildwheel` to v3.3.1 (`298ed2fb`), both Apache-approved
  SHAs, fixing CI permission failures.
@junrushao junrushao force-pushed the junrushao/2026-03-21/py-class-equality branch from f57e9c8 to 20b9b7d Compare March 22, 2026 16:49
@junrushao junrushao changed the title feat(python): structural equality/hashing for py_class + CI action fix feat(python): add structural equality/hashing support to py_class and field Mar 22, 2026
@junrushao junrushao merged commit d8bd189 into apache:main Mar 22, 2026
8 checks passed
junrushao added a commit that referenced this pull request Mar 22, 2026
…peMethod (#508)

## Summary

- Extend `@py_class` to detect and register recognized FFI dunder
methods (`__ffi_repr__`, `__ffi_eq__`, `__s_equal__`, etc.) defined on
Python dataclasses, making them callable from C++ and other FFI
languages
- `_FFI_RECOGNIZED_METHODS` allowlist in `py_class.py` gates which
dunders are collected; `_collect_py_methods()` scans class dict and
`TypeInfo._register_py_methods()` registers via the C API
(`TVMFFITypeRegisterMethod` + `TVMFFITypeRegisterAttr`)
- No C++ changes — `dataclass.cc` is unmodified from upstream

## Changes since v1

- Rebased onto upstream/main (`d8bd1890`) which adds structural
equality/hashing support (#507)
- Resolved merge conflicts: preserved `structure_kind` /
`STRUCTURE_KIND_MAP` from upstream
- Applied Gemini Code Assist review feedback:
- **HIGH**: Fixed `func_any` memory leak in `_register_py_methods` by
adding `TVMFFIObjectDecRef` in a `try/finally` block
- **MEDIUM**: Changed `_collect_py_methods` to iterate
`cls.__dict__.items()` instead of `list(cls.__dict__)` + second lookup

## Test plan

- [x] 12 new dedicated tests covering allowlist filtering, registration,
round-trip dispatch (repr, eq, compare, hash)
- [x] All 693 tests pass (including structural equality tests that now
work with the `structure_kind` base from #507)
- [ ] CI: lint, C++ tests, Python tests, Rust tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants