diff --git a/.copier-answers.yml b/.copier-answers.yml index eab94c2f..cd27ed0e 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: 0.4.4 +_commit: 0.7.0 _src_path: gh:pawamoy/copier-pdm author_email: pawamoy@pm.me author_fullname: "Timoth\xE9e Mazzucotelli" @@ -14,6 +14,6 @@ python_package_command_line_name: mkdocstrings-python python_package_distribution_name: mkdocstrings-python python_package_import_name: mkdocstrings repository_name: python -repository_namespace: pawamoy +repository_namespace: mkdocstrings repository_provider: github.com use_precommit: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dc5c7af..7cf7c656 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,15 +50,13 @@ jobs: run: pdm lock - name: Install dependencies - run: | - pdm install -G duty -G docs -G quality -G typing - pip install safety + run: pdm install -G duty -G docs -G quality -G typing -G security - name: Check if the documentation builds correctly run: pdm run duty check-docs - name: Check the code quality - run: pdm run duty check-code-quality + run: pdm run duty check-quality - name: Check if the code is correctly typed run: pdm run duty check-types @@ -75,10 +73,10 @@ jobs: - macos-latest - windows-latest python-version: - - "3.6" - - "3.7" - "3.8" - "3.9" + - "3.10" + - "3.11-dev" runs-on: ${{ matrix.os }} diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile new file mode 100644 index 00000000..33f285c2 --- /dev/null +++ b/.gitpod.dockerfile @@ -0,0 +1,7 @@ +FROM gitpod/workspace-full +USER gitpod +ENV PIP_USER=no +ENV PYTHON_VERSIONS= +RUN pip3 install pipx; \ + pipx install pdm; \ + pipx ensurepath diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..23a3c2b7 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,13 @@ +vscode: + extensions: + - ms-python.python + +image: + file: .gitpod.dockerfile + +ports: +- port: 8000 + onOpen: notify + +tasks: +- init: make setup diff --git a/CHANGELOG.md b/CHANGELOG.md index 49212ce3..5b44c751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [0.1.0](https://github.com/mkdocstrings/python/releases/tag/0.1.0) - 2021-12-19 + +[Compare with first commit](https://github.com/mkdocstrings/python/compare/0032f18c9f902c3e75e0e00114ca8fa6a810c8f5...0.1.0) + +### Features +- Implement handler and add templates ([dbb580a](https://github.com/mkdocstrings/python/commit/dbb580aa79f6b2f8a089c80bdc67d0f7457c2d30) by Timothée Mazzucotelli). + +### Bug Fixes +- Fix separate signature feature ([da6e81c](https://github.com/mkdocstrings/python/commit/da6e81c897899f09e1dae7bb8930ce6782aeb306) by Timothée Mazzucotelli). +- Fix signature template (parameters annotations) ([b34ead0](https://github.com/mkdocstrings/python/commit/b34ead008773880fd8d1d7a2a41768ec27820520) by Timothée Mazzucotelli). +- Only show source when present ([c270d68](https://github.com/mkdocstrings/python/commit/c270d68c9e17204606ae12a2159c04563a18ec2b) by Timothée Mazzucotelli). + +### Code Refactoring +- Return all known anchors ([9bbfe14](https://github.com/mkdocstrings/python/commit/9bbfe1442e2aab28bd6fb2618c943d3f698750ab) by Timothée Mazzucotelli). +- Update for griffe 0.4.0 ([831aabb](https://github.com/mkdocstrings/python/commit/831aabb135db7e75729954adc675af6379f58e24) by Timothée Mazzucotelli). diff --git a/Makefile b/Makefile index 97aa6931..58291575 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,14 @@ SHELL := bash DUTY = $(shell [ -n "${VIRTUAL_ENV}" ] || echo pdm run) duty args = $(foreach a,$($(subst -,_,$1)_args),$(if $(value $a),$a="$($a)")) -check_code_quality_args = files +check_quality_args = files docs_serve_args = host port release_args = version test_args = match BASIC_DUTIES = \ changelog \ + check-dependencies \ clean \ coverage \ docs \ @@ -21,9 +22,7 @@ BASIC_DUTIES = \ release QUALITY_DUTIES = \ - check \ - check-code-quality \ - check-dependencies \ + check-quality \ check-docs \ check-types \ test @@ -32,10 +31,19 @@ QUALITY_DUTIES = \ help: @$(DUTY) --list +.PHONY: lock +lock: + @pdm lock + .PHONY: setup setup: @bash scripts/setup.sh +.PHONY: check +check: + @bash scripts/multirun.sh duty check-quality check-types check-docs + @$(DUTY) check-dependencies + .PHONY: $(BASIC_DUTIES) $(BASIC_DUTIES): @$(DUTY) $@ $(call args,$@) diff --git a/README.md b/README.md index 891cf841..fc1eae9e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # Python for mkdocstrings -[![ci](https://github.com/pawamoy/python/workflows/ci/badge.svg)](https://github.com/pawamoy/python/actions?query=workflow%3Aci) -[![documentation](https://img.shields.io/badge/docs-mkdocs%20material-blue.svg?style=flat)](https://pawamoy.github.io/python/) +[![ci](https://github.com/mkdocstrings/python/workflows/ci/badge.svg)](https://github.com/mkdocstrings/python/actions?query=workflow%3Aci) +[![documentation](https://img.shields.io/badge/docs-mkdocs%20material-blue.svg?style=flat)](https://mkdocstrings.github.io/python/) [![pypi version](https://img.shields.io/pypi/v/python.svg)](https://pypi.org/project/python/) +[![gitpod](https://img.shields.io/badge/gitpod-workspace-blue.svg?style=flat)](https://gitpod.io/#https://github.com/mkdocstrings/python) [![gitter](https://badges.gitter.im/join%20chat.svg)](https://gitter.im/python/community) A Python handler for mkdocstrings. diff --git a/config/flake8.ini b/config/flake8.ini index aab3a995..4126bd51 100644 --- a/config/flake8.ini +++ b/config/flake8.ini @@ -10,6 +10,8 @@ ignore = D105 # multi-line docstring summary should start at the first line D212 + # does not support Parameters sections + D417 # whitespace before ':' (incompatible with Black) E203 # redundant with E0602 (undefined variable) @@ -100,5 +102,7 @@ ignore = WPS428 # redundant with C0415 (not top-level import) WPS433 + # multiline attribute docstring + WPS462 # implicit dict.get usage (generally false-positive) WPS529 diff --git a/config/mypy.ini b/config/mypy.ini index aa988d34..4ac80d76 100644 --- a/config/mypy.ini +++ b/config/mypy.ini @@ -1,6 +1,4 @@ [mypy] ignore_missing_imports = true exclude = tests/fixtures/ - -[mypy-toml.*] -ignore_missing_imports = true +warn_unused_ignores = true diff --git a/docs/gen_ref_nav.py b/docs/gen_ref_nav.py index 3a824137..cc54b86a 100644 --- a/docs/gen_ref_nav.py +++ b/docs/gen_ref_nav.py @@ -7,22 +7,27 @@ nav = mkdocs_gen_files.Nav() for path in sorted(Path("src").glob("**/*.py")): + # if str(path) in exclude: + # continue module_path = path.relative_to("src").with_suffix("") - doc_path = path.relative_to("src", "mkdocstrings").with_suffix(".md") + doc_path = path.relative_to("src").with_suffix(".md") full_doc_path = Path("reference", doc_path) parts = list(module_path.parts) - parts[-1] = f"{parts[-1]}.py" - nav[parts] = doc_path + if 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 = list(parts) + nav[nav_parts] = doc_path with mkdocs_gen_files.open(full_doc_path, "w") as fd: - ident = ".".join(module_path.parts) + ident = ".".join(parts) print("::: " + ident, file=fd) mkdocs_gen_files.set_edit_path(full_doc_path, path) -# add pages manually: -# nav["package", "module"] = "path/to/file.md" - with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: nav_file.writelines(nav.build_literate_nav()) diff --git a/docs/reference/cli.md b/docs/reference/cli.md deleted file mode 100644 index d5221ec5..00000000 --- a/docs/reference/cli.md +++ /dev/null @@ -1 +0,0 @@ -::: mkdocstrings.cli diff --git a/duties.py b/duties.py index ef43ad63..19c0f6bf 100644 --- a/duties.py +++ b/duties.py @@ -1,11 +1,14 @@ """Development tasks.""" +import importlib import os import re import sys +import tempfile +from contextlib import suppress from functools import wraps +from io import StringIO from pathlib import Path -from shutil import which from typing import List, Optional, Pattern from urllib.request import urlopen @@ -105,7 +108,7 @@ def changelog(ctx): ) -@duty(pre=["check_code_quality", "check_types", "check_docs", "check_dependencies"]) +@duty(pre=["check_quality", "check_types", "check_docs", "check_dependencies"]) def check(ctx): """ Check it all! @@ -116,7 +119,7 @@ def check(ctx): @duty -def check_code_quality(ctx, files=PY_SRC): +def check_quality(ctx, files=PY_SRC): """ Check the code quality. @@ -135,22 +138,36 @@ def check_dependencies(ctx): Arguments: ctx: The context instance (passed automatically). """ - nofail = False - safety = which("safety") - if not safety: - pipx = which("pipx") - if pipx: - safety = f"{pipx} run safety" - else: - safety = "safety" - nofail = True - ctx.run( - f"pdm export -f requirements --without-hashes | {safety} check --stdin --full-report", - title="Checking dependencies", - pty=PTY, - nofail=nofail, + # undo possible patching + # see https://github.com/pyupio/safety/issues/348 + for module in sys.modules: # noqa: WPS528 + if module.startswith("safety.") or module == "safety": + del sys.modules[module] # noqa: WPS420 + + importlib.invalidate_caches() + + # reload original, unpatched safety + from safety.formatter import report + from safety.safety import check as safety_check + from safety.util import read_requirements + + # retrieve the list of dependencies + requirements = ctx.run( + ["pdm", "export", "-f", "requirements", "--without-hashes"], + title="Exporting dependencies as requirements", + allow_overrides=False, ) + # check using safety as a library + def safety(): # noqa: WPS430 + packages = list(read_requirements(StringIO(requirements))) + vulns = safety_check(packages=packages, ignore_ids="", key="", db_mirror="", cached=False, proxy={}) + output_report = report(vulns=vulns, full=True, checked_packages=len(packages)) + if vulns: + print(output_report) + + ctx.run(safety, title="Checking dependencies") + def no_docs_py36(nofail=True): """ @@ -190,15 +207,57 @@ def check_docs(ctx): ctx.run("mkdocs build -s", title="Building documentation", pty=PTY) -@duty -def check_types(ctx): +@duty # noqa: WPS231 +def check_types(ctx): # noqa: WPS231 """ Check that the code is correctly typed. Arguments: ctx: The context instance (passed automatically). """ - ctx.run(f"mypy --config-file config/mypy.ini {PY_SRC}", title="Type-checking", pty=PTY) + # NOTE: the following code works around this issue: + # https://github.com/python/mypy/issues/10633 + + # compute packages directory path + py = f"{sys.version_info.major}.{sys.version_info.minor}" + pkgs_dir = Path("__pypackages__", py, "lib").resolve() + + # build the list of available packages + packages = {} + for package in pkgs_dir.glob("*"): + if package.suffix not in {".dist-info", ".pth"} and package.name != "__pycache__": + packages[package.name] = package + + # handle .pth files + for pth in pkgs_dir.glob("*.pth"): + with suppress(OSError): + for package in Path(pth.read_text().splitlines()[0]).glob("*"): # noqa: WPS440 + if package.suffix != ".dist-info": + packages[package.name] = package + + # create a temporary directory to assign to MYPYPATH + with tempfile.TemporaryDirectory() as tmpdir: + + # symlink the stubs + ignore = set() + for stubs in (path for name, path in packages.items() if name.endswith("-stubs")): # noqa: WPS335 + Path(tmpdir, stubs.name).symlink_to(stubs, target_is_directory=True) + # try to symlink the corresponding package + # see https://www.python.org/dev/peps/pep-0561/#stub-only-packages + pkg_name = stubs.name.replace("-stubs", "") + if pkg_name in packages: + ignore.add(pkg_name) + Path(tmpdir, pkg_name).symlink_to(packages[pkg_name], target_is_directory=True) + + # create temporary mypy config to ignore stubbed packages + newconfig = Path("config", "mypy.ini").read_text() + newconfig += "\n" + "\n\n".join(f"[mypy-{pkg}.*]\nignore_errors=true" for pkg in ignore) + tmpconfig = Path(tmpdir, "mypy.ini") + tmpconfig.write_text(newconfig) + + # set MYPYPATH and run mypy + os.environ["MYPYPATH"] = tmpdir + ctx.run(f"mypy --config-file {tmpconfig} {PY_SRC}", title="Type-checking", pty=PTY) @duty(silent=True) @@ -257,7 +316,11 @@ def docs_deploy(ctx): Arguments: ctx: The context instance (passed automatically). """ - ctx.run("mkdocs gh-deploy", title="Deploying documentation") + ctx.run( + "echo 'Not ready yet! It would override mkdocstrings.github.io/python!' && false", + title="Deploying documentation", + nofail=True, + ) @duty @@ -294,7 +357,7 @@ def release(ctx, version): ctx.run("git push --tags", title="Pushing tags", pty=False) ctx.run("pdm build", title="Building dist/wheel", pty=PTY) ctx.run("twine upload --skip-existing dist/*", title="Publishing version", pty=PTY) - docs_deploy.run() # type: ignore + docs_deploy.run() @duty(silent=True) diff --git a/mkdocs.yml b/mkdocs.yml index a7a174fc..1713313f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,8 +1,8 @@ site_name: "Python for mkdocstrings" site_description: "A Python handler for mkdocstrings." -site_url: "https://pawamoy.github.io/python" -repo_url: "https://github.com/pawamoy/python" -repo_name: "pawamoy/python" +site_url: "https://mkdocstrings.github.io/python" +repo_url: "https://github.com/mkdocstrings/python" +repo_name: "mkdocstrings/python" site_dir: "site" nav: diff --git a/pyproject.toml b/pyproject.toml index 43d5dfe1..9b73eb1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,80 +4,96 @@ build-backend = "pdm.pep517.api" [project] name = "mkdocstrings-python" -version = {use_scm = true} description = "A Python handler for mkdocstrings." authors = [{name = "Timothée Mazzucotelli", email = "pawamoy@pm.me"}] license = {file = "LICENSE"} readme = "README.md" -requires-python = ">=3.6" +requires-python = ">=3.8" keywords = [] -dynamic = ["version", "classifiers"] +dynamic = ["version"] classifiers = [ "Development Status :: 4 - Beta", + "Intended Audience :: Developers", "License :: OSI Approved :: ISC License (ISCL)", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Documentation", + "Topic :: Software Development", + "Topic :: Software Development :: Documentation", + "Topic :: Utilities", "Typing :: Typed", ] -dependencies = [] +dependencies = [ + "griffe~=0.4", +] [project.urls] -Homepage = "https://pawamoy.github.io/python" -Documentation = "https://pawamoy.github.io/python" -Changelog = "https://pawamoy.github.io/python/changelog" -Repository = "https://github.com/pawamoy/python" -Issues = "https://github.com/pawamoy/python/issues" -Discussions = "https://github.com/pawamoy/python/discussions" +Homepage = "https://mkdocstrings.github.io/python" +Documentation = "https://mkdocstrings.github.io/python" +Changelog = "https://mkdocstrings.github.io/python/changelog" +Repository = "https://github.com/mkdocstrings/python" +Issues = "https://github.com/mkdocstrings/python/issues" +Discussions = "https://github.com/mkdocstrings/python/discussions" Gitter = "https://gitter.im/python/community" -Funding = "https://github.com/sponsors/pawamoy" - -[project.scripts] -mkdocstrings-python = "mkdocstrings.cli:main" +Funding = "https://github.com/sponsors/mkdocstrings" [tool.pdm] -package-dir = "src" +version = {use_scm = true} +includes = ["src/mkdocstrings"] [tool.pdm.dev-dependencies] -duty = ["duty~=0.6"] +duty = ["duty~=0.7"] docs = [ - "mkdocs~=1.1; python_version >= '3.7'", - "mkdocs-coverage~=0.2; python_version >= '3.7'", - "mkdocs-gen-files~=0.3; python_version >= '3.7'", - "mkdocs-literate-nav~=0.4; python_version >= '3.7'", - "mkdocs-material~=7.1; python_version >= '3.7'", - "mkdocstrings~=0.15; python_version >= '3.7'", - "toml~=0.10; python_version >= '3.7'", + "mkdocs~=1.2", + "mkdocs-coverage~=0.2", + "mkdocs-gen-files~=0.3", + "mkdocs-literate-nav~=0.4", + "mkdocs-material~=8.0", + "mkdocstrings~=0.16", + "toml~=0.10", ] format = [ "autoflake~=1.4", - "black~=20.8b1", - "isort~=5.8", + "black~=21.10b0", + "isort~=5.10", ] maintain = [ # TODO: remove this section when git-changelog is more powerful "git-changelog~=0.4", ] quality = [ - "darglint~=1.7", + "darglint~=1.8", "flake8-bandit~=2.1", "flake8-black~=0.2", - "flake8-bugbear~=21.3", + "flake8-bugbear~=21.9", "flake8-builtins~=1.5", - "flake8-comprehensions~=3.4", + "flake8-comprehensions~=3.7", "flake8-docstrings~=1.6", - "flake8-pytest-style~=1.4", + "flake8-pytest-style~=1.5", "flake8-string-format~=0.3", - "flake8-tidy-imports~=4.2", + "flake8-tidy-imports~=4.5", "flake8-variables-names~=0.0", - "pep8-naming~=0.11", + "pep8-naming~=0.12", "wps-light~=0.15", ] tests = [ "pytest~=6.2", - "pytest-cov~=2.11", - "pytest-randomly~=3.6", + "pytest-cov~=3.0", + "pytest-randomly~=3.10", "pytest-sugar~=0.9", - "pytest-xdist~=2.2", + "pytest-xdist~=2.4", +] +typing = [ + "mypy~=0.910", + "types-markdown~=3.3", + "types-toml~=0.10", ] -typing = ["mypy~=0.812"] +security = ["safety~=1.10"] [tool.black] line-length = 120 diff --git a/scripts/multirun.sh b/scripts/multirun.sh index 7b5d9cf2..fb5fb2e5 100755 --- a/scripts/multirun.sh +++ b/scripts/multirun.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -PYTHON_VERSIONS="${PYTHON_VERSIONS-3.6 3.7 3.8 3.9 3.10 3.11}" +PYTHON_VERSIONS="${PYTHON_VERSIONS-3.8 3.9 3.10 3.11}" if [ -n "${PYTHON_VERSIONS}" ]; then for python_version in ${PYTHON_VERSIONS}; do diff --git a/scripts/setup.sh b/scripts/setup.sh index c5df7b4c..19227388 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -PYTHON_VERSIONS="${PYTHON_VERSIONS-3.6 3.7 3.8 3.9 3.10 3.11}" +PYTHON_VERSIONS="${PYTHON_VERSIONS-3.8 3.9 3.10 3.11}" install_with_pipx() { if ! command -v "$1" &>/dev/null; then diff --git a/src/mkdocstrings/__init__.py b/src/mkdocstrings/__init__.py deleted file mode 100644 index 1e1fb619..00000000 --- a/src/mkdocstrings/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Python for mkdocstrings package. - -A Python handler for mkdocstrings. -""" - -from typing import List - -__all__: List[str] = [] # noqa: WPS410 (the only __variable__ we use) diff --git a/src/mkdocstrings/__main__.py b/src/mkdocstrings/__main__.py deleted file mode 100644 index 53c0db45..00000000 --- a/src/mkdocstrings/__main__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Entry-point module, in case you use `python -m mkdocstrings`. - -Why does this file exist, and why `__main__`? For more info, read: - -- https://www.python.org/dev/peps/pep-0338/ -- https://docs.python.org/3/using/cmdline.html#cmdoption-m -""" - -import sys - -from mkdocstrings.cli import main - -if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) diff --git a/src/mkdocstrings/cli.py b/src/mkdocstrings/cli.py deleted file mode 100644 index d4089fb2..00000000 --- a/src/mkdocstrings/cli.py +++ /dev/null @@ -1,43 +0,0 @@ -# Why does this file exist, and why not put this in `__main__`? -# -# You might be tempted to import things from `__main__` later, -# but that will cause problems: the code will get executed twice: -# -# - When you run `python -m mkdocstrings` python will execute -# `__main__.py` as a script. That means there won't be any -# `mkdocstrings.__main__` in `sys.modules`. -# - When you import `__main__` it will get executed again (as a module) because -# there's no `mkdocstrings.__main__` in `sys.modules`. - -"""Module that contains the command line application.""" - -import argparse -from typing import List, Optional - - -def get_parser() -> argparse.ArgumentParser: - """ - Return the CLI argument parser. - - Returns: - An argparse parser. - """ - return argparse.ArgumentParser(prog="mkdocstrings-python") - - -def main(args: Optional[List[str]] = None) -> int: - """ - Run the main program. - - This function is executed when you type `mkdocstrings-python` or `python -m mkdocstrings`. - - Arguments: - args: Arguments passed from the command line. - - Returns: - An exit code. - """ - parser = get_parser() - opts = parser.parse_args(args=args) - print(opts) # noqa: WPS421 (side-effect in main is fine) - return 0 diff --git a/src/mkdocstrings/handlers/python/__init__.py b/src/mkdocstrings/handlers/python/__init__.py new file mode 100644 index 00000000..5d289836 --- /dev/null +++ b/src/mkdocstrings/handlers/python/__init__.py @@ -0,0 +1,73 @@ +"""This module implements a handler for the Python language.""" + +import posixpath +from typing import Any, BinaryIO, Iterator, Optional, Tuple + +from mkdocstrings.handlers.base import BaseHandler +from mkdocstrings.handlers.python.collector import PythonCollector +from mkdocstrings.handlers.python.renderer import PythonRenderer +from mkdocstrings.inventory import Inventory +from mkdocstrings.loggers import get_logger + +log = get_logger(__name__) + + +class PythonHandler(BaseHandler): + """The Python handler class. + + Attributes: + domain: The cross-documentation domain/language for this handler. + enable_inventory: Whether this handler is interested in enabling the creation + of the `objects.inv` Sphinx inventory file. + """ + + domain: str = "py" # to match Sphinx's default domain + enable_inventory: bool = True + + @classmethod + def load_inventory( + cls, + in_file: BinaryIO, + url: str, + base_url: Optional[str] = None, + **kwargs: Any, + ) -> Iterator[Tuple[str, str]]: + """Yield items and their URLs from an inventory file streamed from `in_file`. + + This implements mkdocstrings' `load_inventory` "protocol" (see plugin.py). + + Arguments: + in_file: The binary file-like object to read the inventory from. + url: The URL that this file is being streamed from (used to guess `base_url`). + base_url: The URL that this inventory's sub-paths are relative to. + **kwargs: Ignore additional arguments passed from the config. + + Yields: + Tuples of (item identifier, item URL). + """ + if base_url is None: + base_url = posixpath.dirname(url) + + for item in Inventory.parse_sphinx(in_file, domain_filter=("py",)).values(): # noqa: WPS526 + yield item.name, posixpath.join(base_url, item.uri) + + +def get_handler( + theme: str, # noqa: W0613 (unused argument config) + custom_templates: Optional[str] = None, + **config: Any, +) -> PythonHandler: + """Simply return an instance of `PythonHandler`. + + Arguments: + theme: The theme to use when rendering contents. + custom_templates: Directory containing custom templates. + **config: Configuration passed to the handler. + + Returns: + An instance of `PythonHandler`. + """ + return PythonHandler( + collector=PythonCollector(), + renderer=PythonRenderer("python", theme, custom_templates), + ) diff --git a/src/mkdocstrings/handlers/python/collector.py b/src/mkdocstrings/handlers/python/collector.py new file mode 100644 index 00000000..ac0b6846 --- /dev/null +++ b/src/mkdocstrings/handlers/python/collector.py @@ -0,0 +1,81 @@ +"""This module implements a collector for the Python language. + +It collects data with [Griffe](https://github.com/pawamoy/griffe). +""" + +from collections import ChainMap + +from griffe import logger as griffe_logger + +from mkdocstrings.handlers.base import BaseCollector, CollectionError, CollectorItem +from mkdocstrings.loggers import get_logger + +griffe_logger.get_logger = get_logger # patch logger to blend in MkDocs logs +from griffe.agents.extensions import load_extensions # noqa: E402 +from griffe.collections import LinesCollection, ModulesCollection # noqa: E402 +from griffe.docstrings.parsers import Parser # noqa: E402 +from griffe.loader import GriffeLoader # noqa: E402 + +logger = get_logger(__name__) + + +class PythonCollector(BaseCollector): + """The class responsible for loading Jinja templates and rendering them. + + It defines some configuration options, implements the `render` method, + and overrides the `update_env` method of the [`BaseRenderer` class][mkdocstrings.handlers.base.BaseRenderer]. + """ + + default_config: dict = {"docstring_style": "google", "docstring_options": {}} + """The default selection options. + + Option | Type | Description | Default + ------ | ---- | ----------- | ------- + **`docstring_style`** | `"google" | "numpy" | "rst" | None` | The docstring style to use. | `"google"` + **`docstring_options`** | dict[str, Any] | The options for the docstring parser. | `{}` + """ + + def __init__(self) -> None: + """Initialize the object.""" + self._modules_collection: ModulesCollection = ModulesCollection() + self._lines_collection: LinesCollection = LinesCollection() + + def collect(self, identifier: str, config: dict) -> CollectorItem: # noqa: WPS231 + """Collect the documentation tree given an identifier and selection options. + + Arguments: + identifier: The dotted-path of a Python object available in the Python path. + config: Selection options, used to alter the data collection done by `pytkdocs`. + + Raises: + CollectionError: When there was a problem collecting the object documentation. + + Returns: + The collected object-tree. + """ + final_config = ChainMap(config, self.default_config) + + module_name = identifier.split(".", 1)[0] + if module_name not in self._modules_collection: + loader = GriffeLoader( + extensions=load_extensions(final_config.get("extensions", [])), + docstring_parser=Parser(final_config["docstring_style"]), + docstring_options=final_config["docstring_options"], + modules_collection=self._modules_collection, + lines_collection=self._lines_collection, + ) + try: + module = loader.load_module(module_name) + except ModuleNotFoundError as error: + raise CollectionError from error + + for _ in range(5): + if loader.follow_aliases(module): + break + else: + logger.warning("some aliases could not be resolved") + + try: + return self._modules_collection[identifier] + except KeyError as error: # noqa: WPS440 + raise CollectionError from error diff --git a/src/mkdocstrings/handlers/python/renderer.py b/src/mkdocstrings/handlers/python/renderer.py new file mode 100644 index 00000000..f68babd8 --- /dev/null +++ b/src/mkdocstrings/handlers/python/renderer.py @@ -0,0 +1,210 @@ +"""This module implements a renderer for the Python language.""" + +from __future__ import annotations + +import enum +import re +import sys +from collections import ChainMap +from typing import Any, Sequence + +from griffe.dataclasses import Alias, Object +from markdown import Markdown +from markupsafe import Markup + +from mkdocstrings.extension import PluginError +from mkdocstrings.handlers.base import BaseRenderer, CollectorItem +from mkdocstrings.loggers import get_logger + +log = get_logger(__name__) + +# TODO: CSS classes everywhere in templates +# TODO: name normalization (filenames, Jinja2 variables, HTML tags, CSS classes) +# TODO: Jinja2 blocks everywhere in templates + + +class Order(enum.Enum): + """Enumeration for the possible members ordering.""" + + alphabetical = "alphabetical" + source = "source" + + +def _sort_key_alphabetical(item: CollectorItem) -> Any: + # chr(sys.maxunicode) is a string that contains the final unicode + # character, so if 'name' isn't found on the object, the item will go to + # the end of the list. + return item.name or chr(sys.maxunicode) + + +def _sort_key_source(item: CollectorItem) -> Any: + # if 'lineno' is none, the item will go to the start of the list. + return item.lineno if item.lineno is not None else -1 + + +order_map = { + Order.alphabetical: _sort_key_alphabetical, + Order.source: _sort_key_source, +} + + +class PythonRenderer(BaseRenderer): + """The class responsible for loading Jinja templates and rendering them. + + It defines some configuration options, implements the `render` method, + and overrides the `update_env` method of the [`BaseRenderer` class][mkdocstrings.handlers.base.BaseRenderer]. + + Attributes: + fallback_theme: The theme to fallback to. + default_config: The default rendering options, + see [`default_config`][mkdocstrings.handlers.python.PythonRenderer.default_config]. + """ + + fallback_theme = "material" + + default_config: dict = { + "show_root_heading": False, + "show_root_toc_entry": True, + "show_root_full_path": True, + "show_root_members_full_path": False, + "show_object_full_path": False, + "show_category_heading": False, + "show_if_no_docstring": False, + "show_signature_annotations": False, + "separate_signature": False, + "line_length": 60, + "show_source": True, + "show_bases": True, + "show_submodules": True, + "group_by_category": True, + "heading_level": 2, + "members_order": Order.alphabetical.value, + } + """The default rendering options. + + Option | Type | Description | Default + ------ | ---- | ----------- | ------- + **`show_root_heading`** | `bool` | Show the heading of the object at the root of the documentation tree. | `False` + **`show_root_toc_entry`** | `bool` | If the root heading is not shown, at least add a ToC entry for it. | `True` + **`show_root_full_path`** | `bool` | Show the full Python path for the root object heading. | `True` + **`show_object_full_path`** | `bool` | Show the full Python path of every object. | `False` + **`show_root_members_full_path`** | `bool` | Show the full Python path of objects that are children of the root object (for example, classes in a module). When False, `show_object_full_path` overrides. | `False` + **`show_category_heading`** | `bool` | When grouped by categories, show a heading for each category. | `False` + **`show_if_no_docstring`** | `bool` | Show the object heading even if it has no docstring or children with docstrings. | `False` + **`show_signature_annotations`** | `bool` | Show the type annotations in methods and functions signatures. | `False` + **`separate_signature`** | `bool` | Whether to put the whole signature in a foldable code block below the heading. | `False` + **`line_length`** | `int` | Maximum line length when formatting code. | `60` + **`show_source`** | `bool` | Show the source code of this object. | `True` + **`show_bases`** | `bool` | Show the base classes of a class. | `True` + **`show_submodules`** | `bool` | When rendering a module, show its submodules recursively. | `True` + **`group_by_category`** | `bool` | Group the object's children by categories: attributes, classes, functions, methods, and modules. | `True` + **`heading_level`** | `int` | The initial heading level to use. | `2` + **`members_order`** | `str` | The members ordering to use. Options: `alphabetical` - order by the members names, `source` - order members as they appear in the source file. | `alphabetical` + """ # noqa: E501 + + def render(self, data: CollectorItem, config: dict) -> str: # noqa: D102 (ignore missing docstring) + final_config = ChainMap(config, self.default_config) + + template = self.env.get_template(f"{data.kind.value}.html") + + # Heading level is a "state" variable, that will change at each step + # of the rendering recursion. Therefore, it's easier to use it as a plain value + # than as an item in a dictionary. + heading_level = final_config["heading_level"] + try: + final_config["members_order"] = Order(final_config["members_order"]) + except ValueError: + choices = "', '".join(item.value for item in Order) + raise PluginError(f"Unknown members_order '{final_config['members_order']}', choose between '{choices}'.") + + return template.render( + **{"config": final_config, data.kind.value: data, "heading_level": heading_level, "root": True}, + ) + + def get_anchors(self, data: CollectorItem) -> list[str]: # noqa: D102 (ignore missing docstring) + return list({data.path, data.canonical_path, *data.aliases}) + + def update_env(self, md: Markdown, config: dict) -> None: # noqa: D102 (ignore missing docstring) + super().update_env(md, config) + self.env.trim_blocks = True + self.env.lstrip_blocks = True + self.env.keep_trailing_newline = False + self.env.filters["crossref"] = self.do_crossref + self.env.filters["multi_crossref"] = self.do_multi_crossref + self.env.filters["order_members"] = self.do_order_members + self.env.filters["format_signature"] = self.do_format_signature + + def do_format_signature(self, signature: str, line_length: int) -> str: + """Format a signature using Black. + + Parameters: + signature: The signature to format. + line_length: The line length to give to Black. + + Returns: + The same code, formatted. + """ + from black import Mode, format_str + + code = signature.strip() + if len(code) < line_length: + return code + mode = Mode(line_length=line_length) + formatted = format_str(f"def {code}: pass", mode=mode) + # remove starting `def ` and trailing `: pass` + return formatted[4:-5].strip()[:-1] + + def do_order_members(self, members: Sequence[Object | Alias], order: Order) -> Sequence[Object | Alias]: + """Order members given an ordering method. + + Parameters: + members: The members to order. + order: The ordering method. + + Returns: + The same members, ordered. + """ + return sorted(members, key=order_map[order]) + + def do_crossref(self, path: str, brief: bool = True) -> Markup: + """Filter to create cross-references. + + Parameters: + path: The path to link to. + brief: Show only the last part of the path, add full path as hover. + + Returns: + Markup text. + """ + full_path = path + if brief: + path = full_path.split(".")[-1] + return Markup("{path}").format( + full_path=full_path, path=path + ) + + def do_multi_crossref(self, text: str, code: bool = True) -> Markup: + """Filter to create cross-references. + + Parameters: + text: The text to scan. + code: Whether to wrap the result in a code tag. + + Returns: + Markup text. + """ + group_number = 0 + variables = {} + + def repl(match): # noqa: WPS430 + nonlocal group_number # noqa: WPS420 + group_number += 1 + path = match.group() + path_var = f"path{group_number}" + variables[path_var] = path + return f"{{{path_var}}}" + + text = re.sub(r"([\w.]+)", repl, text) + if code: + text = f"{text}" + return Markup(text).format(**variables) diff --git a/src/mkdocstrings/templates/python/material/_base/attribute.html b/src/mkdocstrings/templates/python/material/_base/attribute.html new file mode 100644 index 00000000..4f8da7e7 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/attribute.html @@ -0,0 +1,58 @@ +{{ log.debug() }} +{% if config.show_if_no_docstring or attribute %} + +
+ {% with html_id = attribute.path %} + + {% if not root or config.show_root_heading %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} + {% endif %} + + {% filter heading(heading_level, + role="data" if attribute.parent.kind.value == "module" else "attr", + id=html_id, + class="doc doc-heading", + toc_label=attribute.name) %} + + {% filter highlight(language="python", inline=True) %} + {% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %} + {% if attribute.annotation %}: {{ attribute.annotation }}{% endif %} + {% if attribute.value %} = {{ attribute.value }}{% endif %} + {% endfilter %} + + {% with labels = attribute.labels %} + {% include "labels.html" with context %} + {% endwith %} + + {% endfilter %} + + {% else %} + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="data" if attribute.parent.kind.value == "module" else "attr", + id=html_id, + toc_label=attribute.path, + hidden=True) %} + {% endfilter %} + {% endif %} + {% set heading_level = heading_level - 1 %} + {% endif %} + +
+ {% with docstring_sections = attribute.docstring.parsed %} + {% include "docstring.html" with context %} + {% endwith %} +
+ + {% endwith %} +
+ +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/children.html b/src/mkdocstrings/templates/python/material/_base/children.html new file mode 100644 index 00000000..5cf217f5 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/children.html @@ -0,0 +1,96 @@ +{{ log.debug() }} +{% if obj.members %} + +
+ + {% if config.group_by_category %} + + {% with %} + + {% if config.show_category_heading %} + {% set extra_level = 1 %} + {% else %} + {% set extra_level = 0 %} + {% endif %} + + {% if config.show_category_heading and obj.attributes.values()|any %} + {% filter heading(heading_level, id=html_id ~ "-attributes") %}Attributes{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for attribute in obj.attributes.values()|order_members(config.members_order) %} + {% if not attribute.is_alias or attribute.is_explicitely_exported %} + {% include "attribute.html" with context %} + {% endif %} + {% endfor %} + {% endwith %} + + {% if config.show_category_heading and obj.classes.values()|any %} + {% filter heading(heading_level, id=html_id ~ "-classes") %}Classes{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for class in obj.classes.values()|order_members(config.members_order) %} + {% if not class.is_alias or class.is_explicitely_exported %} + {% include "class.html" with context %} + {% endif %} + {% endfor %} + {% endwith %} + + {% if config.show_category_heading and obj.functions.values()|any %} + {% filter heading(heading_level, id=html_id ~ "-functions") %}Functions{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for function in obj.functions.values()|order_members(config.members_order) %} + {% if not function.is_alias or function.is_explicitely_exported %} + {% include "function.html" with context %} + {% endif %} + {% endfor %} + {% endwith %} + + {% if config.show_submodules %} + {% if config.show_category_heading and obj.modules.values()|any %} + {% filter heading(heading_level, id=html_id ~ "-modules") %}Modules{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for module in obj.modules.values()|order_members(config.members_order) %} + {% if not module.is_alias or module.is_explicitely_exported %} + {% include "module.html" with context %} + {% endif %} + {% endfor %} + {% endwith %} + {% endif %} + + {% endwith %} + + {% else %} + + {% for child in obj.members.values()|order_members(config.members_order) %} + + {% if child.kind.value == "attribute" %} + {% with attribute = child %} + {% include "attribute.html" with context %} + {% endwith %} + + {% elif child.kind.value == "class" %} + {% with class = child %} + {% include "class.html" with context %} + {% endwith %} + + {% elif child.kind.value == "function" %} + {% with function = child %} + {% include "function.html" with context %} + {% endwith %} + + {% elif child.kind.value == "module" and config.show_submodules %} + {% with module = child %} + {% include "module.html" with context %} + {% endwith %} + + {% endif %} + + {% endfor %} + + {% endif %} + +
+ +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/class.html b/src/mkdocstrings/templates/python/material/_base/class.html new file mode 100644 index 00000000..37724e17 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/class.html @@ -0,0 +1,74 @@ +{{ log.debug() }} +{% if config.show_if_no_docstring or class %} + +
+ {% with html_id = class.path %} + + {% if not root or config.show_root_heading %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} + {% endif %} + + {% filter heading(heading_level, + role="class", + id=html_id, + class="doc doc-heading", + toc_label=class.name) %} + + + {% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %} + {% if config.show_bases and class.bases %} + ({% for expression in class.bases -%} + {% include "expression.html" with context %}{% if not loop.last %}, {% endif %} + {% endfor %}) + {% endif %} + + + {% with labels = class.labels %} + {% include "labels.html" with context %} + {% endwith %} + + {% endfilter %} + + {% else %} + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="class", + id=html_id, + toc_label=class.path, + hidden=True) %} + {% endfilter %} + {% endif %} + {% set heading_level = heading_level - 1 %} + {% endif %} + +
+ {% with docstring_sections = class.docstring.parsed %} + {% include "docstring.html" with context %} + {% endwith %} + + {% if config.show_source and class.source %} +
+ Source code in {{ class.relative_filepath }} + {{ class.source|highlight(language="python", linestart=class.lineno, linenums=True) }} +
+ {% endif %} + + {% with obj = class %} + {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% include "children.html" with context %} + {% endwith %} +
+ + {% endwith %} +
+ +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring.html b/src/mkdocstrings/templates/python/material/_base/docstring.html new file mode 100644 index 00000000..bdf60ffa --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring.html @@ -0,0 +1,26 @@ +{{ log.debug() }} +{% if docstring_sections %} + {% for section in docstring_sections %} + {% if section.kind.value == "text" %} + {{ section.value|convert_markdown(heading_level, html_id) }} + {% elif section.kind.value == "attributes" %} + {% include "docstring/attributes.html" with context %} + {% elif section.kind.value == "parameters" %} + {% include "docstring/parameters.html" with context %} + {% elif section.kind.value == "other parameters" %} + {% include "docstring/other_parameters.html" with context %} + {% elif section.kind.value == "raises" %} + {% include "docstring/raises.html" with context %} + {% elif section.kind.value == "warns" %} + {% include "docstring/warns.html" with context %} + {% elif section.kind.value == "yields" %} + {% include "docstring/yields.html" with context %} + {% elif section.kind.value == "receives" %} + {% include "docstring/receives.html" with context %} + {% elif section.kind.value == "returns" %} + {% include "docstring/returns.html" with context %} + {% elif section.kind.value == "examples" %} + {% include "docstring/examples.html" with context %} + {% endif %} + {% endfor %} +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/attributes.html b/src/mkdocstrings/templates/python/material/_base/docstring/attributes.html new file mode 100644 index 00000000..13515121 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/attributes.html @@ -0,0 +1,72 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Attributes:" }}

+ + + + + + + + + + {% for attribute in section.value %} + + + + + + {% endfor %} + +
NameTypeDescription
{{ attribute.name }} + {% if attribute.annotation %} + {% with expression = attribute.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ attribute.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Attributes:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for attribute in section.value %} + + + + + {% endfor %} + +
ATTRIBUTEDESCRIPTION
{{ attribute.name }} + {{ attribute.description|convert_markdown(heading_level, html_id) }} +

+ {% if attribute.annotation %} + + TYPE: + {% with expression = attribute.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/examples.html b/src/mkdocstrings/templates/python/material/_base/docstring/examples.html new file mode 100644 index 00000000..553308ff --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/examples.html @@ -0,0 +1,9 @@ +{{ log.debug() }} +

{{ section.title or "Examples:" }}

+{% for section_type, sub_section in section.value %} + {% if section_type == "markdown" %} + {{ sub_section|convert_markdown(heading_level, html_id) }} + {% elif section_type == "examples" %} + {{ sub_section|highlight(language="python", linenums=False) }} + {% endif %} +{% endfor %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/other_parameters.html b/src/mkdocstrings/templates/python/material/_base/docstring/other_parameters.html new file mode 100644 index 00000000..d31ef7fc --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/other_parameters.html @@ -0,0 +1,72 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Other Parameters:" }}

+ + + + + + + + + + {% for parameter in section.value %} + + + + + + {% endfor %} + +
NameTypeDescription
{{ parameter.name }} + {% if parameter.annotation %} + {% with expression = parameter.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ parameter.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Other Parameters:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for parameter in section.value %} + + + + + {% endfor %} + +
PARAMETERDESCRIPTION
{{ parameter.name }} + {{ parameter.description|convert_markdown(heading_level, html_id) }} +

+ {% if parameter.annotation %} + + TYPE: + {% with expression = parameter.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/parameters.html b/src/mkdocstrings/templates/python/material/_base/docstring/parameters.html new file mode 100644 index 00000000..9bc227a5 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/parameters.html @@ -0,0 +1,90 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Parameters:" }}

+ + + + + + + + + + + {% for parameter in section.value %} + + + + + + + {% endfor %} + +
NameTypeDescriptionDefault
{{ parameter.name }} + {% if parameter.annotation %} + {% with expression = parameter.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ parameter.description|convert_markdown(heading_level, html_id) }} + {% if parameter.default %} + {% with expression = parameter.default %} + {% include "expression.html" with context %} + {% endwith %} + {% else %} + required + {% endif %} +
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Parameters:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for parameter in section.value %} + + + + + {% endfor %} + +
PARAMETERDESCRIPTION
{{ parameter.name }} + {{ parameter.description|convert_markdown(heading_level, html_id) }} +

+ {% if parameter.annotation %} + + TYPE: + {% with expression = parameter.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} + {% if parameter.default %} + + DEFAULT: + {% with expression = parameter.default %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/raises.html b/src/mkdocstrings/templates/python/material/_base/docstring/raises.html new file mode 100644 index 00000000..1d327666 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/raises.html @@ -0,0 +1,70 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Raises:" }}

+ + + + + + + + + {% for raises in section.value %} + + + + + {% endfor %} + +
TypeDescription
+ {% if raises.annotation %} + {% with expression = raises.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ raises.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Raises:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for raises in section.value %} + + + + + {% endfor %} + +
RAISESDESCRIPTION
{{ raises.name }} + {{ raises.description|convert_markdown(heading_level, html_id) }} +

+ {% if raises.annotation %} + + TYPE: + {% with expression = raises.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/receives.html b/src/mkdocstrings/templates/python/material/_base/docstring/receives.html new file mode 100644 index 00000000..d3261f43 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/receives.html @@ -0,0 +1,70 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Receives:" }}

+ + + + + + + + + + {% with receives = section.value %} + + + {% endwith %} + + +
TypeDescription
+ {% if receives.annotation %} + {% with expression = receives.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ receives.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Receives:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for receive in section.value %} + + + + + {% endfor %} + +
RECEIVESDESCRIPTION
{{ receive.name }} + {{ receive.description|convert_markdown(heading_level, html_id) }} +

+ {% if receive.annotation %} + + TYPE: + {% with expression = receive.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/returns.html b/src/mkdocstrings/templates/python/material/_base/docstring/returns.html new file mode 100644 index 00000000..d3d06f7e --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/returns.html @@ -0,0 +1,65 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} + {% set name_column = section.value|selectattr("name")|any %} +

{{ section.title or "Returns:" }}

+ + + + {% if name_column %}{% endif %} + + + + + + {% for returns in section.value %} + + {% if name_column %}{% endif %} + + + + {% endfor %} + +
NameTypeDescription
{% if returns.name %}{{ returns.name }}{% endif %} + {% if returns.annotation %} + {% with expression = returns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ returns.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Returns:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + {% for returns in section.value %} + + + + {% endfor %} + +
RETURNS
+ {{ returns.description|convert_markdown(heading_level, html_id) }} +

+ TYPE: + {% with expression = returns.annotation %} + {% include "expression.html" with context %} + {% endwith %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/warns.html b/src/mkdocstrings/templates/python/material/_base/docstring/warns.html new file mode 100644 index 00000000..070edf9f --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/warns.html @@ -0,0 +1,70 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Warns:" }}

+ + + + + + + + + {% for warns in section.value %} + + + + + {% endfor %} + +
TypeDescription
+ {% if warns.annotation %} + {% with expression = warns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ warns.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Warns:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for warns in section.value %} + + + + + {% endfor %} + +
WARNSDESCRIPTION
{{ warns.name }} + {{ warns.description|convert_markdown(heading_level, html_id) }} +

+ {% if warns.annotation %} + + TYPE: + {% with expression = warns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/yields.html b/src/mkdocstrings/templates/python/material/_base/docstring/yields.html new file mode 100644 index 00000000..2ba09a65 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/docstring/yields.html @@ -0,0 +1,70 @@ +{{ log.debug() }} +{% if config.docstring_section_style == "table" %} +

{{ section.title or "Yields:" }}

+ + + + + + + + + + {% with yields = section.value %} + + + {% endwith %} + + +
TypeDescription
+ {% if yields.annotation %} + {% with expression = yields.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + {{ yields.description|convert_markdown(heading_level, html_id) }}
+{% elif config.docstring_section_style == "list" %} +

{{ section.title or "Yields:" }}

+ +{% elif config.docstring_section_style == "spacy" %} + + + + + + + + + {% for yields in section.value %} + + + + + {% endfor %} + +
YIELDSDESCRIPTION
{{ yields.name }} + {{ yields.description|convert_markdown(heading_level, html_id) }} +

+ {% if yields.annotation %} + + TYPE: + {% with expression = yields.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+{% endif %} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/material/_base/expression.html b/src/mkdocstrings/templates/python/material/_base/expression.html new file mode 100644 index 00000000..29751104 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/expression.html @@ -0,0 +1,10 @@ +{%- set original_expression = expression -%} +{%- if original_expression is iterable and original_expression is not string -%} + {%- for expression in original_expression -%} + {%- include "expression.html" with context -%} + {%- endfor -%} +{%- elif original_expression is string -%} + {{ original_expression }} +{%- else -%} + {{ original_expression.source }} +{%- endif -%} diff --git a/src/mkdocstrings/templates/python/material/_base/function.html b/src/mkdocstrings/templates/python/material/_base/function.html new file mode 100644 index 00000000..39f8333e --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/function.html @@ -0,0 +1,77 @@ +{{ log.debug() }} +{% if config.show_if_no_docstring or function %} + +
+ {% with html_id = function.path %} + + {% if not root or config.show_root_heading %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} + {% endif %} + + {% filter heading(heading_level, + role="function", + id=html_id, + class="doc doc-heading", + toc_label=function.name ~ "()") %} + + {% if config.separate_signature %} + {% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %}() + {% else %} + {% filter highlight(language="python", inline=True) %} + {% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %} + {% include "signature.html" with context %} + {% endfilter %} + {% endif %} + + {% with labels = function.labels %} + {% include "labels.html" with context %} + {% endwith %} + + {% endfilter %} + + {% if config.separate_signature %} + {% filter highlight(language="python", inline=False) %} + {% filter format_signature(config.line_length) %} + {% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %} + {% include "signature.html" with context %} + {% endfilter %} + {% endfilter %} + {% endif %} + + {% else %} + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="function", + id=html_id, + toc_label=function.path, + hidden=True) %} + {% endfilter %} + {% endif %} + {% set heading_level = heading_level - 1 %} + {% endif %} + +
+ {% with docstring_sections = function.docstring.parsed %} + {% include "docstring.html" with context %} + {% endwith %} + + {% if config.show_source and function.source %} +
+ Source code in {{ function.relative_filepath }} + {{ function.source|highlight(language="python", linestart=function.lineno, linenums=True) }} +
+ {% endif %} +
+ + {% endwith %} +
+ +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/labels.html b/src/mkdocstrings/templates/python/material/_base/labels.html new file mode 100644 index 00000000..69a2da4c --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/labels.html @@ -0,0 +1,8 @@ +{{ log.debug() }} +{% if properties %} + + {% for property in properties %} + {{ property }} + {% endfor %} + +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/module.html b/src/mkdocstrings/templates/python/material/_base/module.html new file mode 100644 index 00000000..ad0cef4f --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/module.html @@ -0,0 +1,60 @@ +{{ log.debug() }} +{% if config.show_if_no_docstring or module %} + +
+ {% with html_id = module.path %} + + {% if not root or config.show_root_heading %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} + {% endif %} + + {% filter heading(heading_level, + role="module", + id=html_id, + class="doc doc-heading", + toc_label=module.name) %} + + {% if show_full_path %}{{ module.path }}{% else %}{{ module.name }}{% endif %} + + {% with labels = module.labels %} + {% include "labels.html" with context %} + {% endwith %} + + {% endfilter %} + + {% else %} + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="module", + id=html_id, + toc_label=module.path, + hidden=True) %} + {% endfilter %} + {% endif %} + {% set heading_level = heading_level - 1 %} + {% endif %} + +
+ {% with docstring_sections = module.docstring.parsed %} + {% include "docstring.html" with context %} + {% endwith %} + + {% with obj = module %} + {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% include "children.html" with context %} + {% endwith %} +
+ + {% endwith %} +
+ +{% endif %} diff --git a/src/mkdocstrings/templates/python/material/_base/signature.html b/src/mkdocstrings/templates/python/material/_base/signature.html new file mode 100644 index 00000000..74386e12 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/_base/signature.html @@ -0,0 +1,39 @@ +{{ log.debug() }} +{%- with -%} + {%- set ns = namespace(render_pos_only_separator=True, render_kw_only_separator=True, equal="=") -%} + + {%- if config.show_signature_annotations -%} + {%- set ns.equal = " = " -%} + {%- endif -%} + + ( + {%- for parameter in function.parameters -%} + + {%- if parameter.kind.value == "positional-only" -%} + {%- if ns.render_pos_only_separator -%} + {%- set ns.render_pos_only_separator = False %}/, {% endif -%} + {%- elif parameter.kind.value == "keyword-only" -%} + {%- if ns.render_kw_only_separator -%} + {%- set ns.render_kw_only_separator = False %}*, {% endif -%} + {%- endif -%} + + {%- if config.show_signature_annotations and parameter.annotation is not none -%} + {%- set annotation = ": " + parameter.annotation|safe -%} + {%- endif -%} + + {%- if parameter.default is not none and parameter.kind.value != "variadic positional" and parameter.kind.value != "variadic keyword" -%} + {%- set default = ns.equal + parameter.default|safe -%} + {%- endif -%} + + {%- if parameter.kind.value == "variadic positional" -%} + {%- set ns.render_kw_only_separator = False -%} + {%- endif -%} + + {{ parameter.name }}{{ annotation }}{{ default }} + {%- if not loop.last %}, {% endif -%} + + {%- endfor -%} + ) + {%- if config.show_signature_annotations and "return_annotation" in signature %} -> {{ signature.return_annotation }}{%- endif -%} + +{%- endwith -%} diff --git a/src/mkdocstrings/templates/python/material/attribute.html b/src/mkdocstrings/templates/python/material/attribute.html new file mode 100644 index 00000000..78050206 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/attribute.html @@ -0,0 +1 @@ +{% extends "_base/attribute.html" %} diff --git a/src/mkdocstrings/templates/python/material/children.html b/src/mkdocstrings/templates/python/material/children.html new file mode 100644 index 00000000..5fcb7388 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/children.html @@ -0,0 +1 @@ +{% extends "_base/children.html" %} diff --git a/src/mkdocstrings/templates/python/material/class.html b/src/mkdocstrings/templates/python/material/class.html new file mode 100644 index 00000000..c1e411a9 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/class.html @@ -0,0 +1 @@ +{% extends "_base/class.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring.html b/src/mkdocstrings/templates/python/material/docstring.html new file mode 100644 index 00000000..9df79c58 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring.html @@ -0,0 +1 @@ +{% extends "_base/docstring.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/attributes.html b/src/mkdocstrings/templates/python/material/docstring/attributes.html new file mode 100644 index 00000000..60b5e73a --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/attributes.html @@ -0,0 +1 @@ +{% extends "_base/docstring/attributes.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/examples.html b/src/mkdocstrings/templates/python/material/docstring/examples.html new file mode 100644 index 00000000..96f28261 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/examples.html @@ -0,0 +1 @@ +{% extends "_base/docstring/examples.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/other_parameters.html b/src/mkdocstrings/templates/python/material/docstring/other_parameters.html new file mode 100644 index 00000000..86c40256 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/other_parameters.html @@ -0,0 +1 @@ +{% extends "_base/docstring/other_parameters.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/parameters.html b/src/mkdocstrings/templates/python/material/docstring/parameters.html new file mode 100644 index 00000000..ca3ae309 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/parameters.html @@ -0,0 +1 @@ +{% extends "_base/docstring/parameters.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/raises.html b/src/mkdocstrings/templates/python/material/docstring/raises.html new file mode 100644 index 00000000..0c789823 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/raises.html @@ -0,0 +1 @@ +{% extends "_base/docstring/raises.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/receives.html b/src/mkdocstrings/templates/python/material/docstring/receives.html new file mode 100644 index 00000000..8cf03922 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/receives.html @@ -0,0 +1 @@ +{% extends "_base/docstring/receives.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/returns.html b/src/mkdocstrings/templates/python/material/docstring/returns.html new file mode 100644 index 00000000..19d92dda --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/returns.html @@ -0,0 +1 @@ +{% extends "_base/docstring/returns.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/warns.html b/src/mkdocstrings/templates/python/material/docstring/warns.html new file mode 100644 index 00000000..2bef95fb --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/warns.html @@ -0,0 +1 @@ +{% extends "_base/docstring/warns.html" %} diff --git a/src/mkdocstrings/templates/python/material/docstring/yields.html b/src/mkdocstrings/templates/python/material/docstring/yields.html new file mode 100644 index 00000000..45e6cd6a --- /dev/null +++ b/src/mkdocstrings/templates/python/material/docstring/yields.html @@ -0,0 +1 @@ +{% extends "_base/docstring/yields.html" %} diff --git a/src/mkdocstrings/templates/python/material/expression.html b/src/mkdocstrings/templates/python/material/expression.html new file mode 100644 index 00000000..23c3515f --- /dev/null +++ b/src/mkdocstrings/templates/python/material/expression.html @@ -0,0 +1 @@ +{% extends "_base/expression.html" %} diff --git a/src/mkdocstrings/templates/python/material/function.html b/src/mkdocstrings/templates/python/material/function.html new file mode 100644 index 00000000..c44f96a8 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/function.html @@ -0,0 +1 @@ +{% extends "_base/function.html" %} diff --git a/src/mkdocstrings/templates/python/material/labels.html b/src/mkdocstrings/templates/python/material/labels.html new file mode 100644 index 00000000..d835d7fb --- /dev/null +++ b/src/mkdocstrings/templates/python/material/labels.html @@ -0,0 +1 @@ +{% extends "_base/labels.html" %} diff --git a/src/mkdocstrings/templates/python/material/module.html b/src/mkdocstrings/templates/python/material/module.html new file mode 100644 index 00000000..ea9a2fad --- /dev/null +++ b/src/mkdocstrings/templates/python/material/module.html @@ -0,0 +1 @@ +{% extends "_base/module.html" %} diff --git a/src/mkdocstrings/templates/python/material/signature.html b/src/mkdocstrings/templates/python/material/signature.html new file mode 100644 index 00000000..4b756b9c --- /dev/null +++ b/src/mkdocstrings/templates/python/material/signature.html @@ -0,0 +1 @@ +{% extends "_base/signature.html" %} diff --git a/src/mkdocstrings/templates/python/material/style.css b/src/mkdocstrings/templates/python/material/style.css new file mode 100644 index 00000000..350ce132 --- /dev/null +++ b/src/mkdocstrings/templates/python/material/style.css @@ -0,0 +1,35 @@ +/* Don't capitalize names. */ +h5.doc-heading { + text-transform: none !important; +} + +/* Avoid breaking parameters name, etc. in table cells. */ +.doc-contents td code { + word-break: normal !important; +} + +/* For pieces of Markdown rendered in table cells. */ +.doc-contents td p { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +/* Max width for docstring sections tables. */ +.doc .md-typeset__table, +.doc .md-typeset__table table { + display: table !important; + width: 100%; +} +.doc .md-typeset__table tr { + display: table-row; +} + +/* Avoid line breaks in rendered fields. */ +.field-body p { + display: inline; +} + +/* Defaults in Spacy table style/ */ +.doc-param-default { + float: right; +} \ No newline at end of file diff --git a/src/mkdocstrings/templates/python/mkdocs/exceptions.html b/src/mkdocstrings/templates/python/mkdocs/exceptions.html new file mode 100644 index 00000000..677c867b --- /dev/null +++ b/src/mkdocstrings/templates/python/mkdocs/exceptions.html @@ -0,0 +1,7 @@ +{{ log.debug() }} +
+
Exceptions:
+ {% for exception in exceptions %} +
{{ ("`" + exception.annotation + "`: " + exception.description)|convert_markdown(heading_level, html_id) }}
+ {% endfor %} +
diff --git a/src/mkdocstrings/templates/python/mkdocs/keyword_args.html b/src/mkdocstrings/templates/python/mkdocs/keyword_args.html new file mode 100644 index 00000000..16af0ea0 --- /dev/null +++ b/src/mkdocstrings/templates/python/mkdocs/keyword_args.html @@ -0,0 +1,7 @@ +{{ log.debug() }} +
+
Keyword arguments:
+ {% for kwarg in kwargs %} +
{{ ("**" + kwarg.name + ":** " + ("`" + kwarg.annotation + "` – " if kwarg.annotation else "") + kwarg.description)|convert_markdown(heading_level, html_id) }}
+ {% endfor %} +
diff --git a/src/mkdocstrings/templates/python/mkdocs/parameters.html b/src/mkdocstrings/templates/python/mkdocs/parameters.html new file mode 100644 index 00000000..f745789b --- /dev/null +++ b/src/mkdocstrings/templates/python/mkdocs/parameters.html @@ -0,0 +1,7 @@ +{{ log.debug() }} +
+
Arguments:
+ {% for parameter in parameters %} +
{{ ("**" + parameter.name + ":** " + ("`" + parameter.annotation + "` – " if parameter.annotation else "") + parameter.description)|convert_markdown(heading_level, html_id) }}
+ {% endfor %} +
diff --git a/src/mkdocstrings/templates/python/mkdocs/return.html b/src/mkdocstrings/templates/python/mkdocs/return.html new file mode 100644 index 00000000..b38d61d1 --- /dev/null +++ b/src/mkdocstrings/templates/python/mkdocs/return.html @@ -0,0 +1,5 @@ +{{ log.debug() }} +
+
Returns:
+
{{ (("`" + return.annotation + "` – " if return.annotation else "") + return.description)|convert_markdown(heading_level, html_id) }}
+
diff --git a/src/mkdocstrings/templates/python/mkdocs/style.css b/src/mkdocstrings/templates/python/mkdocs/style.css new file mode 100644 index 00000000..9db45032 --- /dev/null +++ b/src/mkdocstrings/templates/python/mkdocs/style.css @@ -0,0 +1,11 @@ +.doc-contents { + padding-left: 20px; +} + +.doc-contents dd>p { + margin-bottom: 0.5rem; +} + +.doc-contents dl+dl { + margin-top: -0.5rem; +} diff --git a/src/mkdocstrings/templates/python/mkdocs/yield.html b/src/mkdocstrings/templates/python/mkdocs/yield.html new file mode 100644 index 00000000..dad0f0e9 --- /dev/null +++ b/src/mkdocstrings/templates/python/mkdocs/yield.html @@ -0,0 +1,5 @@ +{{ log.debug() }} +
+
Yields:
+
{{ (("`" + yield.annotation + "` – " if yield.annotation else "") + yield.description)|convert_markdown(heading_level, html_id) }}
+
diff --git a/src/mkdocstrings/templates/python/readthedocs/exceptions.html b/src/mkdocstrings/templates/python/readthedocs/exceptions.html new file mode 100644 index 00000000..715bdaf9 --- /dev/null +++ b/src/mkdocstrings/templates/python/readthedocs/exceptions.html @@ -0,0 +1,19 @@ +{{ log.debug() }} + + + + + + + + + + + +
Exceptions: +
    + {% for exception in exceptions %} +
  • {{ ("`" + exception.annotation + "` – " + exception.description)|convert_markdown(heading_level, html_id) }}
  • + {% endfor %} +
+
diff --git a/src/mkdocstrings/templates/python/readthedocs/other_parameters.html b/src/mkdocstrings/templates/python/readthedocs/other_parameters.html new file mode 100644 index 00000000..3c15308e --- /dev/null +++ b/src/mkdocstrings/templates/python/readthedocs/other_parameters.html @@ -0,0 +1,19 @@ +{{ log.debug() }} + + + + + + + + + + + +
Keyword arguments: +
    + {% for kwarg in kwargs %} +
  • {{ ("**" + kwarg.name + "**" + (" (`" + kwarg.annotation + "`)" if kwarg.annotation else "") + " – " + kwarg.description)|convert_markdown(heading_level, html_id) }}
  • + {% endfor %} +
+
diff --git a/src/mkdocstrings/templates/python/readthedocs/parameters.html b/src/mkdocstrings/templates/python/readthedocs/parameters.html new file mode 100644 index 00000000..197a411e --- /dev/null +++ b/src/mkdocstrings/templates/python/readthedocs/parameters.html @@ -0,0 +1,19 @@ +{{ log.debug() }} + + + + + + + + + + + +
Parameters: +
    + {% for parameter in parameters %} +
  • {{ ("**" + parameter.name + "**" + (" (`" + parameter.annotation + "`)" if parameter.annotation else "") + " – " + parameter.description)|convert_markdown(heading_level, html_id) }}
  • + {% endfor %} +
+
diff --git a/src/mkdocstrings/templates/python/readthedocs/returns.html b/src/mkdocstrings/templates/python/readthedocs/returns.html new file mode 100644 index 00000000..74bf65bb --- /dev/null +++ b/src/mkdocstrings/templates/python/readthedocs/returns.html @@ -0,0 +1,17 @@ +{{ log.debug() }} + + + + + + + + + + + +
Returns: +
    +
  • {{ ((("`" + return.annotation + "` – ") if return.annotation else "") + return.description)|convert_markdown(heading_level, html_id) }}
  • +
+
diff --git a/src/mkdocstrings/templates/python/readthedocs/style.css b/src/mkdocstrings/templates/python/readthedocs/style.css new file mode 100644 index 00000000..2cafca81 --- /dev/null +++ b/src/mkdocstrings/templates/python/readthedocs/style.css @@ -0,0 +1,27 @@ +/* Avoid breaking parameters name, etc. in table cells. */ +.doc-contents td code { + word-break: normal !important; +} + +/* For pieces of Markdown rendered in table cells. */ +.doc-contents td p { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +/* Avoid breaking code headings. */ +.doc-heading code { + white-space: normal; +} + +/* Improve rendering of parameters, returns and exceptions. */ +.doc-contents .field-name { + min-width: 100px; +} +.doc-contents .field-name, .field-body { + border: none !important; + padding: 0 !important; +} +.doc-contents .field-list { + margin: 0 !important; +} diff --git a/src/mkdocstrings/templates/python/readthedocs/yields.html b/src/mkdocstrings/templates/python/readthedocs/yields.html new file mode 100644 index 00000000..7591f62c --- /dev/null +++ b/src/mkdocstrings/templates/python/readthedocs/yields.html @@ -0,0 +1,17 @@ +{{ log.debug() }} + + + + + + + + + + + +
Yields: +
    +
  • {{ ((("`" + yield.annotation + "` – ") if yield.annotation else "") + yield.description)|convert_markdown(heading_level, html_id) }}
  • +
+