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 4edf4f3  feat(cython): Expose TypeAttr via `_lookup_type_attr` (#247)
4edf4f3 is described below

commit 4edf4f30e50c52e082ad178eb91016378335040d
Author: Junru Shao <[email protected]>
AuthorDate: Sat Nov 8 17:31:55 2025 -0800

    feat(cython): Expose TypeAttr via `_lookup_type_attr` (#247)
    
    This PR introduces an API that exposes type attributes on Python side.
    For now, there's no type attribute being defined, but I personally do
    anticipate usecases (e.g. `__repr__`, `__metadata__`, etc.) being used
    as part of stubgen & dataclass push.
---
 include/tvm/ffi/c_api.h          | 6 +++---
 python/tvm_ffi/core.pyi          | 1 +
 python/tvm_ffi/cython/base.pxi   | 5 +++++
 python/tvm_ffi/cython/object.pxi | 9 +++++++++
 src/ffi/object.cc                | 8 ++++----
 tests/python/test_metadata.py    | 6 +++++-
 6 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/include/tvm/ffi/c_api.h b/include/tvm/ffi/c_api.h
index ebe1a99..e773208 100644
--- a/include/tvm/ffi/c_api.h
+++ b/include/tvm/ffi/c_api.h
@@ -156,9 +156,6 @@ typedef enum {
   kTVMFFITensor = 70,
   /*! \brief Array object. */
   kTVMFFIArray = 71,
-  //----------------------------------------------------------------
-  // more complex objects
-  //----------------------------------------------------------------
   /*! \brief Map object. */
   kTVMFFIMap = 72,
   /*! \brief Runtime dynamic loaded module object. */
@@ -175,6 +172,9 @@ typedef enum {
    * \sa TVMFFIObjectCreateOpaque
    */
   kTVMFFIOpaquePyObject = 74,
+  //----------------------------------------------------------------
+  // more complex objects
+  //----------------------------------------------------------------
   kTVMFFIStaticObjectEnd,
   // [Section] Dynamic Boxed: [kTVMFFIDynObjectBegin, +oo)
   /*! \brief Start of type indices that are allocated at runtime. */
diff --git a/python/tvm_ffi/core.pyi b/python/tvm_ffi/core.pyi
index d5d43b7..8141748 100644
--- a/python/tvm_ffi/core.pyi
+++ b/python/tvm_ffi/core.pyi
@@ -67,6 +67,7 @@ def _register_object_by_index(type_index: int, type_cls: 
type) -> TypeInfo: ...
 def _object_type_key_to_index(type_key: str) -> int | None: ...
 def _set_type_cls(type_info: TypeInfo, type_cls: type) -> None: ...
 def _lookup_or_register_type_info_from_type_key(type_key: str) -> TypeInfo: ...
+def _lookup_type_attr(type_index: int, attr_key: str) -> Any: ...
 
 class Error(Object):
     def __init__(self, kind: str, message: str, backtrace: str) -> None: ...
diff --git a/python/tvm_ffi/cython/base.pxi b/python/tvm_ffi/cython/base.pxi
index 597956b..a24a5d8 100644
--- a/python/tvm_ffi/cython/base.pxi
+++ b/python/tvm_ffi/cython/base.pxi
@@ -244,6 +244,10 @@ cdef extern from "tvm/ffi/c_api.h":
         const TVMFFIMethodInfo* methods
         const TVMFFITypeMetadata* metadata
 
+    ctypedef struct TVMFFITypeAttrColumn:
+        const TVMFFIAny* data
+        size_t size
+
     int TVMFFIObjectDecRef(TVMFFIObjectHandle obj) nogil
     int TVMFFIObjectIncRef(TVMFFIObjectHandle obj) nogil
     int TVMFFIObjectCreateOpaque(void* handle, int32_t type_index,
@@ -285,6 +289,7 @@ cdef extern from "tvm/ffi/c_api.h":
     TVMFFIShapeCell* TVMFFIShapeGetCellPtr(TVMFFIObjectHandle obj) nogil
     DLTensor* TVMFFITensorGetDLTensorPtr(TVMFFIObjectHandle obj) nogil
     DLDevice TVMFFIDLDeviceFromIntPair(int32_t device_type, int32_t device_id) 
nogil
+    const TVMFFITypeAttrColumn* TVMFFIGetTypeAttrColumn(const TVMFFIByteArray* 
attr_name) nogil
 
 cdef extern from "tvm/ffi/extra/c_env_api.h":
     ctypedef void* TVMFFIStreamHandle
diff --git a/python/tvm_ffi/cython/object.pxi b/python/tvm_ffi/cython/object.pxi
index 0c5bdac..49c7595 100644
--- a/python/tvm_ffi/cython/object.pxi
+++ b/python/tvm_ffi/cython/object.pxi
@@ -514,6 +514,15 @@ def _lookup_or_register_type_info_from_type_key(type_key: 
str) -> TypeInfo:
     return info
 
 
+def _lookup_type_attr(type_index: int32_t, attr_key: str) -> Any:
+    cdef ByteArrayArg attr_key_bytes = ByteArrayArg(c_str(attr_key))
+    cdef const TVMFFITypeAttrColumn* column = 
TVMFFIGetTypeAttrColumn(&attr_key_bytes.cdata)
+    cdef TVMFFIAny data
+    if column == NULL or column.size <= type_index:
+        return None
+    return make_ret(column.data[type_index])
+
+
 cdef list TYPE_INDEX_TO_CLS = []
 cdef list TYPE_INDEX_TO_INFO = []
 cdef dict TYPE_KEY_TO_INFO = {}
diff --git a/src/ffi/object.cc b/src/ffi/object.cc
index 810d3b1..1671ba8 100644
--- a/src/ffi/object.cc
+++ b/src/ffi/object.cc
@@ -315,7 +315,7 @@ class TypeTable {
   }
 
  private:
-  TypeTable() {
+  TypeTable() : type_attr_columns_{}, type_attr_name_to_column_index_{} {
     type_table_.reserve(TypeIndex::kTVMFFIDynObjectBegin);
     for (int32_t i = 0; i < TypeIndex::kTVMFFIDynObjectBegin; ++i) {
       type_table_.emplace_back(nullptr);
@@ -332,13 +332,13 @@ class TypeTable {
     // reserve the static types
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFINone, 
TypeIndex::kTVMFFINone);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIInt, TypeIndex::kTVMFFIInt);
-    ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIFloat, 
TypeIndex::kTVMFFIFloat);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIBool, 
TypeIndex::kTVMFFIBool);
-    ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIRawStr, 
TypeIndex::kTVMFFIRawStr);
+    ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIFloat, 
TypeIndex::kTVMFFIFloat);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIOpaquePtr, 
TypeIndex::kTVMFFIOpaquePtr);
-    ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDLTensorPtr, 
TypeIndex::kTVMFFIDLTensorPtr);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDataType, 
TypeIndex::kTVMFFIDataType);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDevice, 
TypeIndex::kTVMFFIDevice);
+    ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDLTensorPtr, 
TypeIndex::kTVMFFIDLTensorPtr);
+    ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIRawStr, 
TypeIndex::kTVMFFIRawStr);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIByteArrayPtr, 
TypeIndex::kTVMFFIByteArrayPtr);
     ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIObjectRValueRef,
                             TypeIndex::kTVMFFIObjectRValueRef);
diff --git a/tests/python/test_metadata.py b/tests/python/test_metadata.py
index 787ed91..116afd3 100644
--- a/tests/python/test_metadata.py
+++ b/tests/python/test_metadata.py
@@ -18,7 +18,7 @@ from typing import Any
 
 import pytest
 from tvm_ffi import get_global_func_metadata
-from tvm_ffi.core import TypeInfo, TypeSchema
+from tvm_ffi.core import TypeInfo, TypeSchema, _lookup_type_attr
 from tvm_ffi.testing import _SchemaAllTypes
 
 
@@ -195,3 +195,7 @@ def test_mem_fn_as_global_func() -> None:
     metadata: dict[str, Any] = 
get_global_func_metadata("testing.TestIntPairSum")
     type_schema: TypeSchema = TypeSchema.from_json_str(metadata["type_schema"])
     assert str(type_schema) == "Callable[[testing.TestIntPair], int]"
+
+
+def test_class_metadata_none() -> None:
+    assert _lookup_type_attr(64, "__metadata__") is None

Reply via email to