diff --git a/.copier-answers.yml b/.copier-answers.yml index 01da3106..0e8a2418 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,6 +1,6 @@ # Changes here will be overwritten by Copier -_commit: 1.2.3 -_src_path: gh:pawamoy/copier-pdm.git +_commit: 1.1.0 +_src_path: gh:pawamoy/copier-uv author_email: dev@pawamoy.fr author_fullname: Timothée Mazzucotelli author_username: pawamoy diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..f9d77ee3 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +PATH_add scripts diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 01e293ac..a502284a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,5 @@ github: pawamoy ko_fi: pawamoy +polar: pawamoy custom: - https://www.paypal.me/pawamoy diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c863cf0..3248b1a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ env: LC_ALL: en_US.utf-8 PYTHONIOENCODING: UTF-8 PYTHONPATH: docs + PYTHON_VERSIONS: "" jobs: @@ -29,31 +30,31 @@ jobs: - name: Fetch all tags run: git fetch --depth=1 --tags - - name: Set up PDM - uses: pdm-project/setup-pdm@v4 + - name: Set up Python + uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version: "3.11" - - name: Resolving dependencies - run: pdm lock -v --no-cross-platform -G ci-quality + - name: Install uv + run: pip install uv - name: Install dependencies - run: pdm install -G ci-quality + run: make setup - name: Check if the documentation builds correctly - run: pdm run duty check-docs + run: make check-docs - name: Check the code quality - run: pdm run duty check-quality + run: make check-quality - name: Check if the code is correctly typed - run: pdm run duty check-types + run: make check-types - name: Check for vulnerabilities in dependencies - run: pdm run duty check-dependencies + run: make check-dependencies - name: Check for breaking changes in the API - run: pdm run duty check-api + run: make check-api exclude-test-jobs: runs-on: ubuntu-latest @@ -79,7 +80,6 @@ jobs: needs: exclude-test-jobs strategy: - max-parallel: 4 matrix: os: - ubuntu-latest @@ -99,17 +99,17 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up PDM - uses: pdm-project/setup-pdm@v4 + - name: Set up Python + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - allow-python-prereleases: true + allow-prereleases: true - - name: Resolving dependencies - run: pdm lock -v --no-cross-platform -G ci-tests + - name: Install uv + run: pip install uv - name: Install dependencies - run: pdm install --no-editable -G ci-tests + run: make setup - name: Run the test suite - run: pdm run duty test + run: make test diff --git a/.gitignore b/.gitignore index 1c5aabc0..41fee62d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,24 @@ +# editors .idea/ .vscode/ -__pycache__/ -*.py[cod] -dist/ + +# python *.egg-info/ -build/ -htmlcov/ +*.py[cod] +.venv/ +.venvs/ +/build/ +/dist/ + +# tools .coverage* -pip-wheel-metadata/ +/.pdm-build/ +/htmlcov/ +/site/ + +# cache +.cache/ .pytest_cache/ -.python-version -site/ -pdm.lock -pdm.toml -.pdm-plugins/ -.pdm-python -__pypackages__/ .mypy_cache/ -.venv/ -.cache/ +.ruff_cache/ +__pycache__/ diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile index 0e6d9d35..1590b415 100644 --- a/.gitpod.dockerfile +++ b/.gitpod.dockerfile @@ -2,5 +2,5 @@ FROM gitpod/workspace-full USER gitpod ENV PIP_USER=no RUN pip3 install pipx; \ - pipx install pdm; \ + pipx install uv; \ pipx ensurepath diff --git a/CHANGELOG.md b/CHANGELOG.md index 1934f8db..63336bdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ 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.24.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.24.2) - 2024-04-02 + +[Compare with 0.24.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.24.1...0.24.2) + +### Bug Fixes + +- Support HTML toc labels with Python-Markdown 3.6+ ([c0d0090](https://github.com/mkdocstrings/mkdocstrings/commit/c0d009000678a2ccbfb0c8adfeff3dc83845ee41) by Timothée Mazzucotelli). [Issue-mkdocstrings/python-143](https://github.com/mkdocstrings/python/issues/143) + ## [0.24.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.24.1) - 2024-02-27 [Compare with 0.24.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.24.0...0.24.1) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff84c305..5f86ff10 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,18 +17,18 @@ make setup > NOTE: > If it fails for some reason, > you'll need to install -> [PDM](https://github.com/pdm-project/pdm) +> [uv](https://github.com/astral-sh/uv) > manually. > > You can install it with: > > ```bash > python3 -m pip install --user pipx -> pipx install pdm +> pipx install uv > ``` > > Now you can try running `make setup` again, -> or simply `pdm install`. +> or simply `uv install`. You now have the dependencies installed. @@ -39,13 +39,13 @@ 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 run the task directly with `pdm run duty TASK`. +on multiple Python versions, you run the task directly with `make 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, we provide -[an action to configure VSCode](https://pawamoy.github.io/copier-pdm/work/#vscode-setup) +[an action to configure VSCode](https://pawamoy.github.io/copier-uv/work/#vscode-setup) for the project. ## Development diff --git a/Makefile b/Makefile index 969b8e18..771b333c 100644 --- a/Makefile +++ b/Makefile @@ -1,54 +1,27 @@ -.DEFAULT_GOAL := help -SHELL := bash -DUTY := $(if $(VIRTUAL_ENV),,pdm run) duty -export PDM_MULTIRUN_VERSIONS ?= 3.8 3.9 3.10 3.11 3.12 -export PDM_MULTIRUN_USE_VENVS ?= $(if $(shell pdm config python.use_venv | grep True),1,0) +# If you have `direnv` loaded in your shell, and allow it in the repository, +# the `make` command will point at the `scripts/make` shell script. +# This Makefile is just here to allow auto-completion in the terminal. -args = $(foreach a,$($(subst -,_,$1)_args),$(if $(value $a),$a="$($a)")) -check_quality_args = files -docs_args = host port -release_args = version -test_args = match - -BASIC_DUTIES = \ +actions = \ changelog \ + check \ check-api \ check-dependencies \ + check-docs \ + check-quality \ + check-types \ clean \ coverage \ docs \ docs-deploy \ format \ + help \ release \ + run \ + setup \ + test \ vscode -QUALITY_DUTIES = \ - check-quality \ - check-docs \ - check-types \ - test - -.PHONY: help -help: - @$(DUTY) --list - -.PHONY: lock -lock: - @pdm lock --dev - -.PHONY: setup -setup: - @bash scripts/setup.sh - -.PHONY: check -check: - @pdm multirun duty check-quality check-types check-docs - @$(DUTY) check-dependencies check-api - -.PHONY: $(BASIC_DUTIES) -$(BASIC_DUTIES): - @$(DUTY) $@ $(call args,$@) - -.PHONY: $(QUALITY_DUTIES) -$(QUALITY_DUTIES): - @pdm multirun duty $@ $(call args,$@) +.PHONY: $(actions) +$(actions): + @bash scripts/make "$@" diff --git a/README.md b/README.md index 966e9029..44158d4a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ Come have a chat or ask questions on our [Gitter channel](https://gitter.im/mkdo It means you can use it with any programming language, as long as there is a [**handler**](https://mkdocstrings.github.io/reference/handlers/base/) for it. We currently have [handlers](https://mkdocstrings.github.io/handlers/overview/) - for the [Crystal](https://mkdocstrings.github.io/crystal/) and [Python](https://mkdocstrings.github.io/python/) languages, + for the [Crystal](https://mkdocstrings.github.io/crystal/), [Python](https://mkdocstrings.github.io/python/), + and [VBA](https://pypi.org/project/mkdocstrings-vba/) languages, as well as for [shell scripts/libraries](https://mkdocstrings.github.io/shell/). Maybe you'd like to add another one to the list? :wink: diff --git a/config/black.toml b/config/black.toml deleted file mode 100644 index d24affe5..00000000 --- a/config/black.toml +++ /dev/null @@ -1,3 +0,0 @@ -[tool.black] -line-length = 120 -exclude = "tests/fixtures" diff --git a/config/coverage.ini b/config/coverage.ini index 1bcf0935..18365bd2 100644 --- a/config/coverage.ini +++ b/config/coverage.ini @@ -8,7 +8,8 @@ source = [coverage:paths] equivalent = src/ - __pypackages__/ + .venv/lib/*/site-packages/ + .venvs/*/lib/*/site-packages/ [coverage:report] ignore_errors = True diff --git a/config/git-changelog.toml b/config/git-changelog.toml index 44e2b1fb..57114e0c 100644 --- a/config/git-changelog.toml +++ b/config/git-changelog.toml @@ -6,3 +6,4 @@ parse-refs = false parse-trailers = true sections = ["build", "deps", "feat", "fix", "refactor"] template = "keepachangelog" +versioning = "pep440" diff --git a/config/pytest.ini b/config/pytest.ini index 6b0d5c7a..5b5bd2e7 100644 --- a/config/pytest.ini +++ b/config/pytest.ini @@ -1,10 +1,4 @@ [pytest] -norecursedirs = - .git - .tox - .env - dist - build python_files = test_*.py *_test.py diff --git a/config/ruff.toml b/config/ruff.toml index 4cd69ff0..a8b26e1e 100644 --- a/config/ruff.toml +++ b/config/ruff.toml @@ -1,53 +1,26 @@ target-version = "py38" line-length = 120 + +[lint] exclude = [ - "fixtures", - "site", + "tests/fixtures/*.py", ] select = [ - "A", - "ANN", - "ARG", - "B", - "BLE", - "C", - "C4", + "A", "ANN", "ARG", + "B", "BLE", + "C", "C4", "COM", - "D", - "DTZ", - "E", - "ERA", - "EXE", - "F", - "FBT", + "D", "DTZ", + "E", "ERA", "EXE", + "F", "FBT", "G", - "I", - "ICN", - "INP", - "ISC", + "I", "ICN", "INP", "ISC", "N", - "PGH", - "PIE", - "PL", - "PLC", - "PLE", - "PLR", - "PLW", - "PT", - "PYI", + "PGH", "PIE", "PL", "PLC", "PLE", "PLR", "PLW", "PT", "PYI", "Q", - "RUF", - "RSE", - "RET", - "S", - "SIM", - "SLF", - "T", - "T10", - "T20", - "TCH", - "TID", - "TRY", + "RUF", "RSE", "RET", + "S", "SIM", "SLF", + "T", "T10", "T20", "TCH", "TID", "TRY", "UP", "W", "YTT", @@ -73,7 +46,7 @@ ignore = [ "TRY003", # Avoid specifying long messages outside the exception class ] -[per-file-ignores] +[lint.per-file-ignores] "src/*/cli.py" = [ "T201", # Print statement ] @@ -91,18 +64,21 @@ ignore = [ "S101", # Use of assert detected ] -[flake8-quotes] +[lint.flake8-quotes] docstring-quotes = "double" -[flake8-tidy-imports] +[lint.flake8-tidy-imports] ban-relative-imports = "all" -[isort] +[lint.isort] known-first-party = ["mkdocstrings"] -[pydocstyle] +[lint.pydocstyle] convention = "google" [format] +exclude = [ + "tests/fixtures/*.py", +] docstring-code-format = true docstring-code-line-length = 80 diff --git a/config/vscode/launch.json b/config/vscode/launch.json index d056ccee..e3288388 100644 --- a/config/vscode/launch.json +++ b/config/vscode/launch.json @@ -9,6 +9,17 @@ "console": "integratedTerminal", "justMyCode": false }, + { + "name": "docs", + "type": "debugpy", + "request": "launch", + "module": "mkdocs", + "justMyCode": false, + "args": [ + "serve", + "-v" + ] + }, { "name": "test", "type": "debugpy", diff --git a/config/vscode/settings.json b/config/vscode/settings.json index 17beee4b..949856d1 100644 --- a/config/vscode/settings.json +++ b/config/vscode/settings.json @@ -1,29 +1,9 @@ { "files.watcherExclude": { - "**/__pypackages__/**": true, "**/.venv*/**": true, + "**/.venvs*/**": true, "**/venv*/**": true }, - "[python]": { - "editor.defaultFormatter": "ms-python.black-formatter" - }, - "python.autoComplete.extraPaths": [ - "__pypackages__/3.8/lib", - "__pypackages__/3.9/lib", - "__pypackages__/3.10/lib", - "__pypackages__/3.11/lib", - "__pypackages__/3.12/lib" - ], - "python.analysis.extraPaths": [ - "__pypackages__/3.8/lib", - "__pypackages__/3.9/lib", - "__pypackages__/3.10/lib", - "__pypackages__/3.11/lib", - "__pypackages__/3.12/lib" - ], - "black-formatter.args": [ - "--config=config/black.toml" - ], "mypy-type-checker.args": [ "--config-file=config/mypy.ini" ], @@ -32,6 +12,7 @@ "python.testing.pytestArgs": [ "--config-file=config/pytest.ini" ], + "ruff.enable": true, "ruff.format.args": [ "--config=config/ruff.toml" ], diff --git a/config/vscode/tasks.json b/config/vscode/tasks.json index 80cd13d2..30008cf2 100644 --- a/config/vscode/tasks.json +++ b/config/vscode/tasks.json @@ -3,84 +3,94 @@ "tasks": [ { "label": "changelog", - "type": "shell", - "command": "pdm run duty changelog" + "type": "process", + "command": "scripts/make", + "args": ["changelog"] }, { "label": "check", - "type": "shell", - "command": "pdm run duty check" + "type": "process", + "command": "scripts/make", + "args": ["check"] }, { "label": "check-quality", - "type": "shell", - "command": "pdm run duty check-quality" + "type": "process", + "command": "scripts/make", + "args": ["check-quality"] }, { "label": "check-types", - "type": "shell", - "command": "pdm run duty check-types" + "type": "process", + "command": "scripts/make", + "args": ["check-types"] }, { "label": "check-docs", - "type": "shell", - "command": "pdm run duty check-docs" + "type": "process", + "command": "scripts/make", + "args": ["check-docs"] }, { "label": "check-dependencies", - "type": "shell", - "command": "pdm run duty check-dependencies" + "type": "process", + "command": "scripts/make", + "args": ["check-dependencies"] }, { "label": "check-api", - "type": "shell", - "command": "pdm run duty check-api" + "type": "process", + "command": "scripts/make", + "args": ["check-api"] }, { "label": "clean", - "type": "shell", - "command": "pdm run duty clean" + "type": "process", + "command": "scripts/make", + "args": ["clean"] }, { "label": "docs", - "type": "shell", - "command": "pdm run duty docs" + "type": "process", + "command": "scripts/make", + "args": ["docs"] }, { "label": "docs-deploy", - "type": "shell", - "command": "pdm run duty docs-deploy" + "type": "process", + "command": "scripts/make", + "args": ["docs-deploy"] }, { "label": "format", - "type": "shell", - "command": "pdm run duty format" - }, - { - "label": "lock", - "type": "shell", - "command": "pdm lock -G:all" + "type": "process", + "command": "scripts/make", + "args": ["format"] }, { "label": "release", - "type": "shell", - "command": "pdm run duty release ${input:version}" + "type": "process", + "command": "scripts/make", + "args": ["release", "${input:version}"] }, { "label": "setup", - "type": "shell", - "command": "bash scripts/setup.sh" + "type": "process", + "command": "scripts/make", + "args": ["setup"] }, { "label": "test", - "type": "shell", - "command": "pdm run duty test coverage", + "type": "process", + "command": "scripts/make", + "args": ["test", "coverage"], "group": "test" }, { "label": "vscode", - "type": "shell", - "command": "pdm run duty vscode" + "type": "process", + "command": "scripts/make", + "args": ["vscode"] } ], "inputs": [ diff --git a/devdeps.txt b/devdeps.txt new file mode 100644 index 00000000..58700f78 --- /dev/null +++ b/devdeps.txt @@ -0,0 +1,28 @@ +build>=1.0 +duty>=0.10 +black>=23.9 +markdown-callouts>=0.3 +markdown-exec>=1.7 +mkdocs>=1.5 +mkdocs-coverage>=1.0 +mkdocs-gen-files>=0.5 +mkdocs-git-committers-plugin-2>=1.2 +mkdocs-literate-nav>=0.6 +mkdocs-material>=9.4 +mkdocs-minify-plugin>=0.7 +mkdocs-redirects>=1.2 +mkdocstrings[python]>=0.23 +tomli>=2.0; python_version < '3.11' +black>=23.9 +blacken-docs>=1.16 +git-changelog>=2.3 +ruff>=0.0 +pytest>=7.4 +pytest-cov>=4.1 +pytest-randomly>=3.15 +pytest-xdist>=3.3 +mypy>=1.5 +types-markdown>=3.5 +types-pyyaml>=6.0 +safety>=2.3 +twine>=5.0 diff --git a/docs/insiders/goals.yml b/docs/insiders/goals.yml index a96ac51b..0e27b997 100644 --- a/docs/insiders/goals.yml +++ b/docs/insiders/goals.yml @@ -1 +1,13 @@ -goals: {} \ No newline at end of file +goals: + 500: + name: PlasmaVac User Guide + features: [] + 1000: + name: GraviFridge Fluid Renewal + features: [] + 1500: + name: HyperLamp Navigation Tips + features: [] + 2000: + name: FusionDrive Ejection Configuration + features: [] diff --git a/docs/insiders/index.md b/docs/insiders/index.md index 6babfb67..d88e8e7c 100644 --- a/docs/insiders/index.md +++ b/docs/insiders/index.md @@ -59,24 +59,39 @@ a handful of them, [thanks to our awesome sponsors][sponsors]! --> data_source = [ "docs/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"), + ("griffe-warnings-deprecated", "https://mkdocstrings.github.io/griffe-warnings-deprecated/", "insiders/goals.yml"), ("mkdocstrings-python", "https://mkdocstrings.github.io/python/", "insiders/goals.yml"), ("mkdocstrings-shell", "https://mkdocstrings.github.io/shell/", "insiders/goals.yml"), + ("mkdocstrings-typescript", "https://mkdocstrings.github.io/typescript/", "insiders/goals.yml"), ] ``` -```python exec="1" session="insiders" +```python exec="1" session="insiders" idprefix="" --8<-- "scripts/insiders.py" -print( - f"""The moment you become a sponsor, you'll get **immediate - 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 unreleased_features: - feature.render(badge=True) +if unreleased_features: + print( + "The moment you [become a sponsor](#how-to-become-a-sponsor), you'll get **immediate " + f"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 unreleased_features: + feature.render(badge=True) + + print( + "\n\nThese are just the features related to this project. " + "[See the complete feature list on the author's main Insiders page](https://pawamoy.github.io/insiders/#whats-in-it-for-me)." + ) +else: + print( + "The moment you [become a sponsor](#how-to-become-a-sponsor), you'll get immediate " + "access to all released features that you can start using right away, and " + "which are exclusively available to sponsors. At this moment, there are no " + "Insiders features for this project, but checkout the [next funding goals](#goals) " + "to see what's coming, as well as **[the feature list for all Insiders projects](https://pawamoy.github.io/insiders/#whats-in-it-for-me).**" + ) ``` @@ -121,10 +136,10 @@ You can cancel your sponsorship anytime.[^5]
`
+ sponsors.forEach(function (sponsor) {
+ html += `
+
+
+
+ `
+ });
+ html += '
'
- sponsors.forEach(function (sponsor) {
- html += `
-
-
-
- `
- });
- html += '
'
-src = Path(__file__).parent.parent / "src"
+root = Path(__file__).parent.parent
+src = root / "src"
for path in sorted(src.rglob("*.py")):
module_path = path.relative_to(src).with_suffix("")
@@ -30,7 +31,7 @@
ident = ".".join(parts)
fd.write(f"::: {ident}")
- mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path)
+ mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path.relative_to(root))
with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())
diff --git a/scripts/insiders.py b/scripts/insiders.py
index 0cee92cb..15212486 100644
--- a/scripts/insiders.py
+++ b/scripts/insiders.py
@@ -78,9 +78,16 @@ def human_readable_amount(self) -> str: # noqa: D102
def render(self, rel_base: str = "..") -> None: # noqa: D102
print(f"#### $ {self.human_readable_amount} — {self.name}\n")
- for feature in self.features:
- feature.render(rel_base)
- print("")
+ if self.features:
+ for feature in self.features:
+ feature.render(rel_base)
+ print("")
+ else:
+ print("There are no features in this goal for this project. ")
+ print(
+ "[See the features in this goal **for all Insiders projects.**]"
+ f"(https://pawamoy.github.io/insiders/#{self.amount}-{self.name.lower().replace(' ', '-')})",
+ )
def load_goals(data: str, funding: int = 0, project: Project | None = None) -> dict[int, Goal]:
diff --git a/scripts/make b/scripts/make
new file mode 100755
index 00000000..f690126e
--- /dev/null
+++ b/scripts/make
@@ -0,0 +1,159 @@
+#!/usr/bin/env bash
+
+set -e
+export PYTHON_VERSIONS=${PYTHON_VERSIONS-3.8 3.9 3.10 3.11 3.12}
+
+exe=""
+prefix=""
+
+
+# Install runtime and development dependencies,
+# as well as current project in editable mode.
+uv_install() {
+ uv pip compile pyproject.toml devdeps.txt | uv pip install -r -
+ if [ -z "${CI}" ]; then
+ uv pip install -e .
+ else
+ uv pip install "mkdocstrings @ ."
+ fi
+}
+
+
+# Setup the development environment by installing dependencies
+# in multiple Python virtual environments with uv:
+# one venv per Python version in `.venvs/$py`,
+# and an additional default venv in `.venv`.
+setup() {
+ if ! command -v uv &>/dev/null; then
+ echo "make: setup: uv must be installed, see https://github.com/astral-sh/uv" >&2
+ return 1
+ fi
+
+ if [ -n "${PYTHON_VERSIONS}" ]; then
+ for version in ${PYTHON_VERSIONS}; do
+ if [ ! -d ".venvs/${version}" ]; then
+ uv venv --python "${version}" ".venvs/${version}"
+ fi
+ VIRTUAL_ENV="${PWD}/.venvs/${version}" uv_install
+ done
+ fi
+
+ if [ ! -d .venv ]; then uv venv --python python; fi
+ uv_install
+}
+
+
+# Activate a Python virtual environments.
+# The annoying operating system also requires
+# that we set some global variables to help it find commands...
+activate() {
+ local path
+ if [ -f "$1/bin/activate" ]; then
+ source "$1/bin/activate"
+ return 0
+ fi
+ if [ -f "$1/Scripts/activate.bat" ]; then
+ "$1/Scripts/activate.bat"
+ exe=".exe"
+ prefix="$1/Scripts/"
+ return 0
+ fi
+ echo "run: Cannot activate venv $1" >&2
+ return 1
+}
+
+
+# Run a command in all configured Python virtual environments.
+# We handle the case when the `PYTHON_VERSIONS` environment variable
+# is unset or empty, for robustness.
+multirun() {
+ local cmd="$1"
+ shift
+
+ if [ -n "${PYTHON_VERSIONS}" ]; then
+ for version in ${PYTHON_VERSIONS}; do
+ (activate ".venvs/${version}" && MULTIRUN=1 "${prefix}${cmd}${exe}" "$@")
+ done
+ else
+ (activate .venv && "${prefix}${cmd}${exe}" "$@")
+ fi
+}
+
+
+# Run a command in the default Python virtual environment.
+# We rely on `multirun`'s handling of empty `PYTHON_VERSIONS`.
+singlerun() {
+ PYTHON_VERSIONS= multirun "$@"
+}
+
+
+# Record options following a command name,
+# until a non-option argument is met or there are no more arguments.
+# Output each option on a new line, so the parent caller can store them in an array.
+# Return the number of times the parent caller must shift arguments.
+options() {
+ local shift_count=0
+ for arg in "$@"; do
+ if [[ "${arg}" =~ ^- || "${arg}" =~ ^.+= ]]; then
+ echo "${arg}"
+ ((shift_count++))
+ else
+ break
+ fi
+ done
+ return ${shift_count}
+}
+
+
+# Main function.
+main() {
+ local cmd
+ while [ $# -ne 0 ]; do
+ cmd="$1"
+ shift
+
+ # Handle `run` early to simplify `case` below.
+ if [ "${cmd}" = "run" ]; then
+ singlerun "$@"
+ exit $?
+ fi
+
+ # Handle `multirun` early to simplify `case` below.
+ if [ "${cmd}" = "multirun" ]; then
+ multirun "$@"
+ exit $?
+ fi
+
+ # All commands except `run` and `multirun` can be chained on a single line.
+ # Some of them accept options in two formats: `-f`, `--flag` and `param=value`.
+ # Some of them don't, and will print warnings/errors if options were given.
+ opts=($(options "$@")) || shift $?
+
+ case "${cmd}" in
+ # The following commands require special handling.
+ help|"")
+ singlerun duty --list ;;
+ setup)
+ setup ;;
+ check)
+ multirun duty check-quality check-types check-docs
+ singlerun duty check-dependencies check-api
+ ;;
+
+ # The following commands run in all venvs.
+ check-quality|\
+ check-docs|\
+ check-types|\
+ test)
+ multirun duty "${cmd}" "${opts[@]}" ;;
+
+ # The following commands run in the default venv only.
+ *)
+ singlerun duty "${cmd}" "${opts[@]}" ;;
+ esac
+ done
+}
+
+
+# Execute the main function.
+main "$@"
diff --git a/scripts/setup.sh b/scripts/setup.sh
deleted file mode 100755
index e4d8187e..00000000
--- a/scripts/setup.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-if ! command -v pdm &>/dev/null; then
- if ! command -v pipx &>/dev/null; then
- python3 -m pip install --user pipx
- fi
- pipx install pdm
-fi
-if ! pdm self list 2>/dev/null | grep -q pdm-multirun; then
- pdm install --plugins
-fi
-
-if [ -n "${PDM_MULTIRUN_VERSIONS}" ]; then
- if [ "${PDM_MULTIRUN_USE_VENVS}" -eq "1" ]; then
- for version in ${PDM_MULTIRUN_VERSIONS}; do
- if ! pdm venv --path "${version}" &>/dev/null; then
- pdm venv create --name "${version}" "${version}"
- fi
- done
- fi
- pdm multirun -v pdm install --dev
-else
- pdm install --dev
-fi
diff --git a/src/mkdocstrings/debug.py b/src/mkdocstrings/debug.py
index 35ede743..b5da78f2 100644
--- a/src/mkdocstrings/debug.py
+++ b/src/mkdocstrings/debug.py
@@ -37,6 +37,8 @@ class Environment:
"""Python interpreter name."""
interpreter_version: str
"""Python interpreter version."""
+ interpreter_path: str
+ """Path to Python executable."""
platform: str
"""Operating System."""
packages: list[Package]
@@ -83,6 +85,7 @@ def get_debug_info() -> Environment:
return Environment(
interpreter_name=py_name,
interpreter_version=py_version,
+ interpreter_path=sys.executable,
platform=platform.platform(),
variables=[Variable(var, val) for var in variables if (val := os.getenv(var))],
packages=[Package(pkg, get_version(pkg)) for pkg in packages],
@@ -93,7 +96,7 @@ def print_debug_info() -> None:
"""Print debug/environment information."""
info = get_debug_info()
print(f"- __System__: {info.platform}")
- print(f"- __Python__: {info.interpreter_name} {info.interpreter_version}")
+ print(f"- __Python__: {info.interpreter_name} {info.interpreter_version} ({info.interpreter_path})")
print("- __Environment variables__:")
for var in info.variables:
print(f" - `{var.name}`: `{var.value}`")
diff --git a/src/mkdocstrings/extension.py b/src/mkdocstrings/extension.py
index 7830d441..b22d0888 100644
--- a/src/mkdocstrings/extension.py
+++ b/src/mkdocstrings/extension.py
@@ -228,7 +228,7 @@ def _process_block(
return rendered, handler, data
-class _PostProcessor(Treeprocessor):
+class _HeadingsPostProcessor(Treeprocessor):
def run(self, root: Element) -> None:
self._remove_duplicated_headings(root)
@@ -249,6 +249,17 @@ def _remove_duplicated_headings(self, parent: Element) -> None:
parent.text = (parent.text or "") + carry_text
+class _TocLabelsTreeProcessor(Treeprocessor):
+ def run(self, root: Element) -> None: # noqa: ARG002
+ self._override_toc_labels(self.md.toc_tokens) # type: ignore[attr-defined]
+
+ def _override_toc_labels(self, tokens: list[dict[str, Any]]) -> None:
+ for token in tokens:
+ if (label := token.get("data-toc-label")) and token["name"] != label:
+ token["name"] = label
+ self._override_toc_labels(token["children"])
+
+
class MkdocstringsExtension(Extension):
"""Our Markdown extension.
@@ -284,7 +295,12 @@ def extendMarkdown(self, md: Markdown) -> None: # noqa: N802 (casing: parent me
priority=75, # Right before markdown.blockprocessors.HashHeaderProcessor
)
md.treeprocessors.register(
- _PostProcessor(md),
- "mkdocstrings_post",
+ _HeadingsPostProcessor(md),
+ "mkdocstrings_post_headings",
priority=4, # Right after 'toc'.
)
+ # md.treeprocessors.register(
+ # _TocLabelsTreeProcessor(md),
+ # "mkdocstrings_post_toc_labels",
+ # priority=4, # Right after 'toc'.
+ # )
diff --git a/tests/test_extension.py b/tests/test_extension.py
index 5f268c07..affd6c6a 100644
--- a/tests/test_extension.py
+++ b/tests/test_extension.py
@@ -105,26 +105,46 @@ def test_no_double_toc(ext_markdown: Markdown, expect_permalink: str) -> None:
{
"level": 1,
"id": "aa",
+ "html": "aa",
"name": "aa",
+ "data-toc-label": "",
"children": [
{
"level": 2,
"id": "tests.fixtures.headings--foo",
+ "html": "Foo",
"name": "Foo",
+ "data-toc-label": "",
"children": [
{
"level": 4,
"id": "tests.fixtures.headings--bar",
+ "html": "Bar",
"name": "Bar",
+ "data-toc-label": "",
"children": [
- {"level": 6, "id": "tests.fixtures.headings--baz", "name": "Baz", "children": []},
+ {
+ "level": 6,
+ "id": "tests.fixtures.headings--baz",
+ "html": "Baz",
+ "name": "Baz",
+ "data-toc-label": "",
+ "children": [],
+ },
],
},
],
},
],
},
- {"level": 1, "id": "bb", "name": "bb", "children": []},
+ {
+ "level": 1,
+ "id": "bb",
+ "html": "bb",
+ "name": "bb",
+ "data-toc-label": "",
+ "children": [],
+ },
]