diff --git a/.copier-answers.yml b/.copier-answers.yml index cd27ed0e..a57431e6 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: 0.7.0 +_commit: 0.8.1 _src_path: gh:pawamoy/copier-pdm author_email: pawamoy@pm.me author_fullname: "Timoth\xE9e Mazzucotelli" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cf7c656..a9b12e44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,7 @@ jobs: - macos-latest - windows-latest python-version: + - "3.7" - "3.8" - "3.9" - "3.10" diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b44c751..b369fcc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ 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.2.0](https://github.com/mkdocstrings/python/releases/tag/0.2.0) - 2021-12-28 + +[Compare with 0.1.0](https://github.com/mkdocstrings/python/compare/0.1.0...0.2.0) + +### Build +- Depend on griffe >= 0.7.1 ([34f7ebd](https://github.com/mkdocstrings/python/commit/34f7ebd41f3ebda025ad87e3b52a7226fcb93720) by Timothée Mazzucotelli). +- Upgrade griffe, no upper bound ([8f0aa42](https://github.com/mkdocstrings/python/commit/8f0aa42eed07424a1377708897d92f9894f4abdb) by Timothée Mazzucotelli). + +### Features +- Add `show_signature` rendering option ([0f07c2e](https://github.com/mkdocstrings/python/commit/0f07c2e51a51a56eeb5d32fdf05dbed7243f0bc5) by Will Da Silva). + +### Bug Fixes +- Fix templates for named docstring elements ([47868a1](https://github.com/mkdocstrings/python/commit/47868a143bf2c462abd5ad85bd0ab8dca7bc5f82) by Timothée Mazzucotelli). + + ## [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) diff --git a/README.md b/README.md index fc1eae9e..099db3d0 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ A Python handler for mkdocstrings. ## Requirements -Python for mkdocstrings requires Python 3.6 or above. +Python for mkdocstrings requires Python 3.7 or above.
-To install Python 3.6, I recommend using pyenv. +To install Python 3.7, I recommend using pyenv. ```bash # install pyenv @@ -24,11 +24,11 @@ export PATH="${HOME}/.pyenv/bin:${PATH}" export PYENV_ROOT="${HOME}/.pyenv" eval "$(pyenv init -)" -# install Python 3.6 -pyenv install 3.6.12 +# install Python 3.7 +pyenv install 3.7.12 # make it available globally -pyenv global system 3.6.12 +pyenv global system 3.7.12 ```
@@ -36,12 +36,11 @@ pyenv global system 3.6.12 With `pip`: ```bash -python3.6 -m pip install mkdocstrings-python +pip install mkdocstrings-python ``` With [`pipx`](https://github.com/pipxproject/pipx): ```bash -python3.6 -m pip install --user pipx - -pipx install --python python3.6 mkdocstrings-python +python3.7 -m pip install --user pipx +pipx install mkdocstrings-python ``` diff --git a/config/coverage.ini b/config/coverage.ini index b1c19eab..421b9684 100644 --- a/config/coverage.ini +++ b/config/coverage.ini @@ -2,7 +2,7 @@ branch = true parallel = true source = - src/ + src/mkdocstrings/handlers/ tests/ [coverage:paths] diff --git a/config/mypy.ini b/config/mypy.ini index 4ac80d76..814e2ac8 100644 --- a/config/mypy.ini +++ b/config/mypy.ini @@ -2,3 +2,4 @@ ignore_missing_imports = true exclude = tests/fixtures/ warn_unused_ignores = true +show_error_codes = true diff --git a/docs/gen_ref_nav.py b/docs/gen_ref_nav.py old mode 100644 new mode 100755 index cc54b86a..15febda8 --- a/docs/gen_ref_nav.py +++ b/docs/gen_ref_nav.py @@ -7,8 +7,6 @@ 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").with_suffix(".md") full_doc_path = Path("reference", doc_path) diff --git a/duties.py b/duties.py index 19c0f6bf..f23da62d 100644 --- a/duties.py +++ b/duties.py @@ -6,7 +6,6 @@ import sys import tempfile from contextlib import suppress -from functools import wraps from io import StringIO from pathlib import Path from typing import List, Optional, Pattern @@ -43,7 +42,6 @@ def update_changelog( marker: str, version_regex: str, template_url: str, - commit_style: str, ) -> None: """ Update the given changelog file in place. @@ -53,15 +51,16 @@ def update_changelog( marker: The line after which to insert new contents. version_regex: A regular expression to find currently documented versions in the file. template_url: The URL to the Jinja template used to render contents. - commit_style: The style of commit messages to parse. """ from git_changelog.build import Changelog + from git_changelog.commit import AngularStyle from jinja2.sandbox import SandboxedEnvironment + AngularStyle.DEFAULT_RENDER.insert(0, AngularStyle.TYPES["build"]) env = SandboxedEnvironment(autoescape=False) template_text = urlopen(template_url).read().decode("utf8") # noqa: S310 template = env.from_string(template_text) - changelog = Changelog(".", style=commit_style) + changelog = Changelog(".", style="angular") if len(changelog.versions_list) == 1: last_version = changelog.versions_list[0] @@ -101,7 +100,6 @@ def changelog(ctx): "marker": "", "version_regex": r"^## \[v?(?P[^\]]+)", "template_url": template_url, - "commit_style": "angular", }, title="Updating changelog", pty=PTY, @@ -169,32 +167,7 @@ def safety(): # noqa: WPS430 ctx.run(safety, title="Checking dependencies") -def no_docs_py36(nofail=True): - """ - Decorate a duty that builds docs to warn that it's not possible on Python 3.6. - - Arguments: - nofail: Whether to fail or not. - - Returns: - The decorated function. - """ - - def decorator(func): - @wraps(func) - def wrapper(ctx): - if sys.version_info <= (3, 7, 0): - ctx.run(["false"], title="Docs can't be built on Python 3.6", nofail=nofail, quiet=True) - else: - func(ctx) - - return wrapper - - return decorator - - @duty -@no_docs_py36() def check_docs(ctx): """ Check if the documentation builds correctly. @@ -282,7 +255,6 @@ def clean(ctx): @duty -@no_docs_py36(nofail=False) def docs(ctx): """ Build the documentation locally. @@ -294,7 +266,6 @@ def docs(ctx): @duty -@no_docs_py36(nofail=False) def docs_serve(ctx, host="127.0.0.1", port=8000): """ Serve the documentation (localhost:8000). @@ -308,7 +279,6 @@ def docs_serve(ctx, host="127.0.0.1", port=8000): @duty -@no_docs_py36(nofail=False) def docs_deploy(ctx): """ Deploy the documentation on GitHub pages. diff --git a/mkdocs.yml b/mkdocs.yml index 1713313f..9be7c230 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -68,6 +68,10 @@ plugins: nav_file: SUMMARY.md - coverage - mkdocstrings: + handlers: + python: + import: + - https://mkdocstrings.github.io/objects.inv watch: - src/mkdocstrings diff --git a/pyproject.toml b/pyproject.toml index 9b73eb1f..4b3dec58 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description = "A Python handler for mkdocstrings." authors = [{name = "Timothée Mazzucotelli", email = "pawamoy@pm.me"}] license = {file = "LICENSE"} readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.7" keywords = [] dynamic = ["version"] classifiers = [ @@ -18,6 +18,7 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -29,7 +30,7 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "griffe~=0.4", + "griffe>=0.7.1", ] [project.urls] @@ -47,53 +48,54 @@ version = {use_scm = true} includes = ["src/mkdocstrings"] [tool.pdm.dev-dependencies] -duty = ["duty~=0.7"] +duty = ["duty>=0.7"] docs = [ - "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", + "mkdocs>=1.2", + "mkdocs-coverage>=0.2", + "mkdocs-gen-files>=0.3", + "mkdocs-literate-nav>=0.4", + "mkdocs-material>=7.3", + "mkdocs-section-index>=0.3", + "mkdocstrings>=0.16", + "toml>=0.10", ] format = [ - "autoflake~=1.4", - "black~=21.10b0", - "isort~=5.10", + "autoflake>=1.4", + "black>=21.10b0", + "isort>=5.10", ] maintain = [ # TODO: remove this section when git-changelog is more powerful - "git-changelog~=0.4", + "git-changelog>=0.4", ] quality = [ - "darglint~=1.8", - "flake8-bandit~=2.1", - "flake8-black~=0.2", - "flake8-bugbear~=21.9", - "flake8-builtins~=1.5", - "flake8-comprehensions~=3.7", - "flake8-docstrings~=1.6", - "flake8-pytest-style~=1.5", - "flake8-string-format~=0.3", - "flake8-tidy-imports~=4.5", - "flake8-variables-names~=0.0", - "pep8-naming~=0.12", - "wps-light~=0.15", + "darglint>=1.8", + "flake8-bandit>=2.1", + "flake8-black>=0.2", + "flake8-bugbear>=21.9", + "flake8-builtins>=1.5", + "flake8-comprehensions>=3.7", + "flake8-docstrings>=1.6", + "flake8-pytest-style>=1.5", + "flake8-string-format>=0.3", + "flake8-tidy-imports>=4.5", + "flake8-variables-names>=0.0", + "pep8-naming>=0.12", + "wps-light>=0.15", ] tests = [ - "pytest~=6.2", - "pytest-cov~=3.0", - "pytest-randomly~=3.10", - "pytest-sugar~=0.9", - "pytest-xdist~=2.4", + "pytest>=6.2", + "pytest-cov>=3.0", + "pytest-randomly>=3.10", + "pytest-sugar>=0.9", + "pytest-xdist>=2.4", ] typing = [ - "mypy~=0.910", - "types-markdown~=3.3", - "types-toml~=0.10", + "mypy>=0.910", + "types-markdown>=3.3", + "types-toml>=0.10", ] -security = ["safety~=1.10"] +security = ["safety>=1.10"] [tool.black] line-length = 120 diff --git a/scripts/fixsetup.sh b/scripts/fixsetup.sh new file mode 100755 index 00000000..4be38461 --- /dev/null +++ b/scripts/fixsetup.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +PYTHON_VERSIONS="${PYTHON_VERSIONS-3.7 3.8 3.9 3.10 3.11}" + +for python_version in ${PYTHON_VERSIONS}; do + rm -rf "__pypackages__/${python_version}/lib/mkdocstrings" + rm -f "__pypackages__/${python_version}/lib/mkdocstrings.pth" + rm -rf "__pypackages__/${python_version}/lib/mkdocs_autorefs" + rm -f "__pypackages__/${python_version}/lib/mkdocs_autorefs.pth" + cp -r ../mkdocstrings/src/mkdocstrings "__pypackages__/${python_version}/lib/" + cp -r src/mkdocstrings/* "__pypackages__/${python_version}/lib/mkdocstrings" + cp -r ../mkdocs-autorefs/src/mkdocs_autorefs "__pypackages__/${python_version}/lib/" +done diff --git a/scripts/multirun.sh b/scripts/multirun.sh index fb5fb2e5..609dfd44 100755 --- a/scripts/multirun.sh +++ b/scripts/multirun.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -PYTHON_VERSIONS="${PYTHON_VERSIONS-3.8 3.9 3.10 3.11}" +PYTHON_VERSIONS="${PYTHON_VERSIONS-3.7 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 19227388..f0a41cf8 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -PYTHON_VERSIONS="${PYTHON_VERSIONS-3.8 3.9 3.10 3.11}" +PYTHON_VERSIONS="${PYTHON_VERSIONS-3.7 3.8 3.9 3.10 3.11}" install_with_pipx() { if ! command -v "$1" &>/dev/null; then diff --git a/src/mkdocstrings/handlers/python/renderer.py b/src/mkdocstrings/handlers/python/renderer.py index f68babd8..77465398 100644 --- a/src/mkdocstrings/handlers/python/renderer.py +++ b/src/mkdocstrings/handlers/python/renderer.py @@ -70,6 +70,7 @@ class PythonRenderer(BaseRenderer): "show_object_full_path": False, "show_category_heading": False, "show_if_no_docstring": False, + "show_signature": True, "show_signature_annotations": False, "separate_signature": False, "line_length": 60, @@ -91,7 +92,8 @@ class PythonRenderer(BaseRenderer): **`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` + **`show_signature`** | `bool` | Show method and function signatures. | `True` + **`show_signature_annotations`** | `bool` | Show the type annotations in method and function 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` diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/raises.html b/src/mkdocstrings/templates/python/material/_base/docstring/raises.html index 1d327666..2de94208 100644 --- a/src/mkdocstrings/templates/python/material/_base/docstring/raises.html +++ b/src/mkdocstrings/templates/python/material/_base/docstring/raises.html @@ -49,19 +49,15 @@ {% for raises in section.value %} - {{ raises.name }} + + + {% with expression = raises.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {{ raises.description|convert_markdown(heading_level, html_id) }} -

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

{% endfor %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/receives.html b/src/mkdocstrings/templates/python/material/_base/docstring/receives.html index d3261f43..f6d9c821 100644 --- a/src/mkdocstrings/templates/python/material/_base/docstring/receives.html +++ b/src/mkdocstrings/templates/python/material/_base/docstring/receives.html @@ -1,16 +1,19 @@ {{ log.debug() }} {% if config.docstring_section_style == "table" %} + {% set name_column = section.value|selectattr("name")|any %}

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

+ {% if name_column %}{% endif %} - - {% with receives = section.value %} + {% for receives in section.value %} + + {% if name_column %}{% endif %} - {% endwith %} - + + {% endfor %}
NameType Description
{% if receives.name %}{{ receives.name }}{% endif %} {% if receives.annotation %} {% with expression = receives.annotation %} @@ -19,24 +22,26 @@ {% 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" %} @@ -47,21 +52,31 @@ - {% for receive in section.value %} + {% for receives in section.value %} - - + {% endfor %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/returns.html b/src/mkdocstrings/templates/python/material/_base/docstring/returns.html index d3d06f7e..1c5824b3 100644 --- a/src/mkdocstrings/templates/python/material/_base/docstring/returns.html +++ b/src/mkdocstrings/templates/python/material/_base/docstring/returns.html @@ -45,18 +45,38 @@ {% elif config.docstring_section_style == "spacy" %}
{{ receive.name }} - {{ receive.description|convert_markdown(heading_level, html_id) }} -

- {% if receive.annotation %} - +

+ {% if receives.name %} + {{ receives.name }} + {% elif receives.annotation %} + + {% with expression = receives.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} + + {{ receives.description|convert_markdown(heading_level, html_id) }} + {% if receives.name and receives.annotation %} +

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

+

+ {% endif %}
+ + + + + + - {% for returns in section.value %} + {% endfor %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/warns.html b/src/mkdocstrings/templates/python/material/_base/docstring/warns.html index 070edf9f..7285398a 100644 --- a/src/mkdocstrings/templates/python/material/_base/docstring/warns.html +++ b/src/mkdocstrings/templates/python/material/_base/docstring/warns.html @@ -49,19 +49,15 @@ {% for warns in section.value %} - + {% endfor %} diff --git a/src/mkdocstrings/templates/python/material/_base/docstring/yields.html b/src/mkdocstrings/templates/python/material/_base/docstring/yields.html index 2ba09a65..eabbedf8 100644 --- a/src/mkdocstrings/templates/python/material/_base/docstring/yields.html +++ b/src/mkdocstrings/templates/python/material/_base/docstring/yields.html @@ -1,16 +1,19 @@ {{ log.debug() }} {% if config.docstring_section_style == "table" %} + {% set name_column = section.value|selectattr("name")|any %}

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

RETURNSDESCRIPTION
RETURNS
+ {% if returns.name %} + {{ returns.name }} + {% elif returns.annotation %} + + {% with expression = returns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} + {{ returns.description|convert_markdown(heading_level, html_id) }} -

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

+ {% if returns.name and returns.annotation %} +

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

+ {% endif %}
{{ warns.name }} + + {% with expression = warns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {{ warns.description|convert_markdown(heading_level, html_id) }} -

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

+ {% if name_column %}{% endif %} - - {% with yields = section.value %} + {% for yields in section.value %} + + {% if name_column %}{% endif %} - {% endwith %} - + + {% endfor %}
NameType Description
{% if yields.name %}{{ yields.name }}{% endif %} {% if yields.annotation %} {% with expression = yields.annotation %} @@ -19,24 +22,26 @@ {% 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" %} @@ -49,19 +54,29 @@ {% for yields in section.value %} - + {% endfor %} diff --git a/src/mkdocstrings/templates/python/material/_base/signature.html b/src/mkdocstrings/templates/python/material/_base/signature.html index 74386e12..10d3bb31 100644 --- a/src/mkdocstrings/templates/python/material/_base/signature.html +++ b/src/mkdocstrings/templates/python/material/_base/signature.html @@ -1,39 +1,42 @@ {{ log.debug() }} -{%- with -%} - {%- set ns = namespace(render_pos_only_separator=True, render_kw_only_separator=True, equal="=") -%} +{%- if config.show_signature -%} + {%- with -%} - {%- if config.show_signature_annotations -%} - {%- set ns.equal = " = " -%} - {%- endif -%} + {%- set ns = namespace(render_pos_only_separator=True, render_kw_only_separator=True, equal="=") -%} - ( - {%- for parameter in function.parameters -%} + {%- if config.show_signature_annotations -%} + {%- set ns.equal = " = " -%} + {%- endif -%} - {%- 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 -%} + ( + {%- for parameter in function.parameters -%} - {%- if config.show_signature_annotations and parameter.annotation is not none -%} - {%- set annotation = ": " + parameter.annotation|safe -%} - {%- endif -%} + {%- 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 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 config.show_signature_annotations and parameter.annotation is not none -%} + {%- set annotation = ": " + parameter.annotation|safe -%} + {%- endif -%} - {%- if parameter.kind.value == "variadic positional" -%} - {%- set ns.render_kw_only_separator = False -%} - {%- 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 -%} - {{ parameter.name }}{{ annotation }}{{ default }} - {%- if not loop.last %}, {% endif -%} + {%- if parameter.kind.value == "variadic positional" -%} + {%- set ns.render_kw_only_separator = False -%} + {%- endif -%} - {%- endfor -%} - ) - {%- if config.show_signature_annotations and "return_annotation" in signature %} -> {{ signature.return_annotation }}{%- endif -%} + {{ parameter.name }}{{ annotation }}{{ default }} + {%- if not loop.last %}, {% endif -%} -{%- endwith -%} + {%- endfor -%} + ) + {%- if config.show_signature_annotations and "return_annotation" in signature %} -> {{ signature.return_annotation }}{%- endif -%} + + {%- endwith -%} +{%- endif -%} \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 3be27baf..b81fc562 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1 +1,86 @@ """Configuration for the pytest test suite.""" + +from __future__ import annotations + +from collections import ChainMap + +import pytest +from markdown.core import Markdown +from mkdocs import config + +try: + from mkdocs.config.defaults import get_schema +except ImportError: + + def get_schema() -> tuple[tuple]: # noqa: WPS440 + """Fallback for old versions of MkDocs. + + Returns: + The default schema. + """ + return config.DEFAULT_SCHEMA + + +@pytest.fixture(name="mkdocs_conf") +def fixture_mkdocs_conf(request, tmp_path): + """Yield a MkDocs configuration object. + + Parameters: + request: Pytest fixture. + tmp_path: Pytest fixture. + + Yields: + MkDocs config. + """ + conf = config.Config(schema=get_schema()) + while hasattr(request, "_parent_request") and hasattr(request._parent_request, "_parent_request"): # noqa: WPS437 + request = request._parent_request # noqa: WPS437 + + conf_dict = { + "site_name": "foo", + "site_url": "https://example.org/", + "site_dir": str(tmp_path), + "plugins": [{"mkdocstrings": {"default_handler": "python"}}], + **getattr(request, "param", {}), + } + # Re-create it manually as a workaround for https://github.com/mkdocs/mkdocs/issues/2289 + mdx_configs = dict(ChainMap(*conf_dict.get("markdown_extensions", []))) + + conf.load_dict(conf_dict) + assert conf.validate() == ([], []) + + conf["mdx_configs"] = mdx_configs + conf["markdown_extensions"].insert(0, "toc") # Guaranteed to be added by MkDocs. + + conf = conf["plugins"]["mkdocstrings"].on_config(conf) + conf = conf["plugins"]["autorefs"].on_config(conf) + yield conf + conf["plugins"]["mkdocstrings"].on_post_build(conf) + + +@pytest.fixture(name="plugin") +def fixture_plugin(mkdocs_conf): + """Return a plugin instance. + + Parameters: + mkdocs_conf: Pytest fixture: [tests.conftest.fixture_mkdocs_conf][]. + + Returns: + mkdocstrings plugin instance. + """ + plugin = mkdocs_conf["plugins"]["mkdocstrings"] + plugin.md = Markdown(extensions=mkdocs_conf["markdown_extensions"], extension_configs=mkdocs_conf["mdx_configs"]) + return plugin + + +@pytest.fixture(name="ext_markdown") +def fixture_ext_markdown(plugin): + """Return a Markdown instance with MkdocstringsExtension. + + Parameters: + plugin: Pytest fixture: [tests.conftest.fixture_plugin][]. + + Returns: + A Markdown instance. + """ + return plugin.md diff --git a/tests/test_cli.py b/tests/test_cli.py deleted file mode 100644 index 652c09d0..00000000 --- a/tests/test_cli.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Tests for the `cli` module.""" - -import pytest - -from mkdocstrings import cli - - -def test_main(): - """Basic CLI test.""" - assert cli.main([]) == 0 - - -def test_show_help(capsys): - """ - Show help. - - Arguments: - capsys: Pytest fixture to capture output. - """ - with pytest.raises(SystemExit): - cli.main(["-h"]) - captured = capsys.readouterr() - assert "mkdocstrings-python" in captured.out diff --git a/tests/test_collector.py b/tests/test_collector.py new file mode 100644 index 00000000..23513436 --- /dev/null +++ b/tests/test_collector.py @@ -0,0 +1,25 @@ +"""Tests for the handlers.python module.""" + +import pytest + +from mkdocstrings.handlers.python.collector import CollectionError, PythonCollector + + +def test_collect_missing_module(): + """Assert error is raised for missing modules.""" + collector = PythonCollector() + with pytest.raises(CollectionError): + collector.collect("aaaaaaaa", {}) + + +def test_collect_missing_module_item(): + """Assert error is raised for missing items within existing modules.""" + collector = PythonCollector() + with pytest.raises(CollectionError): + collector.collect("mkdocstrings.aaaaaaaa", {}) + + +def test_collect_module(): + """Assert existing module can be collected.""" + collector = PythonCollector() + assert collector.collect("mkdocstrings", {}) diff --git a/tests/test_themes.py b/tests/test_themes.py new file mode 100644 index 00000000..779e4433 --- /dev/null +++ b/tests/test_themes.py @@ -0,0 +1,40 @@ +"""Tests for the different themes we claim to support.""" + +import sys + +import pytest + + +@pytest.mark.parametrize( + "plugin", + [ + {"theme": "mkdocs"}, + {"theme": "readthedocs"}, + {"theme": {"name": "material"}}, + ], + indirect=["plugin"], +) +@pytest.mark.parametrize( + "module", + [ + "mkdocstrings.extension", + "mkdocstrings.inventory", + "mkdocstrings.loggers", + "mkdocstrings.plugin", + "mkdocstrings.handlers.base", + "mkdocstrings.handlers.python", + "mkdocstrings.handlers.rendering", + ], +) +@pytest.mark.skipif(sys.version_info < (3, 7), reason="material is not installed on Python 3.6") +def test_render_themes_templates_python(module, plugin): + """Test rendering of a given theme's templates. + + Parameters: + module: Parametrized argument. + plugin: Pytest fixture: [tests.conftest.fixture_plugin][]. + """ + handler = plugin.handlers.get_handler("python") + handler.renderer._update_env(plugin.md, plugin.handlers._config) # noqa: WPS437 + data = handler.collector.collect(module, {}) + handler.renderer.render(data, {})
{{ yields.name }} + {% if yields.name %} + {{ yields.name }} + {% elif yields.annotation %} + + {% with expression = yields.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} + {{ yields.description|convert_markdown(heading_level, html_id) }} -

- {% if yields.annotation %} + {% if yields.name and yields.annotation %} +

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

+

+ {% endif %}