diff --git a/.copier-answers.yml b/.copier-answers.yml index 1dc4ac4..225aa5e 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: 1.2.0 +_commit: 1.2.2 _src_path: gh:mkdocstrings/handler-template author_email: dev@pawamoy.fr author_fullname: Timothée Mazzucotelli diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6940069..594d1c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - - name: Fetch all tags - run: git fetch --depth=1 --tags + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 @@ -106,6 +106,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 45bcf5a..9388125 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,8 +11,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Fetch all tags - run: git fetch --depth=1 --tags + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 with: diff --git a/README.md b/README.md index a65bf00..937a3a8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ [![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-708FCC.svg?style=flat)](https://mkdocstrings.github.io/python/) [![pypi version](https://img.shields.io/pypi/v/mkdocstrings-python.svg)](https://pypi.org/project/mkdocstrings-python/) -[![gitpod](https://img.shields.io/badge/gitpod-workspace-708FCC.svg?style=flat)](https://gitpod.io/#https://github.com/mkdocstrings/python) [![gitter](https://badges.gitter.im/join%20chat.svg)](https://app.gitter.im/#/room/#python:gitter.im) --- diff --git a/docs/insiders/index.md b/docs/insiders/index.md index 3bc3aa5..17a11ce 100644 --- a/docs/insiders/index.md +++ b/docs/insiders/index.md @@ -92,6 +92,8 @@ else: ``` +Additionally, your sponsorship will give more weight to your upvotes on issues, helping us prioritize work items in our backlog. For more information on how we prioritize work, see this page: [Backlog management](https://pawamoy.github.io/backlog/). + ## How to become a sponsor Thanks for your interest in sponsoring! In order to become an eligible sponsor diff --git a/pyproject.toml b/pyproject.toml index 636a67f..a30c8aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,8 @@ version = {source = "scm"} package-dir = "src" includes = ["src/mkdocstrings_handlers"] editable-backend = "editables" + +# Include as much as possible in the source distribution, to help redistributors. excludes = ["**/.pytest_cache"] source-includes = [ "config", @@ -66,15 +68,21 @@ source-includes = [ ] [tool.pdm.build.wheel-data] +# Manual pages can be included in the wheel. +# Depending on the installation tool, they will be accessible to users. +# pipx supports it, uv does not yet, see https://github.com/astral-sh/uv/issues/4731. data = [ {path = "share/**/*", relative-to = "."}, ] [tool.uv] -dev-dependencies = [ - # dev - "editables>=0.5", +# Tell uv to ignore constraints on the main package. +# This is needed when the current project doesn't have Git tags (fork, CI). +override-dependencies = ["mkdocstrings-python"] +sources = { mkdocstrings-python = { workspace = true } } +[dependency-groups] +dev = [ # maintenance "build>=1.2", "git-changelog>=2.5", diff --git a/scripts/gen_credits.py b/scripts/gen_credits.py index 51ebe2f..8524053 100644 --- a/scripts/gen_credits.py +++ b/scripts/gen_credits.py @@ -27,7 +27,7 @@ pyproject = tomllib.load(pyproject_file) project = pyproject["project"] project_name = project["name"] -devdeps = [dep for dep in pyproject["tool"]["uv"]["dev-dependencies"] if not dep.startswith("-e")] +devdeps = [dep for dep in pyproject["dependency-groups"]["dev"] if not dep.startswith("-e")] PackageMetadata = dict[str, Union[str, Iterable[str]]] Metadata = dict[str, PackageMetadata] diff --git a/scripts/make b/scripts/make deleted file mode 100755 index ac43062..0000000 --- a/scripts/make +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 -"""Management commands.""" - -from __future__ import annotations - -import os -import shutil -import subprocess -import sys -from contextlib import contextmanager -from pathlib import Path -from textwrap import dedent -from typing import Any, Iterator - -PYTHON_VERSIONS = os.getenv("PYTHON_VERSIONS", "3.9 3.10 3.11 3.12 3.13 3.14").split() - - -def shell(cmd: str, capture_output: bool = False, **kwargs: Any) -> str | None: - """Run a shell command.""" - if capture_output: - return subprocess.check_output(cmd, shell=True, text=True, **kwargs) # noqa: S602 - subprocess.run(cmd, shell=True, check=True, stderr=subprocess.STDOUT, **kwargs) # noqa: S602 - return None - - -@contextmanager -def environ(**kwargs: str) -> Iterator[None]: - """Temporarily set environment variables.""" - original = dict(os.environ) - os.environ.update(kwargs) - try: - yield - finally: - os.environ.clear() - os.environ.update(original) - - -def uv_install(venv: Path) -> None: - """Install dependencies using uv.""" - with environ(UV_PROJECT_ENVIRONMENT=str(venv), PYO3_USE_ABI3_FORWARD_COMPATIBILITY="1"): - if "CI" in os.environ: - shell("uv sync --no-editable") - else: - shell("uv sync") - - -def setup() -> None: - """Setup the project.""" - if not shutil.which("uv"): - raise ValueError("make: setup: uv must be installed, see https://github.com/astral-sh/uv") - - print("Installing dependencies (default environment)") # noqa: T201 - default_venv = Path(".venv") - if not default_venv.exists(): - shell("uv venv --python python") - uv_install(default_venv) - - if PYTHON_VERSIONS: - for version in PYTHON_VERSIONS: - print(f"\nInstalling dependencies (python{version})") # noqa: T201 - venv_path = Path(f".venvs/{version}") - if not venv_path.exists(): - shell(f"uv venv --python {version} {venv_path}") - with environ(UV_PROJECT_ENVIRONMENT=str(venv_path.resolve())): - uv_install(venv_path) - - -def run(version: str, cmd: str, *args: str, no_sync: bool = False, **kwargs: Any) -> None: - """Run a command in a virtual environment.""" - kwargs = {"check": True, **kwargs} - uv_run = ["uv", "run"] - if no_sync: - uv_run.append("--no-sync") - if version == "default": - with environ(UV_PROJECT_ENVIRONMENT=".venv"): - subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510 - else: - with environ(UV_PROJECT_ENVIRONMENT=f".venvs/{version}", MULTIRUN="1"): - subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510 - - -def multirun(cmd: str, *args: str, **kwargs: Any) -> None: - """Run a command for all configured Python versions.""" - if PYTHON_VERSIONS: - for version in PYTHON_VERSIONS: - run(version, cmd, *args, **kwargs) - else: - run("default", cmd, *args, **kwargs) - - -def allrun(cmd: str, *args: str, **kwargs: Any) -> None: - """Run a command in all virtual environments.""" - run("default", cmd, *args, **kwargs) - if PYTHON_VERSIONS: - multirun(cmd, *args, **kwargs) - - -def clean() -> None: - """Delete build artifacts and cache files.""" - paths_to_clean = ["build", "dist", "htmlcov", "site", ".coverage*", ".pdm-build"] - for path in paths_to_clean: - shell(f"rm -rf {path}") - - cache_dirs = {".cache", ".pytest_cache", ".mypy_cache", ".ruff_cache", "__pycache__"} - for dirpath in Path(".").rglob("*/"): - if dirpath.parts[0] not in (".venv", ".venvs") and dirpath.name in cache_dirs: - shutil.rmtree(dirpath, ignore_errors=True) - - -def vscode() -> None: - """Configure VSCode to work on this project.""" - Path(".vscode").mkdir(parents=True, exist_ok=True) - shell("cp -v config/vscode/* .vscode") - - -def main() -> int: - """Main entry point.""" - args = list(sys.argv[1:]) - if not args or args[0] == "help": - if len(args) > 1: - run("default", "duty", "--help", args[1]) - else: - print( - dedent( - """ - Available commands - help Print this help. Add task name to print help. - setup Setup all virtual environments (install dependencies). - run Run a command in the default virtual environment. - multirun Run a command for all configured Python versions. - allrun Run a command in all virtual environments. - 3.x Run a command in the virtual environment for Python 3.x. - clean Delete build artifacts and cache files. - vscode Configure VSCode to work on this project. - """ - ), - flush=True, - ) # noqa: T201 - if os.path.exists(".venv"): - print("\nAvailable tasks", flush=True) # noqa: T201 - run("default", "duty", "--list", no_sync=True) - return 0 - - while args: - cmd = args.pop(0) - - if cmd == "run": - run("default", *args) - return 0 - - if cmd == "multirun": - multirun(*args) - return 0 - - if cmd == "allrun": - allrun(*args) - return 0 - - if cmd.startswith("3."): - run(cmd, *args) - return 0 - - opts = [] - while args and (args[0].startswith("-") or "=" in args[0]): - opts.append(args.pop(0)) - - if cmd == "clean": - clean() - elif cmd == "setup": - setup() - elif cmd == "vscode": - vscode() - elif cmd == "check": - multirun("duty", "check-quality", "check-types", "check-docs") - run("default", "duty", "check-api") - elif cmd in {"check-quality", "check-docs", "check-types", "test"}: - multirun("duty", cmd, *opts) - else: - run("default", "duty", cmd, *opts) - - return 0 - - -if __name__ == "__main__": - try: - sys.exit(main()) - except subprocess.CalledProcessError as process: - if process.output: - print(process.output, file=sys.stderr) # noqa: T201 - sys.exit(process.returncode) diff --git a/scripts/make b/scripts/make new file mode 120000 index 0000000..c2eda0d --- /dev/null +++ b/scripts/make @@ -0,0 +1 @@ +make.py \ No newline at end of file diff --git a/scripts/make.py b/scripts/make.py new file mode 100755 index 0000000..3d42729 --- /dev/null +++ b/scripts/make.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +"""Management commands.""" + +from __future__ import annotations + +import os +import shutil +import subprocess +import sys +from contextlib import contextmanager +from pathlib import Path +from textwrap import dedent +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from collections.abc import Iterator + + +PYTHON_VERSIONS = os.getenv("PYTHON_VERSIONS", "3.9 3.10 3.11 3.12 3.13 3.14").split() + + +def shell(cmd: str, *, capture_output: bool = False, **kwargs: Any) -> str | None: + """Run a shell command.""" + if capture_output: + return subprocess.check_output(cmd, shell=True, text=True, **kwargs) # noqa: S602 + subprocess.run(cmd, shell=True, check=True, stderr=subprocess.STDOUT, **kwargs) # noqa: S602 + return None + + +@contextmanager +def environ(**kwargs: str) -> Iterator[None]: + """Temporarily set environment variables.""" + original = dict(os.environ) + os.environ.update(kwargs) + try: + yield + finally: + os.environ.clear() + os.environ.update(original) + + +def uv_install(venv: Path) -> None: + """Install dependencies using uv.""" + with environ(UV_PROJECT_ENVIRONMENT=str(venv), PYO3_USE_ABI3_FORWARD_COMPATIBILITY="1"): + if "CI" in os.environ: + shell("uv sync --no-editable") + else: + shell("uv sync") + + +def setup() -> None: + """Setup the project.""" + if not shutil.which("uv"): + raise ValueError("make: setup: uv must be installed, see https://github.com/astral-sh/uv") + + print("Installing dependencies (default environment)") + default_venv = Path(".venv") + if not default_venv.exists(): + shell("uv venv") + uv_install(default_venv) + + if PYTHON_VERSIONS: + for version in PYTHON_VERSIONS: + print(f"\nInstalling dependencies (python{version})") + venv_path = Path(f".venvs/{version}") + if not venv_path.exists(): + shell(f"uv venv --python {version} {venv_path}") + with environ(UV_PROJECT_ENVIRONMENT=str(venv_path.resolve())): + uv_install(venv_path) + + +def run(version: str, cmd: str, *args: str, **kwargs: Any) -> None: + """Run a command in a virtual environment.""" + kwargs = {"check": True, **kwargs} + uv_run = ["uv", "run", "--no-sync"] + if version == "default": + with environ(UV_PROJECT_ENVIRONMENT=".venv"): + subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510 + else: + with environ(UV_PROJECT_ENVIRONMENT=f".venvs/{version}", MULTIRUN="1"): + subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510 + + +def multirun(cmd: str, *args: str, **kwargs: Any) -> None: + """Run a command for all configured Python versions.""" + if PYTHON_VERSIONS: + for version in PYTHON_VERSIONS: + run(version, cmd, *args, **kwargs) + else: + run("default", cmd, *args, **kwargs) + + +def allrun(cmd: str, *args: str, **kwargs: Any) -> None: + """Run a command in all virtual environments.""" + run("default", cmd, *args, **kwargs) + if PYTHON_VERSIONS: + multirun(cmd, *args, **kwargs) + + +def clean() -> None: + """Delete build artifacts and cache files.""" + paths_to_clean = ["build", "dist", "htmlcov", "site", ".coverage*", ".pdm-build"] + for path in paths_to_clean: + shutil.rmtree(path, ignore_errors=True) + + cache_dirs = {".cache", ".pytest_cache", ".mypy_cache", ".ruff_cache", "__pycache__"} + for dirpath in Path(".").rglob("*/"): + if dirpath.parts[0] not in (".venv", ".venvs") and dirpath.name in cache_dirs: + shutil.rmtree(dirpath, ignore_errors=True) + + +def vscode() -> None: + """Configure VSCode to work on this project.""" + shutil.copytree("config/vscode", ".vscode", dirs_exist_ok=True) + + +def main() -> int: + """Main entry point.""" + args = list(sys.argv[1:]) + if not args or args[0] == "help": + if len(args) > 1: + run("default", "duty", "--help", args[1]) + else: + print( + dedent( + """ + Available commands + help Print this help. Add task name to print help. + setup Setup all virtual environments (install dependencies). + run Run a command in the default virtual environment. + multirun Run a command for all configured Python versions. + allrun Run a command in all virtual environments. + 3.x Run a command in the virtual environment for Python 3.x. + clean Delete build artifacts and cache files. + vscode Configure VSCode to work on this project. + """, + ), + flush=True, + ) + if os.path.exists(".venv"): + print("\nAvailable tasks", flush=True) + run("default", "duty", "--list") + return 0 + + while args: + cmd = args.pop(0) + + if cmd == "run": + run("default", *args) + return 0 + + if cmd == "multirun": + multirun(*args) + return 0 + + if cmd == "allrun": + allrun(*args) + return 0 + + if cmd.startswith("3."): + run(cmd, *args) + return 0 + + opts = [] + while args and (args[0].startswith("-") or "=" in args[0]): + opts.append(args.pop(0)) + + if cmd == "clean": + clean() + elif cmd == "setup": + setup() + elif cmd == "vscode": + vscode() + elif cmd == "check": + multirun("duty", "check-quality", "check-types", "check-docs") + run("default", "duty", "check-api") + elif cmd in {"check-quality", "check-docs", "check-types", "test"}: + multirun("duty", cmd, *opts) + else: + run("default", "duty", cmd, *opts) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except subprocess.CalledProcessError as process: + if process.output: + print(process.output, file=sys.stderr) + sys.exit(process.returncode)