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

Head commit for run:
b58c2e3d7deadbd60c7480f5c84633966260bc9a / Junru Shao <[email protected]>
feat(stubgen): Package generation with `--init-*` flags (#295)

This commit adds explicit `--init-*` flags so that packages can be
bootstrapped cleanly from a single command.

**Usage.** for the my-ffi-extension example):

```
tvm-ffi-stubgen examples/packaging/python \
  --dlls examples/packaging/build/libmy_ffi_extension.dylib \
  --init-pypkg  my-ffi-extension \
  --init-lib    my_ffi_extension \
  --init-prefix "my_ffi_extension."
```

What each flag means:

- `PATH`: the files/directories to scan; the directory of the first
entry becomes the root where `_ffi_api.py`/`__init__.py` stubs are
generated.
- `--dlls`: preload the built shared library so global function/type
metadata is available (here the dylib from the packaging example build).
- `--init-pypkg`: the published Python package name (wheel/sdist name),
used in the loader string.
- `--init-lib`: the CMake target/basename of the shared library
(`lib<init-lib>.so`/`.dylib`/`.dll`).
- `--init-prefix`: registry prefix to include when generating
globals/objects (e.g. `my_ffi_extension.`).

**Behavior**.

- The tool creates missing `_ffi_api.py` and `__init__.py` under the
derived path/prefix.
- It scans existing stub blocks, honors ty-map and imports, and adds an
`__all__` section without duplication on reruns.
- Re-running the command is idempotent: previously generated sections
are detected and not appended again.

**Example**. See `my_ffi_extension/__init__.py` and
`my_ffi_extension/_ffi_api.py`.

**How to use this tool**

```
>>> tvm-ffi-stubgen --help
usage: tvm-ffi-stubgen [-h] [--imports IMPORTS] [--dlls LIBS] [--init-pypkg 
INIT_PYPKG] [--init-lib INIT_LIB] [--init-prefix INIT_PREFIX] [--indent INDENT] 
[--verbose] [--dry-run] [PATH ...]

Generate type stubs for TVM FFI extensions.

In `--init-*` mode, it generates missing `_ffi_api.py` and `__init__.py` files, 
based on the registered global functions and object types in the loaded 
libraries.

In normal mode, it processes the given files/directories in-place, generating 
type stubs inside special `tvm-ffi-stubgen` blocks. Scroo down for more details.

positional arguments:
  PATH                  Files or directories to process. Directories are 
scanned recursively; only .py and .pyi files are modified. Use tvm-ffi-stubgen 
markers to select where stubs are generated. (default: None)

options:
  -h, --help            show this help message and exit
  --imports IMPORTS     Additional imports to load before generation, separated 
by ';' (e.g. 'pkgA;pkgB.submodule'). (default: )
  --dlls LIBS           Shared libraries to preload before generation (e.g. TVM 
runtime or your extension), separated by ';'. This ensures global function and 
object metadata is available. Platform-specific suffixes like .so/.dylib/.dll 
are supported. (default: )
  --init-pypkg INIT_PYPKG
                        Python package name to generate stubs for (e.g. 
apache-tvm-ffi). Required together with --init-lib, --init-path, and 
--init-prefix. (default: )
  --init-lib INIT_LIB   CMake target that produces the shared library to load 
for stub generation (e.g. tvm_ffi_shared). Required together with --init-pypkg 
and --init-prefix. (default: )
  --init-prefix INIT_PREFIX
                        Global function/object prefix to include when 
generating stubs (e.g. tvm_ffi.). Required together with --init-pypkg and 
--init-lib. (default: )
  --indent INDENT       Extra spaces added inside each generated block, 
relative to the indentation of the corresponding '# tvm-ffi-stubgen(begin):' 
line. (default: 4)
  --verbose             Print a unified diff of changes to each file. This is 
useful for debugging or previewing changes before applying them. (default: 
False)
  --dry-run             Don't write changes to files. This is useful for 
previewing changes without modifying any files. (default: False)

========
Examples
========

  # Single file
  tvm-ffi-stubgen python/tvm_ffi/_ffi_api.py

  # Recursively scan directories
  tvm-ffi-stubgen python/tvm_ffi examples/packaging/python/my_ffi_extension

  # Preload extension libraries
  tvm-ffi-stubgen --dlls build/libmy_ext.so;build/libmy_2nd_ext.so 
my_pkg/_ffi_api.py

  # Package-level init (my-ffi-extension)
  tvm-ffi-stubgen examples/packaging/python \
    --dlls examples/packaging/build/libmy_ffi_extension.dylib \
    --init-pypkg my-ffi-extension \
    --init-lib my_ffi_extension \
    --init-prefix "my_ffi_extension."

=====================
Syntax of stub blocks
=====================

Global functions
~~~~~~~~~~~~~~~~

    ```
    # tvm-ffi-stubgen(begin): global/<registry-prefix>@<import-from (default: 
tvm_ffi)>
    # tvm-ffi-stubgen(end)
    ```

Generates TYPE_CHECKING-only stubs for functions in the global registry under 
the prefix.

Example:

    ```
    # tvm-ffi-stubgen(begin): global/[email protected]
    # fmt: off
    _FFI_INIT_FUNC("ffi", __name__)
    if TYPE_CHECKING:
        def Array(*args: Any) -> Any: ...
        def ArrayGetItem(_0: Sequence[Any], _1: int, /) -> Any: ...
        def ArraySize(_0: Sequence[Any], /) -> int: ...
        def Bytes(_0: bytes, /) -> bytes: ...
        ...
        def StructuralHash(_0: Any, _1: bool, _2: bool, /) -> int: ...
        def SystemLib(*args: Any) -> Any: ...
        def ToJSONGraph(_0: Any, _1: Any, /) -> Any: ...
        def ToJSONGraphString(_0: Any, _1: Any, /) -> str: ...
    # fmt: on
    # tvm-ffi-stubgen(end)
    ```

Objects
~~~~~~~

    ```
    # tvm-ffi-stubgen(begin): object/<type_key>
    # tvm-ffi-stubgen(end)
    ```

Generates fields/methods for a class defined using TVM-FFI Object APIs.

Example:

    ```
    @register_object("ffi.reflection.AccessPath")
    class AccessPath(tvm_ffi.Object):
        # tvm-ffi-stubgen(begin): object/ffi.reflection.AccessPath
        # fmt: off
        parent: Object | None
        step: AccessStep | None
        depth: int
        if TYPE_CHECKING:
            @staticmethod
            def _root() -> AccessPath: ...
            def _extend(self, _1: AccessStep, /) -> AccessPath: ...
            def _attr(self, _1: str, /) -> AccessPath: ...
            def _array_item(self, _1: int, /) -> AccessPath: ...
            def _map_item(self, _1: Any, /) -> AccessPath: ...
            def _attr_missing(self, _1: str, /) -> AccessPath: ...
            def _array_item_missing(self, _1: int, /) -> AccessPath: ...
            def _map_item_missing(self, _1: Any, /) -> AccessPath: ...
            def _is_prefix_of(self, _1: AccessPath, /) -> bool: ...
            def _to_steps(self, /) -> Sequence[AccessStep]: ...
            def _path_equal(self, _1: AccessPath, /) -> bool: ...
        # fmt: on
        # tvm-ffi-stubgen(end)
    ```

Import section
~~~~~~~~~~~~~~

    ```
    # tvm-ffi-stubgen(begin): import-section
    # fmt: off
    # isort: off
    from __future__ import annotations
    from ..registry import init_ffi_api as _FFI_INIT_FUNC
    from typing import TYPE_CHECKING
    if TYPE_CHECKING:
        from collections.abc import Mapping, Sequence
        from tvm_ffi import Device, Object, Tensor, dtype
        from tvm_ffi.testing import TestIntPair
        from typing import Any, Callable
    # isort: on
    # fmt: on
    # tvm-ffi-stubgen(end)
    ```

Auto-populates imports used by generated stubs.

Export
~~~~~~

    ```
    # tvm-ffi-stubgen(begin): export/_ffi_api
    # fmt: off
    # isort: off
    from ._ffi_api import *  # noqa: F403
    from ._ffi_api import __all__ as _ffi_api__all__
    if "__all__" not in globals():
        __all__ = []
    __all__.extend(_ffi_api__all__)
    # isort: on
    # fmt: on
    # tvm-ffi-stubgen(end)
    ```

Re-exports a generated submodule's __all__ into the parent.

__all__
~~~~~~~

    ```
    __all__ = [
        # tvm-ffi-stubgen(begin): __all__
        "LIB",
        "IntPair",
        "raise_error",
        # tvm-ffi-stubgen(end)
    ]
    ```

Populates __all__ with generated classes/functions and LIB (if present).

Type map
~~~~~~~~

    ```
    # tvm-ffi-stubgen(ty-map): <type_key> -> <python_type>
    ```

Maps runtime type keys to Python types used in generation.

Example:

    ```
    # tvm-ffi-stubgen(ty-map): ffi.reflection.AccessStep -> 
ffi.access_path.AccessStep
    ```

Import object
~~~~~~~~~~~~~

    ```
    # tvm-ffi-stubgen(import-object): <from>; <type_checking_only>; <alias>
    ```

Injects a custom import into generated code, optionally TYPE_CHECKING-only.

Example:

    ```
    # tvm-ffi-stubgen(import-object): ffi.Object;False;_ffi_Object
    ```

Skip file
~~~~~~~~~

    ```
    # tvm-ffi-stubgen(skip-file)
    ```

Prevents stubgen from modifying the file.
```

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

With regards,
GitHub Actions via GitBox


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

Reply via email to