diff --git a/.copier-answers.yml b/.copier-answers.yml
index 62b9e3c8..c720007f 100644
--- a/.copier-answers.yml
+++ b/.copier-answers.yml
@@ -1,5 +1,5 @@
# Changes here will be overwritten by Copier
-_commit: 0.15.7
+_commit: 0.16.6
_src_path: gh:pawamoy/copier-pdm.git
author_email: pawamoy@pm.me
author_fullname: Timothée Mazzucotelli
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2b5ed158..f4a3f0cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,7 +4,7 @@ on:
push:
pull_request:
branches:
- - master
+ - main
defaults:
run:
@@ -26,6 +26,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
+ - name: Fetch all tags
+ run: git fetch --depth=1 --tags
+
- name: Set up PDM
uses: pdm-project/setup-pdm@v3
with:
@@ -52,8 +55,29 @@ jobs:
- name: Check for breaking changes in the API
run: pdm run duty check-api
+ exclude-test-jobs:
+ runs-on: ubuntu-latest
+ outputs:
+ jobs: ${{ steps.exclude-jobs.outputs.jobs }}
+ steps:
+ - id: exclude-jobs
+ run: |
+ if ${{ github.repository_owner == 'pawamoy-insiders' }}; then
+ echo 'jobs=[
+ {"os": "macos-latest"},
+ {"os": "windows-latest"},
+ {"python-version": "3.9"},
+ {"python-version": "3.10"},
+ {"python-version": "3.11"},
+ {"python-version": "3.12"}
+ ]' | tr -d '[:space:]' >> $GITHUB_OUTPUT
+ else
+ echo 'jobs=[]' >> $GITHUB_OUTPUT
+ fi
+
tests:
+ needs: exclude-test-jobs
strategy:
max-parallel: 4
matrix:
@@ -62,13 +86,14 @@ jobs:
- macos-latest
- windows-latest
python-version:
- - "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
-
+ - "3.12"
+ exclude: ${{ fromJSON(needs.exclude-test-jobs.outputs.jobs) }}
runs-on: ${{ matrix.os }}
+ continue-on-error: ${{ matrix.python-version == '3.12' }}
steps:
- name: Checkout
@@ -78,6 +103,7 @@ jobs:
uses: pdm-project/setup-pdm@v3
with:
python-version: ${{ matrix.python-version }}
+ allow-python-prereleases: true
- name: Resolving dependencies
run: pdm lock -v --no-cross-platform -G ci-tests
diff --git a/.github/workflows/dists.yml b/.github/workflows/dists.yml
deleted file mode 100644
index 41833b63..00000000
--- a/.github/workflows/dists.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: dists
-
-on: push
-permissions:
- contents: write
-
-jobs:
- build:
- name: Build dists
- runs-on: ubuntu-latest
- if: github.repository_owner == 'pawamoy-insiders'
- steps:
- - name: Checkout
- uses: actions/checkout@v3
- - name: Setup Python
- uses: actions/setup-python@v3
- - name: Install build
- run: python -m pip install build
- - name: Build dists
- run: python -m build
- - name: Upload dists artifact
- uses: actions/upload-artifact@v3
- with:
- name: mkdocstrings-insiders
- path: ./dist/*
- - name: Create release and upload assets
- uses: softprops/action-gh-release@v1
- if: startsWith(github.ref, 'refs/tags/')
- with:
- files: ./dist/*
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..1baebea4
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,45 @@
+name: release
+
+on: push
+permissions:
+ contents: write
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ if: startsWith(github.ref, 'refs/tags/')
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Fetch all tags
+ run: git fetch --depth=1 --tags
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ - name: Install build
+ if: github.repository_owner == 'pawamoy-insiders'
+ run: python -m pip install build
+ - name: Build dists
+ if: github.repository_owner == 'pawamoy-insiders'
+ run: python -m build
+ - name: Upload dists artifact
+ uses: actions/upload-artifact@v3
+ if: github.repository_owner == 'pawamoy-insiders'
+ with:
+ name: mkdocstrings-insiders
+ path: ./dist/*
+ - name: Install git-changelog
+ if: github.repository_owner != 'pawamoy-insiders'
+ run: pip install git-changelog
+ - name: Prepare release notes
+ if: github.repository_owner != 'pawamoy-insiders'
+ run: git-changelog --release-notes > release-notes.md
+ - name: Create release with assets
+ uses: softprops/action-gh-release@v1
+ if: github.repository_owner == 'pawamoy-insiders'
+ with:
+ files: ./dist/*
+ - name: Create release
+ uses: softprops/action-gh-release@v1
+ if: github.repository_owner != 'pawamoy-insiders'
+ with:
+ body_path: release-notes.md
diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile
index 33f285c2..0e6d9d35 100644
--- a/.gitpod.dockerfile
+++ b/.gitpod.dockerfile
@@ -1,7 +1,6 @@
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/CHANGELOG.md b/CHANGELOG.md
index bbeb8ce6..fc3a0fb0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,34 @@ 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.23.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.23.0) - 2023-08-28
+
+[Compare with 0.22.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.22.0...0.23.0)
+
+### Breaking Changes
+
+- Removed `BaseCollector` and `BaseRenderer` classes: they were merged into the `BaseHandler` class.
+- Removed the watch feature, as MkDocs now provides it natively.
+- Removed support for `selection` and `rendering` keys in YAML blocks: use `options` instead.
+- Removed support for loading handlers from the `mkdocstrings.handler` namespace.
+ Handlers must now be packaged under the `mkdocstrings_handlers` namespace.
+
+### Features
+
+- Register all anchors for each object in the inventory ([228fb73](https://github.com/mkdocstrings/mkdocstrings/commit/228fb737caca4e20e600053bf59cbfa3e9c73906) by Timothée Mazzucotelli).
+
+### Bug Fixes
+
+- Don't add `codehilite` CSS class to inline code ([7690d41](https://github.com/mkdocstrings/mkdocstrings/commit/7690d41e2871997464367e673023585c4fb05e26) by Timothée Mazzucotelli).
+- Support cross-references for API docs rendered in top-level index page ([b194452](https://github.com/mkdocstrings/mkdocstrings/commit/b194452be93aee33b3c28a468762b4d96c501f4f) by Timothée Mazzucotelli).
+
+### Code Refactoring
+
+- Sort inventories before writing them to disk ([9371e9f](https://github.com/mkdocstrings/mkdocstrings/commit/9371e9fc7dd68506b73aa1580a12c5f5cd779aba) by Timothée Mazzucotelli).
+- Stop accepting sets as return value of `get_anchors` (only tuples), to preserve order ([2e10374](https://github.com/mkdocstrings/mkdocstrings/commit/2e10374be258e9713b26f73dd06d0c2520ec07a5) by Timothée Mazzucotelli).
+- Remove deprecated parts ([0a90a47](https://github.com/mkdocstrings/mkdocstrings/commit/0a90a474c8dcbd95821700d7dab63f03e392c40f) by Timothée Mazzucotelli).
+- Use proper parameters in `Inventory.register` method ([433c6e0](https://github.com/mkdocstrings/mkdocstrings/commit/433c6e01aab9333589f755e483f124db0836f143) by Timothée Mazzucotelli).
+
## [0.22.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.22.0) - 2023-05-25
[Compare with 0.21.2](https://github.com/mkdocstrings/mkdocstrings/compare/0.21.2...0.22.0)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4ecc0fa0..0b86ff4b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -39,20 +39,19 @@ Run `make help` to see all the available actions!
This project uses [duty](https://github.com/pawamoy/duty) to run tasks.
A Makefile is also provided. The Makefile will try to run certain tasks
on multiple Python versions. If for some reason you don't want to run the task
-on multiple Python versions, you can do one of the following:
-
-1. `export PYTHON_VERSIONS= `: this will run the task
- with only the current Python version
-2. run the task directly with `pdm run duty TASK`
+on multiple Python versions, you run the task directly with `pdm run duty TASK`.
The Makefile detects if a virtual environment is activated,
so `make` will work the same with the virtualenv activated or not.
+If you work in VSCode,
+[see examples of tasks and run configurations](https://pawamoy.github.io/copier-pdm/work/#vscode-setup).
+
## Development
As usual:
-1. create a new branch: `git checkout -b feature-or-bugfix-name`
+1. create a new branch: `git switch -c feature-or-bugfix-name`
1. edit the code and/or the documentation
**Before committing:**
@@ -138,7 +137,7 @@ git commit --fixup=SHA
Once all the changes are approved, you can squash your commits:
```bash
-git rebase -i --autosquash master
+git rebase -i --autosquash main
```
And force-push:
diff --git a/Makefile b/Makefile
index b71d86ce..5696baac 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
.DEFAULT_GOAL := help
SHELL := bash
-
-DUTY = $(shell [ -n "${VIRTUAL_ENV}" ] || echo pdm run) duty
+DUTY := $(if $(VIRTUAL_ENV),,pdm run) duty
+export PDM_MULTIRUN_VERSIONS ?= 3.8 3.9 3.10 3.11 3.12
args = $(foreach a,$($(subst -,_,$1)_args),$(if $(value $a),$a="$($a)"))
check_quality_args = files
diff --git a/README.md b/README.md
index 52300c96..06872728 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,18 @@ Come have a chat or ask questions on our [Gitter channel](https://gitter.im/mkdo
- **Reasonable defaults:**
you should be able to just drop the plugin in your configuration and enjoy your auto-generated docs.
+## Used by
+
+*mkdocstrings* is used by well-known companies, projects and scientific teams:
+[Ansible](https://molecule.readthedocs.io/configuration/),
+[Apache](https://streampipes.apache.org/docs/docs/python/latest/reference/client/client/),
+[Google](https://docs.kidger.site/jaxtyping/api/runtime-type-checking/),
+[Jitsi](https://jitsi.github.io/jiwer/reference/alignment/),
+[Microsoft](https://microsoft.github.io/presidio/api/analyzer_python/),
+[Prefect](https://docs.prefect.io/2.10.12/api-ref/prefect/agent/),
+[Pydantic](https://docs.pydantic.dev/dev-v2/api/main/),
+[and more...](https://github.com/mkdocstrings/mkdocstrings/network/dependents)
+
## Installation
With `pip`:
diff --git a/config/mypy.ini b/config/mypy.ini
index cb0dd886..814e2ac8 100644
--- a/config/mypy.ini
+++ b/config/mypy.ini
@@ -3,5 +3,3 @@ ignore_missing_imports = true
exclude = tests/fixtures/
warn_unused_ignores = true
show_error_codes = true
-namespace_packages = true
-explicit_package_bases = true
diff --git a/config/pytest.ini b/config/pytest.ini
index 5a493959..6b0d5c7a 100644
--- a/config/pytest.ini
+++ b/config/pytest.ini
@@ -20,3 +20,7 @@ filterwarnings =
error
# TODO: remove once pytest-xdist 4 is released
ignore:.*rsyncdir:DeprecationWarning:xdist
+ # TODO: https://github.com/Python-Markdown/markdown/issues/1355
+ ignore:.*Testing:DeprecationWarning:markdown
+ # TODO: https://github.com/facelessuser/pymdown-extensions/issues/2113
+ ignore:.*Testing:DeprecationWarning:pymdownx
diff --git a/config/ruff.toml b/config/ruff.toml
index 53824875..c6e4a55c 100644
--- a/config/ruff.toml
+++ b/config/ruff.toml
@@ -1,4 +1,4 @@
-target-version = "py37"
+target-version = "py38"
line-length = 132
exclude = [
"fixtures",
@@ -65,7 +65,6 @@ ignore = [
"E501", # Line too long
"ERA001", # Commented out code
"G004", # Logging statement uses f-string
- "INP001", # File is part of an implicit namespace package
"PLR0911", # Too many return statements
"PLR0912", # Too many branches
"PLR0913", # Too many arguments to function call
diff --git a/docs/css/insiders.css b/docs/css/insiders.css
index 81dbd756..b5547bd1 100644
--- a/docs/css/insiders.css
+++ b/docs/css/insiders.css
@@ -95,4 +95,31 @@ a.insiders {
transition: all .25s;
vertical-align: bottom !important;
width: 1.2rem;
+}
+
+.premium-sponsors {
+ text-align: center;
+}
+
+#silver-sponsors img {
+ height: 140px;
+}
+
+#bronze-sponsors img {
+ height: 140px;
+}
+
+#bronze-sponsors p {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+
+#bronze-sponsors a {
+ display: block;
+ flex-shrink: 0;
+}
+
+.sponsors-total {
+ font-weight: bold;
}
\ No newline at end of file
diff --git a/docs/css/mkdocstrings.css b/docs/css/mkdocstrings.css
index af758331..3960e49e 100644
--- a/docs/css/mkdocstrings.css
+++ b/docs/css/mkdocstrings.css
@@ -5,24 +5,23 @@ div.doc-contents:not(.first) {
}
/* Mark external links as such. */
+a.external::after,
a.autorefs-external::after {
/* https://primer.style/octicons/arrow-up-right-24 */
- background-image: url('data:image/svg+xml,');
+ mask-image: url('data:image/svg+xml,');
+ -webkit-mask-image: url('data:image/svg+xml,');
content: ' ';
display: inline-block;
vertical-align: middle;
position: relative;
- bottom: 0.1em;
- margin-left: 0.2em;
- margin-right: 0.1em;
- height: 0.7em;
- width: 0.7em;
- border-radius: 100%;
+ height: 1em;
+ width: 1em;
background-color: var(--md-typeset-a-color);
}
+a.external:hover::after,
a.autorefs-external:hover::after {
background-color: var(--md-accent-fg-color);
}
diff --git a/docs/insiders/goals.yml b/docs/insiders/goals.yml
index 896b9240..a96ac51b 100644
--- a/docs/insiders/goals.yml
+++ b/docs/insiders/goals.yml
@@ -1 +1 @@
-goals: {}
+goals: {}
\ No newline at end of file
diff --git a/docs/insiders/index.md b/docs/insiders/index.md
index 0f5b0de9..bfb2d428 100644
--- a/docs/insiders/index.md
+++ b/docs/insiders/index.md
@@ -59,6 +59,8 @@ a handful of them, [thanks to our awesome sponsors][sponsors]! -->
data_source = [
"docs/insiders/goals.yml",
("mkdocstrings-python", "https://mkdocstrings.github.io/python/", "insiders/goals.yml"),
+ ("griffe-pydantic", "https://mkdocstrings.github.io/griffe-pydantic/", "insiders/goals.yml"),
+ ("griffe-typing-deprecated", "https://mkdocstrings.github.io/griffe-typing-deprecated/", "insiders/goals.yml"),
]
```
@@ -68,10 +70,10 @@ data_source = [
```python exec="1" session="insiders"
print(f"""The moment you become a sponsor, you'll get **immediate
-access to {len(completed_features)} additional features** that you can start using right away, and
+access to {len(unreleased_features)} additional features** that you can start using right away, and
which are currently exclusively available to sponsors:\n""")
-for feature in completed_features:
+for feature in unreleased_features:
feature.render(badge=True)
```
@@ -112,17 +114,20 @@ You can cancel your sponsorship anytime.[^5]
regarding your payment, and GitHub doesn't offer refunds, sponsorships are
non-refundable.
-```python exec="1" session="insiders"
-print_join_sponsors_button()
-```
+[:octicons-heart-fill-24:{ .pulse } Join our awesome sponsors](https://github.com/sponsors/pawamoy){ .md-button .md-button--primary }
-
+
'
+ sponsors.forEach(function (sponsor) {
+ html += `
+
+
+
+ `
+ });
+ html += '
'
for path in sorted(Path("src").rglob("*.py")):
module_path = path.relative_to("src").with_suffix("")
- doc_path = path.relative_to("src", "mkdocstrings").with_suffix(".md")
+ doc_path = path.relative_to("src/mkdocstrings").with_suffix(".md")
full_doc_path = Path("reference", doc_path)
parts = tuple(module_path.parts)
@@ -20,13 +21,14 @@
elif parts[-1].startswith("_"):
continue
- nav[parts] = doc_path.as_posix()
+ nav_parts = [f"{mod_symbol} {part}" for part in parts]
+ nav[tuple(nav_parts)] = doc_path.as_posix()
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
ident = ".".join(parts)
fd.write(f"::: {ident}")
- mkdocs_gen_files.set_edit_path(full_doc_path, Path("../") / path)
+ mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path)
with mkdocs_gen_files.open("reference/SUMMARY.txt", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())
diff --git a/scripts/insiders.py b/scripts/insiders.py
index 0d23a45a..6f8d0d84 100644
--- a/scripts/insiders.py
+++ b/scripts/insiders.py
@@ -9,7 +9,6 @@
from datetime import date, datetime, timedelta
from itertools import chain
from pathlib import Path
-from textwrap import dedent
from typing import Iterable, cast
from urllib.error import HTTPError
from urllib.parse import urljoin
@@ -101,7 +100,7 @@ def load_goals(data: str, funding: int = 0, project: Project | None = None) -> d
Feature(
name=feature_data["name"],
ref=feature_data["ref"],
- since=feature_data["since"]
+ since=feature_data.get("since")
and datetime.strptime(feature_data["since"], "%Y/%m/%d").date(), # noqa: DTZ007
project=project,
)
@@ -185,32 +184,9 @@ def load_json(url: str) -> str | list | dict: # noqa: D103
current_funding = numbers["total"]
sponsors_count = numbers["count"]
goals = funding_goals(data_source, funding=current_funding)
-all_features = feature_list(goals.values())
-completed_features = sorted(
- (ft for ft in all_features if ft.since),
+ongoing_goals = [goal for goal in goals.values() if not goal.complete]
+unreleased_features = sorted(
+ (ft for ft in feature_list(ongoing_goals) if ft.since),
key=lambda ft: cast(date, ft.since),
reverse=True,
)
-
-
-def print_join_sponsors_button() -> None: # noqa: D103
- btn_classes = "{ .md-button .md-button--primary }"
- print(
- dedent(
- f"""
- [:octicons-heart-fill-24:{{ .pulse }}
- Join our {sponsors_count} awesome sponsors]({sponsor_url}){btn_classes}
- """,
- ),
- )
-
-
-def print_sponsors() -> None: # noqa: D103
- private_sponsors_count = sponsors_count - len(sponsors)
- for sponsor in sponsors:
- print(
- f""""""
- f"""{result.text}')
+ # From the maintainer of codehilite, the codehilite CSS class, as defined by the user,
+ # should never be added to inline code, because codehilite does not support inline code.
+ # See https://github.com/Python-Markdown/markdown/issues/1220#issuecomment-1692160297.
+ css_class = "" if self._highlighter == "codehilite" else kwargs["css_class"]
+ return Markup(f'{result.text}')
return Markup(result)
diff --git a/src/mkdocstrings/inventory.py b/src/mkdocstrings/inventory.py
index 42e9b3db..f1c8962a 100644
--- a/src/mkdocstrings/inventory.py
+++ b/src/mkdocstrings/inventory.py
@@ -20,7 +20,7 @@ def __init__(
domain: str,
role: str,
uri: str,
- priority: str = "1",
+ priority: int = 1,
dispname: str | None = None,
):
"""Initialize the object.
@@ -30,14 +30,14 @@ def __init__(
domain: The item domain, like 'python' or 'crystal'.
role: The item role, like 'class' or 'method'.
uri: The item URI.
- priority: The item priority. It can help for inventory suggestions.
+ priority: The item priority. Only used internally by mkdocstrings and Sphinx.
dispname: The item display name.
"""
self.name: str = name
self.domain: str = domain
self.role: str = role
self.uri: str = uri
- self.priority: str = priority
+ self.priority: int = priority
self.dispname: str = dispname or name
def format_sphinx(self) -> str:
@@ -67,7 +67,7 @@ def parse_sphinx(cls, line: str) -> InventoryItem:
uri = uri[:-1] + name
if dispname == "-":
dispname = name
- return cls(name, domain, role, uri, priority, dispname)
+ return cls(name, domain, role, uri, int(priority), dispname)
class Inventory(dict):
@@ -88,15 +88,33 @@ def __init__(self, items: list[InventoryItem] | None = None, project: str = "pro
self.project = project
self.version = version
- def register(self, *args: str, **kwargs: str) -> None:
+ def register(
+ self,
+ name: str,
+ domain: str,
+ role: str,
+ uri: str,
+ priority: int = 1,
+ dispname: str | None = None,
+ ) -> None:
"""Create and register an item.
Arguments:
- *args: Arguments passed to [InventoryItem][mkdocstrings.inventory.InventoryItem].
- **kwargs: Keyword arguments passed to [InventoryItem][mkdocstrings.inventory.InventoryItem].
+ name: The item name.
+ domain: The item domain, like 'python' or 'crystal'.
+ role: The item role, like 'class' or 'method'.
+ uri: The item URI.
+ priority: The item priority. Only used internally by mkdocstrings and Sphinx.
+ dispname: The item display name.
"""
- item = InventoryItem(*args, **kwargs)
- self[item.name] = item
+ self[name] = InventoryItem(
+ name=name,
+ domain=domain,
+ role=role,
+ uri=uri,
+ priority=priority,
+ dispname=dispname,
+ )
def format_sphinx(self) -> bytes:
"""Format this inventory as a Sphinx `objects.inv` file.
@@ -117,7 +135,10 @@ def format_sphinx(self) -> bytes:
.encode("utf8")
)
- lines = [item.format_sphinx().encode("utf8") for item in self.values()]
+ lines = [
+ item.format_sphinx().encode("utf8")
+ for item in sorted(self.values(), key=lambda item: (item.domain, item.name))
+ ]
return header + zlib.compress(b"\n".join(lines) + b"\n", 9)
@classmethod
@@ -129,7 +150,7 @@ def parse_sphinx(cls, in_file: BinaryIO, *, domain_filter: Collection[str] = ())
domain_filter: A collection of domain values to allow (and filter out all other ones).
Returns:
- An `Inventory` containing the collected `InventoryItem`s.
+ An inventory containing the collected items.
"""
for _ in range(4):
in_file.readline()
diff --git a/src/mkdocstrings/plugin.py b/src/mkdocstrings/plugin.py
index 4c902935..484d3ead 100644
--- a/src/mkdocstrings/plugin.py
+++ b/src/mkdocstrings/plugin.py
@@ -34,7 +34,7 @@
if TYPE_CHECKING:
from jinja2.environment import Environment
from mkdocs.config import Config
- from mkdocs.livereload import LiveReloadServer
+ from mkdocs.config.defaults import MkDocsConfig
if sys.version_info < (3, 10):
from typing_extensions import ParamSpec
@@ -43,11 +43,6 @@
log = get_logger(__name__)
-SELECTION_OPTS_KEY: str = "selection"
-"""Deprecated. The name of the selection parameter in YAML configuration blocks."""
-RENDERING_OPTS_KEY: str = "rendering"
-"""Deprecated. The name of the rendering parameter in YAML configuration blocks."""
-
InventoryImportType = List[Tuple[str, Mapping[str, Any]]]
InventoryLoaderType = Callable[..., Iterable[Tuple[str, str]]]
@@ -75,14 +70,12 @@ class MkdocstringsPlugin(BasePlugin):
- `on_config`
- `on_env`
- `on_post_build`
- - `on_serve`
Check the [Developing Plugins](https://www.mkdocs.org/user-guide/plugins/#developing-plugins) page of `mkdocs`
for more information about its plugin system.
"""
- config_scheme: tuple[tuple[str, MkType]] = (
- ("watch", MkType(list, default=[])), # type: ignore[assignment]
+ config_scheme: tuple[tuple[str, MkType]] = ( # type: ignore[assignment]
("handlers", MkType(dict, default={})),
("default_handler", MkType(str, default="python")),
("custom_templates", MkType(str, default=None)),
@@ -94,13 +87,12 @@ class MkdocstringsPlugin(BasePlugin):
Available options are:
- - **`watch` (deprecated)**: A list of directories to watch. Only used when serving the documentation with mkdocs.
- Whenever a file changes in one of directories, the whole documentation is built again, and the browser refreshed.
- Deprecated in favor of the now built-in `watch` feature of MkDocs.
- - **`default_handler`**: The default handler to use. The value is the name of the handler module. Default is "python".
- - **`enabled`**: Whether to enable the plugin. Default is true. If false, *mkdocstrings* will not collect or render anything.
- **`handlers`**: Global configuration of handlers. You can set global configuration per handler, applied everywhere,
but overridable in each "autodoc" instruction. Example:
+ - **`default_handler`**: The default handler to use. The value is the name of the handler module. Default is "python".
+ - **`custom_templates`**: Custom templates to use when rendering API objects.
+ - **`enable_inventory`**: Whether to enable object inventory creation.
+ - **`enabled`**: Whether to enable the plugin. Default is true. If false, *mkdocstrings* will not collect or render anything.
```yaml
plugins:
@@ -108,11 +100,11 @@ class MkdocstringsPlugin(BasePlugin):
handlers:
python:
options:
- selection_opt: true
- rendering_opt: "value"
+ option1: true
+ option2: "value"
rust:
options:
- selection_opt: 2
+ option9: 2
```
"""
@@ -137,37 +129,7 @@ def handlers(self) -> Handlers:
raise RuntimeError("The plugin hasn't been initialized with a config yet")
return self._handlers
- # TODO: remove once watch feature is removed
- def on_serve(
- self,
- server: LiveReloadServer,
- config: Config, # noqa: ARG002
- builder: Callable,
- *args: Any, # noqa: ARG002
- **kwargs: Any, # noqa: ARG002
- ) -> None:
- """Watch directories.
-
- Hook for the [`on_serve` event](https://www.mkdocs.org/user-guide/plugins/#on_serve).
- In this hook, we add the directories specified in the plugin's configuration to the list of directories
- watched by `mkdocs`. Whenever a change occurs in one of these directories, the documentation is built again
- and the site reloaded.
-
- Arguments:
- server: The `livereload` server instance.
- config: The MkDocs config object (unused).
- builder: The function to build the site.
- *args: Additional arguments passed by MkDocs.
- **kwargs: Additional arguments passed by MkDocs.
- """
- if not self.plugin_enabled:
- return
- if self.config["watch"]:
- for element in self.config["watch"]:
- log.debug(f"Adding directory '{element}' to watcher")
- server.watch(element, builder)
-
- def on_config(self, config: Config, **kwargs: Any) -> Config: # noqa: ARG002
+ def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
"""Instantiate our Markdown extension.
Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config).
@@ -179,7 +141,6 @@ def on_config(self, config: Config, **kwargs: Any) -> Config: # noqa: ARG002
Arguments:
config: The MkDocs config object.
- **kwargs: Additional arguments passed by MkDocs.
Returns:
The modified config.
@@ -238,9 +199,6 @@ def on_config(self, config: Config, **kwargs: Any) -> Config: # noqa: ARG002
self._inv_futures[future] = (loader, import_item)
inv_loader.shutdown(wait=False)
- if self.config["watch"]:
- self._warn_about_watch_option()
-
return config
@property
@@ -311,7 +269,7 @@ def on_post_build(
For example, a handler could open a subprocess in the background and keep it open
to feed it "autodoc" instructions and get back JSON data. If so, it should then close the subprocess at some point:
- the proper place to do this is in the collector's `teardown` method, which is indirectly called by this hook.
+ the proper place to do this is in the handler's `teardown` method, which is indirectly called by this hook.
Arguments:
config: The MkDocs config object.
@@ -362,11 +320,3 @@ def _load_inventory(cls, loader: InventoryLoaderType, url: str, **kwargs: Any) -
result = dict(loader(content, url=url, **kwargs))
log.debug(f"Loaded inventory from {url!r}: {len(result)} items")
return result
-
- @classmethod
- @functools.lru_cache(maxsize=None) # Warn only once
- def _warn_about_watch_option(cls) -> None:
- log.info(
- "DEPRECATION: mkdocstrings' watch feature is deprecated in favor of MkDocs' watch feature, "
- "see https://www.mkdocs.org/user-guide/configuration/#watch",
- )
diff --git a/tests/conftest.py b/tests/conftest.py
index a2ea6b26..2119d1f3 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -24,6 +24,7 @@ def fixture_mkdocs_conf(request: pytest.FixtureRequest, tmp_path: Path) -> Itera
request = request._parent_request
conf_dict = {
+ "config_file_path": "mkdocs_tests.yml",
"site_name": "foo",
"site_url": "https://example.org/",
"site_dir": str(tmp_path),
@@ -31,7 +32,7 @@ def fixture_mkdocs_conf(request: pytest.FixtureRequest, tmp_path: Path) -> Itera
**getattr(request, "param", {}),
}
# Re-create it manually as a workaround for https://github.com/mkdocs/mkdocs/issues/2289
- mdx_configs: dict[str, Any] = dict(ChainMap(*conf_dict.get("markdown_extensions", []))) # type: ignore[arg-type]
+ mdx_configs: dict[str, Any] = dict(ChainMap(*conf_dict.get("markdown_extensions", [])))
conf.load_dict(conf_dict)
assert conf.validate() == ([], [])
diff --git a/tests/test_extension.py b/tests/test_extension.py
index f7c3cecc..8c687629 100644
--- a/tests/test_extension.py
+++ b/tests/test_extension.py
@@ -2,7 +2,6 @@
from __future__ import annotations
-import logging
import re
import sys
from textwrap import dedent
@@ -138,7 +137,7 @@ def test_use_custom_handler(ext_markdown: Markdown) -> None:
def test_dont_register_every_identifier_as_anchor(plugin: MkdocstringsPlugin, ext_markdown: Markdown) -> None:
"""Assert that we don't preemptively register all identifiers of a rendered object."""
handler = plugin._handlers.get_handler("python") # type: ignore[union-attr]
- ids = {"id1", "id2", "id3"}
+ ids = ("id1", "id2", "id3")
handler.get_anchors = lambda _: ids # type: ignore[method-assign]
ext_markdown.convert("::: tests.fixtures.headings")
autorefs = ext_markdown.parser.blockprocessors["mkdocstrings"]._autorefs
@@ -147,14 +146,7 @@ def test_dont_register_every_identifier_as_anchor(plugin: MkdocstringsPlugin, ex
assert identifier not in autorefs._abs_url_map
-def test_use_deprecated_yaml_keys(ext_markdown: Markdown, caplog: pytest.LogCaptureFixture) -> None:
- """Check that using the deprecated 'selection' and 'rendering' YAML keys emits a deprecation warning."""
- caplog.set_level(logging.INFO)
- assert "h1" not in ext_markdown.convert("::: tests.fixtures.headings\n rendering:\n heading_level: 2")
- assert "single 'options' YAML key" in caplog.text
-
-
-def test_use_new_options_yaml_key(ext_markdown: Markdown) -> None:
- """Check that using the new 'options' YAML key works as expected."""
+def test_use_options_yaml_key(ext_markdown: Markdown) -> None:
+ """Check that using the 'options' YAML key works as expected."""
assert "h1" in ext_markdown.convert("::: tests.fixtures.headings\n options:\n heading_level: 1")
assert "h1" not in ext_markdown.convert("::: tests.fixtures.headings\n options:\n heading_level: 2")
diff --git a/tests/test_handlers.py b/tests/test_handlers.py
index 777173e8..4a07e98b 100644
--- a/tests/test_handlers.py
+++ b/tests/test_handlers.py
@@ -2,17 +2,17 @@
from __future__ import annotations
-from contextlib import suppress
-from pathlib import Path
from typing import TYPE_CHECKING
import pytest
from jinja2.exceptions import TemplateNotFound
from markdown import Markdown
-from mkdocstrings.handlers.base import BaseRenderer, Highlighter
+from mkdocstrings.handlers.base import Highlighter
if TYPE_CHECKING:
+ from pathlib import Path
+
from mkdocstrings.plugin import MkdocstringsPlugin
@@ -32,7 +32,7 @@ def test_highlighter_without_pygments(extension_name: str) -> None:
)
assert (
hl.highlight("import foo", language="python", inline=True)
- == 'import foo'
+ == f'import foo'
)
@@ -53,30 +53,25 @@ def test_highlighter_basic(extension_name: str | None, inline: bool) -> None:
assert "import foo" not in actual # Highlighting has split it up.
-@pytest.fixture(name="extended_templates")
-def fixture_extended_templates(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> Path: # noqa: D103
- monkeypatch.setattr(BaseRenderer, "get_extended_templates_dirs", lambda self, handler: [tmp_path])
- return tmp_path
-
-
-def test_extended_templates(extended_templates: Path, plugin: MkdocstringsPlugin) -> None:
+def test_extended_templates(tmp_path: Path, plugin: MkdocstringsPlugin) -> None:
"""Test the extended templates functionality.
Parameters:
- extended_templates: Temporary folder.
+ tmp_path: Temporary folder.
plugin: Instance of our plugin.
"""
handler = plugin._handlers.get_handler("python") # type: ignore[union-attr]
- # assert mocked method added temp path to loader
- search_paths = handler.env.loader.searchpath # type: ignore[union-attr]
- assert any(str(extended_templates) in path for path in search_paths)
+ # monkeypatch Jinja env search path
+ search_paths = [
+ base_theme := tmp_path / "base_theme",
+ base_fallback_theme := tmp_path / "base_fallback_theme",
+ extended_theme := tmp_path / "extended_theme",
+ extended_fallback_theme := tmp_path / "extended_fallback_theme",
+ ]
+ handler.env.loader.searchpath = search_paths # type: ignore[union-attr]
# assert "new" template is not found
- for path in search_paths:
- # TODO: use missing_ok=True once support for Python 3.7 is dropped
- with suppress(FileNotFoundError):
- Path(path).joinpath("new.html").unlink()
with pytest.raises(expected_exception=TemplateNotFound):
handler.env.get_template("new.html")
@@ -84,20 +79,18 @@ def test_extended_templates(extended_templates: Path, plugin: MkdocstringsPlugin
# start with last one and go back up
handler.env.cache = None
- extended_fallback_theme = extended_templates.joinpath(handler.fallback_theme)
extended_fallback_theme.mkdir()
extended_fallback_theme.joinpath("new.html").write_text("extended fallback new")
assert handler.env.get_template("new.html").render() == "extended fallback new"
- extended_theme = extended_templates.joinpath("mkdocs")
extended_theme.mkdir()
extended_theme.joinpath("new.html").write_text("extended new")
assert handler.env.get_template("new.html").render() == "extended new"
- base_fallback_theme = Path(search_paths[1])
+ base_fallback_theme.mkdir()
base_fallback_theme.joinpath("new.html").write_text("base fallback new")
assert handler.env.get_template("new.html").render() == "base fallback new"
- base_theme = Path(search_paths[0])
+ base_theme.mkdir()
base_theme.joinpath("new.html").write_text("base new")
assert handler.env.get_template("new.html").render() == "base new"