diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000..3321fbe --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,71 @@ +parse: + additional_commands: + pybind11_mkdoc: + kwargs: + OUTPUT: 1 + PYBIND11_MODULE: 1 + HEADERS: "*" + EXTRA_ARGS: "*" + +format: + line_width: 99 + tab_size: 2 + + # If an argument group contains more than this many sub-groups + # (parg or kwarg groups) then force it to a vertical layout. + max_subgroups_hwrap: 2 + + # If a positional argument group contains more than this many + # arguments, then force it to a vertical layout. + max_pargs_hwrap: 6 + + # If a cmdline positional group consumes more than this many + # lines without nesting, then invalidate the layout (and nest) + max_rows_cmdline: 2 + separate_ctrl_name_with_space: false + separate_fn_name_with_space: false + dangle_parens: false + + # If the trailing parenthesis must be 'dangled' on its on + # 'line, then align it to this reference: `prefix`: the start' + # 'of the statement, `prefix-indent`: the start of the' + # 'statement, plus one indentation level, `child`: align to' + # the column of the arguments + dangle_align: prefix + # If the statement spelling length (including space and + # parenthesis) is smaller than this amount, then force reject + # nested layouts. + min_prefix_chars: 4 + + # If the statement spelling length (including space and + # parenthesis) is larger than the tab width by more than this + # amount, then force reject un-nested layouts. + max_prefix_chars: 10 + + # If a candidate layout is wrapped horizontally but it exceeds + # this many lines, then reject the layout. + max_lines_hwrap: 2 + + line_ending: unix + + # Format command names consistently as 'lower' or 'upper' case + command_case: canonical + + # Format keywords consistently as 'lower' or 'upper' case + # unchanged is valid too + keyword_case: "upper" + + # A list of command names which should always be wrapped + always_wrap: [] + + # If true, the argument lists which are known to be sortable + # will be sorted lexicographically + enable_sort: true + + # If true, the parsers may infer whether or not an argument + # list is sortable (without annotation). + autosort: false + +# Reflowing comments destroys hand-made lists and examples +markup: + enable_markup: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 658de93..24746ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: @@ -41,7 +41,7 @@ jobs: - name: Test package run: uv run --with "clang<19" --group test pytest - + checks_windows: strategy: fail-fast: false diff --git a/.gitignore b/.gitignore index 623b582..d0e41ea 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,3 @@ dmypy.json # Cython debug symbols cython_debug/ - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..410a980 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,119 @@ +# 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)?$ + # These two are written by CMake itself + exclude: ^pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdocConfig(Version)?\.cmake$ + +# 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 diff --git a/README.md b/README.md index e18d794..7eb2c01 100644 --- a/README.md +++ b/README.md @@ -76,21 +76,21 @@ py::class_(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. @@ -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 ) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 5407ce3..dcb3dd7 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -3,10 +3,9 @@ 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__ *= *[\"']" -) + 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}") @@ -15,27 +14,20 @@ 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) diff --git a/cmake/pybind11_mkdoc_functions.cmake b/cmake/pybind11_mkdoc_functions.cmake index 7a5c00f..adfb66f 100644 --- a/cmake/pybind11_mkdoc_functions.cmake +++ b/cmake/pybind11_mkdoc_functions.cmake @@ -1,13 +1,13 @@ # 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 +# 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 +# * HEADERS - The header files to create docs for. These can be absolute paths or relative to the # current source directory. # # The optional parameters are: @@ -16,53 +16,48 @@ # Example usage: # pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc) # pybind11_mkdoc( -# OUTPUT my_pybind11_module_doc.h +# OUTPUT my_pybind11_module_doc.h # PYBIND11_MODULE my_pybind11_module -# HEADERS +# 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}" - ) +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 "$") + # Include directories for the pybind11 module + set(prop "$") - # 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} "$<$:-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} + "$<$:-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() diff --git a/pybind11_mkdoc/__init__.py b/pybind11_mkdoc/__init__.py index 21ad05d..1cfb59d 100644 --- a/pybind11_mkdoc/__init__.py +++ b/pybind11_mkdoc/__init__.py @@ -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): @@ -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", diff --git a/pybind11_mkdoc/mkdoc_lib.py b/pybind11_mkdoc/mkdoc_lib.py index 90bd583..d90a911 100755 --- a/pybind11_mkdoc/mkdoc_lib.py +++ b/pybind11_mkdoc/mkdoc_lib.py @@ -114,7 +114,9 @@ def sanitize_name(name): section_command_re = re.compile(r"\s*[\\@](\w+)(?:\[([^\]]+)\])?(?:\s+(.*))?$") code_segment_re = re.compile(r"(```)") -prefix_re = re.compile(r"(\s*)((?:[*\-•]\s)|(?:\(?\d+[\.)]\s)|(?:[\w:]+(?:\s+\[[^\]]+\])?:(?:\s+|$)))") +prefix_re = re.compile( + r"(\s*)((?:[*\-•]\s)|(?:\(?\d+[\.)]\s)|(?:[\w:]+(?:\s+\[[^\]]+\])?:(?:\s+|$)))" +) named_arg_re = re.compile(r"([\w:]+)\s*(.*)") IGNORED_DOXYGEN_COMMANDS = { @@ -182,8 +184,14 @@ def sanitize_name(name): # Applied before the Doxygen sections are consumed. BLOCK_DOXYGEN_REPLACEMENTS = [ - (re.compile(r"[\\@]code\s?(.*?)\s?[\\@]endcode", flags=re.DOTALL), "```\n\\1\n```\n"), - (re.compile(r"[\\@]verbatim\s?(.*?)\s?[\\@]endverbatim", flags=re.DOTALL), "```\n\\1\n```\n"), + ( + re.compile(r"[\\@]code\s?(.*?)\s?[\\@]endcode", flags=re.DOTALL), + "```\n\\1\n```\n", + ), + ( + re.compile(r"[\\@]verbatim\s?(.*?)\s?[\\@]endverbatim", flags=re.DOTALL), + "```\n\\1\n```\n", + ), ] MARKUP_REPLACEMENTS = [ @@ -381,7 +389,9 @@ def _consume_doxygen_sections(s): result += _format_named_entries("Template Args", t_params) result += _format_list_entries("Returns", returns) result += _format_named_entries("Raises", raises) - result += _format_section_entries((heading, " ".join(text).strip()) for heading, text in sections) + result += _format_section_entries( + (heading, " ".join(text).strip()) for heading, text in sections + ) return "\n".join(result) @@ -500,7 +510,9 @@ def flush_paragraph(paragraph=paragraph, wrapped=wrapped): continue prefix, indent = get_prefix_and_indent(line) - if paragraph and ((indent != current_indent) or (prefix and prefix != current_prefix)): + if paragraph and ( + (indent != current_indent) or (prefix and prefix != current_prefix) + ): # Prefix/indent changed → start new paragraph flush_paragraph() @@ -693,10 +705,16 @@ def read_args(args): cpp_dirs = [] if "-stdlib=libc++" not in args: - cpp_dirs.append(max(glob("/usr/include/c++/*"), default=None, key=_folder_version)) + cpp_dirs.append( + max(glob("/usr/include/c++/*"), default=None, key=_folder_version) + ) cpp_dirs.append( - max(glob(f"/usr/include/{platform.machine()}-linux-gnu/c++/*"), default=None, key=_folder_version) + max( + glob(f"/usr/include/{platform.machine()}-linux-gnu/c++/*"), + default=None, + key=_folder_version, + ) ) elif llvm_dir is not None: cpp_dirs.append(str(PurePosixPath(llvm_dir) / "include" / "c++" / "v1")) @@ -706,7 +724,9 @@ def read_args(args): elif llvm_dir is not None: cpp_dirs.append( max( - glob(str(PurePosixPath(llvm_dir) / "lib" / "clang" / "*" / "include")), + glob( + str(PurePosixPath(llvm_dir) / "lib" / "clang" / "*" / "include") + ), default=None, key=_folder_version, ) @@ -717,7 +737,13 @@ def read_args(args): # Capability to specify additional include directories manually if "CPP_INCLUDE_DIRS" in os.environ: - cpp_dirs.extend([cpp_dir for cpp_dir in os.environ["CPP_INCLUDE_DIRS"].split() if os.path.exists(cpp_dir)]) + cpp_dirs.extend( + [ + cpp_dir + for cpp_dir in os.environ["CPP_INCLUDE_DIRS"].split() + if os.path.exists(cpp_dir) + ] + ) for cpp_dir in cpp_dirs: if cpp_dir is None: diff --git a/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake index 7a5c00f..adfb66f 100644 --- a/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake +++ b/pybind11_mkdoc/share/cmake/pybind11_mkdoc/pybind11_mkdoc_functions.cmake @@ -1,13 +1,13 @@ # 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 +# 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 +# * HEADERS - The header files to create docs for. These can be absolute paths or relative to the # current source directory. # # The optional parameters are: @@ -16,53 +16,48 @@ # Example usage: # pybind11_add_module(my_pybind11_module src/my_pybind11_module.cc) # pybind11_mkdoc( -# OUTPUT my_pybind11_module_doc.h +# OUTPUT my_pybind11_module_doc.h # PYBIND11_MODULE my_pybind11_module -# HEADERS +# 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}" - ) +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 "$") + # Include directories for the pybind11 module + set(prop "$") - # 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} "$<$:-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} + "$<$:-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() diff --git a/tests/cli_test.py b/tests/cli_test.py index c9e7dcc..6fc46ee 100644 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -21,7 +21,9 @@ def test_simple_header_cli(tmp_path: Path, name: str) -> None: # Run pybind11-mkdoc and put the output in a temp file tf = tmp_path / "tmp.h" header = DIR / "sample_header_docs" / name - subprocess.run([sys.executable, "-m", "pybind11_mkdoc", "-o", tf, header], check=True) + subprocess.run( + [sys.executable, "-m", "pybind11_mkdoc", "-o", tf, header], check=True + ) # Ensure the header file matches res = tf.read_text(encoding="utf-8") @@ -48,7 +50,14 @@ def test_append_definition(definition: str, expected_arg: str) -> None: def test_parse_failure_sets_exit_code(tmp_path: Path) -> None: tf = tmp_path / "tmp.h" result = subprocess.run( - [sys.executable, "-m", "pybind11_mkdoc", "-o", tf, tmp_path / "does_not_exist.h"], + [ + sys.executable, + "-m", + "pybind11_mkdoc", + "-o", + tf, + tmp_path / "does_not_exist.h", + ], check=False, capture_output=True, ) diff --git a/tests/cmake_test.py b/tests/cmake_test.py index c84c2c0..27b4d7f 100644 --- a/tests/cmake_test.py +++ b/tests/cmake_test.py @@ -10,7 +10,15 @@ def test_pybind11_mkdoc_cmake(tmp_path: Path) -> None: # Run pybind11-mkdoc and put the output in a temp file build_dir = tmp_path / "build" subprocess.run( - ["cmake", "-B", build_dir, "-S", DIR / "cmake_docs", f"-DPython_EXECUTABLE={sys.executable}"], check=True + [ + "cmake", + "-B", + build_dir, + "-S", + DIR / "cmake_docs", + f"-DPython_EXECUTABLE={sys.executable}", + ], + check=True, ) subprocess.run(["cmake", "--build", build_dir], check=True) @@ -31,7 +39,14 @@ def test_pybind11_mkdoc_cmake_extra_args(tmp_path: Path) -> None: env["PYBIND11_TEST_EXTRA_ARGS"] = "-DMY_EXTRA_DEFINE=1;-DMY_OTHER_DEFINE=1" subprocess.run( - ["cmake", "-B", build_dir, "-S", DIR / "cmake_docs", f"-DPython_EXECUTABLE={sys.executable}"], + [ + "cmake", + "-B", + build_dir, + "-S", + DIR / "cmake_docs", + f"-DPython_EXECUTABLE={sys.executable}", + ], check=True, env=env, ) diff --git a/tests/doxygen_parsing_test.py b/tests/doxygen_parsing_test.py index 986d579..4e92cb7 100644 --- a/tests/doxygen_parsing_test.py +++ b/tests/doxygen_parsing_test.py @@ -98,7 +98,10 @@ def test_function_docstrings_end_with_blank_line_before_closing_quotes(): * Details begin after the summary. */""") - assert format_function_docstring(comment) == "Summary line.\n\nDetails begin after the summary.\n\n" + assert ( + format_function_docstring(comment) + == "Summary line.\n\nDetails begin after the summary.\n\n" + ) def test_single_line_function_docstrings_do_not_get_extra_blank_lines(): diff --git a/tests/duplicate_name_test.py b/tests/duplicate_name_test.py index a42969e..754e619 100644 --- a/tests/duplicate_name_test.py +++ b/tests/duplicate_name_test.py @@ -9,7 +9,9 @@ def test_suffixed_names_do_not_collide(tmp_path): - comments = pybind11_mkdoc.mkdoc_lib.extract_all([str(DIR / "duplicate_name_docs" / "duplicate_name.h")]) + comments = pybind11_mkdoc.mkdoc_lib.extract_all( + [str(DIR / "duplicate_name_docs" / "duplicate_name.h")] + ) output = tmp_path / "docs.h" with output.open("w") as fd: diff --git a/tests/long_parameter_test.py b/tests/long_parameter_test.py index 76c5430..a815be8 100644 --- a/tests/long_parameter_test.py +++ b/tests/long_parameter_test.py @@ -7,7 +7,9 @@ def test_long_parameter(capsys): - comments = pybind11_mkdoc.mkdoc_lib.extract_all([os.path.join(DIR, "long_parameter_docs", "long_parameter.h")]) + comments = pybind11_mkdoc.mkdoc_lib.extract_all( + [os.path.join(DIR, "long_parameter_docs", "long_parameter.h")] + ) pybind11_mkdoc.mkdoc_lib.write_header(comments, sys.stdout) res = capsys.readouterr() diff --git a/tests/read_args_test.py b/tests/read_args_test.py index b536ad0..2b55f8f 100644 --- a/tests/read_args_test.py +++ b/tests/read_args_test.py @@ -14,14 +14,23 @@ def config_calls(monkeypatch): """Record cindex.Config.set_library_* calls instead of configuring libclang.""" calls = {} monkeypatch.setattr(cindex.Config, "loaded", False) - monkeypatch.setattr(cindex.Config, "set_library_file", lambda p: calls.__setitem__("file", p)) - monkeypatch.setattr(cindex.Config, "set_library_path", lambda p: calls.__setitem__("path", p)) + monkeypatch.setattr( + cindex.Config, "set_library_file", lambda p: calls.__setitem__("file", p) + ) + monkeypatch.setattr( + cindex.Config, "set_library_path", lambda p: calls.__setitem__("path", p) + ) return calls @pytest.fixture def clean_env(monkeypatch): - for var in ["LIBCLANG_PATH", "LLVM_DIR_PATH", "CLANG_INCLUDE_DIR", "CPP_INCLUDE_DIRS"]: + for var in [ + "LIBCLANG_PATH", + "LLVM_DIR_PATH", + "CLANG_INCLUDE_DIR", + "CPP_INCLUDE_DIRS", + ]: monkeypatch.delenv(var, raising=False) @@ -58,7 +67,9 @@ def test_linux_libclang_path_without_llvm_dir(monkeypatch, config_calls, tmp_pat @pytest.mark.usefixtures("linux", "clean_env") -def test_linux_libclang_path_without_llvm_dir_libcpp(monkeypatch, config_calls, tmp_path): +def test_linux_libclang_path_without_llvm_dir_libcpp( + monkeypatch, config_calls, tmp_path +): lib = tmp_path / "libclang.so.1" lib.touch() monkeypatch.setattr(mkdoc_lib, "glob", lambda _pattern: []) @@ -102,7 +113,10 @@ def test_macos_xcode_preferred(monkeypatch, config_calls): assert config_calls["path"] == XCODE + "Toolchains/XcodeDefault.xctoolchain/usr/lib" idx = parameters.index("-isysroot") - assert parameters[idx + 1] == XCODE + "Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" + assert ( + parameters[idx + 1] + == XCODE + "Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" + ) @pytest.mark.usefixtures("darwin", "clean_env") diff --git a/tests/sample_header_test.py b/tests/sample_header_test.py index b4aad48..4a22299 100644 --- a/tests/sample_header_test.py +++ b/tests/sample_header_test.py @@ -9,8 +9,13 @@ def test_generate_headers(capsys, tmp_path): with open(DIR / "sample_header_docs" / "sample_header_truth.h") as f: expected = f.read() - comments = pybind11_mkdoc.mkdoc_lib.extract_all([str(DIR / "sample_header_docs" / "sample_header.h")]) - assert [c[0] for c in comments] == ["mkd_doc_RootLevelSymbol", "mkd_doc_drake_MidLevelSymbol"] + comments = pybind11_mkdoc.mkdoc_lib.extract_all( + [str(DIR / "sample_header_docs" / "sample_header.h")] + ) + assert [c[0] for c in comments] == [ + "mkd_doc_RootLevelSymbol", + "mkd_doc_drake_MidLevelSymbol", + ] output = tmp_path / "docs.h" with output.open("w") as fd: @@ -34,7 +39,9 @@ def test_generate_headers_2(capsys, tmp_path): with open(DIR / "sample_header_docs" / "sample_header_2_truth.h") as f: expected = f.read() - comments = pybind11_mkdoc.mkdoc_lib.extract_all([str(DIR / "sample_header_docs" / "sample_header_2.h")]) + comments = pybind11_mkdoc.mkdoc_lib.extract_all( + [str(DIR / "sample_header_docs" / "sample_header_2.h")] + ) output = tmp_path / "docs.h" with output.open("w") as fd: