You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by ju...@apache.org on 2026/02/14 23:34:19 UTC
(tvm-ffi) 01/01: feat: Support direct construction of `tvm_ffi.Function` from callables
This is an automated email from the ASF dual-hosted git repository.
junrushao pushed a commit to branch revert-406-revert-395-2026-01-09/py-func-enhance
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
commit 8cf37564d9e0790d62f758e4f8b953120b54546f
Author: Junru Shao <ju...@gmail.com>
AuthorDate: Mon Jan 12 10:39:43 2026 -0800
feat: Support direct construction of `tvm_ffi.Function` from callables
Add `__init__` to the Cython `Function` class so users can write:
fadd = tvm_ffi.Function(add)
instead of going through `tvm_ffi.convert_to_tvm_func`. The constructor:
- Validates that the argument is callable
- Copies the handle (with incref) if the input is already a Function
- Otherwise converts via `_convert_to_ffi_func_handle`
Also adds the corresponding type stub in `core.pyi` and a test in
`test_function.py`.
Re-lands the original change reverted in #406.
---
python/tvm_ffi/core.pyi | 1 +
python/tvm_ffi/cython/function.pxi | 21 +++++++++++++++++++++
tests/python/test_function.py | 9 +++++++++
3 files changed, 31 insertions(+)
diff --git a/python/tvm_ffi/core.pyi b/python/tvm_ffi/core.pyi
index 2cee79c..1c3a3da 100644
--- a/python/tvm_ffi/core.pyi
+++ b/python/tvm_ffi/core.pyi
@@ -184,6 +184,7 @@ class DLTensorTestWrapper:
def _dltensor_test_wrapper_c_dlpack_from_pyobject_as_intptr() -> int: ...
class Function(Object):
+ def __init__(self, func: Callable[..., Any]) -> None: ...
@property
def release_gil(self) -> bool: ...
@release_gil.setter
diff --git a/python/tvm_ffi/cython/function.pxi b/python/tvm_ffi/cython/function.pxi
index ec1542d..6a9638b 100644
--- a/python/tvm_ffi/cython/function.pxi
+++ b/python/tvm_ffi/cython/function.pxi
@@ -889,6 +889,27 @@ cdef class Function(Object):
def __cinit__(self) -> None:
self.c_release_gil = _RELEASE_GIL_BY_DEFAULT
+ def __init__(self, func: Callable[..., Any]) -> None:
+ """Initialize a Function from a Python callable.
+
+ This constructor allows creating a `tvm_ffi.Function` directly
+ from a Python function or another `tvm_ffi.Function` instance.
+
+ Parameters
+ ----------
+ func : Callable[..., Any]
+ The Python callable to wrap.
+ """
+ cdef TVMFFIObjectHandle chandle = NULL
+ if not callable(func):
+ raise TypeError(f"func must be callable, got {type(func)}")
+ if isinstance(func, Function):
+ chandle = (<Object>func).chandle
+ TVMFFIObjectIncRef(chandle)
+ else:
+ _convert_to_ffi_func_handle(func, &chandle)
+ self.chandle = chandle
+
property release_gil:
"""Whether calls release the Python GIL while executing."""
diff --git a/tests/python/test_function.py b/tests/python/test_function.py
index 686fc08..de8aa7f 100644
--- a/tests/python/test_function.py
+++ b/tests/python/test_function.py
@@ -153,6 +153,15 @@ def test_pyfunc_convert() -> None:
assert fapply(add, 1, 3.3) == 4.3
+def test_pyfunc_init() -> None:
+ def add(a: int, b: int) -> int:
+ return a + b
+
+ fadd = tvm_ffi.Function(add)
+ assert isinstance(fadd, tvm_ffi.Function)
+ assert fadd(1, 2) == 3
+
+
def test_global_func() -> None:
@tvm_ffi.register_global_func("mytest.echo")
def echo(x: Any) -> Any: