diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4230068..e854e95 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -39,6 +39,10 @@ jobs: with: python-version: ${{ matrix.python-version }} uv-dependency-install-flags: "--all-extras --group docs" + - name: Install Graphviz + run: | + sudo apt-get update + sudo apt-get install -y graphviz - name: docs run: | uv run --no-sync mkdocs build --strict diff --git a/.gitignore b/.gitignore index 1f87080..6722197 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ docs/fgen/api/* !docs/fgen/api/.gitkeep docs/fgen-runtime/api/* !docs/fgen-runtime/api/.gitkeep +docs/fortran-api/* +!docs/fortran-api/.gitkeep # Databases *.db diff --git a/changelog/16.docs.md b/changelog/16.docs.md new file mode 100644 index 0000000..6611726 --- /dev/null +++ b/changelog/16.docs.md @@ -0,0 +1 @@ +Added documentation of the Fortran back-end/API using [ford](https://forddocs.readthedocs.io/en/stable/) diff --git a/docs/NAVIGATION.md b/docs/NAVIGATION.md index 46f9460..fb48646 100644 --- a/docs/NAVIGATION.md +++ b/docs/NAVIGATION.md @@ -13,4 +13,5 @@ See https://oprypin.github.io/mkdocs-literate-nav/ - [Dependency pinning and testing](further-background/dependency-pinning-and-testing.md) - [Development](development.md) - [API reference](api/example_fgen_basic/) +- [Fortran API](fortran-api/home.html) - [Changelog](changelog.md) diff --git a/docs/development.md b/docs/development.md index 832dfe1..65472c8 100644 --- a/docs/development.md +++ b/docs/development.md @@ -31,6 +31,35 @@ Try and keep your merge requests as small as possible This makes life much easier for reviewers which allows contributions to be accepted at a faster rate. +## Using uv with a compiled package + +Using uv with a compiled package is a bit more painful. +Whenever you do `uv run` or `uv sync` or similar, +uv tries to install the compiled package as an editable package. +This can then cause issues on later calls to `uv run` or `uv sync` +as having compiled packages as editable packages doesn't really work +(you get errors like +`ImportError: re-building the meson-python editable wheel package failed`). +The way around this is to: + +1. use the `--no-editable` flag with `uv sync` + so that uv doesn't do an editable install +1. use the `--no-sync` flag with `uv run` + (and any other command that takes this flag) + so that `uv` doesn't try and re-build packages +1. use the `--reinstall-package` flag with `uv run` + whenever you want to be sure that the latest changes + will be used for running a command + (yes, this makes running things slower, + but slower and reliable is better than broken) + +We include these flags in our `Makefile` and GitHub workflows +if you want to see them in use. + +If you forget and run `uv run ...` in your terminal. +The easiest solution seems to be to delete your virtual environment entirely and start again. +We haven't found a way to get out of an accidental editable install. + ## Language We use British English for our development. diff --git a/docs/fortran-api/.gitkeep b/docs/fortran-api/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/gen_fortran_api.py b/docs/gen_fortran_api.py new file mode 100644 index 0000000..2fadef0 --- /dev/null +++ b/docs/gen_fortran_api.py @@ -0,0 +1,63 @@ +""" +Drive Ford to create Fortran API docs +""" + +from __future__ import annotations + +import shutil +import subprocess +from pathlib import Path + +import mkdocs_gen_files + +REPO_ROOT = Path(__file__).parents[1] + +FORD_OUTPUT_DIR = Path("docs") / "fortran-api" + +ford = shutil.which("ford") +if ford is None: + msg = "Could not find FORD executable" + raise AssertionError(msg) + +subprocess.run( # noqa: S603 + [ford, "ford_config.md", "--output_dir", str(FORD_OUTPUT_DIR)], + check=True, +) + +# Copy files across using mkdocs_gen_files +# so it knows to include the files in the final docs. +for entry in (REPO_ROOT / FORD_OUTPUT_DIR).rglob("*"): + if not entry.is_file(): + continue + + with open(entry, "rb") as fh: + contents = fh.read() + + target_file = entry.relative_to(REPO_ROOT / "docs") + with mkdocs_gen_files.open(target_file, "wb") as fh: + fh.write(contents) + + if target_file.name == "index.html": + # Also create a home.html file which we can point to from `NAVIGATION.md`. + # I don't know why just pointing to `index.html` doesn't work, + # but it doesn't (maybe cause `index.html` is a special name?). + target_file = target_file.parent / "home.html" + + with mkdocs_gen_files.open(target_file, "wb") as fh: + fh.write(contents) + +# # If we want to move back to using literate-nav for maanging our navigation, +# # also for the Fortran bits, we'll need something like the below +# # and adjustments to the existing `NAVIGATION.md`. +# with mkdocs_gen_files.open( +# (FORD_OUTPUT_DIR).relative_to("docs") / "NAVIGATION.md", "w" +# ) as fh: +# fh.writelines("* [example_fgen_basic](home.html)") + +# Remove the ford files (which were just copied) +shutil.rmtree(REPO_ROOT / FORD_OUTPUT_DIR) + +# Put back the gitkeep file +gitkeep = REPO_ROOT / FORD_OUTPUT_DIR / ".gitkeep" +gitkeep.parent.mkdir() +gitkeep.touch() diff --git a/docs/index.md b/docs/index.md index 1fe13ca..e26f209 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1 +1,10 @@ ---8<--- "README.md:description" + +## API docs + +Our Python API is documented in [API][example_fgen_basic_1]. +The Fortran API is documented in [Fortran API](./fortran-api/). +At present, the Fortran API docs are a sub-website so you can navigate to them +but there are no buttons to navigate back to the main docs page +(so you have to instead return yourself by re-entering the URL +or pressing back, sorry, we hope to improve this in future). diff --git a/environment-docs-conda-base.yml b/environment-docs-conda-base.yml index 0d2d79b..8cc26e0 100644 --- a/environment-docs-conda-base.yml +++ b/environment-docs-conda-base.yml @@ -9,3 +9,4 @@ dependencies: - pip - gcc - gfortran + - graphviz diff --git a/ford_config.md b/ford_config.md new file mode 100644 index 0000000..92adf44 --- /dev/null +++ b/ford_config.md @@ -0,0 +1,8 @@ +--- +project: Example fgen - basic +author: TODO align this with pyproject.toml +src_dir: src +graph: true +--- + +API docs for Fortran components! diff --git a/mkdocs.yml b/mkdocs.yml index d7d5c78..7c7421d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,7 @@ plugins: - gen-files: scripts: - docs/gen_doc_stubs.py + - docs/gen_fortran_api.py # Make the navigation easier to handle/auto-generate if we wish # https://oprypin.github.io/mkdocs-literate-nav/ - literate-nav: @@ -56,7 +57,7 @@ plugins: allow_errors: false # theme: dark include_source: True - ignore: ["*.ipynb", "*.md", "docs/gen_doc_stubs.py"] + ignore: ["*.ipynb", "*.md", "docs/gen_doc_stubs.py", "docs/gen_fortran_api.py"] remove_tag_config: remove_input_tags: - remove_input diff --git a/pyproject.toml b/pyproject.toml index ac8fd09..0246127 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,6 +77,8 @@ docs = [ # Key dependencies # ---------------- "attrs>=25.3.0", + "ford>=6.0.1", + "graphviz>=0.21", "mkdocs-autorefs>=1.4.2", "mkdocs-gen-files>=0.5.0", "mkdocs-literate-nav>=0.6.2", diff --git a/requirements-docs-locked.txt b/requirements-docs-locked.txt index b3ea620..1eb5ec2 100644 --- a/requirements-docs-locked.txt +++ b/requirements-docs-locked.txt @@ -29,8 +29,10 @@ exceptiongroup==1.3.0 ; python_full_version < '3.11' executing==2.1.0 fastjsonschema==2.21.1 fonttools==4.59.0 +ford==6.1.13 fqdn==1.5.1 ghp-import==2.1.0 +graphviz==0.21 griffe==1.11.0 h11==0.14.0 httpcore==1.0.7 @@ -63,6 +65,7 @@ jupytext==1.17.2 kiwisolver==1.4.7 ; python_full_version < '3.10' kiwisolver==1.4.9 ; python_full_version >= '3.10' markdown==3.7 +markdown-include==0.8.1 markdown-it-py==3.0.0 markupsafe==3.0.2 matplotlib==3.9.4 ; python_full_version < '3.10' @@ -112,6 +115,7 @@ pymdown-extensions==10.16.1 pyparsing==3.2.3 python-dateutil==2.9.0.post0 python-json-logger==3.2.1 +python-markdown-math==0.9 pywin32==308 ; platform_python_implementation != 'PyPy' and sys_platform == 'win32' pywinpty==2.0.14 ; os_name == 'nt' pyyaml==6.0.2 @@ -132,7 +136,9 @@ stack-data==0.6.3 terminado==0.18.1 tinycss2==1.4.0 tomli==2.2.1 ; python_full_version < '3.11' +toposort==1.10 tornado==6.4.2 +tqdm==4.67.1 traitlets==5.14.3 types-python-dateutil==2.9.0.20241206 typing-extensions==4.12.2 diff --git a/uv.lock b/uv.lock index 15d032b..4d6a544 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.9" resolution-markers = [ "python_full_version >= '3.13' and sys_platform == 'win32'", @@ -764,7 +764,9 @@ plots = [ [package.dev-dependencies] all-dev = [ { name = "attrs" }, + { name = "ford" }, { name = "fprettify" }, + { name = "graphviz" }, { name = "jupyterlab" }, { name = "jupytext" }, { name = "liccheck" }, @@ -806,6 +808,8 @@ dev = [ ] docs = [ { name = "attrs" }, + { name = "ford" }, + { name = "graphviz" }, { name = "jupyterlab" }, { name = "jupytext" }, { name = "mkdocs" }, @@ -845,7 +849,9 @@ provides-extras = ["plots", "full"] [package.metadata.requires-dev] all-dev = [ { name = "attrs", specifier = ">=25.3.0" }, + { name = "ford", specifier = ">=6.0.1" }, { name = "fprettify", specifier = ">=0.3.7" }, + { name = "graphviz", specifier = ">=0.21" }, { name = "jupyterlab", specifier = ">=4.4.5" }, { name = "jupytext", specifier = ">=1.17.2" }, { name = "liccheck", specifier = ">=0.9.2" }, @@ -887,6 +893,8 @@ dev = [ ] docs = [ { name = "attrs", specifier = ">=25.3.0" }, + { name = "ford", specifier = ">=6.0.1" }, + { name = "graphviz", specifier = ">=0.21" }, { name = "jupyterlab", specifier = ">=4.4.5" }, { name = "jupytext", specifier = ">=1.17.2" }, { name = "mkdocs", specifier = ">=1.6.1" }, @@ -1020,6 +1028,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/9c/df0ef2c51845a13043e5088f7bb988ca6cd5bb82d5d4203d6a158aa58cf2/fonttools-4.59.0-py3-none-any.whl", hash = "sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d", size = 1128050, upload-time = "2025-07-16T12:04:52.687Z" }, ] +[[package]] +name = "ford" +version = "6.1.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "graphviz" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markdown-include" }, + { name = "pygments" }, + { name = "python-markdown-math" }, + { name = "toposort" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/80/a8750198772c8647aa2c8d1459d5d8dbedd317a2ba18fdad73802073e1d5/FORD-6.1.13.tar.gz", hash = "sha256:95b743ea25c5a9c6a9e13db3633e04f91e11d1debb69f48ca3ef7fefc51f0559", size = 5849087, upload-time = "2022-07-01T15:19:31.983Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/49/00fb42b10bcb6b241f3c29248afa55000554aa05fb67588a4f2616361953/FORD-6.1.13-py3-none-any.whl", hash = "sha256:701ecd4b8744714a50cd31a8b49a95a85d647716b9d971a60ab1b58c53032048", size = 666132, upload-time = "2022-07-01T15:19:29.65Z" }, +] + [[package]] name = "fprettify" version = "0.3.7" @@ -1053,6 +1081,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, ] +[[package]] +name = "graphviz" +version = "0.21" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload-time = "2025-06-15T09:35:05.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" }, +] + [[package]] name = "griffe" version = "1.11.0" @@ -1785,6 +1822,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349, upload-time = "2024-08-16T15:55:16.176Z" }, ] +[[package]] +name = "markdown-include" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/d8/66bf162fe6c1adb619f94a6da599323eecacf15b6d57469d0fd0421c10df/markdown-include-0.8.1.tar.gz", hash = "sha256:1d0623e0fc2757c38d35df53752768356162284259d259c486b4ab6285cdbbe3", size = 21873, upload-time = "2023-02-07T09:47:26.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/e2/c4d20b21a05fe0fee571649cebc05f7f72e80b1a743f932e7326125e6c9e/markdown_include-0.8.1-py3-none-any.whl", hash = "sha256:32f0635b9cfef46997b307e2430022852529f7a5b87c0075c504283e7cc7db53", size = 18837, upload-time = "2023-02-07T09:47:25.03Z" }, +] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -2976,6 +3025,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090", size = 14924, upload-time = "2024-12-16T06:48:03.25Z" }, ] +[[package]] +name = "python-markdown-math" +version = "0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/68/fbea05ec6fb318bdcf56ea47596605614554f51d77bfd14f6fb481139ad8/python_markdown_math-0.9.tar.gz", hash = "sha256:567395553dc4941e79b3789a1096dcabb3fda9539d150d558ef3507948b264a3", size = 8680, upload-time = "2025-04-10T10:10:31.84Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/68/ecf3535c40845de2efd8ac2d092dd5fca0868219fa3684d9e58ef7abeece/python_markdown_math-0.9-py3-none-any.whl", hash = "sha256:ac9932df517a5c0f6d01c56e7a44d065eca4a420893ac45f7a6937c67cb41e86", size = 6046, upload-time = "2025-04-10T10:10:30.318Z" }, +] + [[package]] name = "pywin32" version = "308" @@ -3523,6 +3584,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, ] +[[package]] +name = "toposort" +version = "1.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/19/8e955d90985ecbd3b9adb2a759753a6840da2dff3c569d412b2c9217678b/toposort-1.10.tar.gz", hash = "sha256:bfbb479c53d0a696ea7402601f4e693c97b0367837c8898bc6471adfca37a6bd", size = 11132, upload-time = "2023-02-27T13:59:51.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/17/57b444fd314d5e1593350b9a31d000e7411ba8e17ce12dc7ad54ca76b810/toposort-1.10-py3-none-any.whl", hash = "sha256:cbdbc0d0bee4d2695ab2ceec97fe0679e9c10eab4b2a87a9372b929e70563a87", size = 8500, upload-time = "2023-02-25T20:07:06.538Z" }, +] + [[package]] name = "tornado" version = "6.4.2" @@ -3557,6 +3627,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/93/1b/2f7b88506e22d9798c139261af4946865c0787cfa345514ca3c70173a9cc/towncrier-24.8.0-py3-none-any.whl", hash = "sha256:9343209592b839209cdf28c339ba45792fbfe9775b5f9c177462fd693e127d8d", size = 56981, upload-time = "2024-08-23T14:52:26.659Z" }, ] +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + [[package]] name = "traitlets" version = "5.14.3"