diff --git a/cookiecutter.json b/cookiecutter.json index 0a9db92..c700ccc 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -4,11 +4,12 @@ "project_description": "[Description for project.]", "author": "Jane Doe", "author_email": "jane_doe@imperial.ac.uk", + "use_bsd3_licence": false, "packaging": [ "poetry", "pip-tools" ], - "use_bsd3_licence": false, + "mkdocs": false, "add_precommit_workflows": true, "automerge_bot_prs": false, "use_windows_ci_runner": false, @@ -20,6 +21,7 @@ "author": "Enter your full name", "author_email": "Enter your email address", "packaging": "Select the Python packaging tool you wish to use", + "mkdocs": "Whether to provide a skeleton for documentation, using MkDocs and publishing on GitHub Pages", "use_bsd3_licence": "Whether to use Imperial's default open-source licence (BSD 3-clause)", "add_precommit_workflows": "Add Github Actions to run pre-commit hooks (only needed for private repositories)", "use_windows_ci_runner": "Add a GitHub Actions runner for Windows (needed if your software targets Windows)", diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 13dafad..5c80298 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,13 +1,17 @@ import os from glob import glob from itertools import chain +from shutil import rmtree REMOVE_PATHS = chain( ( "{% if not cookiecutter.use_bsd3_licence %}LICENSE{% endif %}", "{% if not cookiecutter.add_precommit_workflows %}.github/workflows/pre-commit*.yml{% endif %}", "{% if not cookiecutter.automerge_bot_prs %}.github/workflows/auto-merge.yml{% endif %}", - "{% if cookiecutter.packaging != 'pip-tools' %}*requirements.txt{% endif %}", + "{% if cookiecutter.packaging != 'pip-tools' %}requirements.txt{% endif %}", + "{% if cookiecutter.packaging != 'pip-tools' %}dev-requirements.txt{% endif %}", + "{% if cookiecutter.packaging != 'pip-tools' or not cookiecutter.mkdocs %}doc-requirements.txt{% endif %}", + "{% if not cookiecutter.mkdocs %}docs{% endif %}", ), glob("README.*.jinja"), ) @@ -15,8 +19,8 @@ for path in REMOVE_PATHS: path = path.strip() if path: - for file in glob(path): - if os.path.isfile(file): - os.unlink(file) + for inode in glob(path): + if os.path.isfile(inode): + os.unlink(inode) else: - os.rmdir(file) + rmtree(path) diff --git a/{{ cookiecutter.project_slug }}/doc-requirements.txt b/{{ cookiecutter.project_slug }}/doc-requirements.txt new file mode 100644 index 0000000..a79d81e --- /dev/null +++ b/{{ cookiecutter.project_slug }}/doc-requirements.txt @@ -0,0 +1,113 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --extra=doc --output-file=doc-requirements.txt pyproject.toml +# +babel==2.15.0 + # via mkdocs-material +certifi==2024.7.4 + # via requests +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # mkdocs + # mkdocstrings +colorama==0.4.6 + # via + # griffe + # mkdocs-material +ghp-import==2.1.0 + # via mkdocs +griffe==0.48.0 + # via mkdocstrings-python +idna==3.7 + # via requests +jinja2==3.1.4 + # via + # mkdocs + # mkdocs-material + # mkdocstrings +markdown==3.6 + # via + # mkdocs + # mkdocs-autorefs + # mkdocs-material + # mkdocstrings + # pymdown-extensions +markupsafe==2.1.5 + # via + # jinja2 + # mkdocs + # mkdocs-autorefs + # mkdocstrings +mergedeep==1.3.4 + # via + # mkdocs + # mkdocs-get-deps +mkdocs==1.6.0 + # via + # mkdocs-autorefs + # mkdocs-gen-files + # mkdocs-literate-nav + # mkdocs-material + # mkdocs-section-index + # mkdocstrings + # my_project (pyproject.toml) +mkdocs-autorefs==1.0.1 + # via mkdocstrings +mkdocs-gen-files==0.5.0 + # via my_project (pyproject.toml) +mkdocs-get-deps==0.2.0 + # via mkdocs +mkdocs-literate-nav==0.6.1 + # via my_project (pyproject.toml) +mkdocs-material==9.5.31 + # via my_project (pyproject.toml) +mkdocs-material-extensions==1.3.1 + # via mkdocs-material +mkdocs-section-index==0.3.9 + # via my_project (pyproject.toml) +mkdocstrings==0.25.2 + # via + # mkdocstrings-python + # my_project (pyproject.toml) +mkdocstrings-python==1.10.7 + # via my_project (pyproject.toml) +packaging==24.1 + # via mkdocs +paginate==0.5.6 + # via mkdocs-material +pathspec==0.12.1 + # via mkdocs +platformdirs==4.2.2 + # via + # mkdocs-get-deps + # mkdocstrings +pygments==2.18.0 + # via mkdocs-material +pymdown-extensions==10.9 + # via + # mkdocs-material + # mkdocstrings +python-dateutil==2.9.0.post0 + # via ghp-import +pyyaml==6.0.1 + # via + # mkdocs + # mkdocs-get-deps + # pymdown-extensions + # pyyaml-env-tag +pyyaml-env-tag==0.1 + # via mkdocs +regex==2024.7.24 + # via mkdocs-material +requests==2.32.3 + # via mkdocs-material +six==1.16.0 + # via python-dateutil +urllib3==2.2.2 + # via requests +watchdog==4.0.1 + # via mkdocs diff --git a/{{ cookiecutter.project_slug }}/docs/gen_ref_nav.py b/{{ cookiecutter.project_slug }}/docs/gen_ref_nav.py new file mode 100644 index 0000000..947aecf --- /dev/null +++ b/{{ cookiecutter.project_slug }}/docs/gen_ref_nav.py @@ -0,0 +1,32 @@ +"""Generate the code reference pages and navigation.""" + +from pathlib import Path + +import mkdocs_gen_files + +nav = mkdocs_gen_files.Nav() + +for path in sorted(Path("{{ cookiecutter.project_slug }}").glob("**/*.py")): + module_path = path.relative_to(".").with_suffix("") + doc_path = path.relative_to(".").with_suffix(".md") + full_doc_path = Path("reference", doc_path) + + parts = list(module_path.parts) + if ".array_cache" in parts: + continue + elif parts[-1] == "__init__": + parts = parts[:-1] + doc_path = doc_path.with_name("index.md") + full_doc_path = full_doc_path.with_name("index.md") + elif parts[-1] == "__main__": + continue + nav[parts] = doc_path + + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + ident = ".".join(parts) + print("::: " + ident, file=fd) + + mkdocs_gen_files.set_edit_path(full_doc_path, Path("../") / path) + +with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: + nav_file.writelines(nav.build_literate_nav()) diff --git a/{{ cookiecutter.project_slug }}/docs/index.md b/{{ cookiecutter.project_slug }}/docs/index.md new file mode 100644 index 0000000..62ae5c6 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/docs/index.md @@ -0,0 +1,2 @@ + +--8<-- "README.md" diff --git a/{{ cookiecutter.project_slug }}/docs/stylesheets/extra.css b/{{ cookiecutter.project_slug }}/docs/stylesheets/extra.css new file mode 100644 index 0000000..5e00d38 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/docs/stylesheets/extra.css @@ -0,0 +1,27 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); +} + +/* Mark external links as such. */ +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + background-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + position: relative; + top: 0.1em; + margin-left: 0.2em; + margin-right: 0.1em; + + height: 1em; + width: 1em; + border-radius: 100%; + background-color: var(--md-typeset-a-color); +} + +a.autorefs-external:hover::after { + background-color: var(--md-accent-fg-color); +} diff --git a/{{ cookiecutter.project_slug }}/mkdocs.yml b/{{ cookiecutter.project_slug }}/mkdocs.yml new file mode 100644 index 0000000..ee68581 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/mkdocs.yml @@ -0,0 +1,39 @@ +site_name: {{ cookiecutter.project_name }} +watch: [{{ cookiecutter.project_slug }}] + +theme: + name: material + +extra_css: + - stylesheets/extra.css + +markdown_extensions: + - admonition + - pymdownx.snippets: + check_paths: true + - toc: + permalink: ยค + +plugins: + - search + - gen-files: + scripts: + - docs/gen_ref_nav.py + - literate-nav: + nav_file: SUMMARY.md + - section-index + - mkdocstrings: + default_handler: python + handlers: + python: + options: + show_source: true + show_root_heading: true + show_category_heading: true + merge_init_into_class: true + paths: [{{ cookiecutter.project_slug }}] + +nav: + - {{ cookiecutter.project_name }} documentation: index.md + # defer to gen-files + literate-nav + - Code Reference: reference/ diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml index 0f6a8d9..cbff708 100644 --- a/{{ cookiecutter.project_slug }}/pyproject.toml +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -18,7 +18,16 @@ pytest-mypy = "^0.10.0" pytest-mock = "^3.7.0" pre-commit = "^3.0.4" ruff = "^0.4.4" - +{% if cookiecutter.mkdocs %} +[tool.poetry.group.docs.dependencies] +mkdocs = "^1.6.0" +mkdocstrings = "^0.25.1" +mkdocstrings-python = "^1.10.0" +mkdocs-material = "^9.5.25" +mkdocs-gen-files = "^0.5.0" +mkdocs-literate-nav = "^0.6.1" +mkdocs-section-index = "^0.3.9" +{% endif %} [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" @@ -43,9 +52,18 @@ dev = [ "pytest", "pytest-cov", "pytest-mypy", - "pytest-mock" + "pytest-mock", ] - +{% if cookiecutter.mkdocs %}doc = [ + "mkdocs", + "mkdocstrings", + "mkdocstrings-python", + "mkdocs-material", + "mkdocs-gen-files", + "mkdocs-literate-nav", + "mkdocs-section-index", +] +{% endif %} [build-system] requires = ["setuptools", "setuptools-scm"] build-backend = "setuptools.build_meta"