This is an automated email from the ASF dual-hosted git repository.

tqchen 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 9c0b869  doc(python): Add example coverage to docstrings (#206)
9c0b869 is described below

commit 9c0b86932aaa1abbe033f8cfec916cd35971d91e
Author: Junru Shao <[email protected]>
AuthorDate: Thu Oct 30 05:07:55 2025 -0700

    doc(python): Add example coverage to docstrings (#206)
    
    This PR refines Python-side documentation. It includes:
    
    - Adding example code to every public API as much as possible
    - Making existing examples copy-pastable as much as possible
    - Polish writing
    - Clarifies a few API usage, e.g. system_lib
---
 docs/reference/python/index.rst    |   8 +-
 python/tvm_ffi/_convert.py         |  39 ++++++++-
 python/tvm_ffi/_dtype.py           | 157 +++++++++++++++++++++++++++++++++++--
 python/tvm_ffi/_tensor.py          |  11 +++
 python/tvm_ffi/access_path.py      |  29 ++++++-
 python/tvm_ffi/base.py             |   2 +-
 python/tvm_ffi/container.py        |  26 +++---
 python/tvm_ffi/cython/device.pxi   |   5 +-
 python/tvm_ffi/cython/function.pxi |   6 +-
 python/tvm_ffi/cython/object.pxi   |   4 +
 python/tvm_ffi/cython/tensor.pxi   |   4 +
 python/tvm_ffi/error.py            |  15 ++--
 python/tvm_ffi/module.py           |  95 +++++++++++++---------
 python/tvm_ffi/registry.py         |  66 ++++++++++++++--
 python/tvm_ffi/serialization.py    |  28 +++++--
 python/tvm_ffi/stream.py           |  54 ++++++++++---
 python/tvm_ffi/utils/lockfile.py   |  13 +++
 src/ffi/testing/testing.cc         |   2 +
 18 files changed, 468 insertions(+), 96 deletions(-)

diff --git a/docs/reference/python/index.rst b/docs/reference/python/index.rst
index db01ab3..3a5541e 100644
--- a/docs/reference/python/index.rst
+++ b/docs/reference/python/index.rst
@@ -99,6 +99,7 @@ Stream Context
   StreamContext
   use_torch_stream
   use_raw_stream
+  get_raw_stream
 
 
 Inline Loading
@@ -118,8 +119,11 @@ Misc
 .. autosummary::
   :toctree: generated/
 
-  serialization
-  access_path
+  serialization.from_json_graph_str
+  serialization.to_json_graph_str
+  access_path.AccessKind
+  access_path.AccessPath
+  access_path.AccessStep
   convert
   ObjectConvertible
 
diff --git a/python/tvm_ffi/_convert.py b/python/tvm_ffi/_convert.py
index 1ff91af..43a564c 100644
--- a/python/tvm_ffi/_convert.py
+++ b/python/tvm_ffi/_convert.py
@@ -14,7 +14,7 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-"""Conversion utilities to bring python objects into ffi values."""
+"""Conversion utilities to convert Python objects into TVM FFI values."""
 
 from __future__ import annotations
 
@@ -38,18 +38,51 @@ except ImportError:
 
 
 def convert(value: Any) -> Any:  # noqa: PLR0911,PLR0912
-    """Convert a python object to ffi values.
+    """Convert a Python object into TVM FFI values.
+
+    This helper mirrors the automatic argument conversion that happens when
+    calling FFI functions. It is primarily useful in tests or places where
+    an explicit conversion is desired.
 
     Parameters
     ----------
     value
-        The python object to be converted.
+        The Python object to be converted.
 
     Returns
     -------
     ffi_obj
         The converted TVM FFI object.
 
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        # Lists and tuples become tvm_ffi.Array
+        a = tvm_ffi.convert([1, 2, 3])
+        assert isinstance(a, tvm_ffi.Array)
+
+        # Dicts become tvm_ffi.Map
+        m = tvm_ffi.convert({"a": 1, "b": 2})
+        assert isinstance(m, tvm_ffi.Map)
+
+        # Strings and bytes become zero-copy FFI-aware types
+        s = tvm_ffi.convert("hello")
+        b = tvm_ffi.convert(b"bytes")
+        assert isinstance(s, tvm_ffi.core.String)
+        assert isinstance(b, tvm_ffi.core.Bytes)
+
+        # Callables are wrapped as tvm_ffi.Function
+        f = tvm_ffi.convert(lambda x: x + 1)
+        assert isinstance(f, tvm_ffi.Function)
+
+        # Array libraries that support DLPack export can be converted to Tensor
+        import numpy as np
+        x = tvm_ffi.convert(np.arange(4, dtype="int32"))
+        assert isinstance(x, tvm_ffi.Tensor)
+
     Note
     ----
     Function arguments to ffi function calls are
diff --git a/python/tvm_ffi/_dtype.py b/python/tvm_ffi/_dtype.py
index de2d1f1..5079226 100644
--- a/python/tvm_ffi/_dtype.py
+++ b/python/tvm_ffi/_dtype.py
@@ -14,7 +14,7 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-"""dtype class."""
+"""Lightweight ``dtype`` wrapper for TVM FFI."""
 
 # pylint: disable=invalid-name
 from __future__ import annotations
@@ -47,11 +47,35 @@ class DataTypeCode(IntEnum):
 
 
 class dtype(str):
-    """TVM FFI dtype class.
+    """Lightweight ``dtype`` in TVM FFI.
+
+    ``dtype`` behaves like a Python ``str`` but also carries an internal FFI
+    representation. You can construct it from strings, NumPy/ML dtypes, or
+    via :py:meth:`from_dlpack_data_type`.
 
     Parameters
     ----------
     dtype_str
+        The string representation of the dtype.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        # Create from string
+        f32 = tvm_ffi.dtype("float32")
+        assert f32.bits == 32
+        assert f32.itemsize == 4
+
+        # Adjust lanes to create vector types
+        v4f32 = f32.with_lanes(4)
+        assert v4f32 == "float32x4"
+
+        # Round-trip from a DLPack (code, bits, lanes) triple
+        f16 = tvm_ffi.dtype.from_dlpack_data_type((2, 16, 1))
+        assert f16 == "float16"
 
     Note
     ----
@@ -78,11 +102,31 @@ class dtype(str):
         Parameters
         ----------
         dltype_data_type
-            The DLPack data type tuple (type_code, bits, lanes).
+            The DLPack data type tuple ``(type_code, bits, lanes)``.
 
         Returns
         -------
-        The created dtype.
+        dtype
+            The created dtype.
+
+        Examples
+        --------
+        .. code-block:: python
+
+            import tvm_ffi
+
+            # Create float16 and int8 directly from DLPack triples
+            f16 = tvm_ffi.dtype.from_dlpack_data_type((2, 16, 1))
+            i8 = tvm_ffi.dtype.from_dlpack_data_type((0, 8, 1))
+            assert f16 == "float16"
+            assert i8 == "int8"
+
+        See Also
+        --------
+        :py:class:`tvm_ffi.dtype`
+            User-facing dtype wrapper.
+        :py:meth:`tvm_ffi.dtype.with_lanes`
+            Create vector dtypes from a scalar base.
 
         """
         cdtype = core._create_dtype_from_tuple(
@@ -104,13 +148,29 @@ class dtype(str):
         Parameters
         ----------
         lanes
-            The number of lanes.
+            The number of lanes for the resulting vector type.
 
         Returns
         -------
         dtype
             The new dtype with the given number of lanes.
 
+        Examples
+        --------
+        .. code-block:: python
+
+            import tvm_ffi
+
+            f32 = tvm_ffi.dtype("float32")
+            v4f32 = f32.with_lanes(4)
+            assert v4f32 == "float32x4"
+            assert v4f32.bits == f32.bits and v4f32.lanes == 4
+
+        See Also
+        --------
+        :py:meth:`tvm_ffi.dtype.from_dlpack_data_type`
+            Construct from a DLPack ``(code, bits, lanes)`` triple.
+
         """
         cdtype = core._create_dtype_from_tuple(
             core.DataType,
@@ -124,18 +184,105 @@ class dtype(str):
 
     @property
     def itemsize(self) -> int:
+        """Size of one element in bytes.
+
+        The size is computed as ``bits * lanes // 8``. When the number of
+        lanes is greater than 1, the ``itemsize`` represents the byte size
+        of the vector element.
+
+        Examples
+        --------
+        .. code-block:: python
+
+            import tvm_ffi
+
+            assert tvm_ffi.dtype("float32").itemsize == 4
+            assert tvm_ffi.dtype("float32").with_lanes(4).itemsize == 16
+
+        See Also
+        --------
+        :py:attr:`tvm_ffi.dtype.bits`
+            Bit width of the scalar base type.
+        :py:attr:`tvm_ffi.dtype.lanes`
+            Number of lanes for vector types.
+        :py:meth:`tvm_ffi.dtype.with_lanes`
+            Create a vector dtype from a scalar base.
+
+        """
         return self._tvm_ffi_dtype.itemsize
 
     @property
     def type_code(self) -> int:
+        """Integer DLDataTypeCode of the scalar base type.
+
+        Examples
+        --------
+        .. code-block:: python
+
+            import tvm_ffi
+
+            f32 = tvm_ffi.dtype("float32")
+            # The type code is an integer following DLPack conventions
+            assert isinstance(f32.type_code, int)
+            # Consistent with constructing from an explicit (code, bits, lanes)
+            assert f32.type_code == tvm_ffi.dtype.from_dlpack_data_type((2, 
32, 1)).type_code
+
+        See Also
+        --------
+        :py:meth:`tvm_ffi.dtype.from_dlpack_data_type`
+            Construct a dtype from a DLPack ``(code, bits, lanes)`` triple.
+
+        """
         return self._tvm_ffi_dtype.type_code
 
     @property
     def bits(self) -> int:
+        """Number of bits of the scalar base type.
+
+        Examples
+        --------
+        .. code-block:: python
+
+            import tvm_ffi
+
+            assert tvm_ffi.dtype("int8").bits == 8
+            v4f32 = tvm_ffi.dtype("float32").with_lanes(4)
+            assert v4f32.bits == 32  # per-lane bit width
+
+        See Also
+        --------
+        :py:attr:`tvm_ffi.dtype.itemsize`
+            Byte size accounting for lanes.
+        :py:attr:`tvm_ffi.dtype.lanes`
+            Number of lanes for vector types.
+
+        """
         return self._tvm_ffi_dtype.bits
 
     @property
     def lanes(self) -> int:
+        """Number of lanes (for vector types).
+
+        Returns ``1`` for scalar dtypes and the lane count for vector dtypes
+        created via :py:meth:`tvm_ffi.dtype.with_lanes`.
+
+        Examples
+        --------
+        .. code-block:: python
+
+            import tvm_ffi
+
+            assert tvm_ffi.dtype("float32").lanes == 1
+            assert tvm_ffi.dtype("float32").with_lanes(4).lanes == 4
+
+        See Also
+        --------
+        :py:meth:`tvm_ffi.dtype.with_lanes`
+            Create a vector dtype from a scalar base.
+        :py:attr:`tvm_ffi.dtype.itemsize`
+            Byte size accounting for lanes.
+
+        """
         return self._tvm_ffi_dtype.lanes
 
 
diff --git a/python/tvm_ffi/_tensor.py b/python/tvm_ffi/_tensor.py
index 4c9714b..5005bc6 100644
--- a/python/tvm_ffi/_tensor.py
+++ b/python/tvm_ffi/_tensor.py
@@ -43,6 +43,16 @@ class Shape(tuple, PyNativeObject):
     This class subclasses :class:`tuple` so it can be used in most places where
     :class:`tuple` is used in Python array APIs.
 
+    Examples
+    --------
+    .. code-block:: python
+
+        import numpy as np
+        import tvm_ffi
+
+        x = tvm_ffi.from_dlpack(np.arange(6, dtype="int32").reshape(2, 3))
+        assert x.shape == (2, 3)
+
     """
 
     _tvm_ffi_cached_object: Any
@@ -85,6 +95,7 @@ def device(device_type: str | int | DLDeviceType, index: int 
| None = None) -> D
 
     .. code-block:: python
 
+      import tvm_ffi
       assert tvm_ffi.device("cuda:0") == tvm_ffi.device("cuda", 0)
       assert tvm_ffi.device("cpu:0") == tvm_ffi.device("cpu", 0)
 
diff --git a/python/tvm_ffi/access_path.py b/python/tvm_ffi/access_path.py
index a048a8a..6b9db9c 100644
--- a/python/tvm_ffi/access_path.py
+++ b/python/tvm_ffi/access_path.py
@@ -53,7 +53,25 @@ class AccessStep(Object):
 
 @register_object("ffi.reflection.AccessPath")
 class AccessPath(Object):
-    """Access path container."""
+    """Access path container.
+
+    An ``AccessPath`` describes how to reach a nested attribute or item
+    inside a complex FFI object by recording a sequence of steps
+    (attribute, array index, or map key). It is primarily used by
+    diagnostics to pinpoint structural mismatches.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        from tvm_ffi.access_path import AccessPath
+
+        root = AccessPath.root()
+        # Build a path equivalent to obj.layer.weight[2]
+        p = root.attr("layer").attr("weight").array_item(2)
+        assert isinstance(p, AccessPath)
+
+    """
 
     # tvm-ffi-stubgen(begin): object/ffi.reflection.AccessPath
     if TYPE_CHECKING:
@@ -86,7 +104,14 @@ class AccessPath(Object):
 
     @staticmethod
     def root() -> AccessPath:
-        """Create a root access path."""
+        """Create a root access path.
+
+        Returns
+        -------
+        AccessPath
+            A path representing the root of an object graph.
+
+        """
         return AccessPath._root()
 
     def __eq__(self, other: Any) -> bool:
diff --git a/python/tvm_ffi/base.py b/python/tvm_ffi/base.py
index 45c9be2..2e2ece3 100644
--- a/python/tvm_ffi/base.py
+++ b/python/tvm_ffi/base.py
@@ -41,7 +41,7 @@ if sys.version_info[:2] < (3, 8):  # noqa: UP036
 
 
 def _load_lib() -> ctypes.CDLL:
-    """Load libary by searching possible path."""
+    """Load the tvm_ffi shared library by searching likely paths."""
     lib_path = libinfo.find_libtvm_ffi()
     # The dll search path need to be added explicitly in windows
     if sys.platform.startswith("win32"):
diff --git a/python/tvm_ffi/container.py b/python/tvm_ffi/container.py
index a23fa47..90a84a2 100644
--- a/python/tvm_ffi/container.py
+++ b/python/tvm_ffi/container.py
@@ -124,7 +124,7 @@ def getitem_helper(
 
 @register_object("ffi.Array")
 class Array(core.Object, Sequence[T]):
-    """Array container that represents a sequence of values in ffi.
+    """Array container that represents a sequence of values in the FFI.
 
     :py:func:`tvm_ffi.convert` will map python list/tuple to this class.
 
@@ -133,19 +133,18 @@ class Array(core.Object, Sequence[T]):
     input_list
         The list of values to be stored in the array.
 
-    See Also
-    --------
-    :py:func:`tvm_ffi.convert`
-
     Examples
     --------
     .. code-block:: python
 
         import tvm_ffi
 
-        a = tvm_ffi.convert([1, 2, 3])
-        assert isinstance(a, tvm_ffi.Array)
-        assert len(a) == 3
+        a = tvm_ffi.Array([1, 2, 3])
+        assert tuple(a) == (1, 2, 3)
+
+    See Also
+    --------
+    :py:func:`tvm_ffi.convert`
 
     """
 
@@ -274,22 +273,21 @@ class Map(core.Object, Mapping[K, V]):
     input_dict
         The dictionary of values to be stored in the map.
 
-    See Also
-    --------
-    :py:func:`tvm_ffi.convert`
-
     Examples
     --------
     .. code-block:: python
 
         import tvm_ffi
 
-        amap = tvm_ffi.convert({"a": 1, "b": 2})
-        assert isinstance(amap, tvm_ffi.Map)
+        amap = tvm_ffi.Map({"a": 1, "b": 2})
         assert len(amap) == 2
         assert amap["a"] == 1
         assert amap["b"] == 2
 
+    See Also
+    --------
+    :py:func:`tvm_ffi.convert`
+
     """
 
     def __init__(self, input_dict: Mapping[K, V]) -> None:
diff --git a/python/tvm_ffi/cython/device.pxi b/python/tvm_ffi/cython/device.pxi
index e23fee7..413ef40 100644
--- a/python/tvm_ffi/cython/device.pxi
+++ b/python/tvm_ffi/cython/device.pxi
@@ -35,7 +35,7 @@ def _create_device_from_tuple(cls, device_type, device_id):
 
 
 class DLDeviceType(IntEnum):
-    """Enumeration mirroring DLPack's ``DLDeviceType``.
+    """Enumeration mirroring DLPack's `DLDeviceType 
<https://dmlc.github.io/dlpack/latest/c_api.html#c.DLDeviceType>`_
 
     Values can be compared against :py:meth:`Device.dlpack_device_type`.
 
@@ -43,6 +43,7 @@ class DLDeviceType(IntEnum):
     --------
     .. code-block:: python
 
+        import tvm_ffi
         dev = tvm_ffi.device("cuda", 0)
         assert dev.dlpack_device_type() == tvm_ffi.DLDeviceType.kDLCUDA
 
@@ -83,6 +84,8 @@ cdef class Device:
     --------
     .. code-block:: python
 
+        import tvm_ffi
+
         dev = tvm_ffi.device("cuda:0")
         assert dev.type == "cuda"
         assert dev.index == 0
diff --git a/python/tvm_ffi/cython/function.pxi 
b/python/tvm_ffi/cython/function.pxi
index bf84091..4f9fca6 100644
--- a/python/tvm_ffi/cython/function.pxi
+++ b/python/tvm_ffi/cython/function.pxi
@@ -769,8 +769,10 @@ cdef class Function(Object):
 
     See Also
     --------
-    tvm_ffi.register_global_func: How to register global function.
-    tvm_ffi.get_global_func: How to get global function.
+    :py:func:`tvm_ffi.register_global_func`
+        Register a Python callable as a global FFI function.
+    :py:func:`tvm_ffi.get_global_func`
+        Look up a previously registered global FFI function by name.
     """
     cdef int c_release_gil
     cdef dict __dict__
diff --git a/python/tvm_ffi/cython/object.pxi b/python/tvm_ffi/cython/object.pxi
index 9042cdc..0c5bdac 100644
--- a/python/tvm_ffi/cython/object.pxi
+++ b/python/tvm_ffi/cython/object.pxi
@@ -101,6 +101,8 @@ cdef class Object:
 
     .. code-block:: python
 
+        import tvm_ffi.testing
+
         # Acquire a testing object constructed through FFI
         obj = tvm_ffi.testing.create_object("testing.TestObjectBase", v_i64=12)
         assert isinstance(obj, tvm_ffi.Object)
@@ -214,6 +216,8 @@ cdef class Object:
         --------
         .. code-block:: python
 
+            import tvm_ffi.testing
+
             x = tvm_ffi.testing.create_object("testing.TestObjectBase")
             y = x
             z = tvm_ffi.testing.create_object("testing.TestObjectBase")
diff --git a/python/tvm_ffi/cython/tensor.pxi b/python/tvm_ffi/cython/tensor.pxi
index 0879073..0985056 100644
--- a/python/tvm_ffi/cython/tensor.pxi
+++ b/python/tvm_ffi/cython/tensor.pxi
@@ -177,6 +177,8 @@ def from_dlpack(
     .. code-block:: python
 
         import numpy as np
+        import tvm_ffi
+
         x_np = np.arange(8, dtype="int32")
         x = tvm_ffi.from_dlpack(x_np)
         y_np = np.from_dlpack(x)
@@ -218,6 +220,8 @@ cdef class Tensor(Object):
     .. code-block:: python
 
         import numpy as np
+        import tvm_ffi
+
         x = tvm_ffi.from_dlpack(np.arange(6, dtype="int32"))
         assert x.shape == (6,)
         assert x.dtype == tvm_ffi.dtype("int32")
diff --git a/python/tvm_ffi/error.py b/python/tvm_ffi/error.py
index 14dd2b0..015fe80 100644
--- a/python/tvm_ffi/error.py
+++ b/python/tvm_ffi/error.py
@@ -178,12 +178,17 @@ def register_error(
     --------
     .. code-block:: python
 
-      @tvm.error.register_error
-      class MyError(RuntimeError):
-          pass
+        import tvm_ffi
 
-      err_inst = tvm.error.create_ffi_error("MyError: xyz")
-      assert isinstance(err_inst, MyError)
+        # Register a custom Python exception so tvm_ffi.Error maps to it
+        @tvm_ffi.error.register_error
+        class MyError(RuntimeError):
+            pass
+
+        # Convert a Python exception to an FFI Error and back
+        ffi_err = tvm_ffi.convert(MyError("boom"))
+        py_err = ffi_err.py_error()
+        assert isinstance(py_err, MyError)
 
     """
     if callable(name_or_cls):
diff --git a/python/tvm_ffi/module.py b/python/tvm_ffi/module.py
index 3b09df7..73970e0 100644
--- a/python/tvm_ffi/module.py
+++ b/python/tvm_ffi/module.py
@@ -115,13 +115,14 @@ class Module(core.Object):
     def implements_function(self, name: str, query_imports: bool = False) -> 
bool:
         """Return True if the module defines a global function.
 
-        Note
-        ----
-        that has_function(name) does not imply get_function(name) is non-null 
since the module
-        that has_function(name) does not imply get_function(name) is non-null 
since the module
-        may be, eg, a CSourceModule which cannot supply a packed-func 
implementation of the function
-        without further compilation. However, get_function(name) non null 
should always imply
-        has_function(name).
+        Notes
+        -----
+        ``implements_function(name)`` does not guarantee that
+        ``get_function(name)`` will return a callable, because some module
+        kinds (e.g. a source-only module) may not provide a packed function
+        implementation until further compilation occurs. However, a non-null
+        result from ``get_function(name)`` should imply the module implements
+        the function.
 
         Parameters
         ----------
@@ -133,8 +134,7 @@ class Module(core.Object):
 
         Returns
         -------
-        b
-            True if module (or one of its imports) has a definition for name.
+        True if module (or one of its imports) has a definition for name.
 
         """
         return _ffi_api.ModuleImplementsFunction(self, name, query_imports)
@@ -157,12 +157,11 @@ class Module(core.Object):
             The name of the function
 
         query_imports
-            Whether also query modules imported by this module.
+            Whether to also query modules imported by this module.
 
         Returns
         -------
-        f
-            The result function.
+        The result function.
 
         """
         func = _ffi_api.ModuleGetFunction(self, name, query_imports)
@@ -203,8 +202,7 @@ class Module(core.Object):
 
         Returns
         -------
-        source
-            The result source code.
+        The result source code.
 
         """
         return _ffi_api.ModuleInspectSource(self, fmt)
@@ -218,8 +216,7 @@ class Module(core.Object):
 
         Returns
         -------
-        mask
-            Bitmask of runtime module property
+        Bitmask of runtime module property
 
         """
         return _ffi_api.ModuleGetPropertyMask(self)
@@ -229,8 +226,7 @@ class Module(core.Object):
 
         Returns
         -------
-        b
-            True if the module is binary serializable.
+        True if the module is binary serializable.
 
         """
         return (self.get_property_mask() & 
ModulePropertyMask.BINARY_SERIALIZABLE) != 0
@@ -240,8 +236,7 @@ class Module(core.Object):
 
         Returns
         -------
-        b
-            True if the module is runnable.
+        True if the module is runnable.
 
         """
         return (self.get_property_mask() & ModulePropertyMask.RUNNABLE) != 0
@@ -253,8 +248,7 @@ class Module(core.Object):
 
         Returns
         -------
-        b
-            True if the module is compilation exportable.
+        True if the module is compilation exportable.
 
         """
         return (self.get_property_mask() & 
ModulePropertyMask.COMPILATION_EXPORTABLE) != 0
@@ -275,21 +269,20 @@ class Module(core.Object):
 
         See Also
         --------
-        runtime.Module.export_library : export the module to shared library.
+        tvm.runtime.Module.export_library : export the module to shared 
library.
 
         """
         _ffi_api.ModuleWriteToFile(self, file_name, fmt)
 
 
 def system_lib(symbol_prefix: str = "") -> Module:
-    """Get system-wide library module singleton.
+    """Get system-wide library module singleton with functions prefixed by 
``__tvm_ffi_{symbol_prefix}``.
 
-    System lib is a global module that contains self register functions in 
startup.
-    Unlike normal dso modules which need to be loaded explicitly.
-    It is useful in environments where dynamic loading api like dlopen is 
banned.
+    The library module contains symbols that are registered via 
:cpp:func:`TVMFFIEnvModRegisterSystemLibSymbol`.
 
-    The system lib is intended to be linked and loaded during the entire 
life-cyle of the program.
-    If you want dynamic loading features, use dso modules instead.
+    .. note::
+        The system lib is intended to be statically linked and loaded during 
the entire lifecycle of the program.
+        If you want dynamic loading features, use DSO modules instead.
 
     Parameters
     ----------
@@ -299,8 +292,36 @@ def system_lib(symbol_prefix: str = "") -> Module:
 
     Returns
     -------
-    module
-        The system-wide library module.
+    The system-wide library module.
+
+    Examples
+    --------
+    Register the function ``test_symbol_add_one`` in C++ with the name 
``__tvm_ffi_test_symbol_add_one``
+    via :cpp:func:`TVMFFIEnvModRegisterSystemLibSymbol`.
+
+    .. code-block:: cpp
+
+        // A function to be registered in the system lib
+        static int test_symbol_add_one(void*, const TVMFFIAny* args, int32_t 
num_args, TVMFFIAny* ret) {
+          TVM_FFI_SAFE_CALL_BEGIN();
+          TVM_FFI_CHECK(num_args == 1, "Expected 1 argument, but got: " + 
std::to_string(num_args));
+          int64_t x = reinterpret_cast<const 
AnyView*>(args)[0].cast<int64_t>();
+          reinterpret_cast<Any*>(ret)[0] = x + 1;
+          TVM_FFI_SAFE_CALL_END();
+        }
+
+        // Register the function with name `test_symbol_add_one` prefixed by 
`__tvm_ffi_`
+        int _ = 
TVMFFIEnvModRegisterSystemLibSymbol("__tvm_ffi_testing.add_one", 
reinterpret_cast<void*>(test_symbol_add_one));
+
+    Look up and call the function from Python:
+
+    .. code-block:: python
+
+        import tvm_ffi
+
+        mod: tvm_ffi.Module = tvm_ffi.system_lib("testing.")  # symbols 
prefixed with `__tvm_ffi_testing.`
+        func: tvm_ffi.Function = mod["add_one"]  # looks up 
`__tvm_ffi_testing.add_one`
+        assert func(10) == 11
 
     """
     return _ffi_api.SystemLib(symbol_prefix)
@@ -311,25 +332,25 @@ def load_module(path: str | PathLike) -> Module:
 
     Parameters
     ----------
-    path : str | PathLike
+    path
         The path to the module file.
 
     Returns
     -------
-    module
-        The loaded module
+    The loaded module
 
     Examples
     --------
     .. code-block:: python
 
+        import tvm_ffi
+        from pathlib import Path
+
         # Works with string paths
         mod = tvm_ffi.load_module("path/to/module.so")
-        mod.func_name(*args)
-
         # Also works with pathlib.Path objects
-        from pathlib import Path
         mod = tvm_ffi.load_module(Path("path/to/module.so"))
+
         mod.func_name(*args)
 
     See Also
diff --git a/python/tvm_ffi/registry.py b/python/tvm_ffi/registry.py
index bd37ebd..d149488 100644
--- a/python/tvm_ffi/registry.py
+++ b/python/tvm_ffi/registry.py
@@ -35,12 +35,13 @@ def register_object(type_key: str | type | None = None) -> 
Callable[[type], type
     Parameters
     ----------
     type_key
-        The type key of the node
+        The type key of the node. It requires ``type_key`` to be registered 
already
+        on the C++ side. If not specified, the class name will be used.
 
     Examples
     --------
-    The following code registers MyObject
-    using type key "test.MyObject"
+    The following code registers MyObject using type key "test.MyObject", if 
the
+    type key is already registered on the C++ side.
 
     .. code-block:: python
 
@@ -165,7 +166,20 @@ def get_global_func(name: str, allow_missing: bool = 
False) -> core.Function | N
     Returns
     -------
     func
-        The function to be returned, None if function is missing.
+        The function to be returned, ``None`` if function is missing.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        @tvm_ffi.register_global_func("demo.echo")
+        def echo(x):
+            return x
+
+        f = tvm_ffi.get_global_func("demo.echo")
+        assert f(123) == 123
 
     See Also
     --------
@@ -195,24 +209,60 @@ def remove_global_func(name: str) -> None:
     Parameters
     ----------
     name
-        The name of the global function
+        The name of the global function.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        @tvm_ffi.register_global_func("my.temp")
+        def temp():
+            return 42
+
+        assert tvm_ffi.get_global_func("my.temp", allow_missing=True) is not 
None
+        tvm_ffi.remove_global_func("my.temp")
+        assert tvm_ffi.get_global_func("my.temp", allow_missing=True) is None
+
+    See Also
+    --------
+    :py:func:`tvm_ffi.register_global_func`
+    :py:func:`tvm_ffi.get_global_func`
 
     """
     get_global_func("ffi.FunctionRemoveGlobal")(name)
 
 
 def get_global_func_metadata(name: str) -> dict[str, Any]:
-    """Get the type schema string of a global function by name.
+    """Get metadata (including type schema) for a global function.
 
     Parameters
     ----------
     name
-        The name of the global function
+        The name of the global function.
 
     Returns
     -------
     metadata
-        The metadata of the function
+        A dictionary containing function metadata. The ``type_schema`` field
+        encodes the callable signature.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        meta = tvm_ffi.get_global_func_metadata("testing.add_one")
+        print(meta)
+
+    See Also
+    --------
+    :py:func:`tvm_ffi.get_global_func`
+        Retrieve a callable for an existing global function.
+    :py:func:`tvm_ffi.register_global_func`
+        Register a Python callable as a global FFI function.
 
     """
     return json.loads(get_global_func("ffi.GetGlobalFuncMetadata")(name))
diff --git a/python/tvm_ffi/serialization.py b/python/tvm_ffi/serialization.py
index 285d764..66679ff 100644
--- a/python/tvm_ffi/serialization.py
+++ b/python/tvm_ffi/serialization.py
@@ -14,7 +14,12 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-"""Serialization related utilities to enable some object can be pickled."""
+"""Utilities for serializing and deserializing FFI object graphs.
+
+These helpers produce a stable JSON graph representation that preserves
+object identity and references. It is useful for debugging and for
+lightweight persistence when pickling is not available.
+"""
 
 from __future__ import annotations
 
@@ -26,9 +31,9 @@ from . import _ffi_api
 def to_json_graph_str(obj: Any, metadata: dict[str, Any] | None = None) -> str:
     """Dump an object to a JSON graph string.
 
-    The JSON graph string is a string representation of of the object
-    graph includes the reference information of same objects, which can
-    be used for serialization and debugging.
+    The JSON graph is a textual representation of the object graph that
+    preserves shared references. It can be used for debugging or simple
+    persistence.
 
     Parameters
     ----------
@@ -43,6 +48,17 @@ def to_json_graph_str(obj: Any, metadata: dict[str, Any] | 
None = None) -> str:
     json_str
         The JSON graph string.
 
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        a = tvm_ffi.convert([1, 2, 3])
+        s = tvm_ffi.serialization.to_json_graph_str(a)
+        b = tvm_ffi.serialization.from_json_graph_str(s)
+        assert list(b) == [1, 2, 3]
+
     """
     return _ffi_api.ToJSONGraphString(obj, metadata)
 
@@ -50,8 +66,8 @@ def to_json_graph_str(obj: Any, metadata: dict[str, Any] | 
None = None) -> str:
 def from_json_graph_str(json_str: str) -> Any:
     """Load an object from a JSON graph string.
 
-    The JSON graph string is a string representation of of the object
-    graph that also includes the reference information.
+    The JSON graph string is produced by :py:func:`to_json_graph_str` and
+    can be converted back into the corresponding FFI-backed objects.
 
     Parameters
     ----------
diff --git a/python/tvm_ffi/stream.py b/python/tvm_ffi/stream.py
index ee71e5d..a805378 100644
--- a/python/tvm_ffi/stream.py
+++ b/python/tvm_ffi/stream.py
@@ -124,7 +124,8 @@ try:
 
         Note
         ----
-        When working with raw cudaStream_t handle, using 
:py:func:`tvm_ffi.use_raw_stream` instead.
+        When working with a raw ``cudaStream_t`` handle, use
+        :py:func:`tvm_ffi.use_raw_stream` instead.
 
         """
         return TorchStreamContext(context)
@@ -137,7 +138,7 @@ except ImportError:
 
 
 def use_raw_stream(device: core.Device, stream: int | c_void_p) -> 
StreamContext:
-    """Create a ffi stream context with given device and stream handle.
+    """Create an FFI stream context with the given device and stream handle.
 
     Parameters
     ----------
@@ -145,28 +146,45 @@ def use_raw_stream(device: core.Device, stream: int | 
c_void_p) -> StreamContext
         The device to which the stream belongs.
 
     stream
-        The stream handle.
+        The stream handle (for example, a CUDA ``cudaStream_t`` as an integer, 
or ``0``).
 
     Returns
     -------
     context
-        The ffi stream context.
+        The FFI stream context.
+
+    Examples
+    --------
+    The example below uses a CPU device and a dummy stream handle. On CUDA, 
pass a
+    real ``cudaStream_t`` integer.
+
+    .. code-block:: python
 
-    Note
-    ----
-    When working with torch stram or cuda graph, using 
:py:func:`tvm_ffi.use_torch_stream` instead.
+        import tvm_ffi
+
+        dev = tvm_ffi.device("cpu:0")
+        with tvm_ffi.use_raw_stream(dev, 0):
+            # Within the context, the current stream for this device is set
+            assert tvm_ffi.get_raw_stream(dev) == 0
+
+    See Also
+    --------
+    :py:func:`tvm_ffi.use_torch_stream`
+        Use a Torch stream or CUDA graph as the source of truth.
+    :py:func:`tvm_ffi.get_raw_stream`
+        Query the current FFI stream for a device.
 
     """
     if not isinstance(stream, (int, c_void_p)):
         raise ValueError(
-            "use_raw_stream only accepts int or c_void_p as stram input, "
+            "use_raw_stream only accepts int or c_void_p as stream input, "
             "try use_torch_stream when using torch.cuda.Stream or 
torch.cuda.graph"
         )
     return StreamContext(device, stream)
 
 
 def get_raw_stream(device: core.Device) -> int:
-    """Get the current ffi stream of given device.
+    """Get the current FFI stream of a given device.
 
     Parameters
     ----------
@@ -176,7 +194,23 @@ def get_raw_stream(device: core.Device) -> int:
     Returns
     -------
     stream
-        The current ffi stream.
+        The current FFI stream as an integer handle.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        import tvm_ffi
+
+        dev = tvm_ffi.device("cpu:0")
+        # Default stream is implementation-defined; set it explicitly
+        with tvm_ffi.use_raw_stream(dev, 0):
+            assert tvm_ffi.get_raw_stream(dev) == 0
+
+    See Also
+    --------
+    :py:func:`tvm_ffi.use_raw_stream`
+        Set the current stream for a device.
 
     """
     return core._env_get_current_stream(device.dlpack_device_type(), 
device.index)
diff --git a/python/tvm_ffi/utils/lockfile.py b/python/tvm_ffi/utils/lockfile.py
index 6efe80f..da98491 100644
--- a/python/tvm_ffi/utils/lockfile.py
+++ b/python/tvm_ffi/utils/lockfile.py
@@ -35,6 +35,19 @@ class FileLock:
 
     This class implements an advisory lock, which must be respected by all
     cooperating processes.
+
+    Examples
+    --------
+    .. code-block:: python
+
+        from tvm_ffi.utils import FileLock
+
+        with FileLock("/tmp/my.lock"):
+            # Critical section guarded by the lock.
+            # Other processes attempting to acquire the same lock will block
+            # (or fail, if using ``acquire()``) until this context exits.
+            do_work()
+
     """
 
     def __init__(self, lock_file_path: str) -> None:
diff --git a/src/ffi/testing/testing.cc b/src/ffi/testing/testing.cc
index cccd89e..bccc5c0 100644
--- a/src/ffi/testing/testing.cc
+++ b/src/ffi/testing/testing.cc
@@ -446,6 +446,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .def("testing.schema_no_args", []() { return 1; })
       .def("testing.schema_no_return", [](int64_t x) {})
       .def("testing.schema_no_args_no_return", []() {});
+  TVMFFIEnvModRegisterSystemLibSymbol("__tvm_ffi_testing.add_one",
+                                      
reinterpret_cast<void*>(__add_one_c_symbol));
 }
 
 }  // namespace ffi


Reply via email to