Skip to content

Commit 22c2e15

Browse files
authored
[MLIR][Python] enable type stub auto-generation (#155741)
This PR turns on automatic type stub generation (rather than relying on hand-written/updated stubs). It uses nanobind's [stubgen facility](https://nanobind.readthedocs.io/en/latest/typing.html#stub-generation). If you would like to enable this functionality you can add `GENERATE_TYPE_STUBS` to `declare_mlir_python_extension` .
1 parent 25ebdfe commit 22c2e15

File tree

13 files changed

+128
-3185
lines changed

13 files changed

+128
-3185
lines changed

.ci/all_requirements.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,9 @@ ml-dtypes==0.5.1 ; python_version < "3.13" \
194194
--hash=sha256:d13755f8e8445b3870114e5b6240facaa7cb0c3361e54beba3e07fa912a6e12b \
195195
--hash=sha256:fd918d4e6a4e0c110e2e05be7a7814d10dc1b95872accbf6512b80a109b71ae1
196196
# via -r mlir/python/requirements.txt
197-
nanobind==2.7.0 \
198-
--hash=sha256:73b12d0e751d140d6c1bf4b215e18818a8debfdb374f08dc3776ad208d808e74 \
199-
--hash=sha256:f9f1b160580c50dcf37b6495a0fd5ec61dc0d95dae5f8004f87dd9ad7eb46b34
197+
nanobind==2.9.2 \
198+
--hash=sha256:c37957ffd5eac7eda349cff3622ecd32e5ee1244ecc912c99b5bc8188bafd16e \
199+
--hash=sha256:e7608472de99d375759814cab3e2c94aba3f9ec80e62cfef8ced495ca5c27d6e
200200
# via -r mlir/python/requirements.txt
201201
numpy==2.0.2 \
202202
--hash=sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a \
@@ -383,6 +383,10 @@ swig==4.3.1 \
383383
--hash=sha256:efec16327029f682f649a26da726bb0305be8800bd0f1fa3e81bf0769cf5b476 \
384384
--hash=sha256:fc496c0d600cf1bb2d91e28d3d6eae9c4301e5ea7a0dec5a4281b5efed4245a8
385385
# via -r lldb/test/requirements.txt
386+
typing-extensions==4.15.0 \
387+
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
388+
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
389+
# via -r mlir/python/requirements.txt
386390
urllib3==2.5.0 \
387391
--hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \
388392
--hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc

mlir/cmake/modules/AddMLIRPython.cmake

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,57 @@ function(declare_mlir_python_sources name)
9999
endif()
100100
endfunction()
101101

102+
# Function: generate_type_stubs
103+
# Turns on automatic type stub generation (via nanobind's stubgen) for extension modules.
104+
# Arguments:
105+
# MODULE_NAME: The name of the extension module as specified in declare_mlir_python_extension.
106+
# DEPENDS_TARGET: The dso target corresponding to the extension module
107+
# (e.g., something like StandalonePythonModules.extension._standaloneDialectsNanobind.dso)
108+
# MLIR_DEPENDS_TARGET: The dso target corresponding to the main/core extension module
109+
# (e.g., something like StandalonePythonModules.extension._mlir.dso)
110+
# OUTPUT_DIR: The root output directory to emit the type stubs into.
111+
# Outputs:
112+
# NB_STUBGEN_CUSTOM_TARGET: The target corresponding to generation which other targets can depend on.
113+
function(generate_type_stubs MODULE_NAME DEPENDS_TARGET MLIR_DEPENDS_TARGET OUTPUT_DIR)
114+
if(EXISTS ${nanobind_DIR}/../src/stubgen.py)
115+
set(NB_STUBGEN "${nanobind_DIR}/../src/stubgen.py")
116+
elseif(EXISTS ${nanobind_DIR}/../stubgen.py)
117+
set(NB_STUBGEN "${nanobind_DIR}/../stubgen.py")
118+
else()
119+
message(FATAL_ERROR "generate_type_stubs(): could not locate 'stubgen.py'!")
120+
endif()
121+
file(REAL_PATH "${NB_STUBGEN}" NB_STUBGEN)
122+
123+
set(_module "${MLIR_PYTHON_PACKAGE_PREFIX}._mlir_libs.${MODULE_NAME}")
124+
file(REAL_PATH "${MLIR_BINARY_DIR}/${MLIR_BINDINGS_PYTHON_INSTALL_PREFIX}/.." _import_path)
125+
126+
set(NB_STUBGEN_CMD
127+
"${Python_EXECUTABLE}"
128+
"${NB_STUBGEN}"
129+
--module
130+
"${_module}"
131+
-i
132+
"${_import_path}"
133+
--recursive
134+
--include-private
135+
--output-dir
136+
"${OUTPUT_DIR}")
137+
138+
set(NB_STUBGEN_OUTPUT "${OUTPUT_DIR}/${MODULE_NAME}.pyi")
139+
add_custom_command(
140+
OUTPUT ${NB_STUBGEN_OUTPUT}
141+
COMMAND ${NB_STUBGEN_CMD}
142+
WORKING_DIRECTORY "${CMAKE_CURRENT_FUNCTION_LIST_DIR}"
143+
DEPENDS
144+
"${MLIR_DEPENDS_TARGET}.extension._mlir.dso"
145+
"${MLIR_DEPENDS_TARGET}.sources.MLIRPythonSources.Core.Python"
146+
"${DEPENDS_TARGET}"
147+
)
148+
set(_name "MLIRPythonModuleStubs_${_module}")
149+
add_custom_target("${_name}" ALL DEPENDS ${NB_STUBGEN_OUTPUT})
150+
set(NB_STUBGEN_CUSTOM_TARGET "${_name}" PARENT_SCOPE)
151+
endfunction()
152+
102153
# Function: declare_mlir_python_extension
103154
# Declares a buildable python extension from C++ source files. The built
104155
# module is considered a python source file and included as everything else.
@@ -115,9 +166,10 @@ endfunction()
115166
# on. These will be collected for all extensions and put into an
116167
# aggregate dylib that is linked against.
117168
# PYTHON_BINDINGS_LIBRARY: Either pybind11 or nanobind.
169+
# GENERATE_TYPE_STUBS: Enable type stub generation.
118170
function(declare_mlir_python_extension name)
119171
cmake_parse_arguments(ARG
120-
""
172+
"GENERATE_TYPE_STUBS"
121173
"ROOT_DIR;MODULE_NAME;ADD_TO_PARENT;PYTHON_BINDINGS_LIBRARY"
122174
"SOURCES;PRIVATE_LINK_LIBS;EMBED_CAPI_LINK_LIBS"
123175
${ARGN})
@@ -135,12 +187,13 @@ function(declare_mlir_python_extension name)
135187
set_target_properties(${name} PROPERTIES
136188
# Yes: Leading-lowercase property names are load bearing and the recommended
137189
# way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
138-
EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS;mlir_python_BINDINGS_LIBRARY"
190+
EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS;mlir_python_BINDINGS_LIBRARY;mlir_python_GENERATE_TYPE_STUBS"
139191
mlir_python_SOURCES_TYPE extension
140192
mlir_python_EXTENSION_MODULE_NAME "${ARG_MODULE_NAME}"
141193
mlir_python_EMBED_CAPI_LINK_LIBS "${ARG_EMBED_CAPI_LINK_LIBS}"
142194
mlir_python_DEPENDS ""
143195
mlir_python_BINDINGS_LIBRARY "${ARG_PYTHON_BINDINGS_LIBRARY}"
196+
mlir_python_GENERATE_TYPE_STUBS "${ARG_GENERATE_TYPE_STUBS}"
144197
)
145198

146199
# Set the interface source and link_libs properties of the target
@@ -243,6 +296,22 @@ function(add_mlir_python_modules name)
243296
)
244297
add_dependencies(${modules_target} ${_extension_target})
245298
mlir_python_setup_extension_rpath(${_extension_target})
299+
get_target_property(_generate_type_stubs ${sources_target} mlir_python_GENERATE_TYPE_STUBS)
300+
if(_generate_type_stubs)
301+
generate_type_stubs(
302+
${_module_name}
303+
${_extension_target}
304+
${name}
305+
"${CMAKE_CURRENT_SOURCE_DIR}/mlir/_mlir_libs/_mlir"
306+
)
307+
declare_mlir_python_sources(
308+
"${MLIR_PYTHON_PACKAGE_PREFIX}.${_module_name}_type_stub_gen"
309+
ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mlir"
310+
ADD_TO_PARENT "${sources_target}"
311+
SOURCES_GLOB "_mlir_libs/${_module_name}/**/*.pyi"
312+
)
313+
add_dependencies("${modules_target}" "${NB_STUBGEN_CUSTOM_TARGET}")
314+
endif()
246315
else()
247316
message(SEND_ERROR "Unrecognized source type '${_source_type}' for python source target ${sources_target}")
248317
return()
@@ -678,26 +747,28 @@ function(add_mlir_python_extension libname extname)
678747
# the super project handle compile options as it wishes.
679748
get_property(NB_LIBRARY_TARGET_NAME TARGET ${libname} PROPERTY LINK_LIBRARIES)
680749
target_compile_options(${NB_LIBRARY_TARGET_NAME}
681-
PRIVATE
682-
-Wall -Wextra -Wpedantic
683-
-Wno-c++98-compat-extra-semi
684-
-Wno-cast-qual
685-
-Wno-covered-switch-default
686-
-Wno-nested-anon-types
687-
-Wno-unused-parameter
688-
-Wno-zero-length-array
689-
${eh_rtti_enable})
750+
PRIVATE
751+
-Wall -Wextra -Wpedantic
752+
-Wno-c++98-compat-extra-semi
753+
-Wno-cast-qual
754+
-Wno-covered-switch-default
755+
-Wno-deprecated-literal-operator
756+
-Wno-nested-anon-types
757+
-Wno-unused-parameter
758+
-Wno-zero-length-array
759+
${eh_rtti_enable})
690760

691761
target_compile_options(${libname}
692-
PRIVATE
693-
-Wall -Wextra -Wpedantic
694-
-Wno-c++98-compat-extra-semi
695-
-Wno-cast-qual
696-
-Wno-covered-switch-default
697-
-Wno-nested-anon-types
698-
-Wno-unused-parameter
699-
-Wno-zero-length-array
700-
${eh_rtti_enable})
762+
PRIVATE
763+
-Wall -Wextra -Wpedantic
764+
-Wno-c++98-compat-extra-semi
765+
-Wno-cast-qual
766+
-Wno-covered-switch-default
767+
-Wno-deprecated-literal-operator
768+
-Wno-nested-anon-types
769+
-Wno-unused-parameter
770+
-Wno-zero-length-array
771+
${eh_rtti_enable})
701772
endif()
702773

703774
if(APPLE)

mlir/examples/standalone/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ declare_mlir_python_extension(StandalonePythonSources.NanobindExtension
3939
EMBED_CAPI_LINK_LIBS
4040
StandaloneCAPI
4141
PYTHON_BINDINGS_LIBRARY nanobind
42+
GENERATE_TYPE_STUBS
4243
)
4344

4445

0 commit comments

Comments
 (0)