Skip to content

Commit

Permalink
Generating Python API docs.
Browse files Browse the repository at this point in the history
This PR adds support for generating Python API documentation in HTML format
using Sphinx from the MaterialX Python that are built in the `lib/`
directory.

A new CMake build option named `MATERIALX_BUILD_PYTHON_DOCS` allows
developers to turn generating Python API documentation on.

When `MATERIALX_BUILD_PYTHON_DOCS` is set to `ON`, `MATERIALX_BUILD_PYTHON`
is set to `ON` as well, ensuring we have Python modules for which to build
the Python API docs.

The core functionality of generating Python API documentation lives in a
new directory named `documents/PythonAPI/`. It is controlled with a new
`CMakeLists.txt` file in that directory, which defines a new target named
`MaterialXDocsPython`, similar to the existing target `MaterialXDocs` that
generates API documentation for the MaterialX C++ API.

To facilitate the curation and addition of docstrings in the implementation
files within `source/PyMaterialX/`, this PR adds a new helper macro named
`PYMATERIALX_DOCSTRING` that allows developers of Python modules to define
docstrings using the following pattern:
```cpp
PYMATERIALX_DOCSTRING(R"docstring(
...markdown text here...
)docstring");
```

Revised docstrings for modules and classes are to be added in subsequent PRs
separately.

Documentation in markdown format from the existing `DeveloperGuide` is
integrated into the new Python API documentation by way of symlinking the
four main `.md` files into the `documents/PythonAPI/sources/` directory
from which Sphinx generates the resulting HTML documentation.

Warnings that are issued when generating the documentation via Sphinx are
to be addressed in a separate PR for the markdown files:
AcademySoftwareFoundation#2037

To build the docs from scratch on macOS, I've used the following build
script, naming it `build.sh` in the `MaterialX` checkout directory:
```bash

echo build.sh: Updating Git submodules...
git submodule update --init --recursive

python3 -m venv /tmp/venv
source /tmp/venv/bin/activate.csh

echo build.sh: Installing dependencies...
python3 -m pip install myst_parser  # https://pypi.org/project/myst-parser/

echo build.sh: Making build directory and changing into it...
mkdir build
cd build

echo build.sh: Configuring...
cmake .. \
    --fresh \
    -DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX15.0.sdk \
    -DMATERIALX_BUILD_PYTHON=ON \
    -DMATERIALX_BUILD_VIEWER=ON \
    -DMATERIALX_BUILD_GRAPH_EDITOR=ON \
    -DMATERIALX_BUILD_DOCS=ON \
    -DMATERIALX_BUILD_PYTHON_DOCS=ON \
    -DMATERIALX_BUILD_TESTS=ON \
&& \
echo build.sh: Building... \
&& \
cmake --build . -j 8 \
&& \
echo build.sh: Building target MaterialXDocs... \
&& \
cmake --build . --target MaterialXDocs \
&& \
echo build.sh: Building target MaterialXDocsPython... \
&& \
cmake --build . --target MaterialXDocsPython \
&& \
afplay /System/Library/Sounds/Blow.aiff

deactivate
```
The build output currently ends with the following messages:
```python
The parsed MaterialX Python API consists of:
    * 11 modules
    * 48 functions
    * 139 classes
    * 1175 methods
    * 6 exception types

WARNING: 48 functions look like they do not have docstrings yet.
WARNING: 1019 methods look like they do not have docstrings yet.
WARNING: 32 functions look like their parameters have not all been named using `py::arg()`.
WARNING: 499 methods look like their parameters have not all been named using `py::arg()`.
build succeeded, 168 warnings.

The HTML pages are in ..
[100%] Built target MaterialXDocsPython
```

Split from AcademySoftwareFoundation#1567.

Update AcademySoftwareFoundation#342.

Signed-off-by: Stefan Habel <19556655+StefanHabel@users.noreply.github.com>
  • Loading branch information
StefanHabel committed Oct 3, 2024
1 parent 0653e1d commit 6c8efaf
Show file tree
Hide file tree
Showing 16 changed files with 1,186 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build
documents/PythonAPI/sources/generated/
dist
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ endif()

project(MaterialX VERSION ${MATERIALX_LIBRARY_VERSION})

# Build options
option(MATERIALX_BUILD_PYTHON "Build the MaterialX Python package from C++ bindings. Requires Python 3.6 or greater." OFF)
option(MATERIALX_BUILD_VIEWER "Build the MaterialX Viewer." OFF)
option(MATERIALX_BUILD_GRAPH_EDITOR "Build the MaterialX Graph Editor." OFF)
option(MATERIALX_BUILD_DOCS "Create HTML documentation using Doxygen. Requires that Doxygen be installed." OFF)
option(MATERIALX_BUILD_PYTHON_DOCS "Create HTML documentation for the MaterialX Python API using Sphinx. Requires that Sphinx be installed. Sets MATERIALX_BUILD_PYTHON to ON." OFF)
if(MATERIALX_BUILD_PYTHON_DOCS)
set(MATERIALX_BUILD_PYTHON ON)
endif()

option(MATERIALX_BUILD_GEN_GLSL "Build the GLSL shader generator back-end." ON)
option(MATERIALX_BUILD_GEN_OSL "Build the OSL shader generator back-end." ON)
Expand Down Expand Up @@ -158,6 +163,7 @@ message(STATUS "Setting namespace to '${MATERIALX_NAMESPACE}'")
set (MATERIALX_LIBNAME_SUFFIX "" CACHE STRING "Specify a suffix to all libraries that are built")

mark_as_advanced(MATERIALX_BUILD_DOCS)
mark_as_advanced(MATERIALX_BUILD_PYTHON_DOCS)
mark_as_advanced(MATERIALX_BUILD_GEN_GLSL)
mark_as_advanced(MATERIALX_BUILD_GEN_OSL)
mark_as_advanced(MATERIALX_BUILD_GEN_MDL)
Expand Down Expand Up @@ -507,6 +513,9 @@ endif()
if(MATERIALX_BUILD_DOCS)
add_subdirectory(documents)
endif()
if(MATERIALX_BUILD_PYTHON_DOCS)
add_subdirectory(documents/PythonAPI)
endif()

if(MATERIALX_BUILD_JS)
add_subdirectory(source/JsMaterialX)
Expand Down
18 changes: 18 additions & 0 deletions cmake/modules/FindSphinx.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
include(FindPackageHandleStandardArgs)

find_package(Python3)
if(PYTHON3_FOUND)
get_filename_component(_PYTHON_EXECUTABLE_DIR "${PYTHON_EXECUTABLE}" DIRECTORY)
set(_SPHINX_SEARCH_PATHS
"${_PYTHON_EXECUTABLE_DIR}"
"${_PYTHON_EXECUTABLE_DIR}/bin"
"${_PYTHON_EXECUTABLE_DIR}/Scripts"
"${_PYTHON_EXECUTABLE_DIR}/../opt/sphinx-doc/bin")
message(STATUS "Looking for Sphinx in the following directories: ${_SPHINX_SEARCH_PATHS}")
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build sphinx-build.exe
HINTS ${_SPHINX_SEARCH_PATHS})
mark_as_advanced(SPHINX_EXECUTABLE)

find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE)
endif()
2 changes: 2 additions & 0 deletions documents/DeveloperGuide/MainPage.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX Viewer. Insta

To generate HTML documentation for the MaterialX C++ API, make sure a version of [Doxygen](https://www.doxygen.org/) is on your path, and select the advanced option `MATERIALX_BUILD_DOCS` in CMake. This option will add a target named `MaterialXDocs` to your project, which can be built as an independent step from your development environment.

To generate HTML documentation for the MaterialX Python API, make sure a version of [Sphinx](https://www.sphinx-doc.org/) is on your path, and select the advanced option `MATERIALX_BUILD_PYTHON_DOCS` in CMake. This option will add a target named `MaterialXDocsPython` to your project, which can be built as an independent step from your development environment.

## Installing MaterialX

Building the `install` target of your project will install the MaterialX C++ and Python libraries to the folder specified by the `CMAKE_INSTALL_PREFIX` setting, and will install MaterialX Python as a third-party library in your Python environment. Installation of MaterialX Python as a third-party library can be disabled by setting `MATERIALX_INSTALL_PYTHON` to `OFF`.
Expand Down
53 changes: 53 additions & 0 deletions documents/PythonAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Use `CMAKE_MODULE_PATH` to be able to find the Sphinx executables
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")

find_package(Sphinx REQUIRED)

set(SPHINX_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SPHINX_RST_SOURCE_DIR ${SPHINX_SOURCE_DIR}/sources)
set(SPHINX_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(SPHINX_HTML_OUTPUT_DIR ${SPHINX_OUTPUT_DIR})
set(MATERIALX_PYTHON_DOCS_TARGET_DEPENDENCIES
MaterialXCore
PyMaterialXCore
PyMaterialXFormat
PyMaterialXGenShader
PyMaterialXGenGlsl
PyMaterialXGenOsl
PyMaterialXGenMdl
PyMaterialXGenMsl
PyMaterialXRender
PyMaterialXRenderGlsl
PyMaterialXRenderOsl
PyMaterialXRenderMsl)

# Generate the Sphinx configuration file `conf.py` from `conf.py.in`
set(MATERIALX_PYTHONPATH ${CMAKE_BINARY_DIR}/lib)
set(MATERIALX_LOGO_FILENAME "MaterialXLogo_200x155.png")
configure_file(${SPHINX_SOURCE_DIR}/conf.py.in
${SPHINX_OUTPUT_DIR}/conf.py)

# Add a custom target to invoke `sphinx-build` to generate the Python API docs,
# which depends on the Python bindings to be built
add_custom_target(MaterialXDocsPython
${SPHINX_EXECUTABLE} --fresh-env --conf-dir ${SPHINX_OUTPUT_DIR}
${SPHINX_RST_SOURCE_DIR}
${SPHINX_HTML_OUTPUT_DIR}
WORKING_DIRECTORY ${SPHINX_OUTPUT_DIR}
DEPENDS ${MATERIALX_PYTHON_DOCS_TARGET_DEPENDENCIES}
COMMENT "Building MaterialX Python API Documentation: ${SPHINX_HTML_OUTPUT_DIR}/index.html")

# Add post-build commands to copy our logo and custom style sheet to the "_static" folder
add_custom_command(TARGET MaterialXDocsPython
POST_BUILD COMMAND
${CMAKE_COMMAND} -E copy
${SPHINX_SOURCE_DIR}/custom.css
${SPHINX_HTML_OUTPUT_DIR}/_static/custom.css)
add_custom_command(TARGET MaterialXDocsPython
POST_BUILD COMMAND
${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/documents/Images/${MATERIALX_LOGO_FILENAME}
${SPHINX_HTML_OUTPUT_DIR}/_static/)

install(DIRECTORY ${SPHINX_OUTPUT_DIR}
DESTINATION "documents/PythonAPI" MESSAGE_NEVER)
Loading

0 comments on commit 6c8efaf

Please sign in to comment.