cpdocs 0.3.1__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. {cpdocs-0.3.1 → cpdocs-0.3.2}/PKG-INFO +1 -1
  2. cpdocs-0.3.2/examples/fortran-basic/docs/api.md +12 -0
  3. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/properdocs.yml +1 -0
  4. {cpdocs-0.3.1 → cpdocs-0.3.2}/pyproject.toml +1 -1
  5. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/__init__.py +1 -1
  6. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/build.py +11 -129
  7. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/cli.py +4 -4
  8. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/contract.py +5 -5
  9. cpdocs-0.3.2/src/cpdocs/languages/__init__.py +138 -0
  10. cpdocs-0.3.2/src/cpdocs/languages/base.py +63 -0
  11. cpdocs-0.3.2/src/cpdocs/languages/cpp/__init__.py +8 -0
  12. cpdocs-0.3.1/src/cpdocs/clang_backend.py → cpdocs-0.3.2/src/cpdocs/languages/cpp/extract.py +2 -2
  13. cpdocs-0.3.2/src/cpdocs/languages/cpp/render.py +125 -0
  14. cpdocs-0.3.2/src/cpdocs/languages/fortran/__init__.py +8 -0
  15. cpdocs-0.3.1/src/cpdocs/fortran_backend.py → cpdocs-0.3.2/src/cpdocs/languages/fortran/extract.py +1 -1
  16. cpdocs-0.3.2/src/cpdocs/languages/fortran/render.py +70 -0
  17. cpdocs-0.3.2/src/cpdocs/languages/python/__init__.py +8 -0
  18. cpdocs-0.3.1/src/cpdocs/python_backend.py → cpdocs-0.3.2/src/cpdocs/languages/python/extract.py +1 -1
  19. cpdocs-0.3.2/src/cpdocs/languages/python/render.py +119 -0
  20. cpdocs-0.3.2/src/cpdocs/languages/rust/__init__.py +8 -0
  21. cpdocs-0.3.1/src/cpdocs/rust_backend.py → cpdocs-0.3.2/src/cpdocs/languages/rust/extract.py +1 -1
  22. cpdocs-0.3.2/src/cpdocs/languages/rust/render.py +80 -0
  23. cpdocs-0.3.2/src/cpdocs/plugins/__init__.py +3 -0
  24. cpdocs-0.3.2/src/cpdocs/plugins/properdocs/__init__.py +7 -0
  25. cpdocs-0.3.1/src/cpdocs/properdocs_plugin.py → cpdocs-0.3.2/src/cpdocs/plugins/properdocs/plugin.py +1 -1
  26. cpdocs-0.3.2/src/cpdocs/providers/__init__.py +3 -0
  27. cpdocs-0.3.1/src/cpdocs/rust_manifest.py → cpdocs-0.3.2/src/cpdocs/providers/cargo.py +1 -1
  28. cpdocs-0.3.2/src/cpdocs/providers/cmake.py +8 -0
  29. cpdocs-0.3.2/src/cpdocs/providers/contract.py +125 -0
  30. cpdocs-0.3.1/src/cpdocs/python_manifest.py → cpdocs-0.3.2/src/cpdocs/providers/python.py +1 -1
  31. cpdocs-0.3.2/src/cpdocs/rendering/__init__.py +7 -0
  32. cpdocs-0.3.1/src/cpdocs/render.py → cpdocs-0.3.2/src/cpdocs/rendering/common.py +29 -210
  33. cpdocs-0.3.1/src/cpdocs/html_renderer.py → cpdocs-0.3.2/src/cpdocs/rendering/html.py +57 -120
  34. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/conftest.py +17 -0
  35. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_api_reference.py +7 -7
  36. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_examples.py +3 -2
  37. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_feature_set_signatures.py +1 -2
  38. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_properdocs_core.py +4 -4
  39. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_rust_provider.py +3 -3
  40. cpdocs-0.3.1/test/test_api_reference.py.rej +0 -9
  41. {cpdocs-0.3.1 → cpdocs-0.3.2}/.github/workflows/docs.yml +0 -0
  42. {cpdocs-0.3.1 → cpdocs-0.3.2}/.github/workflows/test.yml +0 -0
  43. {cpdocs-0.3.1 → cpdocs-0.3.2}/.gitignore +0 -0
  44. {cpdocs-0.3.1 → cpdocs-0.3.2}/LICENSES/Apache-2.0.txt +0 -0
  45. {cpdocs-0.3.1 → cpdocs-0.3.2}/REUSE.toml +0 -0
  46. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/api/index.md +0 -0
  47. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/cpdocs.yml +0 -0
  48. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/examples/index.md +0 -0
  49. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/explanation/architecture.md +0 -0
  50. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/explanation/feature-sets.md +0 -0
  51. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/how-to/ci.md +0 -0
  52. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/how-to/feature-sets.md +0 -0
  53. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/how-to/generated-headers.md +0 -0
  54. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/how-to/other-build-systems.md +0 -0
  55. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/how-to/properdocs.md +0 -0
  56. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/index.md +0 -0
  57. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/api.md +0 -0
  58. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/cli.md +0 -0
  59. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/cmake.md +0 -0
  60. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/comments.md +0 -0
  61. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/configuration.md +0 -0
  62. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/contract.md +0 -0
  63. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/extraction.md +0 -0
  64. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/reference/links.md +0 -0
  65. {cpdocs-0.3.1 → cpdocs-0.3.2}/docs/web/tutorials/first-reference.md +0 -0
  66. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/.gitignore +0 -0
  67. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/CMakeLists.txt +0 -0
  68. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/docs/api/index.md +0 -0
  69. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/docs/cpdocs.yml +0 -0
  70. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/docs/web/api.md +0 -0
  71. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/docs/web/index.md +0 -0
  72. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/include/acme/math.hpp +0 -0
  73. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/properdocs.yml +0 -0
  74. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/readme.md +0 -0
  75. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/basic-cpp/src/math.cpp +0 -0
  76. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/.gitignore +0 -0
  77. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/CMakeLists.txt +0 -0
  78. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/docs/api/index.md +0 -0
  79. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/docs/cpdocs.yml +0 -0
  80. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/docs/web/api.md +0 -0
  81. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/docs/web/index.md +0 -0
  82. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/include/ring/ring.h +0 -0
  83. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/properdocs.yml +0 -0
  84. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/readme.md +0 -0
  85. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/c-basic/src/ring.c +0 -0
  86. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/.gitignore +0 -0
  87. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/CMakeLists.txt +0 -0
  88. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/docs/api/index.md +0 -0
  89. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/docs/cpdocs-minibuild.yml +0 -0
  90. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/docs/cpdocs.yml +0 -0
  91. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/docs/web/api.md +0 -0
  92. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/docs/web/index.md +0 -0
  93. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/include/demo/solver.hpp +0 -0
  94. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/properdocs.yml +0 -0
  95. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/readme.md +0 -0
  96. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-features/tools/minibuild.py +0 -0
  97. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/.gitignore +0 -0
  98. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/CMakeLists.txt +0 -0
  99. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/docs/api/index.md +0 -0
  100. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/docs/cpdocs.yml +0 -0
  101. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/docs/web/api.md +0 -0
  102. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/docs/web/index.md +0 -0
  103. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/include/meta/meta.hpp +0 -0
  104. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/properdocs.yml +0 -0
  105. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/cpp-templates/readme.md +0 -0
  106. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/CMakeLists.txt +0 -0
  107. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/docs/cpdocs.yml +0 -0
  108. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/docs/index.md +0 -0
  109. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/lib/normalize.f90 +0 -0
  110. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/mod/geometry.f90 +0 -0
  111. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/fortran-basic/readme.md +0 -0
  112. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/.gitignore +0 -0
  113. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/CMakeLists.txt +0 -0
  114. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/docs/api/index.md +0 -0
  115. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/docs/cpdocs.yml +0 -0
  116. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/docs/web/api.md +0 -0
  117. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/docs/web/index.md +0 -0
  118. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/generated-template/generated.hpp +0 -0
  119. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/include/acme/core.hpp +0 -0
  120. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/properdocs.yml +0 -0
  121. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/readme.md +0 -0
  122. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/generated-cpp/src/generated.cpp +0 -0
  123. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/.gitignore +0 -0
  124. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/CMakeLists.txt +0 -0
  125. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/docs/api/index.md +0 -0
  126. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/docs/cpdocs.yml +0 -0
  127. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/docs/web/api.md +0 -0
  128. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/docs/web/index.md +0 -0
  129. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/include/geom/vector.hpp +0 -0
  130. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/properdocs.yml +0 -0
  131. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/python/pygeom/__init__.py +0 -0
  132. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/readme.md +0 -0
  133. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/mixed/src/geom.cpp +0 -0
  134. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/.gitignore +0 -0
  135. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/docs/api/index.md +0 -0
  136. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/docs/cpdocs.yml +0 -0
  137. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/docs/web/api.md +0 -0
  138. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/docs/web/index.md +0 -0
  139. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/properdocs.yml +0 -0
  140. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/pyproject.toml +0 -0
  141. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/readme.md +0 -0
  142. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/src/dice/__init__.py +0 -0
  143. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/src/dice/_rng.py +0 -0
  144. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/python-basic/src/dice/core.py +0 -0
  145. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/Cargo.lock +0 -0
  146. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/Cargo.toml +0 -0
  147. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/docs/api.md +0 -0
  148. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/docs/cpdocs.yml +0 -0
  149. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/docs/index.md +0 -0
  150. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/properdocs.yml +0 -0
  151. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/readme.md +0 -0
  152. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/rust-toolchain.toml +0 -0
  153. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/src/geometry.rs +0 -0
  154. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/src/internal.rs +0 -0
  155. {cpdocs-0.3.1 → cpdocs-0.3.2}/examples/rust-basic/src/lib.rs +0 -0
  156. {cpdocs-0.3.1 → cpdocs-0.3.2}/properdocs.yml +0 -0
  157. {cpdocs-0.3.1 → cpdocs-0.3.2}/readme.md +0 -0
  158. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/__main__.py +0 -0
  159. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/config.py +0 -0
  160. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/model.py +0 -0
  161. /cpdocs-0.3.1/src/cpdocs/properdocs_core.py → /cpdocs-0.3.2/src/cpdocs/plugins/properdocs/core.py +0 -0
  162. {cpdocs-0.3.1 → cpdocs-0.3.2}/src/cpdocs/versioning.py +0 -0
  163. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_build.py +0 -0
  164. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_config.py +0 -0
  165. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_contract.py +0 -0
  166. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_rust_example.py +0 -0
  167. {cpdocs-0.3.1 → cpdocs-0.3.2}/test/test_versioning.py +0 -0
  168. {cpdocs-0.3.1 → cpdocs-0.3.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cpdocs
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Semantic, versioned API documentation for C, C++, CUDA, HIP, Fortran, Python and Rust projects
5
5
  Project-URL: Source, https://github.com/ambhora/cpdocs
6
6
  Author-email: Jayesh Badwaik <j.badwaik@fz-juelich.de>
@@ -0,0 +1,12 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 cpdocs developers
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
5
+
6
+ # API reference
7
+
8
+ The API reference is generated from the public Fortran module for every documented feature set.
9
+
10
+ ## Versions
11
+
12
+ @apidocs-versions
@@ -20,3 +20,4 @@ theme:
20
20
 
21
21
  nav:
22
22
  - Home: index.md
23
+ - API reference: api.md
@@ -29,7 +29,7 @@ Source = "https://github.com/ambhora/cpdocs"
29
29
  cpdocs = "cpdocs.cli:main"
30
30
 
31
31
  [project.entry-points."properdocs.plugins"]
32
- cpdocs = "cpdocs.properdocs_plugin:CpdocsPlugin"
32
+ cpdocs = "cpdocs.plugins.properdocs.plugin:CpdocsPlugin"
33
33
 
34
34
  [dependency-groups]
35
35
  dev = ["pytest>=8", "ruff>=0.8", "properdocs>=1.6.7", "mkdocs-materialx"]
@@ -2,4 +2,4 @@
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
  """Language-neutral semantic API documentation generator."""
4
4
 
5
- __version__ = "0.3.1"
5
+ __version__ = "0.3.2"
@@ -15,35 +15,24 @@ import dataclasses
15
15
  import fnmatch
16
16
  import json
17
17
  import os
18
- import re
19
18
  import shutil
20
19
  import subprocess
21
20
  import sys
22
21
  import tempfile
23
22
  from pathlib import Path, PurePosixPath
24
23
 
25
- from .clang_backend import extract_clang_graph
26
- from .config import CpdocsConfig, load_config
27
- from .contract import (
28
- ContractError,
29
- FeatureSetDeclaration,
30
- FeatureSets,
31
- Manifest,
32
- UnitManifest,
33
- read_feature_sets,
34
- read_manifest,
35
- write_feature_set,
36
- )
37
- from .fortran_backend import extract_fortran_graph
38
- from .html_renderer import render_html_site
24
+ from .config import CpdocsConfig
25
+ from .contract import ContractError, UnitManifest
26
+ from .languages import rendering_for
27
+ from .languages.cpp.extract import extract_clang_graph
28
+ from .languages.fortran.extract import extract_fortran_graph
29
+ from .languages.python.extract import build_python_graph
30
+ from .languages.rust.extract import build_rust_graph
39
31
  from .model import ApiGraph, merge_graphs, relative_source_path
40
- from .python_backend import build_python_graph
41
- from .rust_backend import build_rust_graph
32
+ from .providers.contract import discover_feature_sets, resolve_manifest
33
+ from .rendering.html import render_html_site
42
34
  from .versioning import SelectedRef, current_branch, select_refs
43
35
 
44
- _PLACEHOLDER = re.compile(r"\{\{([a-z][a-z0-9-]*)\}\}")
45
- _CONTAINER_KINDS = {"namespace", "package", "module"}
46
-
47
36
 
48
37
  @dataclasses.dataclass(frozen=True)
49
38
  class Layout:
@@ -71,113 +60,6 @@ class Layout:
71
60
 
72
61
 
73
62
 
74
- # --------------------------------------------------------------------------------------------------
75
- # Talking to the build system
76
- # --------------------------------------------------------------------------------------------------
77
-
78
-
79
- def _expand(command: str, values: dict[str, str], *, allowed: set[str], name: str) -> str:
80
- placeholders = set(_PLACEHOLDER.findall(command))
81
- unknown = sorted(placeholders - allowed)
82
- if unknown:
83
- raise RuntimeError(
84
- f"cpdocs.yml: build.{name} uses unknown placeholders: {', '.join(unknown)}"
85
- )
86
- return _PLACEHOLDER.sub(lambda match: values[match.group(1)], command)
87
-
88
-
89
- def _run_command(
90
- command: str,
91
- *,
92
- source: Path,
93
- values: dict[str, str],
94
- allowed: set[str],
95
- name: str,
96
- log: Path,
97
- ) -> None:
98
- expanded = _expand(command, values, allowed=allowed, name=name)
99
- environment = dict(os.environ)
100
- # Commands invoked from a source checkout should be able to use cpdocs' own helper CLI just as
101
- # they can when cpdocs is installed. This is only an execution-environment convenience; the
102
- # build-system contract itself remains the JSON files and command placeholders.
103
- package_root = str(Path(__file__).resolve().parents[1])
104
- pythonpath = environment.get("PYTHONPATH")
105
- environment["PYTHONPATH"] = package_root + (os.pathsep + pythonpath if pythonpath else "")
106
- log.parent.mkdir(parents=True, exist_ok=True)
107
- with log.open("w", encoding="utf-8") as stream:
108
- stream.write("$ " + expanded + "\n")
109
- stream.flush()
110
- result = subprocess.run(
111
- expanded,
112
- cwd=source,
113
- shell=True,
114
- check=False,
115
- text=True,
116
- stdout=subprocess.PIPE,
117
- stderr=subprocess.STDOUT,
118
- env=environment,
119
- )
120
- stream.write(result.stdout)
121
- if result.returncode != 0:
122
- raise RuntimeError(
123
- f"build-system command failed (build.{name}):\n {expanded}\n\n"
124
- + result.stdout.rstrip()
125
- )
126
-
127
-
128
- def discover_feature_sets(command: str, *, source: Path, work: Path) -> FeatureSets:
129
- """Run ``build.feature-sets`` and read ``feature-sets.json``."""
130
-
131
- directory = work / "feature-sets"
132
- shutil.rmtree(directory, ignore_errors=True)
133
- tmpdir = directory / "tmp"
134
- tmpdir.mkdir(parents=True)
135
- output = directory / "feature-sets.json"
136
- _run_command(
137
- command,
138
- source=source.resolve(),
139
- values={
140
- "source": str(source.resolve()),
141
- "tmpdir": str(tmpdir.resolve()),
142
- "output-file": str(output.resolve()),
143
- "python": sys.executable,
144
- },
145
- allowed={"source", "tmpdir", "output-file", "python"},
146
- name="feature-sets",
147
- log=directory / "log.txt",
148
- )
149
- return read_feature_sets(output)
150
-
151
-
152
- def resolve_manifest(
153
- command: str, feature_set: FeatureSetDeclaration, *, source: Path, work: Path
154
- ) -> Manifest:
155
- """Run ``build.build`` once for one concrete feature set and read ``manifest.json``."""
156
-
157
- directory = work / "feature-sets" / feature_set.key
158
- shutil.rmtree(directory, ignore_errors=True)
159
- tmpdir = directory / "tmp"
160
- tmpdir.mkdir(parents=True)
161
- feature_set_file = directory / "feature-set.json"
162
- output = directory / "manifest.json"
163
- write_feature_set(feature_set_file, feature_set)
164
- _run_command(
165
- command,
166
- source=source.resolve(),
167
- values={
168
- "source": str(source.resolve()),
169
- "tmpdir": str(tmpdir.resolve()),
170
- "feature-set": str(feature_set_file.resolve()),
171
- "output-file": str(output.resolve()),
172
- "python": sys.executable,
173
- },
174
- allowed={"source", "tmpdir", "feature-set", "output-file", "python"},
175
- name="build",
176
- log=directory / "log.txt",
177
- )
178
- return read_manifest(output, source=source.resolve())
179
-
180
-
181
63
  # --------------------------------------------------------------------------------------------------
182
64
  # Extraction
183
65
  # --------------------------------------------------------------------------------------------------
@@ -441,7 +323,8 @@ def _check_undocumented(graph: ApiGraph, level: str) -> None:
441
323
  missing = sorted(
442
324
  entity.qualified_name
443
325
  for entity in graph.entities.values()
444
- if entity.kind not in _CONTAINER_KINDS and not entity.documentation.strip()
326
+ if entity.kind not in rendering_for(entity.language).container_kinds
327
+ and not entity.documentation.strip()
445
328
  )
446
329
  if not missing:
447
330
  return
@@ -764,7 +647,6 @@ __all__ = [
764
647
  "build_current",
765
648
  "build_graph",
766
649
  "build_versions",
767
- "cmake_module",
768
650
  "discover_feature_sets",
769
651
  "recorded_default_version",
770
652
  "resolve_manifest",
@@ -10,10 +10,10 @@ from pathlib import Path
10
10
  from . import __version__
11
11
  from .build import build_current, build_versions
12
12
  from .config import DEFAULT_CONFIG, load_config
13
- from .python_manifest import write_feature_sets as write_python_feature_sets
14
- from .python_manifest import write_manifest as write_python_manifest
15
- from .rust_manifest import write_feature_sets as write_rust_feature_sets
16
- from .rust_manifest import write_manifest as write_rust_manifest
13
+ from .providers.python import write_feature_sets as write_python_feature_sets
14
+ from .providers.python import write_manifest as write_python_manifest
15
+ from .providers.cargo import write_feature_sets as write_rust_feature_sets
16
+ from .providers.cargo import write_manifest as write_rust_manifest
17
17
 
18
18
 
19
19
  def _path(value: str) -> Path:
@@ -173,16 +173,16 @@ def read_manifest(path: Path, *, source: Path) -> Manifest:
173
173
  )
174
174
  )
175
175
 
176
- def paths(field: str) -> tuple[Path, ...]:
176
+ def paths(field: str, *, data: dict[str, Any], where: str) -> tuple[Path, ...]:
177
177
  return tuple(
178
178
  _path(item, source)
179
179
  for item in _string_tuple(data.get(field, []), f"{where}.{field}", path)
180
180
  )
181
181
 
182
- headers = paths("headers")
183
- sources = paths("sources")
184
- modules = paths("modules")
185
- executables = paths("executables")
182
+ headers = paths("headers", data=data, where=where)
183
+ sources = paths("sources", data=data, where=where)
184
+ modules = paths("modules", data=data, where=where)
185
+ executables = paths("executables", data=data, where=where)
186
186
  generated = bool(data.get("generated", False))
187
187
 
188
188
  parse: ParseOptions | None = None
@@ -0,0 +1,138 @@
1
+ # SPDX-FileCopyrightText: 2026 cpdocs developers
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """Programming-language adapters for extraction and presentation."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from pathlib import Path
8
+
9
+ from .base import LanguageRendering
10
+ from .cpp.render import RENDERING as CPP
11
+ from .fortran.render import RENDERING as FORTRAN
12
+ from .python.render import RENDERING as PYTHON
13
+ from .rust.render import RENDERING as RUST
14
+
15
+ _RENDERINGS = {
16
+ "c": CPP,
17
+ "cpp": CPP,
18
+ "cuda": CPP,
19
+ "hip": CPP,
20
+ "fortran": FORTRAN,
21
+ "python": PYTHON,
22
+ "rust": RUST,
23
+ }
24
+
25
+ _LANGUAGE_LABELS = {
26
+ "c": "C",
27
+ "cpp": "C++",
28
+ "cuda": "CUDA",
29
+ "hip": "HIP",
30
+ "fortran": "Fortran",
31
+ "python": "Python",
32
+ "rust": "Rust",
33
+ }
34
+
35
+ _KIND_LABELS = {
36
+ "namespace": "namespace",
37
+ "module": "module",
38
+ "package": "package",
39
+ "class": "class",
40
+ "struct": "struct",
41
+ "derived_type": "derived type",
42
+ "union": "union",
43
+ "enum": "enum",
44
+ "trait": "trait",
45
+ "protocol": "protocol",
46
+ "type_alias": "type alias",
47
+ "concept": "concept",
48
+ "function": "function",
49
+ "subroutine": "subroutine",
50
+ "method": "method",
51
+ "constructor": "constructor",
52
+ "property": "property",
53
+ "attribute": "attribute",
54
+ "variable": "variable",
55
+ "constant": "constant",
56
+ "macro": "macro",
57
+ "deduction_guide": "deduction guide",
58
+ }
59
+
60
+ _KIND_MARKERS = {
61
+ "namespace": "N",
62
+ "module": "M",
63
+ "package": "P",
64
+ "class": "C",
65
+ "struct": "S",
66
+ "derived_type": "T",
67
+ "union": "U",
68
+ "enum": "E",
69
+ "trait": "T",
70
+ "protocol": "P",
71
+ "function": "F",
72
+ "subroutine": "F",
73
+ "method": "F",
74
+ "constructor": "F",
75
+ "type_alias": "T",
76
+ "variable": "V",
77
+ "attribute": "A",
78
+ "property": "P",
79
+ "constant": "C",
80
+ "macro": "D",
81
+ "concept": "K",
82
+ "deduction_guide": "G",
83
+ }
84
+
85
+
86
+ def rendering_for(language: str) -> LanguageRendering:
87
+ """Return rendering semantics for one programming language."""
88
+
89
+ try:
90
+ return _RENDERINGS[language]
91
+ except KeyError as error:
92
+ raise ValueError(f"unsupported API language: {language}") from error
93
+
94
+
95
+ def language_label(language: str) -> str:
96
+ return _LANGUAGE_LABELS.get(language, language)
97
+
98
+
99
+ def kind_label(kind: str, language: str | None = None) -> str:
100
+ if language in _RENDERINGS:
101
+ specific = _RENDERINGS[language].kind_labels.get(kind)
102
+ if specific is not None:
103
+ return specific
104
+ return _KIND_LABELS.get(kind, kind.replace("_", " "))
105
+
106
+
107
+ def kind_marker(kind: str, language: str | None = None) -> str:
108
+ if language in _RENDERINGS:
109
+ specific = _RENDERINGS[language].kind_markers.get(kind)
110
+ if specific is not None:
111
+ return specific
112
+ return _KIND_MARKERS.get(kind, "·")
113
+
114
+
115
+ def source_language(path: str) -> str:
116
+ suffix = Path(path).suffix.casefold()
117
+ if suffix in {".cu", ".cuh"}:
118
+ return "cuda"
119
+ if suffix == ".hip":
120
+ return "hip"
121
+ if suffix in {".c"}:
122
+ return "c"
123
+ if suffix in {".h", ".hh", ".hpp", ".hxx", ".cc", ".cpp", ".cxx"}:
124
+ return "cpp"
125
+ for language in ("fortran", "python", "rust"):
126
+ if suffix in _RENDERINGS[language].source_suffixes:
127
+ return language
128
+ return "text"
129
+
130
+
131
+ __all__ = [
132
+ "LanguageRendering",
133
+ "kind_label",
134
+ "kind_marker",
135
+ "language_label",
136
+ "rendering_for",
137
+ "source_language",
138
+ ]
@@ -0,0 +1,63 @@
1
+ # SPDX-FileCopyrightText: 2026 cpdocs developers
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """Language-specific presentation contract used by generic renderers."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from collections.abc import Callable
8
+ from dataclasses import dataclass
9
+
10
+ from ..model import ApiEntity, ApiSignature
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class LanguageRendering:
15
+ """Rendering rules that belong to a programming language, not to HTML."""
16
+
17
+ separator: str
18
+ container_kinds: frozenset[str]
19
+ class_like_kinds: frozenset[str]
20
+ type_page_kinds: frozenset[str]
21
+ type_like_kinds: frozenset[str]
22
+ function_kinds: frozenset[str]
23
+ member_value_kinds: frozenset[str]
24
+ source_suffixes: frozenset[str]
25
+ kind_markers: dict[str, str]
26
+ kind_labels: dict[str, str]
27
+ signature_spelling: Callable[[ApiEntity, ApiSignature], str]
28
+ entity_declaration: Callable[[ApiEntity], str]
29
+ member_summary: Callable[[ApiEntity], str]
30
+ member_group: Callable[[ApiEntity], str | None]
31
+
32
+
33
+ def parameter_spelling(signature: ApiSignature) -> str:
34
+ """Render conventional typed parameters used by C-family, Fortran and Rust APIs."""
35
+
36
+ values: list[str] = []
37
+ for parameter in signature.parameters:
38
+ value = parameter.type or parameter.name
39
+ if parameter.name and parameter.type:
40
+ value += f" {parameter.name}"
41
+ if parameter.default is not None:
42
+ value += f" = {parameter.default}"
43
+ values.append(value)
44
+ return ", ".join(values)
45
+
46
+
47
+ def assigned_property(entity: ApiEntity) -> str:
48
+ """Return an ``= value`` property without its marker."""
49
+
50
+ return next((value[2:] for value in entity.properties if value.startswith("= ")), "")
51
+
52
+
53
+ def typed_property(entity: ApiEntity, *, ignored: frozenset[str] = frozenset()) -> str:
54
+ """Return the first property that represents a type rather than an assignment/flag."""
55
+
56
+ return next(
57
+ (
58
+ value
59
+ for value in entity.properties
60
+ if not value.startswith("=") and value not in ignored
61
+ ),
62
+ "",
63
+ )
@@ -0,0 +1,8 @@
1
+ # SPDX-FileCopyrightText: 2026 cpdocs developers
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """C-family extraction and rendering."""
4
+
5
+ from .extract import extract_clang_graph
6
+ from .render import RENDERING
7
+
8
+ __all__ = ["RENDERING", "extract_clang_graph"]
@@ -19,8 +19,8 @@ from dataclasses import replace
19
19
  from functools import lru_cache
20
20
  from pathlib import Path
21
21
 
22
- from .contract import ParseOptions
23
- from .model import (
22
+ from ...contract import ParseOptions
23
+ from ...model import (
24
24
  ApiAttribute,
25
25
  ApiEntity,
26
26
  ApiGraph,
@@ -0,0 +1,125 @@
1
+ # SPDX-FileCopyrightText: 2026 cpdocs developers
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """C-family presentation rules for C, C++, CUDA and HIP."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from ...model import ApiEntity, ApiSignature
8
+ from ..base import (
9
+ LanguageRendering,
10
+ assigned_property,
11
+ parameter_spelling,
12
+ typed_property,
13
+ )
14
+
15
+
16
+ def entity_declaration(entity: ApiEntity) -> str:
17
+ if entity.declaration:
18
+ return entity.declaration
19
+ if entity.kind == "namespace":
20
+ value = f"namespace {entity.qualified_name}"
21
+ elif entity.kind in {"class", "struct", "union"}:
22
+ bases = f" : {', '.join(entity.bases)}" if entity.bases else ""
23
+ value = f"{entity.kind} {entity.qualified_name}{bases}"
24
+ elif entity.kind == "enum":
25
+ scoped = " class" if "scoped" in entity.properties else ""
26
+ value = f"enum{scoped} {entity.qualified_name}"
27
+ elif entity.kind == "type_alias":
28
+ value = f"using {entity.qualified_name} = {assigned_property(entity)}".rstrip()
29
+ elif entity.kind in {"attribute", "variable", "constant"}:
30
+ type_name = typed_property(entity)
31
+ assigned = assigned_property(entity)
32
+ value = f"{type_name} {entity.qualified_name}".strip()
33
+ if assigned:
34
+ value += f" = {assigned}"
35
+ elif entity.kind == "concept":
36
+ value = f"concept {entity.qualified_name}"
37
+ elif entity.kind == "macro" and entity.signatures:
38
+ value = entity.signatures[0].spelling or entity.name
39
+ else:
40
+ value = entity.qualified_name
41
+ return f"{entity.template}\n{value}" if entity.template else value
42
+
43
+
44
+ def signature_spelling(entity: ApiEntity, signature: ApiSignature) -> str:
45
+ attribute_spellings = list(
46
+ dict.fromkeys(attribute.spelling for attribute in signature.attributes if attribute.spelling)
47
+ )
48
+ attribute_prefix = " ".join(attribute_spellings)
49
+ if signature.spelling:
50
+ return f"{attribute_prefix} {signature.spelling}".strip()
51
+
52
+ parameters = parameter_spelling(signature)
53
+ prefix_values = [
54
+ value
55
+ for value in entity.properties
56
+ if value in {"inline", "constexpr", "consteval", "static", "virtual"}
57
+ ]
58
+ prefix = (" ".join(prefix_values) + " ") if prefix_values else ""
59
+ result = (signature.returns + " ") if signature.returns else ""
60
+ suffix_values = [value for value in signature.qualifiers if value not in prefix_values]
61
+ suffix = (" " + " ".join(suffix_values)) if suffix_values else ""
62
+ declaration = f"{prefix}{result}{entity.qualified_name}({parameters}){suffix}".strip()
63
+ return f"{attribute_prefix} {declaration}".strip()
64
+
65
+
66
+ def member_summary(entity: ApiEntity) -> str:
67
+ if entity.kind in {"attribute", "variable", "constant"}:
68
+ type_name = typed_property(entity)
69
+ assigned = assigned_property(entity)
70
+ value = f"{type_name} {entity.name}".strip()
71
+ return value + (f" = {assigned}" if assigned else "")
72
+ if entity.kind == "type_alias":
73
+ value = f"using {entity.name} = {assigned_property(entity)}".rstrip()
74
+ return f"{entity.template}\n{value}" if entity.template else value
75
+ if entity.kind in {"class", "struct", "union", "enum"}:
76
+ return f"{entity.kind} {entity.name}"
77
+ return entity.name
78
+
79
+
80
+ def member_group(entity: ApiEntity) -> str | None:
81
+ if entity.kind in {"class", "struct", "union", "enum", "type_alias", "concept"}:
82
+ return "Public Types"
83
+ if entity.kind == "deduction_guide":
84
+ return "Deduction Guides"
85
+ if entity.kind in {"function", "method", "constructor"}:
86
+ return "Public Functions"
87
+ if entity.kind in {"attribute", "variable", "constant"}:
88
+ return "Public Members"
89
+ return None
90
+
91
+
92
+ RENDERING = LanguageRendering(
93
+ separator="::",
94
+ container_kinds=frozenset({"namespace"}),
95
+ class_like_kinds=frozenset({"class", "struct", "union"}),
96
+ type_page_kinds=frozenset({"class", "struct", "union", "enum"}),
97
+ type_like_kinds=frozenset({"class", "struct", "union", "enum", "type_alias", "concept"}),
98
+ function_kinds=frozenset({"function", "method", "constructor", "deduction_guide"}),
99
+ member_value_kinds=frozenset({"attribute", "variable", "constant"}),
100
+ source_suffixes=frozenset(
101
+ {".h", ".hh", ".hpp", ".hxx", ".c", ".cc", ".cpp", ".cxx", ".cu", ".cuh", ".hip"}
102
+ ),
103
+ kind_markers={
104
+ "namespace": "N",
105
+ "class": "C",
106
+ "struct": "S",
107
+ "union": "U",
108
+ "enum": "E",
109
+ "function": "F",
110
+ "method": "F",
111
+ "constructor": "F",
112
+ "type_alias": "T",
113
+ "variable": "V",
114
+ "attribute": "A",
115
+ "constant": "C",
116
+ "macro": "D",
117
+ "concept": "K",
118
+ "deduction_guide": "G",
119
+ },
120
+ kind_labels={"deduction_guide": "deduction guide", "type_alias": "type alias"},
121
+ signature_spelling=signature_spelling,
122
+ entity_declaration=entity_declaration,
123
+ member_summary=member_summary,
124
+ member_group=member_group,
125
+ )
@@ -0,0 +1,8 @@
1
+ # SPDX-FileCopyrightText: 2026 cpdocs developers
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """Fortran extraction and rendering."""
4
+
5
+ from .extract import extract_fortran_graph
6
+ from .render import RENDERING
7
+
8
+ __all__ = ["RENDERING", "extract_fortran_graph"]
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
  import re
13
13
  from pathlib import Path
14
14
 
15
- from .model import (
15
+ from ...model import (
16
16
  ApiEntity,
17
17
  ApiGraph,
18
18
  ApiParameter,