Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ name: CI
on:
pull_request:
push:
branches:
branches:
- master
tags:
- 'v*'

jobs:
format:
lint:
runs-on: ubuntu-latest
name: Format
name: Lint
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v9.0.0
- run: uvx hatch fmt
- run: uvx prek run -a --show-diff-on-failure

checks:
strategy:
Expand All @@ -41,7 +41,7 @@ jobs:

- name: Test package
run: uv run --with "clang<19" --group test pytest

checks_windows:
strategy:
fail-fast: false
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,3 @@ dmypy.json

# Cython debug symbols
cython_debug/

117 changes: 117 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# To use locally:
#
# prek -a
#
# Or:
#
# prek install # (runs every time you commit in git)
#
# To update this file:
#
# prek autoupdate
#
# See https://github.com/pre-commit/pre-commit

ci:
autoupdate_commit_msg: "chore(deps): update pre-commit hooks"
autofix_commit_msg: "style: pre-commit fixes"
autoupdate_schedule: monthly

# Test fixtures are compared byte-for-byte against generated output
exclude: ^tests/.*_docs/

repos:

# Ruff, the Python auto-correcting linter/formatter written in Rust
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.1
hooks:
- id: ruff-check
args: ["--fix", "--show-fixes"]
- id: ruff-format

# Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v2.3.0"
hooks:
- id: mypy
exclude: ^tests/
additional_dependencies:
- pytest

# CMake formatting
- repo: https://github.com/cheshirekow/cmake-format-precommit
rev: "v0.6.13"
hooks:
- id: cmake-format
additional_dependencies: [pyyaml]
types: [file]
files: (\.cmake|CMakeLists.txt)(.in)?$

# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v6.0.0"
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-docstring-first
- id: check-merge-conflict
- id: check-symlinks
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace

# Also code format the docs
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.20.0"
hooks:
- id: blacken-docs
additional_dependencies:
- black==23.*

# Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: "v1.5.6"
hooks:
- id: remove-tabs

# Avoid directional quotes
- repo: https://github.com/sirosen/texthooks
rev: "0.7.1"
hooks:
- id: fix-ligatures
- id: fix-smartquotes

# Check for spelling
- repo: https://github.com/codespell-project/codespell
rev: "v2.4.3"
hooks:
- id: codespell

# Also check spelling
# Use mirror because pre-commit autoupdate confuses tags in the upstream repo.
# See https://github.com/crate-ci/typos/issues/390
- repo: https://github.com/adhtruong/mirrors-typos
rev: "v1.48.0"
hooks:
- id: typos
args: []

# Disallow some common capitalization mistakes
- repo: local
hooks:
- id: disallow-caps
name: Disallow improper capitalization
language: pygrep
entry: PyBind|\bNumpy\b|Cmake|CCache|PyTest
exclude: ^\.pre-commit-config.yaml$

# Check schemas on some of our YAML files
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.37.4
hooks:
- id: check-github-workflows
- id: check-dependabot
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,21 @@ py::class_<MyClass>(m, "MyClass", DOC(MyClass))

### CMake
The `pybind11_mkdoc` CMake function is included to easily generate header for a pybind11 module when
compiling said module in CMake. The function generates the headers based on the arguments provided.
In addition, it add target dependencies so the pybind11-mkdoc header file is generated before
the pybind11 module. Also, it will automatically add the current binary directory to the pybind11
compiling said module in CMake. The function generates the headers based on the arguments provided.
In addition, it add target dependencies so the pybind11-mkdoc header file is generated before
the pybind11 module. Also, it will automatically add the current binary directory to the pybind11
module's includes, so it can easily be included when compiling the module.

The required parameters are:
* OUTPUT - The name of the output file.
* PYBIND11_MODULE - The pybind11 module target that these docs will be used for.
* HEADERS - The header files to create docs for. These can be absoulte paths or relative to the
* HEADERS - The header files to create docs for. These can be absolute paths or relative to the
current source directory.

The optional parameters are:
* EXTRA_ARGS - This string argument will be added verbatim to the pybind11-mkdoc command.

Below is an exmaple of how it is used:
Below is an example of how it is used:
```cmake
# Find pybind11-mkdoc
# This assumes you have already run a find_package for Python.
Expand All @@ -104,9 +104,9 @@ find_package(pybind11_mkdoc REQUIRED CONFIG)
# Add the pybind11 module
pybind11_add_module(my_pybind11_module my_src_files.cc)
pybind11_mkdoc(
OUTPUT my_pybind11_module_docs.h
OUTPUT my_pybind11_module_docs.h
PYBIND11_MODULE my_pybind11_module
HEADERS
HEADERS
header_1.h
/absolute/path/to/header_2.h
)
Expand Down
40 changes: 17 additions & 23 deletions cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.25...4.3)

# Read the version from the Python package; project() accepts numeric components only,
# so any dev/pre-release suffix is dropped.
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/../pybind11_mkdoc/__init__.py" version_line
REGEX "^__version__ *= *[\"']"
)
# Read the version from the Python package; project() accepts numeric components
# only, so any dev/pre-release suffix is dropped.
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/../pybind11_mkdoc/__init__.py"
version_line REGEX "^__version__ *= *[\"']")
if(NOT version_line MATCHES "([0-9]+(\\.[0-9]+)*)")
message(FATAL_ERROR "Could not read __version__ from pybind11_mkdoc/__init__.py")
message(
FATAL_ERROR "Could not read __version__ from pybind11_mkdoc/__init__.py")
endif()

project(pybind11_mkdoc VERSION "${CMAKE_MATCH_1}")
Expand All @@ -15,27 +15,21 @@ include(CMakePackageConfigHelpers)

# Generate version file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion)

# Create config file
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/pybind11_mkdocConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfig.cmake"
INSTALL_DESTINATION pybind11_mkdoc
)
"${CMAKE_CURRENT_SOURCE_DIR}/pybind11_mkdocConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfig.cmake"
INSTALL_DESTINATION pybind11_mkdoc)

# Install config + version
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfigVersion.cmake"
DESTINATION pybind11_mkdoc
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/pybind11_mkdocConfigVersion.cmake"
DESTINATION pybind11_mkdoc)

# Install functions
install(FILES
"${CMAKE_CURRENT_SOURCE_DIR}/pybind11_mkdoc_functions.cmake"
DESTINATION pybind11_mkdoc
)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pybind11_mkdoc_functions.cmake"
DESTINATION pybind11_mkdoc)
110 changes: 52 additions & 58 deletions cmake/pybind11_mkdoc_functions.cmake
Original file line number Diff line number Diff line change
@@ -1,68 +1,62 @@
# This function is used to run pybind11-mkdoc for the headers of a pybind11 module.
# In addition, this will also add target dependencies so the pybind11-mkdoc header
# file is generated before the pybind11 module. Also, this will automatically add
# the current binary directory to the pybind11 module's includes, so it can
# easily be included when compiling the module.
# This function is used to run pybind11-mkdoc for the headers of a pybind11
# module. In addition, this will also add target dependencies so the
# pybind11-mkdoc header file is generated before the pybind11 module. Also, this
# will automatically add the current binary directory to the pybind11 module's
# includes, so it can easily be included when compiling the module.
#
# The required parameters are:
# * OUTPUT - The name of the output file.
# * PYBIND11_MODULE - The pybind11 module target that these docs will be used for.
# * HEADERS - The header files to create docs for. These can be absoulte paths or relative to the
# current source directory.
# The required parameters are: * OUTPUT - The name of the output file. *
# PYBIND11_MODULE - The pybind11 module target that these docs will be used for.
# * HEADERS - The header files to create docs for. These can be absolute paths
# or relative to the current source directory.
#
# The optional parameters are:
# * EXTRA_ARGS - A list of arguments that will be added verbatim to the pybind11-mkdoc command.
# The optional parameters are: * EXTRA_ARGS - A list of arguments that will be
# added verbatim to the pybind11-mkdoc command.
#
# Example usage:
# pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc)
# pybind11_mkdoc(
# OUTPUT my_pybind11_module_doc.h
# PYBIND11_MODULE my_pybind11_module
# HEADERS
# include/my_header_1.h
# /absolute/path/to/header.h
# )
function (pybind11_mkdoc)
set(options)
set(oneValueArgs OUTPUT PYBIND11_MODULE)
set(multiValueArgs HEADERS EXTRA_ARGS)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}" "${oneValueArgs}" "${multiValueArgs}"
)
# Example usage: pybind11_add_module(my_pybind11_module
# src/my_pybind11_module.cc) pybind11_mkdoc( OUTPUT my_pybind11_module_doc.h
# PYBIND11_MODULE my_pybind11_module HEADERS include/my_header_1.h
# /absolute/path/to/header.h )
function(pybind11_mkdoc)
set(options)
set(oneValueArgs OUTPUT PYBIND11_MODULE)
set(multiValueArgs HEADERS EXTRA_ARGS)
cmake_parse_arguments(PARSE_ARGV 0 arg "${options}" "${oneValueArgs}"
"${multiValueArgs}")

# Include directories for the pybind11 module
set(prop "$<TARGET_PROPERTY:${arg_PYBIND11_MODULE},INCLUDE_DIRECTORIES>")
# Include directories for the pybind11 module
set(prop "$<TARGET_PROPERTY:${arg_PYBIND11_MODULE},INCLUDE_DIRECTORIES>")

# Remove the header file from the list
set(HEADERS "")
# Run through all the other arguments.
foreach(header ${arg_HEADERS})
if(IS_ABSOLUTE ${header})
# If it is an absolute path, then add it as is.
list(APPEND HEADERS ${header})
else()
# Otherwise, assume it is relative to the current source directory.
list(APPEND HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/${header}")
endif()
endforeach()
# Remove the header file from the list
set(HEADERS "")
# Run through all the other arguments.
foreach(header ${arg_HEADERS})
if(IS_ABSOLUTE ${header})
# If it is an absolute path, then add it as is.
list(APPEND HEADERS ${header})
else()
# Otherwise, assume it is relative to the current source directory.
list(APPEND HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/${header}")
endif()
endforeach()

# Add a custom target and command for the full header file location that runs pybind11-mkdoc
# We automatically include the source directory and build/include
add_custom_target(
pybind11_mkdoc_${arg_OUTPUT}
DEPENDS ${arg_OUTPUT}
)
# Add a custom target and command for the full header file location that runs
# pybind11-mkdoc We automatically include the source directory and
# build/include
add_custom_target(pybind11_mkdoc_${arg_OUTPUT} DEPENDS ${arg_OUTPUT})

add_custom_command(
OUTPUT ${arg_OUTPUT}
COMMAND ${Python_EXECUTABLE} -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o ${arg_OUTPUT} "$<$<BOOL:${prop}>:-I$<JOIN:${prop},;-I>>" ${HEADERS}
DEPENDS ${HEADERS}
COMMAND_EXPAND_LISTS
)
add_custom_command(
OUTPUT ${arg_OUTPUT}
COMMAND ${Python_EXECUTABLE} -m pybind11_mkdoc ${arg_EXTRA_ARGS} -o
${arg_OUTPUT} "$<$<BOOL:${prop}>:-I$<JOIN:${prop},;-I>>" ${HEADERS}
DEPENDS ${HEADERS}
COMMAND_EXPAND_LISTS)

# Add a dependency so that the pybind11-mkdoc command runs before we try to compile the pybind11 module
add_dependencies(${arg_PYBIND11_MODULE} pybind11_mkdoc_${arg_OUTPUT})
# Add a dependency so that the pybind11-mkdoc command runs before we try to
# compile the pybind11 module
add_dependencies(${arg_PYBIND11_MODULE} pybind11_mkdoc_${arg_OUTPUT})

# Add the current binary directory to the pybind11 module so it can be included easily
target_include_directories(${arg_PYBIND11_MODULE} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
# Add the current binary directory to the pybind11 module so it can be
# included easily
target_include_directories(${arg_PYBIND11_MODULE}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endfunction()
6 changes: 4 additions & 2 deletions pybind11_mkdoc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def _append_include_dir(args: list, include_dir: str, *, verbose: bool = True):
if os.path.isdir(include_dir):
args.append(f"-I{include_dir}")
elif verbose:
print(f"Include directory '{include_dir}' does not exist!", file=sys.stderr) # noqa: T201
print(f"Include directory '{include_dir}' does not exist!", file=sys.stderr)


def _append_definition(args: list, definition: str):
Expand Down Expand Up @@ -87,7 +87,9 @@ def main():
allow_abbrev=False,
)

parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__version__}")
parser.add_argument(
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
)

parser.add_argument(
"-o",
Expand Down
Loading