feat(python): add @py_class decorator for Python-defined FFI dataclasses#506
Conversation
Summary of ChangesHello, 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 significantly enhances the Python FFI system by introducing a new decorator that allows developers to define FFI classes directly in Python using a familiar dataclass-like syntax. This change simplifies the process of creating and managing Python-backed FFI types, improving developer experience and promoting more idiomatic Python code within the TVM ecosystem. The new decorator handles complex aspects like type resolution and dunder method generation automatically, reducing boilerplate and potential errors. Highlights
🧠 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 AssistThe 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
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 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
|
e89418d to
ed289b2
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces the @py_class decorator, enabling the definition of TVM FFI dataclasses directly in Python. This is a significant enhancement, providing dataclass-like semantics including typed fields, __init__ generation, structural comparison, hashing, and robust handling of forward/self-referential types through a two-phase registration mechanism. The implementation demonstrates careful consideration for edge cases, such as KW_ONLY fields, user-defined dunder preservation, and error handling with registration rollback. The accompanying test suite is exceptionally comprehensive, covering a wide array of scenarios from basic field parsing and inheritance to complex type conversions and memory management, ensuring the reliability and correctness of this new feature.
@py_class decorator for Python-defined FFI dataclasses
…asses Add a new `@py_class` decorator that lets users define TVM FFI Object types entirely in Python with dataclass-style field annotations, complementing the existing `@c_class` decorator for C++-backed types. ## Architecture Registration uses a two-phase approach: - **Phase 1** (`_phase1_register_type`): Allocates a C-level type index and inserts the class into the global type registry. Runs eagerly so self-referential and mutually-referential annotations can resolve. - **Phase 2** (`_phase2_register_fields`): Resolves string annotations via `typing.get_type_hints`, converts them to `TypeSchema`/`Field` objects, validates field ordering, registers fields with the Cython layer, and installs `__init__`/`__repr__`/`__eq__`/etc. When `get_type_hints` raises `NameError` (forward reference not yet defined), the class is added to a pending list and retried after each successful phase-2 completion. A deferred `__init__` triggers lazy completion on first instantiation. Failed phase-2 rolls back phase-1 so the type key can be reused. ## Public Interfaces - `@py_class` decorator in `tvm_ffi.dataclasses` (supports bare, string-key, and keyword-argument calling conventions) - Parameters: `type_key`, `init`, `repr`, `eq`, `order`, `unsafe_hash`, `kw_only`, `slots` - Re-exported from `tvm_ffi.dataclasses.__init__` ## Behavioral Changes - None to existing APIs. This is a purely additive feature. ## Tests - 47 test classes covering: basic registration, field parsing, defaults/factories, kw_only, ClassVar, init generation, post_init, repr, equality, ordering, hashing, copy/deepcopy, single and multi-level inheritance, forward/mutual references, dunder preservation, registration rollback, type conversion errors, getter/setter corner cases, memory lifetime, bool alignment, optional fields, Any fields, and FFI global function interop. - 246 tests in `tests/python/test_dataclass_py_class.py` (3533 lines). ## Untested Edge Cases - Thread safety of the pending-class flush mechanism. - Interaction with `importlib.reload()` on modules containing `@py_class`-decorated types. - Deeply nested generic type annotations (e.g. `List[Optional[Map[str, Array[int]]]]`).
ed289b2 to
ef44efb
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces the @py_class decorator, a significant feature that enables defining TVM FFI objects purely in Python with a dataclass-like syntax. The implementation is robust, handling complex scenarios like forward and mutual references through a two-phase registration process and lazy initialization. The code is well-structured and documented. I've identified a critical thread-safety issue in the registration logic that should be addressed, as well as a minor opportunity for code simplification. Overall, this is an excellent contribution.
Summary
Add
@py_class, a new decorator that lets users define TVM FFI Object types entirely in Python with dataclass-style field annotations. This complements@c_class(which wraps C++-backed types) by enabling pure-Python FFI types that participate in the same object system -- type registry, reference counting, cross-language serialization, and packed-function interop.Motivation
Currently, defining a new FFI-visible type requires either writing C++ (
ObjectDef<T>) or using@c_classwhich expects C++ reflection metadata.@py_classremoves the C++ requirement entirely: annotate fields with Python types, and the decorator handles type-index allocation, field registration, and dunder generation.Usage
Architecture
Registration is split into two phases to handle forward and mutual references:
_phase1_register_type): Allocates a C-level type index and inserts the class into the global type registry. Runs eagerly so that self-referential and mutually-referential annotations can be resolved._phase2_register_fields): Resolves string annotations viatyping.get_type_hints, converts them toTypeSchema/Fieldobjects, validates field ordering, registers fields with the Cython layer, and installs__init__/__repr__/__eq__/etc.When
get_type_hintsraisesNameError(forward reference not yet defined), the class is deferred to a pending list and retried after each successful phase-2. A temporary__init__triggers lazy completion on first instantiation. Failed phase-2 rolls back phase-1 so the type key can be reused.Public Interfaces
@py_classtvm_ffi.dataclasses.py_classtype_key,init,repr,eq,order,unsafe_hash,kw_only,slotsdataclasses.dataclasssemanticsTest Plan
tests/python/test_dataclass_py_class.py, 3533 lines)Untested Edge Cases
importlib.reload()on modules containing@py_class-decorated typesList[Optional[Map[str, Array[int]]]])