The GitHub Actions job "CI" on tvm-ffi.git/main has succeeded.
Run started by GitHub user tqchen (triggered by tqchen).

Head commit for run:
b87196f998868b2dfb76a7bf2be8795f75b099b8 / Junru Shao <[email protected]>
feat(python): expose recursive compare to Python with comprehensive tests (#484)

## Summary

- Expose `RecursiveEq`, `RecursiveLt`, `RecursiveLe`, `RecursiveGt`,
`RecursiveGe` C++ comparison functions to Python via `_ffi_api` typed
stubs
- Add three new testing dataclasses (`TestCompare`, `TestCustomCompare`,
`TestEqWithoutHash`) to `tvm_ffi.testing`
- Add comprehensive `test_dataclass_compare.py` (1272 lines, 101 test
cases) covering recursive structural comparison end-to-end from Python

## Architecture

- **Python FFI surface**: `_ffi_api.py` gains five
`Recursive{Eq,Lt,Le,Gt,Ge}` typed stubs plus `GetKwargsObject` and
`MakeInit` (from upstream stub regeneration). These delegate to the C++
`ffi.Recursive*` global functions already registered in the runtime.
- **Testing infrastructure**: `tvm_ffi.testing` gains `TestCompare`
(field-level `Compare(false)` opt-out), `TestCustomCompare` (custom
`__ffi_eq__`/`__ffi_compare__` hooks comparing only `key`), and
`TestEqWithoutHash` (equality without hash — exercises the hash-guard
path where ordering falls back to reflection). All three are
`@register_object`-decorated with C++ reflection stubs.

## Public Interfaces

- No public API changes. `RecursiveEq`/`RecursiveLt`/etc. are internal
`_ffi_api` symbols used by tests; the C++ functions were already
registered on `main`.

## Behavioral Changes

- No runtime behavioral changes. This PR adds Python-side bindings and
tests only.

## Test Plan

101 tests in `test_dataclass_compare.py` covering:

- **Primitives**: int (including int64 extremes where naive subtraction
overflows), float (signed zero, infinity), NaN (equality-only; ordering
raises `TypeError`; payload-insensitive), bool, string (SmallStr/Str
heap boundary, embedded NUL), bytes (SmallBytes/Bytes boundary, embedded
NUL, high-bit)
- **Special values**: `None` ordering (less than any non-None),
type-mismatch (eq returns `False`, ordering raises `TypeError`)
- **Inline types**: `DataType`, `Device`
- **Containers**: `Array`, `List`, `Map`, `Dict`, `Shape` — equality,
lexicographic ordering, empty/prefix/length-mismatch, nested composition
(3-level deep)
- **Reflected objects**: `TestIntPair` field-by-field structural
comparison, `TestCompare` with `Compare(false)` field exclusion,
`TestCustomCompare` with custom `__ffi_eq__`/`__ffi_compare__` hooks,
cross-type object comparison, inherited fields (2- and 3-level
inheritance)
- **Cycle detection**: same-pointer identity (returns `True`), distinct
cyclic `List`/`Dict` under equality (returns `True` via on-stack pair
memoization), distinct cyclic structures under ordering (raises
`ValueError`)
- **Ordering laws**: trichotomy (exactly one of lt/eq/gt),
derived-operator consistency (le ↔ lt∨eq, ge ↔ gt∨eq, lt ↔ ¬ge, gt ↔
¬le), antisymmetry, and O(n³) transitivity for Lt and Le over
`TestIntPair` values
- **Advanced**: `CompareOff` flag inside containers and nested objects,
`EqWithoutHash` hash guard (eq-only hook with reflection fallback for
ordering), `Function` objects (no reflected fields → always equal),
depth-1000 nested singleton arrays (iterative stack)

```
uv run pytest -vvs tests/python/test_dataclass_compare.py
# 101 passed, 0 failed
```

## Untested Edge Cases

- Asymmetric cycles (`a → b → a` where the two sides have different
cycle structure). The C++ `on_stack_` set tracks `(lhs, rhs)` pairs so
this should terminate correctly, but no explicit test covers it. Risk:
low.
- `Tuple` and `Variant` containers are not exercised (no Python
constructor surface for `Variant` in `tvm_ffi`).

Report URL: https://github.com/apache/tvm-ffi/actions/runs/22509298188

With regards,
GitHub Actions via GitBox


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to