Skip to content

Commit e5150f7

Browse files
committed
feat: Add python stub files for code completion and static analysis
Signed-off-by: Chad Dombrova <chadrik@gmail.com>
1 parent bb70340 commit e5150f7

11 files changed

Lines changed: 1945 additions & 3 deletions

File tree

.github/workflows/wheel.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ jobs:
150150
- name: Build wheels
151151
uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1
152152
env:
153+
# pass GITHUB_ACTIONS through to the build container so that custom
154+
# processes can tell they are running in CI.
155+
CIBW_ENVIRONMENT_PASS_LINUX: GITHUB_ACTIONS
153156
CIBW_BUILD: ${{ matrix.python }}
154157
CIBW_ARCHS: ${{ matrix.arch }}
155158
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux }}

INSTALL.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,19 @@ the headers, and the CLI tools to a platform-specific, Python-specific location.
389389
See the [scikit-build-core docs](https://scikit-build-core.readthedocs.io/en/latest/configuration.html#configuring-cmake-arguments-and-defines)
390390
for more information on customizing and overriding build-tool options and CMake arguments.
391391

392+
This repo contains python type stubs which are generated from `pybind11` signatures.
393+
The workflow for releasing new stubs is as follows:
394+
395+
- Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/)
396+
- Run `make pystubs` locally to generate updated stubs in `src/python/stubs/__init__.pyi`
397+
- Commit the new stubs and push to Github
398+
- In CI, the stubs will be included in the wheels built by `cibuildwheel`, as defined in `.github/wheel.yml`
399+
- In CI, one of the `cibuildwheel` Github actions will rebuild the stubs to a
400+
temp location and verify that they match what has been committed to the repo.
401+
This step ensures that if changes to the C++ source code and bindings results
402+
in a change to the stubs, developers are notified of the need to regenerate
403+
the stubs, so that changes can be reviewed and the rules in `generate_stubs.py`
404+
can be updated, if necessary.
392405

393406
Test Images
394407
-----------

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ build: config
243243
${CMAKE} --build . --config ${CMAKE_BUILD_TYPE} \
244244
)
245245

246+
pystubs: config
247+
@ ( cd ${build_dir} ; \
248+
${CMAKE} --build . --config ${CMAKE_BUILD_TYPE} --target pystubs \
249+
)
250+
246251
# 'make install' builds everthing and installs it in 'dist'.
247252
# Suppress pointless output from docs installation.
248253
install: build

pyproject.toml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,21 @@ CXXFLAGS = "-Wno-error=stringop-overflow -Wno-pragmas"
122122
SKBUILD_CMAKE_BUILD_TYPE = "MinSizeRel"
123123

124124
[tool.cibuildwheel.windows.environment]
125-
SKBUILD_CMAKE_BUILD_TYPE = "MinSizeRel"
125+
SKBUILD_CMAKE_BUILD_TYPE = "MinSizeRel"
126+
127+
[[tool.cibuildwheel.overrides]]
128+
# Trigger the build & validation of the python stubs for certain platforms.
129+
# The test command acts as a kind of "post-build" callback where it's possible
130+
# for the stub-generator to import the freshly-built wheel.
131+
# There are two entry-points which are designed to call generate_stubs.py through
132+
# this test command:
133+
# - `make pystubs` is called during local development to generate the
134+
# stubs and copy them into the git repo to be committed and reviewed.
135+
# - in CI, the cibuildwheel action is used to validate that the stubs match what
136+
# has been committed to the repo.
137+
select = "cp311-manylinux_*64"
138+
test-requires = "mypy~=1.15.0 stubgenlib~=0.1.0"
139+
inherit.test-command = "append"
140+
test-command = [
141+
"python {project}/src/python/stubs/generate_stubs.py --out-path '/output' --validate-path '{project}/src/python/stubs/__init__.pyi'",
142+
]

src/cmake/pythonutils.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ macro (setup_python_module)
156156
RUNTIME DESTINATION ${PYTHON_SITE_DIR} COMPONENT user
157157
LIBRARY DESTINATION ${PYTHON_SITE_DIR} COMPONENT user)
158158

159-
install(FILES __init__.py DESTINATION ${PYTHON_SITE_DIR} COMPONENT user)
159+
install (FILES __init__.py stubs/__init__.pyi stubs/py.typed
160+
DESTINATION ${PYTHON_SITE_DIR} COMPONENT user)
160161

161162
endmacro ()
162163

src/python/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33
# https://github.com/AcademySoftwareFoundation/OpenImageIO
44

5-
5+
add_subdirectory (stubs)
66

77
file (GLOB python_srcs *.cpp)
88
setup_python_module (TARGET PyOpenImageIO
@@ -19,3 +19,4 @@ set_target_properties(PyOpenImageIO PROPERTIES
1919
UNITY_BUILD_BATCH_SIZE ${UNITY_SMALL_BATCH_SIZE})
2020
set_source_files_properties(${python_srcs} PROPERTIES
2121
UNITY_GROUP PyOpenImageIO)
22+

src/python/stubs/CMakeLists.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
# Setup the pystub target, which is not built by default.
3+
4+
set (_stub_file "${CMAKE_SOURCE_DIR}/src/python/stubs/__init__.pyi")
5+
6+
# Note: the python version must be kept in sync with `[[tool.cibuildwheel.overrides]]` in pyproject.toml.
7+
# The stubs are generated within a container so the version of python does not need to match
8+
# the version being built.
9+
# Note: the version of cibuildwheel should be kept in sync with .github/workflows/wheel.yml
10+
add_custom_command (COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/python/stubs/generate_stubs_local.py
11+
--repo-root ${CMAKE_SOURCE_DIR} --python-version="3.11" --cibuildwheel-version="2.21.1"
12+
--output-dir "${CMAKE_BINARY_DIR}/wheelhouse"
13+
OUTPUT "${CMAKE_BINARY_DIR}/wheelhouse/OpenImageIO/__init__.pyi"
14+
DEPENDS "${CMAKE_SOURCE_DIR}/src/python/stubs/generate_stubs.py"
15+
DEPENDS "${CMAKE_SOURCE_DIR}/src/python/stubs/generate_stubs_local.py"
16+
COMMENT "pystubs: Generating python stubs"
17+
)
18+
19+
add_custom_command (COMMAND ${CMAKE_COMMAND} -E copy
20+
"${CMAKE_BINARY_DIR}/wheelhouse/OpenImageIO/__init__.pyi"
21+
${_stub_file}
22+
OUTPUT ${_stub_file}
23+
DEPENDS "${CMAKE_BINARY_DIR}/wheelhouse/OpenImageIO/__init__.pyi"
24+
COMMENT "pystubs: Copying generated stubs to source"
25+
)
26+
27+
add_custom_target (pystubs DEPENDS ${_stub_file})

0 commit comments

Comments
 (0)