pax_global_header00006660000000000000000000000064147635622410014524gustar00rootroot0000000000000052 comment=32e415d2ead0d524745ae90af78e1195c827f9ad mkdocstrings-0.29.0/000077500000000000000000000000001476356224100143235ustar00rootroot00000000000000mkdocstrings-0.29.0/.copier-answers.yml000066400000000000000000000013511476356224100200650ustar00rootroot00000000000000# Changes here will be overwritten by Copier. _commit: 1.7.1 _src_path: gh:pawamoy/copier-uv author_email: dev@pawamoy.fr author_fullname: Timothée Mazzucotelli author_username: pawamoy copyright_date: '2019' copyright_holder: Timothée Mazzucotelli copyright_holder_email: dev@pawamoy.fr copyright_license: ISC insiders: true insiders_email: insiders@pawamoy.fr insiders_repository_name: mkdocstrings project_description: Automatic documentation from sources, for MkDocs. project_name: mkdocstrings public_release: true python_package_command_line_name: '' python_package_distribution_name: mkdocstrings python_package_import_name: mkdocstrings repository_name: mkdocstrings repository_namespace: mkdocstrings repository_provider: github.com mkdocstrings-0.29.0/.envrc000066400000000000000000000000211476356224100154320ustar00rootroot00000000000000PATH_add scripts mkdocstrings-0.29.0/.github/000077500000000000000000000000001476356224100156635ustar00rootroot00000000000000mkdocstrings-0.29.0/.github/FUNDING.yml000066400000000000000000000000371476356224100175000ustar00rootroot00000000000000github: pawamoy polar: pawamoy mkdocstrings-0.29.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001476356224100200465ustar00rootroot00000000000000mkdocstrings-0.29.0/.github/ISSUE_TEMPLATE/1-bug.md000066400000000000000000000027221476356224100213060ustar00rootroot00000000000000--- name: Bug report about: Create a bug report to help us improve. title: "bug: " labels: unconfirmed assignees: [pawamoy] --- ### Description of the bug ### To Reproduce ``` WRITE MRE / INSTRUCTIONS HERE ``` ### Full traceback
Full traceback ```python PASTE TRACEBACK HERE ```
### Expected behavior ### Environment information ```bash python -m mkdocstrings._internal.debug # | xclip -selection clipboard ``` PASTE MARKDOWN OUTPUT HERE ### Additional context mkdocstrings-0.29.0/.github/ISSUE_TEMPLATE/2-feature.md000066400000000000000000000012131476356224100221570ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project. title: "feature: " labels: feature assignees: pawamoy --- ### Is your feature request related to a problem? Please describe. ### Describe the solution you'd like ### Describe alternatives you've considered ### Additional context mkdocstrings-0.29.0/.github/ISSUE_TEMPLATE/3-docs.md000066400000000000000000000011311476356224100214540ustar00rootroot00000000000000--- name: Documentation update about: Point at unclear, missing or outdated documentation. title: "docs: " labels: docs assignees: pawamoy --- ### Is something unclear, missing or outdated in our documentation? ### Relevant code snippets ### Link to the relevant documentation section mkdocstrings-0.29.0/.github/ISSUE_TEMPLATE/4-change.md000066400000000000000000000011261476356224100217560ustar00rootroot00000000000000--- name: Change request about: Suggest any other kind of change for this project. title: "change: " assignees: pawamoy --- ### Is your change request related to a problem? Please describe. ### Describe the solution you'd like ### Describe alternatives you've considered ### Additional context mkdocstrings-0.29.0/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000003361476356224100220400ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: I have a question / I need help url: https://github.com/mkdocstrings/mkdocstrings/discussions/new?category=q-a about: Ask and answer questions in the Discussions tab. mkdocstrings-0.29.0/.github/workflows/000077500000000000000000000000001476356224100177205ustar00rootroot00000000000000mkdocstrings-0.29.0/.github/workflows/ci.yml000066400000000000000000000062711476356224100210440ustar00rootroot00000000000000name: ci on: push: pull_request: branches: - main defaults: run: shell: bash env: LANG: en_US.utf-8 LC_ALL: en_US.utf-8 PYTHONIOENCODING: UTF-8 PYTHONPATH: docs PYTHON_VERSIONS: "" jobs: quality: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Setup uv uses: astral-sh/setup-uv@v5 with: enable-cache: true cache-dependency-glob: pyproject.toml - name: Install dependencies run: make setup - name: Check if the documentation builds correctly run: make check-docs - name: Check the code quality run: make check-quality - name: Check if the code is correctly typed run: make check-types - name: Check for breaking changes in the API run: make check-api - name: Store objects inventory for tests uses: actions/upload-artifact@v4 with: name: objects.inv path: site/objects.inv 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.10"}, {"python-version": "3.11"}, {"python-version": "3.12"}, {"python-version": "3.13"}, {"python-version": "3.14"} ]' | tr -d '[:space:]' >> $GITHUB_OUTPUT else echo 'jobs=[ {"os": "macos-latest", "resolution": "lowest-direct"}, {"os": "windows-latest", "resolution": "lowest-direct"} ]' | tr -d '[:space:]' >> $GITHUB_OUTPUT fi tests: needs: - quality - exclude-test-jobs strategy: matrix: os: - ubuntu-latest - macos-latest - windows-latest python-version: - "3.9" - "3.10" - "3.11" - "3.12" - "3.13" - "3.14" resolution: - highest - lowest-direct exclude: ${{ fromJSON(needs.exclude-test-jobs.outputs.jobs) }} runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.python-version == '3.14' }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Setup uv uses: astral-sh/setup-uv@v5 with: enable-cache: true cache-dependency-glob: pyproject.toml cache-suffix: ${{ matrix.resolution }} - name: Install dependencies env: UV_RESOLUTION: ${{ matrix.resolution }} run: make setup - name: Download objects inventory uses: actions/download-artifact@v4 with: name: objects.inv path: site/ - name: Run the test suite run: make test mkdocstrings-0.29.0/.github/workflows/release.yml000066400000000000000000000023661476356224100220720ustar00rootroot00000000000000name: release on: push permissions: contents: write jobs: release: runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Setup uv uses: astral-sh/setup-uv@v5 - name: Build dists if: github.repository_owner == 'pawamoy-insiders' run: uv tool run --from build pyproject-build - name: Upload dists artifact uses: actions/upload-artifact@v4 if: github.repository_owner == 'pawamoy-insiders' with: name: mkdocstrings-insiders path: ./dist/* - name: Prepare release notes if: github.repository_owner != 'pawamoy-insiders' run: uv tool run git-changelog --release-notes > release-notes.md - name: Create release with assets uses: softprops/action-gh-release@v2 if: github.repository_owner == 'pawamoy-insiders' with: files: ./dist/* - name: Create release uses: softprops/action-gh-release@v2 if: github.repository_owner != 'pawamoy-insiders' with: body_path: release-notes.md mkdocstrings-0.29.0/.gitignore000066400000000000000000000003311476356224100163100ustar00rootroot00000000000000# editors .idea/ .vscode/ # python *.egg-info/ *.py[cod] .venv/ .venvs/ /build/ /dist/ # tools .coverage* /.pdm-build/ /htmlcov/ /site/ uv.lock # cache .cache/ .pytest_cache/ .mypy_cache/ .ruff_cache/ __pycache__/ mkdocstrings-0.29.0/CHANGELOG.md000066400000000000000000002267151476356224100161510ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. 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.29.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.29.0) - 2025-03-10 [Compare with 0.28.3](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.3...0.29.0) **This is the last version before v1!** ### Build - Depend on MkDocs 1.6 ([11bc400](https://github.com/mkdocstrings/mkdocstrings/commit/11bc400ab7089a47755f24a790c08f2f904c570b) by Timothée Mazzucotelli). ### Features - Support rendering backlinks through handlers ([d4c7b9c](https://github.com/mkdocstrings/mkdocstrings/commit/d4c7b9c42f2de5df234c1ffefae0405a120e383c) by Timothée Mazzucotelli). [Issue-723](https://github.com/mkdocstrings/mkdocstrings/issues/723), [Issue-mkdocstrings-python-153](https://github.com/mkdocstrings/python/issues/153), [PR-739](https://github.com/mkdocstrings/mkdocstrings/pull/739) ### Code Refactoring - Save and forward titles to autorefs ([f49fb29](https://github.com/mkdocstrings/mkdocstrings/commit/f49fb29582714795ca03febf1ee243aa2992917e) by Timothée Mazzucotelli). - Use a combined event (each split with a different priority) for `on_env` ([8d1dd75](https://github.com/mkdocstrings/mkdocstrings/commit/8d1dd754b4babd3c4f9e6c1d8856be57fe4ba9ea) by Timothée Mazzucotelli). ## [0.28.3](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.28.3) - 2025-03-08 [Compare with 0.28.2](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.2...0.28.3) ### Deprecations All public objects must now be imported from the top-level `mkdocstrings` module. Importing from submodules is deprecated, and will raise errors starting with v1. This should be the last deprecation before v1. ### Build - Make `python` extra depend on latest mkdocstrings-python (1.16.2) ([ba9003e](https://github.com/mkdocstrings/mkdocstrings/commit/ba9003e96c8e5e01900743d5c464cbd228d732f4) by Timothée Mazzucotelli). ### Code Refactoring - Finish exposing/hiding public/internal objects ([0723fc2](https://github.com/mkdocstrings/mkdocstrings/commit/0723fc25fdf5d45bc3b949f370712a706b85fbab) by Timothée Mazzucotelli). - Re-expose public API in the top-level `mkdocstrings` module ([e66e080](https://github.com/mkdocstrings/mkdocstrings/commit/e66e08096d45f6790492d9a0b767d512e42f67a9) by Timothée Mazzucotelli). - Move modules to internal folder ([23fe23f](https://github.com/mkdocstrings/mkdocstrings/commit/23fe23f11011d0470a6342ca85e060e5ac2b6bd6) by Timothée Mazzucotelli). ## [0.28.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.28.2) - 2025-02-24 [Compare with 0.28.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.1...0.28.2) ### Build - Depend on mkdocs-autorefs >= 1.4 ([2c22bdc](https://github.com/mkdocstrings/mkdocstrings/commit/2c22bdc49f6bf5600aefd5ec711747686fda96a8) by Timothée Mazzucotelli). ## [0.28.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.28.1) - 2025-02-14 [Compare with 0.28.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.28.0...0.28.1) ### Bug Fixes - Renew MkDocs' `relpath` processor instead of using same instance ([4ab180d](https://github.com/mkdocstrings/mkdocstrings/commit/4ab180d01964c3ef8005cd72c8d91ba3fd241e27) by Timothée Mazzucotelli). [Issue-mkdocs-3919](https://github.com/mkdocs/mkdocs/issues/3919) ## [0.28.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.28.0) - 2025-02-03 [Compare with 0.27.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.27.0...0.28.0) ### Breaking Changes Although the following changes are "breaking" in terms of public API, we didn't find any public use of these classes and methods on GitHub. - `mkdocstrings.extension.AutoDocProcessor.__init__(parser)`: *Parameter was removed* - `mkdocstrings.extension.AutoDocProcessor.__init__(md)`: *Positional parameter was moved* - `mkdocstrings.extension.AutoDocProcessor.__init__(config)`: *Parameter was removed* - `mkdocstrings.extension.AutoDocProcessor.__init__(handlers)`: *Parameter kind was changed*: `positional or keyword` -> `keyword-only` - `mkdocstrings.extension.AutoDocProcessor.__init__(autorefs)`: *Parameter kind was changed*: `positional or keyword` -> `keyword-only` - `mkdocstrings.extension.MkdocstringsExtension.__init__(config)`: *Parameter was removed* - `mkdocstrings.extension.MkdocstringsExtension.__init__(handlers)`: *Positional parameter was moved* - `mkdocstrings.extension.MkdocstringsExtension.__init__(autorefs)`: *Positional parameter was moved* - `mkdocstrings.handlers.base.Handlers.__init__(config)`: *Parameter was removed* - `mkdocstrings.handlers.base.Handlers.__init__(theme)`: *Parameter was added as required* - `mkdocstrings.handlers.base.Handlers.__init__(default)`: *Parameter was added as required* - `mkdocstrings.handlers.base.Handlers.__init__(inventory_project)`: *Parameter was added as required* - `mkdocstrings.handlers.base.Handlers.__init__(tool_config)`: *Parameter was added as required* Similarly, the following parameters were renamed, but the methods are only called from our own code, using positional arguments. - `mkdocstrings.handlers.base.BaseHandler.collect(config)`: *Parameter was renamed `options`* - `mkdocstrings.handlers.base.BaseHandler.render(config)`: *Parameter was renamed `options`* Finally, the following method was removed, but this is again taken into account in our own code: - `mkdocstrings.handlers.base.BaseHandler.get_anchors`: *Public object was removed* For these reasons, and because we're still in v0, we do not bump to v1 yet. See following deprecations. ### Deprecations *mkdocstrings* 0.28 will start emitting these deprecations warnings: > The `handler` argument is deprecated. The handler name must be specified as a class attribute. Previously, the `get_handler` function would pass a `handler` (name) argument to the handler constructor. This name must now be set on the handler's class directly. ```python class MyHandler: name = "myhandler" ``` > The `domain` attribute must be specified as a class attribute. The `domain` class attribute on handlers is now mandatory and cannot be an empty string. ```python class MyHandler: domain = "mh" ``` > The `theme` argument must be passed as a keyword argument. This argument could previously be passed as a positional argument (from the `get_handler` function), and must now be passed as a keyword argument. > The `custom_templates` argument must be passed as a keyword argument. Same as for `theme`, but with `custom_templates`. > The `mdx` argument must be provided (as a keyword argument). The `get_handler` function now receives a `mdx` argument, which it must forward to the handler constructor and then to the base handler, either explicitly or through `**kwargs`: === "Explicitly" ```python def get_handler(..., mdx, ...): return MyHandler(..., mdx=mdx, ...) class MyHandler: def __init__(self, ..., mdx, ...): super().__init__(..., mdx=mdx, ...) ``` === "Through `**kwargs`" ```python def get_handler(..., **kwargs): return MyHandler(..., **kwargs) class MyHandler: def __init__(self, ..., **kwargs): super().__init__(**kwargs) ``` In the meantime we still retrieve this `mdx` value at a different moment, by reading it from the MkDocs configuration. > The `mdx_config` argument must be provided (as a keyword argument). Same as for `mdx`, but with `mdx_config`. > mkdocstrings v1 will stop handling 'import' in handlers configuration. Instead your handler must define a `get_inventory_urls` method that returns a list of URLs to download. Previously, mkdocstrings would pop the `import` key from a handler's configuration to download each item (URLs). Items could be strings, or dictionaries with a `url` key. Now mkdocstrings gives back control to handlers, which must store this inventory configuration within them, and expose it again through a `get_inventory_urls` method. This method returns a list of tuples: an URL, and a dictionary of options that will be passed again to their `load_inventory` method. Handlers have now full control over the "inventory" setting. ```python from copy import deepcopy def get_handler(..., handler_config, ...): return MyHandler(..., config=handler_config, ...) class MyHandler: def __init__(self, ..., config, ...): self.config = config def get_inventory_urls(self): config = deepcopy(self.config["import"]) return [(inv, {}) if isinstance(inv, str) else (inv.pop("url"), inv) for inv in config] ``` Changing the name of the key (for example from `import` to `inventories`) involves a change in user configuration, and both keys will have to be supported by your handler for some time. ```python def get_handler(..., handler_config, ...): if "inventories" not in handler_config and "import" in handler_config: warn("The 'import' key is renamed 'inventories'", FutureWarning) handler_config["inventories"] = handler_config.pop("import") return MyHandler(..., config=handler_config, ...) ``` > Setting a fallback anchor function is deprecated and will be removed in a future release. This comes from mkdocstrings and mkdocs-autorefs, and will disappear with mkdocstrings v0.28. > mkdocstrings v1 will start using your handler's `get_options` method to build options instead of merging the global and local options (dictionaries). Handlers must now store their own global options (in an instance attribute), and implement a `get_options` method that receives `local_options` (a dict) and returns combined options (dict or custom object). These combined options are then passed to `collect` and `render`, so that these methods can use them right away. ```python def get_handler(..., handler_config, ...): return MyHandler(..., config=handler_config, ...) class MyHandler: def __init__(self, ..., config, ...): self.config = config def get_options(local_options): return {**self.default_options, **self.config["options"], **local_options} ``` > The `update_env(md)` parameter is deprecated. Use `self.md` instead. Handlers can remove the `md` parameter from their `update_env` method implementation, and use `self.md` instead, if they need it. > No need to call `super().update_env()` anymore. Handlers don't have to call the parent `update_env` method from their own implementation anymore, and can just drop the call. > The `get_anchors` method is deprecated. Declare a `get_aliases` method instead, accepting a string (identifier) instead of a collected object. Previously, handlers would implement a `get_anchors` method that received a data object (typed `CollectorItem`) to return aliases for this object. This forced mkdocstrings to collect this object through the handler's `collect` method, which then required some logic with "fallback config" as to prevent unwanted collection. mkdocstrings gives back control to handlers and now calls `get_aliases` instead, which accepts an `identifier` (string) and lets the handler decide how to return aliases for this identifier. For example, it can replicate previous behavior by calling its own `collect` method with its own "fallback config", or do something different (cache lookup, etc.). ```python class MyHandler: def get_aliases(identifier): try: obj = self.collect(identifier, self.fallback_config) # or obj = self._objects_cache[identifier] except CollectionError: # or KeyError return () return ... # previous logic in `get_anchors` ``` > The `config_file_path` argument in `get_handler` functions is deprecated. Use `tool_config.get('config_file_path')` instead. The `config_file_path` argument is now deprecated and only passed to `get_handler` functions if they accept it. If you used it to compute a "base directory", you can now use the `tool_config` argument instead, which is the configuration of the SSG tool in use (here MkDocs): ```python base_dir = Path(tool_config.config_file_path or "./mkdocs.yml").parent ``` **Most of these warnings will disappear with the next version of mkdocstrings-python.** ### Bug Fixes - Update handlers in JSON schema to be an object instead of an array ([3cf7d51](https://github.com/mkdocstrings/mkdocstrings/commit/3cf7d51704378adc50d4ea50080aacae39e0e731) by Matthew Messinger). [Issue-733](https://github.com/mkdocstrings/mkdocstrings/issues/733), [PR-734](https://github.com/mkdocstrings/mkdocstrings/pull/734) - Fix broken table of contents when nesting autodoc instructions ([12c8f82](https://github.com/mkdocstrings/mkdocstrings/commit/12c8f82e9a959ce32cada09f0d2b5c651a705fdb) by Timothée Mazzucotelli). [Issue-348](https://github.com/mkdocstrings/mkdocstrings/issues/348) ### Code Refactoring - Pass `config_file_path` to `get_handler` if it expects it ([8c476ee](https://github.com/mkdocstrings/mkdocstrings/commit/8c476ee0b82c09a5b20d7a773ecaf4be17b9e4d1) by Timothée Mazzucotelli). - Give back inventory control to handlers ([b84653f](https://github.com/mkdocstrings/mkdocstrings/commit/b84653f2b175824c73bd0291fafff8343ba80125) by Timothée Mazzucotelli). [Related-to-issue-719](https://github.com/mkdocstrings/mkdocstrings/issues/719) - Give back control to handlers on how they want to handle global/local options ([c00de7a](https://github.com/mkdocstrings/mkdocstrings/commit/c00de7a42b9072cbaa47ecbf18e3e15a6d5ab634) by Timothée Mazzucotelli). [Issue-719](https://github.com/mkdocstrings/mkdocstrings/issues/719) - Deprecate base handler's `get_anchors` method in favor of `get_aliases` method ([7a668f0](https://github.com/mkdocstrings/mkdocstrings/commit/7a668f0f731401b07123bd02aafbbfc55cd24c0d) by Timothée Mazzucotelli). - Register all identifiers of rendered objects into autorefs ([434d8c7](https://github.com/mkdocstrings/mkdocstrings/commit/434d8c7cd1e3edbdb9d4c45a9b44b290b19d88f1) by Timothée Mazzucotelli). - Use mkdocs-get-deps' download utility to remove duplicated code ([bb87cd8](https://github.com/mkdocstrings/mkdocstrings/commit/bb87cd833f2333e77cb2c2926aa24a434c97391f) by Timothée Mazzucotelli). - Clean up data passed down from plugin to extension and handlers ([b8e8703](https://github.com/mkdocstrings/mkdocstrings/commit/b8e87036e0e1ec5c181b4a2ec5931f1a60636a32) by Timothée Mazzucotelli). [PR-726](https://github.com/mkdocstrings/mkdocstrings/pull/726) ## [0.27.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.27.0) - 2024-11-08 [Compare with 0.26.2](https://github.com/mkdocstrings/mkdocstrings/compare/0.26.2...0.27.0) ### Features - Add support for authentication in inventory file URLs ([1c23c1b](https://github.com/mkdocstrings/mkdocstrings/commit/1c23c1b0fc4a9bdec5e0eb43c8647beab66fec55) by Stefan Mejlgaard). [Issue-707](https://github.com/mkdocstrings/mkdocstrings/issues/707), [PR-710](https://github.com/mkdocstrings/mkdocstrings/pull/710) ### Performance Improvements - Reduce footprint of template debug messages ([5648e5a](https://github.com/mkdocstrings/mkdocstrings/commit/5648e5aca80a5d8ba9e5456efb36b517b9f3cdeb) by Timothée Mazzucotelli). ### Code Refactoring - Use %-formatting for logging messages ([0bbb8ca](https://github.com/mkdocstrings/mkdocstrings/commit/0bbb8caddf34b0a4faa0ed6f26e33102dc892fc8) by Timothée Mazzucotelli). ## [0.26.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.26.2) - 2024-10-12 [Compare with 0.26.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.26.1...0.26.2) ### Build - Drop support for Python 3.8 ([f26edeb](https://github.com/mkdocstrings/mkdocstrings/commit/f26edebe01337caa802a98c13240acdd8332a5fa) by Timothée Mazzucotelli). ## [0.26.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.26.1) - 2024-09-06 [Compare with 0.26.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.26.0...0.26.1) ### Bug Fixes - Instantiate config of the autorefs plugin when it is not enabled by the user ([db2ab34](https://github.com/mkdocstrings/mkdocstrings/commit/db2ab3403a95034987d574a517ddc426a4b4e1bd) by Timothée Mazzucotelli). [Issue-autorefs#57](https://github.com/mkdocstrings/autorefs/issues/57) ## [0.26.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.26.0) - 2024-09-02 [Compare with 0.25.2](https://github.com/mkdocstrings/mkdocstrings/compare/0.25.2...0.26.0) ### Build - Upgrade Python-Markdown lower bound to 3.6 ([28565f9](https://github.com/mkdocstrings/mkdocstrings/commit/28565f97f21bf81b2bc554679c641fba3f639882) by Timothée Mazzucotelli). ### Dependencies - Depend on mkdocs-autorefs v1 ([33aa573](https://github.com/mkdocstrings/mkdocstrings/commit/33aa573efb17b13e7b9da77e29aeccb3fbddd8e8) by Timothée Mazzucotelli). ### Features - Allow hooking into autorefs when converting Markdown docstrings ([b63e726](https://github.com/mkdocstrings/mkdocstrings/commit/b63e72691a8f92dd59b56304125de4a19e0d028c) by Timothée Mazzucotelli). [Based-on-PR-autorefs#46](https://github.com/mkdocstrings/autorefs/pull/46) ## [0.25.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.25.2) - 2024-07-25 [Compare with 0.25.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.25.1...0.25.2) ### Code Refactoring - Give precedence to Markdown heading level (`##`) ([2e5f89e](https://github.com/mkdocstrings/mkdocstrings/commit/2e5f89e8cef11e6447425d3700c29558cd6d241b) by Timothée Mazzucotelli). ## [0.25.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.25.1) - 2024-05-05 [Compare with 0.25.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.25.0...0.25.1) ### Bug Fixes - Always descend into sub-headings when re-applying their label ([cb86e08](https://github.com/mkdocstrings/mkdocstrings/commit/cb86e08bbc5e8057393aa1cd7ca29bc2b40ab5eb) by Timothée Mazzucotelli). [Issue-mkdocstrings/python-158](https://github.com/mkdocstrings/python/issues/158) ## [0.25.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.25.0) - 2024-04-27 [Compare with 0.24.3](https://github.com/mkdocstrings/mkdocstrings/compare/0.24.3...0.25.0) ### Features - Support `once` parameter in logging methods, allowing to log a message only once with a given logger ([1532b59](https://github.com/mkdocstrings/mkdocstrings/commit/1532b59a6efd99fed846cf7edfd0b26525700d3f) by Timothée Mazzucotelli). - Support blank line between `::: path` and YAML options ([d799d2f](https://github.com/mkdocstrings/mkdocstrings/commit/d799d2f3903bce44fb751f8cf3fb8078d25549da) by Timothée Mazzucotelli). [Issue-450](https://github.com/mkdocstrings/mkdocstrings/issues/450) ### Code Refactoring - Allow specifying name of template loggers ([c5b5f69](https://github.com/mkdocstrings/mkdocstrings/commit/c5b5f697c83271d961c7ac795412d6b4964ba2b7) by Timothée Mazzucotelli). ## [0.24.3](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.24.3) - 2024-04-05 [Compare with 0.24.2](https://github.com/mkdocstrings/mkdocstrings/compare/0.24.2...0.24.3) ### Bug Fixes - Support HTML toc labels with Python-Markdown 3.6+ (uncomment code...) ([7fe3e5f](https://github.com/mkdocstrings/mkdocstrings/commit/7fe3e5f28239c08094fb656728369998f52630ea) by Timothée Mazzucotelli). ## [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) ### Code Refactoring - Support new pymdownx-highlight options ([a7a2907](https://github.com/mkdocstrings/mkdocstrings/commit/a7a29079aebcd79be84ac38ce275797920e4c75e) by Timothée Mazzucotelli). - Backup anchors with id and no href, for compatibility with autorefs' Markdown anchors ([b5236b4](https://github.com/mkdocstrings/mkdocstrings/commit/b5236b4333ebde9648c84f6e4b0f4c2b10f3ecd4) by Timothée Mazzucotelli). [PR-#651](https://github.com/mkdocstrings/mkdocstrings/pull/651), [Related-to-mkdocs-autorefs#39](https://github.com/mkdocstrings/autorefs/pull/39), Co-authored-by: Oleh Prypin ## [0.24.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.24.0) - 2023-11-14 [Compare with 0.23.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.23.0...0.24.0) ### Features - Cache downloaded inventories as local file ([ce84dd5](https://github.com/mkdocstrings/mkdocstrings/commit/ce84dd57dc5cd3bf3f4be9623ddaa73e1c1868f0) by Oleh Prypin). [PR #632](https://github.com/mkdocstrings/mkdocstrings/pull/632) ### Bug Fixes - Make `custom_templates` relative to the config file ([370a61d](https://github.com/mkdocstrings/mkdocstrings/commit/370a61d12b33f3fb61f6bddb3939eb8ff6018620) by Waylan Limberg). [Issue #477](https://github.com/mkdocstrings/mkdocstrings/issues/477), [PR #627](https://github.com/mkdocstrings/mkdocstrings/pull/627) - Remove duplicated headings for docstrings nested in tabs/admonitions ([e2123a9](https://github.com/mkdocstrings/mkdocstrings/commit/e2123a935edea0abdc1b439e2c2b76e002c76e2b) by Perceval Wajsburt, [f4a94f7](https://github.com/mkdocstrings/mkdocstrings/commit/f4a94f7d8b8eb1ac01d65bb7237f0077e320ddac) by Oleh Prypin). [Issue #609](https://github.com/mkdocstrings/mkdocstrings/issues/609), [PR #610](https://github.com/mkdocstrings/mkdocstrings/pull/610), [PR #613](https://github.com/mkdocstrings/mkdocstrings/pull/613) ### Code Refactoring - Drop support for MkDocs < 1.4, modernize usages ([b61d4d1](https://github.com/mkdocstrings/mkdocstrings/commit/b61d4d15258c66b14266aa04b456f191f101b2c6) by Oleh Prypin). [PR #629](https://github.com/mkdocstrings/mkdocstrings/pull/629) ## [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) ### Features - Allow extensions to add templates ([cf0af05](https://github.com/mkdocstrings/mkdocstrings/commit/cf0af059eb89240eba0437de417c124389e2f20e) by Timothée Mazzucotelli). [PR #569](https://github.com/mkdocstrings/mkdocstrings/pull/569) ### Code Refactoring - Report inventory loading errors ([2c05d78](https://github.com/mkdocstrings/mkdocstrings/commit/2c05d7854b87251e26c1a2e1810b85702ff110f3) by Timothée Mazzucotelli). Co-authored-by: Oleh Prypin ## [0.21.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.21.2) - 2023-04-06 [Compare with 0.21.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.21.1...0.21.2) ### Bug Fixes - Fix regression with LRU cached method ([85efbd2](https://github.com/mkdocstrings/mkdocstrings/commit/85efbd285d4c8977755bda1c36220b241a9e1502) by Timothée Mazzucotelli). [Issue #549](https://github.com/mkdocstrings/mkdocstrings/issues/549) ## [0.21.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.21.1) - 2023-04-05 [Compare with 0.21.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.21.0...0.21.1) ### Bug Fixes - Fix missing typing-extensions dependency on Python less than 3.10 ([bff760b](https://github.com/mkdocstrings/mkdocstrings/commit/bff760b77c1eedfa770e852aa994a69ff51b0a32) by Timothée Mazzucotelli). [Issue #548](https://github.com/mkdocstrings/mkdocstrings/issues/548) ## [0.21.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.21.0) - 2023-04-05 [Compare with 0.20.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.20.0...0.21.0) ### Features - Expose the full config to handlers ([15dacf6](https://github.com/mkdocstrings/mkdocstrings/commit/15dacf62f8479a05e9604383155ffa6fade0522d) by David Patterson). [Issue #501](https://github.com/mkdocstrings/mkdocstrings/issues/501), [PR #509](https://github.com/mkdocstrings/mkdocstrings/pull/509) ## [0.20.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.20.0) - 2023-01-19 [Compare with 0.19.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.19.1...0.20.0) ### Features - Add `enabled` configuration option ([8cf117d](https://github.com/mkdocstrings/mkdocstrings/commit/8cf117daeefb4fc522145cc567b40eb4256c0a94) by StefanBRas). [Issue #478](https://github.com/mkdocstrings/mkdocstrings/issues/478), [PR #504](https://github.com/mkdocstrings/mkdocstrings/pull/504) ### Bug Fixes - Handle updating Jinja environment of multiple handlers ([a6ea80c](https://github.com/mkdocstrings/mkdocstrings/commit/a6ea80c992f2a200d8cee3c9ff3b651ddd049a3d) by David Patterson). [Related PR #201](https://github.com/mkdocstrings/mkdocstrings/pull/201), [Issue #502](https://github.com/mkdocstrings/mkdocstrings/issues/502), [PR #507](https://github.com/mkdocstrings/mkdocstrings/pull/507) ### Code Refactoring - Make `_load_inventory` accept lists as arguments ([105ed82](https://github.com/mkdocstrings/mkdocstrings/commit/105ed8210d4665f6b52f2cc04d56df2d35cd3caf) by Sorin Sbarnea). [Needed by PR mkdocstrings/python#49](https://github.com/mkdocstrings/python/issues/49), [PR #511](https://github.com/mkdocstrings/mkdocstrings/pull/511) - Remove support for MkDocs < 1.2 (we already depended on MkDocs >= 1.2) ([ac963c8](https://github.com/mkdocstrings/mkdocstrings/commit/ac963c88c793e640d2a7a31392aff1fc2d15ba52) by Timothée Mazzucotelli). ## [0.19.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.19.1) - 2022-12-13 [Compare with 0.19.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.19.0...0.19.1) ### Bug Fixes - Fix regular expression for Sphinx inventory parsing ([348bdd5](https://github.com/mkdocstrings/mkdocstrings/commit/348bdd5e930f3cf7a8e27835189794ec940ae1b7) by Luis Michaelis). [Issue #496](https://github.com/mkdocstrings/mkdocstrings/issues/496), [PR #497](https://github.com/mkdocstrings/mkdocstrings/issues/497) ### Code Refactoring - Small fixes to type annotations ([9214b74](https://github.com/mkdocstrings/mkdocstrings/commit/9214b74367da1f9c808eacc8ceecc4134d5c9d3c) by Oleh Prypin). [PR #470](https://github.com/mkdocstrings/mkdocstrings/issues/470) - Report usage-based warnings as user-facing messages ([03dd7a6](https://github.com/mkdocstrings/mkdocstrings/commit/03dd7a6e4fefa44889bda9899d9b698bcfd07990) by Oleh Prypin). [PR #464](https://github.com/mkdocstrings/mkdocstrings/issues/464) ## [0.19.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.19.0) - 2022-05-28 [Compare with 0.18.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.18.1...0.19.0) ### Highlights We decided to deprecate a few things to pave the way towards a more stable code base, bringing us closer to a v1. - Selection and rendering options are now combined into a single `options` key. Using the old keys will emit a deprecation warning. - The `BaseCollector` and `BaseRenderer` classes are deprecated in favor of `BaseHandler`, which merges their functionality. Using the old classes will emit a deprecation warning. New versions of the Python handler and the legacy Python handler were also released in coordination with *mkdocstrings* 0.19. See their respective changelogs: [python](https://mkdocstrings.github.io/python/changelog/#070-2022-05-28), [python-legacy](https://mkdocstrings.github.io/python-legacy/changelog/#023-2022-05-28). Most notably, the Python handler gained the `members` and `filters` options that prevented many users to switch to it. *mkdocstrings* stopped depending directly on the legacy Python handler. It means you now have to explicitely depend on it, directly or through the extra provided by *mkdocstrings*, if you want to continue using it. ### Packaging / Dependencies - Stop depending directly on mkdocstrings-python-legacy ([9055d58](https://github.com/mkdocstrings/mkdocstrings/commit/9055d582a6244a45a1af1aeccd8bf3436889a1a5) by Timothée Mazzucotelli). [Issue #376](https://github.com/mkdocstrings/mkdocstrings/issues/376) ### Features - Pass config file path to handlers ([cccebc4](https://github.com/mkdocstrings/mkdocstrings/commit/cccebc40c0d51c23381d53432d9355fba9a290ae) by Timothée Mazzucotelli). [Issue #311](https://github.com/mkdocstrings/mkdocstrings/issues/311), [PR #425](https://github.com/mkdocstrings/mkdocstrings/issues/425) ### Code Refactoring - Support options / deprecated options mix-up ([7c71f26](https://github.com/mkdocstrings/mkdocstrings/commit/7c71f2623b667d43c5e9eb8aea881df2c9984a0e) by Timothée Mazzucotelli). - Deprecate watch feature in favor of MkDocs' built-in one ([c20022e](https://github.com/mkdocstrings/mkdocstrings/commit/c20022e6adfd3a18fd698f50355dfce534b9feb9) by Timothée Mazzucotelli). - Log relative template paths if possible, instead of absolute ([91f5f83](https://github.com/mkdocstrings/mkdocstrings/commit/91f5f83408c7aab9124cc19fa47c940541d6f5ec) by Timothée Mazzucotelli). - Deprecate `selection` and `rendering` YAML keys ([3335310](https://github.com/mkdocstrings/mkdocstrings/commit/3335310b985401642fea8322aba503cafa1c50b1) by Timothée Mazzucotelli). [PR #420](https://github.com/mkdocstrings/mkdocstrings/issues/420) - Deprecate `BaseCollector` and `BaseRenderer` ([eb822cb](https://github.com/mkdocstrings/mkdocstrings/commit/eb822cb11ec065da0b1277299aae4ffeeffadc6f) by Timothée Mazzucotelli). [PR #413](https://github.com/mkdocstrings/mkdocstrings/issues/413) ## [0.18.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.18.1) - 2022-03-01 [Compare with 0.18.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.18.0...0.18.1) ### Bug Fixes - Don't preemptively register identifiers as anchors ([c7ac043](https://github.com/mkdocstrings/mkdocstrings/commit/c7ac04324d005d9cf7d2c1f3b2c39f212275d451) by Timothée Mazzucotelli). ## [0.18.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.18.0) - 2022-02-06 [Compare with 0.17.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.17.0...0.18.0) ### Highlights - Python 3.6 support is dropped. - We provide a new, experimental Python handler based on [Griffe](https://github.com/mkdocstrings/griffe). This new handler brings automatic cross-references for every annotation in your code, including references to third-party libraries' APIs if they provide objects inventories and you explicitely [load them](https://mkdocstrings.github.io/usage/#cross-references-to-other-projects-inventories) in `mkdocs.yml`. [See migration notes in the documentation](https://mkdocstrings.github.io/handlers/overview/#about-the-python-handlers). - The "legacy" Python handler now lives in its own repository at https://github.com/mkdocstrings/python-legacy. ### Packaging / Dependencies - Add Crystal extra, update Python extras versions ([b8222b0](https://github.com/mkdocstrings/mkdocstrings/commit/b8222b0150d4743be857bcbf40f014265095885b) by Timothée Mazzucotelli). [PR #374](https://github.com/mkdocstrings/mkdocstrings/pull/374) - Update autorefs to actually required version ([fc6c7f6](https://github.com/mkdocstrings/mkdocstrings/commit/fc6c7f652a420ac29cf16cbb99b11a55aa9b38ea) by Timothée Mazzucotelli). - Drop Python 3.6 support ([7205ac6](https://github.com/mkdocstrings/mkdocstrings/commit/7205ac6cf2861db61c2a5b8bf07d0e6b1a7f49fb) by Timothée Mazzucotelli). ### Features - Allow unwrapping the `

` tag in `convert_markdown` filter ([5351fc8](https://github.com/mkdocstrings/mkdocstrings/commit/5351fc8b417fb20f0681a22f49fcc902579eacdb) by Oleh Prypin). [PR #369](https://github.com/mkdocstrings/mkdocstrings/pull/369) - Support handlers spanning multiple locations ([f42dfc6](https://github.com/mkdocstrings/mkdocstrings/commit/f42dfc61ce4f9f317c4bd17f568e504ed9764d35) by Timothée Mazzucotelli). [PR #355](https://github.com/mkdocstrings/mkdocstrings/pull/355) ### Code Refactoring - Prefix logs with the package name only ([6c2b734](https://github.com/mkdocstrings/mkdocstrings/commit/6c2b7348ae40989e4adccc087feae599fcea949d) by Timothée Mazzucotelli). [PR #375](https://github.com/mkdocstrings/mkdocstrings/pull/375) - Extract the Python handler into its own repository ([74371e4](https://github.com/mkdocstrings/mkdocstrings/commit/74371e49c32059fefd34c7cc7f7b8f085b383237) by Timothée Mazzucotelli). [PR #356](https://github.com/mkdocstrings/mkdocstrings/pull/356) - Support Jinja2 3.1 ([b377227](https://github.com/mkdocstrings/mkdocstrings/commit/b37722716b1e0ed6393ec71308dfb0f85e142f3b) by Timothée Mazzucotelli). [Issue #360](https://github.com/mkdocstrings/mkdocstrings/issues/360), [PR #361](https://github.com/mkdocstrings/mkdocstrings/pull/361) - Find templates in new and deprecated namespaces ([d5d5f18](https://github.com/mkdocstrings/mkdocstrings/commit/d5d5f1844dbac3affacc95f2f3eab57a61d2068c) by Timothée Mazzucotelli). [PR #367](https://github.com/mkdocstrings/mkdocstrings/pull/367) - Support loading handlers from the `mkdocstrings_handlers` namespace ([5c22c6c](https://github.com/mkdocstrings/mkdocstrings/commit/5c22c6ce4e056ac2334e2dfcd47c1f1a7884d352) by Timothée Mazzucotelli). [PR #367](https://github.com/mkdocstrings/mkdocstrings/pull/367) ## [0.17.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.17.0) - 2021-12-27 [Compare with 0.16.2](https://github.com/mkdocstrings/mkdocstrings/compare/0.16.2...0.17.0) ### Features - Add `show_signature` rendering option ([024ee82](https://github.com/mkdocstrings/mkdocstrings/commit/024ee826bb6f0aa297ba857bc18075d6f4162cad) by Will Da Silva). [Issue #341](https://github.com/mkdocstrings/mkdocstrings/issues/341), [PR #342](https://github.com/mkdocstrings/mkdocstrings/pull/342) - Support Keyword Args and Yields sections ([1286427](https://github.com/mkdocstrings/mkdocstrings/commit/12864271b7f997af7b421a834919b1e686793905) by Timothée Mazzucotelli). [Issue #205](https://github.com/mkdocstrings/mkdocstrings/issues/205) and [#324](https://github.com/mkdocstrings/mkdocstrings/issues/324), [PR #331](https://github.com/mkdocstrings/mkdocstrings/pull/331) ### Bug Fixes - Do minimum work when falling back to re-collecting an object to get its anchor ([f6cf570](https://github.com/mkdocstrings/mkdocstrings/commit/f6cf570255df17db1088b6e6cd94bcc823b3b17f) by Timothée Mazzucotelli). [Issue #329](https://github.com/mkdocstrings/mkdocstrings/issues/329), [PR #330](https://github.com/mkdocstrings/mkdocstrings/pull/330) ### Code Refactoring - Return multiple identifiers from fallback method ([78c498c](https://github.com/mkdocstrings/mkdocstrings/commit/78c498c4a6cfc33cc6ceab9829426bd64e518d44) by Timothée Mazzucotelli). [Issue mkdocstrings/autorefs#11](https://github.com/mkdocstrings/autorefs/issues/11), [PR #350](https://github.com/mkdocstrings/mkdocstrings/pull/350) ## [0.16.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.16.2) - 2021-10-04 [Compare with 0.16.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.16.1...0.16.2) ### Dependencies - Support `pymdown-extensions` v9.x ([0831343](https://github.com/mkdocstrings/mkdocstrings/commit/0831343aa8726ed785b17bba1c8d4adf49b46748) by Ofek Lev and [38b22ec](https://github.com/mkdocstrings/mkdocstrings/commit/38b22ec11cded4689115dafc43e16a1e8e40feda) by Timothée Mazzucotelli). ## [0.16.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.16.1) - 2021-09-23 [Compare with 0.16.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.16.0...0.16.1) ### Bug Fixes - Fix ReadTheDocs "return" template ([598621b](https://github.com/mkdocstrings/mkdocstrings/commit/598621bff29d2aeda0e14f350cda36c1a1f418d5) by Timothée Mazzucotelli). ## [0.16.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.16.0) - 2021-09-20 [Compare with 0.15.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.15.0...0.16.0) ### Features - Add a rendering option to change the sorting of members ([b1fff8b](https://github.com/mkdocstrings/mkdocstrings/commit/b1fff8b8ef4d6d77417fc43ed8be4b578d6437e4) by Joe Rickerby). [Issue #114](https://github.com/mkdocstrings/mkdocstrings/issues/114), [PR #274](https://github.com/mkdocstrings/mkdocstrings/pull/274) - Add option to show Python base classes ([436f550](https://github.com/mkdocstrings/mkdocstrings/commit/436f5504ad72ab6d1f5b4303e6b68bc84562c32b) by Brian Koropoff). [Issue #269](https://github.com/mkdocstrings/mkdocstrings/issues/269), [PR #297](https://github.com/mkdocstrings/mkdocstrings/pull/297) - Support loading external Python inventories in Sphinx format ([a8418cb](https://github.com/mkdocstrings/mkdocstrings/commit/a8418cb4c6193d35cdc72508b118a712cf0334e1) by Oleh Prypin). [PR #287](https://github.com/mkdocstrings/mkdocstrings/pull/287) - Support loading external inventories and linking to them ([8b675f4](https://github.com/mkdocstrings/mkdocstrings/commit/8b675f4671f8bbfd2f337ed043e3682b0a0ad0f6) by Oleh Prypin). [PR #277](https://github.com/mkdocstrings/mkdocstrings/pull/277) - Very basic support for MkDocs theme ([974ca90](https://github.com/mkdocstrings/mkdocstrings/commit/974ca9010efca1b8279767faf8efcd2470a8371d) by Oleh Prypin). [PR #272](https://github.com/mkdocstrings/mkdocstrings/pull/272) - Generate objects inventory ([14ed959](https://github.com/mkdocstrings/mkdocstrings/commit/14ed959860a784a835cd71f911081f2026d66c81) and [bbd85a9](https://github.com/mkdocstrings/mkdocstrings/commit/bbd85a92fa70bddfe10a907a4d63b8daf0810cb2) by Timothée Mazzucotelli). [Issue #251](https://github.com/mkdocstrings/mkdocstrings/issues/251), [PR #253](https://github.com/mkdocstrings/mkdocstrings/pull/253) ### Bug Fixes - Don't render empty code blocks for missing type annotations ([d2e9e1e](https://github.com/mkdocstrings/mkdocstrings/commit/d2e9e1ef3cf304081b07f763843a9722bf9b117e) by Oleh Prypin). - Fix custom handler not being used ([6dcf342](https://github.com/mkdocstrings/mkdocstrings/commit/6dcf342fb83b19e385d56d37235f2b23e8c8c767) by Timothée Mazzucotelli). [Issue #259](https://github.com/mkdocstrings/mkdocstrings/issues/259), [PR #263](https://github.com/mkdocstrings/mkdocstrings/pull/263) - Don't hide `setup_commands` errors ([92418c4](https://github.com/mkdocstrings/mkdocstrings/commit/92418c4b3e80b67d5116efa73931fc113daa60e9) by Gabriel Vîjială). [PR #258](https://github.com/mkdocstrings/mkdocstrings/pull/258) ### Code Refactoring - Move writing extra files to an earlier stage in the build ([3890ab5](https://github.com/mkdocstrings/mkdocstrings/commit/3890ab597692e56d7ece576c166373b66ff4e615) by Oleh Prypin). [PR #275](https://github.com/mkdocstrings/mkdocstrings/pull/275) ## [0.15.2](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.15.2) - 2021-06-09 [Compare with 0.15.1](https://github.com/mkdocstrings/mkdocstrings/compare/0.15.1...0.15.2) ### Packaging - MkDocs default schema needs to be obtained differently now ([b3e122b](https://github.com/mkdocstrings/mkdocstrings/commit/b3e122b36d586632738ddedaed7d3df8d5dead44) by Oleh Prypin). [PR #273](https://github.com/mkdocstrings/mkdocstrings/pull/273) - Compatibility with MkDocs 1.2: livereload isn't guaranteed now ([36e8024](https://github.com/mkdocstrings/mkdocstrings/commit/36e80248d2ab9e61975f6c83ae517115c9410fc1) by Oleh Prypin). [PR #294](https://github.com/mkdocstrings/mkdocstrings/pull/294) ## [0.15.1](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.15.1) - 2021-05-16 [Compare with 0.15.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.15.0...0.15.1) ### Bug Fixes - Prevent error during parallel installations ([fac2c71](https://github.com/mkdocstrings/mkdocstrings/commit/fac2c711351f7b62bf5308f19cfc612a3944588a) by Timothée Mazzucotelli). ### Packaging - Support the upcoming major Jinja and MarkupSafe releases ([bb4f9de](https://github.com/mkdocstrings/mkdocstrings/commit/bb4f9de08a77bef85e550d70deb0db13e6aa0c96) by Oleh Prypin). [PR #283](https://github.com/mkdocstrings/mkdocstrings/pull/283) - Accept a higher version of mkdocs-autorefs ([c8de08e](https://github.com/mkdocstrings/mkdocstrings/commit/c8de08e177f78290d3baaca2716d1ec64c9059b6) by Oleh Prypin). [PR #282](https://github.com/mkdocstrings/mkdocstrings/pull/282) ## [0.15.0](https://github.com/mkdocstrings/mkdocstrings/releases/tag/0.15.0) - 2021-02-28 [Compare with 0.14.0](https://github.com/mkdocstrings/mkdocstrings/compare/0.14.0...0.15.0) ### Breaking Changes The following items are *possible* breaking changes: - Cross-linking to arbitrary headings now requires to opt-in to the *autorefs* plugin, which is installed as a dependency of *mkdocstrings*. See [Cross-references to any Markdown heading](https://mkdocstrings.github.io/usage/#cross-references-to-any-markdown-heading). - *mkdocstrings* now respects your configured code highlighting method, so if you are using the CodeHilite extension, the `.highlight` CSS class in the rendered HTML will become `.codehilite`. So make sure to adapt your extra CSS accordingly. Or just switch to using [pymdownx.highlight](https://facelessuser.github.io/pymdown-extensions/extensions/highlight/), it's better supported by *mkdocstrings* anyway. See [Syntax highlighting](https://mkdocstrings.github.io/theming/#syntax-highlighting). - Most of the [CSS rules that *mkdocstrings* used to recommend](https://mkdocstrings.github.io/handlers/python/#recommended-style-material) for manual addition, now become mandatory (auto-injected into the site). This shouldn't *break* any of your styles, but you are welcome to remove the now-redundant lines that you had copied into `extra_css`, [similarly to this diff](https://github.com/mkdocstrings/mkdocstrings/pull/218/files#diff-7889a1924c66ff9318f1d81c4a3b75658d09bebf0db3b2e4023ba3e40294eb73). ### Features - Nicer-looking error outputs - no tracebacks from mkdocstrings ([6baf720](https://github.com/mkdocstrings/mkdocstrings/commit/6baf720850d359ddb55713553a757fe7b2283e10) by Oleh Prypin). [PR #230](https://github.com/mkdocstrings/mkdocstrings/pull/230) - Let handlers add CSS to the pages, do so for Python handler ([05c7a3f](https://github.com/mkdocstrings/mkdocstrings/commit/05c7a3fc83b67d3244ea3bfe97dab19aa53f2d38) by Oleh Prypin). [Issue #189](https://github.com/mkdocstrings/mkdocstrings/issues/189), [PR #218](https://github.com/mkdocstrings/mkdocstrings/pull/218) - Allow linking to an object heading not only by its canonical identifier, but also by its possible aliases ([4789950](https://github.com/mkdocstrings/mkdocstrings/commit/4789950ff43c354d47afbed5c89d5abb917ffee6) by Oleh Prypin). [PR #217](https://github.com/mkdocstrings/mkdocstrings/pull/217) ### Bug Fixes - Propagate the CSS class to inline highlighting as well ([c7d80e6](https://github.com/mkdocstrings/mkdocstrings/commit/c7d80e63a042913b7511c38a788967796dd10997) by Oleh Prypin). [PR #245](https://github.com/mkdocstrings/mkdocstrings/pull/245) - Don't double-escape characters in highlighted headings ([6357144](https://github.com/mkdocstrings/mkdocstrings/commit/6357144b100be6a2e7e6140e035c289c225cec22) by Oleh Prypin). [Issue #228](https://github.com/mkdocstrings/mkdocstrings/issues/228), [PR #241](https://github.com/mkdocstrings/mkdocstrings/pull/241) ### Code Refactoring - Use the autorefs plugin from its new external location ([e2d74ef](https://github.com/mkdocstrings/mkdocstrings/commit/e2d74efb0d59f9a1aa45e42525ceb1d4b7638426) by Oleh Prypin). [PR #235](https://github.com/mkdocstrings/mkdocstrings/pull/235) - Split out Markdown extensions from `handlers` to `handlers.rendering` ([7533852](https://github.com/mkdocstrings/mkdocstrings/commit/7533852e3ac0a378b70a380cef1100421b7d5763) by Oleh Prypin). [PR #233](https://github.com/mkdocstrings/mkdocstrings/pull/233) - Theme-agnostic code highlighting, respecting configs ([f9ea009](https://github.com/mkdocstrings/mkdocstrings/commit/f9ea00979545e39983ba377f1930d73ae94165ea) by Oleh Prypin). [PR #202](https://github.com/mkdocstrings/mkdocstrings/pull/202) - Split out autorefs plugin, make it optional ([fc67656](https://github.com/mkdocstrings/mkdocstrings/commit/fc676564f9b11269b3e0b0482703ac924069a3fa) by Oleh Prypin). [PR #220](https://github.com/mkdocstrings/mkdocstrings/pull/220) - Remove the extra wrapper div from the final doc ([7fe438c](https://github.com/mkdocstrings/mkdocstrings/commit/7fe438c4040a2124b00c39e582ef4c38be7c55c9) by Oleh Prypin). [PR #209](https://github.com/mkdocstrings/mkdocstrings/pull/209) - Don't re-parse the whole subdoc, expose only headings ([15f84f9](https://github.com/mkdocstrings/mkdocstrings/commit/15f84f981982c8e2b15498f5c869ac207f3ce5d7) by Oleh Prypin). [PR #209](https://github.com/mkdocstrings/mkdocstrings/pull/209) - Actually exclude hidden headings from the doc ([0fdb082](https://github.com/mkdocstrings/mkdocstrings/commit/0fdb0821867eb0e14a972a603c22301aafecf4f4) by Oleh Prypin). [PR #209](https://github.com/mkdocstrings/mkdocstrings/pull/209) ## [0.14.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.14.0) - 2021-01-06 [Compare with 0.13.6](https://github.com/pawamoy/mkdocstrings/compare/0.13.6...0.14.0) Special thanks to Oleh [@oprypin](https://github.com/oprypin) Prypin who did an amazing job (this is a euphemism) at improving *mkdocstrings*, fixing hard-to-fix bugs with clever solutions, implementing great new features and refactoring the code for better performance and readability! Thanks Oleh! ### Bug Fixes - Fix double code tags ([e84d401](https://github.com/pawamoy/mkdocstrings/commit/e84d401c6dcb9aecb8cc1a58d3a0f339e1c3e78f) by Timothée Mazzucotelli). - Don't mutate the original Markdown config for permalinks ([8f6b163](https://github.com/pawamoy/mkdocstrings/commit/8f6b163b50551da22f65e9b736e042562f77f2d7) by Oleh Prypin). - Preserve text immediately before an autodoc ([07466fa](https://github.com/pawamoy/mkdocstrings/commit/07466fafb54963a4e35e69007b6291a0382aaeb4) by Oleh Prypin). [PR #207](https://github.com/pawamoy/mkdocstrings/pull/207) - Remove `href` attributes from headings in templates ([d5602ff](https://github.com/pawamoy/mkdocstrings/commit/d5602ff3bb1a75ac1c8c457e972271b6c66eb8dd) by Oleh Prypin). [PR #204](https://github.com/pawamoy/mkdocstrings/pull/204) - Don't let `toc` extension append its permalink twice ([a154f5c](https://github.com/pawamoy/mkdocstrings/commit/a154f5c4c6ef9abd221e1f89e44847ae2cf25436) by Oleh Prypin). [PR #203](https://github.com/pawamoy/mkdocstrings/pull/203) - Fix undefined entity for `¶` ([2c29211](https://github.com/pawamoy/mkdocstrings/commit/2c29211002d515db40e5bdabf6cbf32ec8633a05) by Timothée Mazzucotelli). - Make ids of Markdown sub-documents prefixed with the parent item id ([d493d33](https://github.com/pawamoy/mkdocstrings/commit/d493d33b3827d93e84a7b2e39f0a10dfcb782402) by Oleh Prypin). [Issue #186](https://github.com/pawamoy/mkdocstrings/issues/186) and [#193](https://github.com/pawamoy/mkdocstrings/issues/193), [PR #199](https://github.com/pawamoy/mkdocstrings/pull/199) - More lenient regex for data-mkdocstrings-identifier ([dcfec8e](https://github.com/pawamoy/mkdocstrings/commit/dcfec8edfdff050debc5856dfc213d3119a84792) by Oleh Prypin). - Shift Markdown headings according to the current `heading_level` ([13f41ae](https://github.com/pawamoy/mkdocstrings/commit/13f41aec5a95c82c1229baa4ac3caf4abb2add51) by Oleh Prypin). [Issue #192](https://github.com/pawamoy/mkdocstrings/issues/192), [PR #195](https://github.com/pawamoy/mkdocstrings/pull/195) - Fix footnotes appearing in all following objects ([af24bc2](https://github.com/pawamoy/mkdocstrings/commit/af24bc246a6938ebcae7cf6ff677b194cf1af95c) by Oleh Prypin). [Issue #186](https://github.com/pawamoy/mkdocstrings/issues/186), [PR #195](https://github.com/pawamoy/mkdocstrings/pull/195) - Fix cross-references from the root index page ([9c9f2a0](https://github.com/pawamoy/mkdocstrings/commit/9c9f2a04af94e0d88f57fd76249f7985166a9b88) by Oleh Prypin). [Issue #184](https://github.com/pawamoy/mkdocstrings/issues/184), [PR #185](https://github.com/pawamoy/mkdocstrings/pull/185) - Fix incorrect argument name passed to Markdown ([10ce502](https://github.com/pawamoy/mkdocstrings/commit/10ce502d5fd58f1e5a4e14308ffad1bc3d7116ee) by Timothée Mazzucotelli). - Fix error when a digit immediately follows a code tag ([9b92341](https://github.com/pawamoy/mkdocstrings/commit/9b9234160edc54b53c81a618b12095e7dd829059) by Oleh Prypin). [Issue #169](https://github.com/pawamoy/mkdocstrings/issues/169), [PR #175](https://github.com/pawamoy/mkdocstrings/pull/175) - Detecting paths relative to template directory in logging ([a50046b](https://github.com/pawamoy/mkdocstrings/commit/a50046b5d58d62df4ba13f4c197e80edd1995eb9) by Oleh Prypin). [Issue #166](https://github.com/pawamoy/mkdocstrings/issues/166) ### Code Refactoring - BlockProcessor already receives strings, use them as such ([bcf7da9](https://github.com/pawamoy/mkdocstrings/commit/bcf7da911a310a63351c5082e84bb763d90d5b3b) by Oleh Prypin). - Remove some unused code ([8504084](https://github.com/pawamoy/mkdocstrings/commit/850408421cc027be8374673cc74c71fff26f3833) by Oleh Prypin). [PR #206](https://github.com/pawamoy/mkdocstrings/pull/206) - Improve XML parsing error handling ([ad86410](https://github.com/pawamoy/mkdocstrings/commit/ad864100b644ab1ee8daaa0d3923bc87dee1c5ca) by Timothée Mazzucotelli). - Explicitly use MarkupSafe ([6b9ebe7](https://github.com/pawamoy/mkdocstrings/commit/6b9ebe7d510e82971acef89e9e946af3c0cc96d3) by Oleh Prypin). - Split out the handler cache, expose it through the plugin ([6453026](https://github.com/pawamoy/mkdocstrings/commit/6453026fac287387090a67cce70c078377d107dd) by Oleh Prypin). [Issue #179](https://github.com/pawamoy/mkdocstrings/issues/179), [PR #191](https://github.com/pawamoy/mkdocstrings/pull/191) - Use ChainMap instead of copying dicts ([c634d2c](https://github.com/pawamoy/mkdocstrings/commit/c634d2ce6377de26caa553048bb28ef1e672f7aa) by Oleh Prypin). [PR #171](https://github.com/pawamoy/mkdocstrings/pull/171) - Rename logging to loggers to avoid confusion ([7a119cc](https://github.com/pawamoy/mkdocstrings/commit/7a119ccf27cf77cf2cbd114e7fad0a9e4e97bbd8) by Timothée Mazzucotelli). - Simplify logging ([409f93e](https://github.com/pawamoy/mkdocstrings/commit/409f93ed26d7d8292a8bc7a6c32cb270b3769409) by Timothée Mazzucotelli). ### Features - Allow specifying `heading_level` as a Markdown heading ([10efc28](https://github.com/pawamoy/mkdocstrings/commit/10efc281e04b2a430cec53e49208ccc09e591667) by Oleh Prypin). [PR #170](https://github.com/pawamoy/mkdocstrings/pull/170) - Allow any characters in identifiers ([7ede68a](https://github.com/pawamoy/mkdocstrings/commit/7ede68a0917b494eda2198931a8ad1c97fc8fce4) by Oleh Prypin). [PR #174](https://github.com/pawamoy/mkdocstrings/pull/174) - Allow namespace packages for handlers ([39b0465](https://github.com/pawamoy/mkdocstrings/commit/39b046548f57dc59993241b24d2cf12fb5e488eb) by Timothée Mazzucotelli). - Add template debugging/logging ([33b32c1](https://github.com/pawamoy/mkdocstrings/commit/33b32c1410bf6e8432768865c8aa86b8e091ab59) by Timothée Mazzucotelli). - Add initial support for the ReadTheDocs theme ([1028115](https://github.com/pawamoy/mkdocstrings/commit/1028115682ed0806d6570c749af0e382c67d6120) by Timothée Mazzucotelli). [Issue #107](https://github.com/pawamoy/mkdocstrings/issues/107), [PR #159](https://github.com/pawamoy/mkdocstrings/pull/159) - Add option to show type annotations in signatures ([f94ce9b](https://github.com/pawamoy/mkdocstrings/commit/f94ce9bdb2afc2c41c21a53636980ca077b757ce) by Timothée Mazzucotelli). [Issue #106](https://github.com/pawamoy/mkdocstrings/issues/106) ### Packaging - Accept verions of `pytkdocs` up to 0.10.x (see [changelog](https://pawamoy.github.io/pytkdocs/changelog/#0100-2020-12-06)). ### Performance Improvements - Call `update_env` only once per `Markdown` instance ([b198c74](https://github.com/pawamoy/mkdocstrings/commit/b198c74338dc3b54b999eadeef9946d69277ad77) by Oleh Prypin). [PR #201](https://github.com/pawamoy/mkdocstrings/pull/201) - Disable Jinja's `auto_reload` to reduce disk reads ([3b28c58](https://github.com/pawamoy/mkdocstrings/commit/3b28c58c77642071419d4a98e007d5a854b7984f) by Oleh Prypin). [PR #200](https://github.com/pawamoy/mkdocstrings/pull/200) - Rework autorefs replacement to not re-parse the final HTML ([22a9e4b](https://github.com/pawamoy/mkdocstrings/commit/22a9e4bf1b73f9b9b1a7c4876f0c677f919bc4d7) by Oleh Prypin). [Issue #187](https://github.com/pawamoy/mkdocstrings/issues/187), [PR #188](https://github.com/pawamoy/mkdocstrings/pull/188) ## [0.13.6](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.6) - 2020-09-28 [Compare with 0.13.5](https://github.com/pawamoy/mkdocstrings/compare/0.13.5...0.13.6) ### Bug Fixes - Fix rendering when clicking on hidden toc entries ([2af4d31](https://github.com/pawamoy/mkdocstrings/commit/2af4d310adefec614235a2c1d04d5ff56bf9c220) by Timothée Mazzucotelli). Issue [#60](https://github.com/pawamoy/mkdocstrings/issues/60). ## [0.13.5](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.5) - 2020-09-28 [Compare with 0.13.4](https://github.com/pawamoy/mkdocstrings/compare/0.13.4...0.13.5) ## Packaging - Accept `pytkdocs` version up to 0.9.x ([changelog](https://pawamoy.github.io/pytkdocs/changelog/#090-2020-09-28)). ## [0.13.4](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.4) - 2020-09-25 [Compare with 0.13.3](https://github.com/pawamoy/mkdocstrings/compare/0.13.3...0.13.4) ### Bug Fixes - Bring back arbitrary `**config` to Python handler ([fca7d4c](https://github.com/pawamoy/mkdocstrings/commit/fca7d4c75ffd7a84eaeccd27facd5575604dbfab) by Florimond Manca). Issue [#154](https://github.com/pawamoy/mkdocstrings/issues/154), PR [#155](https://github.com/pawamoy/mkdocstrings/pull/155) ## [0.13.3](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.3) - 2020-09-25 [Compare with 0.13.2](https://github.com/pawamoy/mkdocstrings/compare/0.13.2...0.13.3) ### Packaging - Accept `pytkdocs` version up to 0.8.x ([changelog](https://pawamoy.github.io/pytkdocs/changelog/#080-2020-09-25)). ## [0.13.2](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.2) - 2020-09-08 [Compare with 0.13.1](https://github.com/pawamoy/mkdocstrings/compare/0.13.1...0.13.2) ### Bug Fixes - Fix relative URLs when `use_directory_urls` is false ([421d189](https://github.com/pawamoy/mkdocstrings/commit/421d189fff9ea2608e40d85e0a93e30334782b90) by Timothée Mazzucotelli). References: [#149](https://github.com/pawamoy/mkdocstrings/issues/149) ## [0.13.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.1) - 2020-09-03 [Compare with 0.13.0](https://github.com/pawamoy/mkdocstrings/compare/0.13.0...0.13.1) ### Bug Fixes - Use relative links for cross-references ([9c77f1f](https://github.com/pawamoy/mkdocstrings/commit/9c77f1f461fa87842ae39945f9521ee85b1e413b) by Timothée Mazzucotelli). References: [#144](https://github.com/pawamoy/mkdocstrings/issues/144), [#147](https://github.com/pawamoy/mkdocstrings/issues/147) ## [0.13.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.13.0) - 2020-08-21 [Compare with 0.12.2](https://github.com/pawamoy/mkdocstrings/compare/0.12.2...0.13.0) ### Bug Fixes - Accept dashes in module names ([fcf79d0](https://github.com/pawamoy/mkdocstrings/commit/fcf79d0024ec46c3862c94202864e054c04a6d0b) by Timothée Mazzucotelli). References: [#140](https://github.com/pawamoy/mkdocstrings/issues/140) ### Features - Add option to show full path of direct members only ([d1b9401](https://github.com/pawamoy/mkdocstrings/commit/d1b9401afecb20d3123eec7334605cb15bf9d877) by Aaron Dunmore). References: [#134](https://github.com/pawamoy/mkdocstrings/issues/134), [#136](https://github.com/pawamoy/mkdocstrings/issues/136) ### Packaging - Accept `pymdown-extensions` versions up to 0.8.x ([see release notes](https://facelessuser.github.io/pymdown-extensions/about/releases/8.0/#8.0)) ([178d48d](https://github.com/pawamoy/mkdocstrings/commit/178d48da7a62daf285dfc5f6ff230e8bce82ed53) by Hugo van Kemenade). PR [#146](https://github.com/pawamoy/mkdocstrings/issue/146) ## [0.12.2](https://github.com/pawamoy/mkdocstrings/releases/tag/0.12.2) - 2020-07-24 [Compare with 0.12.1](https://github.com/pawamoy/mkdocstrings/compare/0.12.1...0.12.2) ### Packaging - Accept `pytkdocs` version up to 0.7.x ([changelog](https://pawamoy.github.io/pytkdocs/changelog/#070-2020-07-24)). ## [0.12.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.12.1) - 2020-07-07 [Compare with 0.12.0](https://github.com/pawamoy/mkdocstrings/compare/0.12.0...0.12.1) ### Bug Fixes - Fix HTML-escaped sequence parsing as XML ([db297f1](https://github.com/pawamoy/mkdocstrings/commit/db297f19013fc402eeff1f2827057a959e481c66) by Timothée Mazzucotelli). - Allow running mkdocs from non-default interpreter ([283dd7b](https://github.com/pawamoy/mkdocstrings/commit/283dd7b83eeba675a16d96d2e829851c1273a625) by Jared Khan). ## [0.12.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.12.0) - 2020-06-14 [Compare with 0.11.4](https://github.com/pawamoy/mkdocstrings/compare/0.11.4...0.12.0) ### Features - Support attributes section in Google-style docstrings ([8300253](https://github.com/pawamoy/mkdocstrings/commit/83002532b2294ea33dcec4f2672a5a6d0f64def1) by Timothée Mazzucotelli). References: [#88](https://github.com/pawamoy/mkdocstrings/issues/88) - Support examples section in Google-style docstrings ([650c754](https://github.com/pawamoy/mkdocstrings/commit/650c754afdd5d4fb96b1e2529f378d025a2e7daf) by Iago González). References: [#112](https://github.com/pawamoy/mkdocstrings/issues/112) ### Packaging - Accept `pytkdocs` version up to 0.6.x ([changelog](https://pawamoy.github.io/pytkdocs/changelog/#060-2020-06-14)). ## [0.11.4](https://github.com/pawamoy/mkdocstrings/releases/tag/0.11.4) - 2020-06-08 [Compare with 0.11.3](https://github.com/pawamoy/mkdocstrings/compare/0.11.3...0.11.4) ### Packaging - Accept `pytkdocs` version up to 0.5.x ([changelog](https://pawamoy.github.io/pytkdocs/changelog/#050-2020-06-08)). If it breaks your docs, please [open issues on `pytkdocs`' bug-tracker](https://github.com/pawamoy/pytkdocs/issues), or pin `pytkdocs` version to while waiting for bug fixes <0.5.0 :clown:. ## [0.11.3](https://github.com/pawamoy/mkdocstrings/releases/tag/0.11.3) - 2020-06-07 [Compare with 0.11.2](https://github.com/pawamoy/mkdocstrings/compare/0.11.2...0.11.3) ### Bug Fixes - Support custom theme directory configuration ([1243cf6](https://github.com/pawamoy/mkdocstrings/commit/1243cf673aaf371e5cbf42a3e0d1aa80482398a3) by Abhishek Thakur). References: [#120](https://github.com/pawamoy/mkdocstrings/issues/120), [#121](https://github.com/pawamoy/mkdocstrings/issues/121) ## [0.11.2](https://github.com/pawamoy/mkdocstrings/releases/tag/0.11.2) - 2020-05-20 [Compare with 0.11.1](https://github.com/pawamoy/mkdocstrings/compare/0.11.1...0.11.2) ### Packaging - Increase `pytkdocs` version range to accept 0.4.0 ([changelog](https://pawamoy.github.io/pytkdocs/changelog/#040-2020-05-17)). ## [0.11.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.11.1) - 2020-05-14 [Compare with 0.11.0](https://github.com/pawamoy/mkdocstrings/compare/0.11.0...0.11.1) ### Bug Fixes - Fix integration with mkdocs logging *une bonne fois pour toute* ([3293cbf](https://github.com/pawamoy/mkdocstrings/commit/3293cbf161f05d36de6c1d50b5de9742bf99066e) by Timothée Mazzucotelli). - Discard setup commands stdout ([ea44cea](https://github.com/pawamoy/mkdocstrings/commit/ea44cea33159ed3a6b0b34b4cd52a17a40bd6460) by Timothée Mazzucotelli). References: [#91](https://github.com/pawamoy/mkdocstrings/issues/91) - Use the proper python executable to start subprocesses ([9fe3b39](https://github.com/pawamoy/mkdocstrings/commit/9fe3b3915bd8f15011f8f3632a227d1eb56603fd) by Reece Dunham). References: [#91](https://github.com/pawamoy/mkdocstrings/issues/91), [#103](https://github.com/pawamoy/mkdocstrings/issues/103) ## [0.11.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.11.0) - 2020-04-23 [Compare with 0.10.3](https://github.com/pawamoy/mkdocstrings/compare/0.10.3...0.11.0) ### Bug Fixes - Properly raise on errors (respect strict mode) ([2097208](https://github.com/pawamoy/mkdocstrings/commit/20972082a94b64bec02c77d6a80384d8042f60ea) by Timothée Mazzucotelli). Related issues/PRs: [#86](https://github.com/pawamoy/mkdocstrings/issues/86) - Hook properly to MkDocs logging ([b23daed](https://github.com/pawamoy/mkdocstrings/commit/b23daed3743bbd2d3f024df34582a317c51a1af0) by Timothée Mazzucotelli). Related issues/PRs: [#86](https://github.com/pawamoy/mkdocstrings/issues/86) ### Features - Add `setup_commands` option to python handler ([599f8e5](https://github.com/pawamoy/mkdocstrings/commit/599f8e528f55093b0011b732da959b747c1e02c0) by Ross Mechanic). Related issues/PRs: [#89](https://github.com/pawamoy/mkdocstrings/issues/89), [#90](https://github.com/pawamoy/mkdocstrings/issues/90) - Add option to allow overriding templates ([7360021](https://github.com/pawamoy/mkdocstrings/commit/7360021ab4753706d0f6209ed960050f5d424ad8) by Mikaël Capelle). Related issues/PRs: [#59](https://github.com/pawamoy/mkdocstrings/issues/59), [#82](https://github.com/pawamoy/mkdocstrings/issues/82) ## [0.10.3](https://github.com/pawamoy/mkdocstrings/releases/tag/0.10.3) - 2020-04-10 [Compare with 0.10.2](https://github.com/pawamoy/mkdocstrings/compare/0.10.2...0.10.3) ### Bug Fixes - Handle `site_url` not being defined ([9fb4a9b](https://github.com/pawamoy/mkdocstrings/commit/9fb4a9bbebe2457b389921ba1ee3e1f924c5691b) by Timothée Mazzucotelli). Related issues/PRs: [#77](https://github.com/pawamoy/mkdocstrings/issues/77) ### Packaging This version increases the accepted range of versions for the `pytkdocs` dependency to `>=0.2.0, <0.4.0`. The `pytkdocs` project just released [version 0.3.0](https://pawamoy.github.io/pytkdocs/changelog/#030-2020-04-10) which: - adds support for complex markup in docstrings sections items descriptions - adds support for different indentations in docstrings sections (tabulations or less/more than 4 spaces) - fixes docstring parsing for arguments whose names start with `*`, like `*args` and `**kwargs` ## [0.10.2](https://github.com/pawamoy/mkdocstrings/releases/tag/0.10.2) - 2020-04-07 [Compare with 0.10.1](https://github.com/pawamoy/mkdocstrings/compare/0.10.1...0.10.2) ### Packaging This version increases the accepted range of versions for the `pymdown-extensions` dependency, as well as for the `mkdocs-material` development dependency. Indeed, both these projects recently released major versions 7 and 5 respectively. Users who wish to use these new versions will be able to. See issue [#74](https://github.com/pawamoy/mkdocstrings/issues/74). ## [0.10.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.10.1) - 2020-04-03 [Compare with 0.10.0](https://github.com/pawamoy/mkdocstrings/compare/0.10.0...0.10.1) ### Bug Fixes - Fix jinja2 error for jinja2 < 2.11 ([387f970](https://github.com/pawamoy/mkdocstrings/commit/387f97088ad2b7b25389ae6cf303bae071e90e6c) by Timothée Mazzucotelli). Related issues/PRs: [#67](https://github.com/pawamoy/mkdocstrings/issues/67), [#72](https://github.com/pawamoy/mkdocstrings/issues/72) - Fix missing dependency pymdown-extensions ([648b99d](https://github.com/pawamoy/mkdocstrings/commit/648b99dab9d1af87db474ce7683de50c9bf8996d) by Timothée Mazzucotelli). Related issues/PRs: [#66](https://github.com/pawamoy/mkdocstrings/issues/66) - Fix heading level of hidden toc entries ([475cc62](https://github.com/pawamoy/mkdocstrings/commit/475cc62b1cf4342b82ca8685166306441e4b83c4) by Timothée Mazzucotelli). Related issues/PRs: [#65](https://github.com/pawamoy/mkdocstrings/issues/65) - Fix rendering signatures containing keyword_only ([c6c5add](https://github.com/pawamoy/mkdocstrings/commit/c6c5addd8be65beaf7055c9d0f512e0de8b3eba4) by Timothée Mazzucotelli). Related issues/PRs: [#68](https://github.com/pawamoy/mkdocstrings/issues/68) ## [0.10.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.10.0) - 2020-03-27 [Compare with 0.9.1](https://github.com/pawamoy/mkdocstrings/compare/0.9.1...0.10.0) ### Features - Prepare for new `pytkdocs` version ([336421a](https://github.com/pawamoy/mkdocstrings/commit/336421af95d752671276c2e88c5c173bff4093cc)). Add options `filters` and `members` to the Python collector to reflect the new `pytkdocs` options. See [the default configuration of the Python collector](https://pawamoy.github.io/mkdocstrings/reference/handlers/python/#mkdocstrings.handlers.python.PythonCollector.DEFAULT_CONFIG). ## [0.9.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.9.1) - 2020-03-21 [Compare with 0.9.0](https://github.com/pawamoy/mkdocstrings/compare/0.9.0...0.9.1) ### Bug fixes - Fix cross-references when deploying to GitHub pages ([36f804b](https://github.com/pawamoy/mkdocstrings/commit/36f804beab01531c0331ed89d21f3e5e15bd8585)). ## [0.9.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.9.0) - 2020-03-21 [Compare with 0.8.0](https://github.com/pawamoy/mkdocstrings/compare/0.8.0...0.9.0) This version is a big refactor. We will just list the new features without pointing to particular commits. The documentation rendering looks slightly different, and should be better than before. No identified breaking changes for end-users. ### Features - **Language agnostic:** we moved the code responsible for loading Python documentation into a new project, [`pytkdocs`](https://github.com/pawamoy/pytkdocs), and implemented a "handlers" logic, effectively allowing to support any given language. Waiting for your handlers contributions :wink:! - **Multiple themes support:** handlers can offer templates for multiple `mkdocs` themes. - **Better cross-references:** cross-references now not only work between documented objects (between all languages, given the objects' identifiers are unique), but also for every heading of your Markdown pages. - **Configuration options:** the rendering of Python documentation can now be configured, (globally and locally thanks to the handlers system), [check the docs!](https://pawamoy.github.io/mkdocstrings/reference/handlers/python/#mkdocstrings.handlers.python.PythonRenderer.DEFAULT_CONFIG) Also see the [recommended CSS](https://pawamoy.github.io/mkdocstrings/handlers/python/#recommended-style). - **Proper logging messages:** `mkdocstrings` now logs debug, warning and error messages, useful when troubleshooting. ### Bug fixes - Various fixes and better error handling. ## [0.8.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.8.0) - 2020-03-04 [Compare with 0.7.2](https://github.com/pawamoy/mkdocstrings/compare/0.7.2...0.8.0) ### Breaking Changes - Be compatible with Mkdocs >= 1.1 ([5a974a4](https://github.com/pawamoy/mkdocstrings/commit/5a974a4eb810904d6836e216d8539affc8acaa6f)). This is a breaking change as we're not compatible with versions of Mkdocs below 1.1 anymore. If you cannot upgrade Mkdocs to 1.1, pin mkdocstrings' version to 0.7.2. ## [0.7.2](https://github.com/pawamoy/mkdocstrings/releases/tag/0.7.2) - 2020-03-04 [Compare with 0.7.1](https://github.com/pawamoy/mkdocstrings/compare/0.7.1...0.7.2) ### Bug Fixes - Catch `OSError` when trying to get source lines ([8e8d604](https://github.com/pawamoy/mkdocstrings/commit/8e8d604ba95363c140841c84535d2350d7ebbfe3)). - Do not render signature empty sentinel ([16dfd73](https://github.com/pawamoy/mkdocstrings/commit/16dfd73cf30d01314dba756d3f10308b99c87dcc)). - Fix for nested classes and their attributes ([7fef903](https://github.com/pawamoy/mkdocstrings/commit/7fef9037c5299d6106347b0db29f85a644f85c16)). - Fix `relative_file_path` method ([52715ad](https://github.com/pawamoy/mkdocstrings/commit/52715adc59fe2e26a9e91df88bac8b8b32d4635e)). - Wrap file path in backticks to escape it ([2525f39](https://github.com/pawamoy/mkdocstrings/commit/2525f39ad8c181679fa33db8e6dfaa28eb39c289)). ## [0.7.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.7.1) - 2020-02-18 [Compare with 0.7.0](https://github.com/pawamoy/mkdocstrings/compare/0.7.0...0.7.1) ### Bug Fixes - Replace literal slash with os.sep for Windows compatibility ([70f9af5](https://github.com/pawamoy/mkdocstrings/commit/70f9af5e33cda694cda33870c84a770c853d84b5)). ## [0.7.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.7.0) - 2020-01-13 [Compare with 0.6.1](https://github.com/pawamoy/mkdocstrings/compare/0.6.1...0.7.0) ### Bug Fixes - Don't mark args or kwargs as required ([4049d6f](https://github.com/pawamoy/mkdocstrings/commit/4049d6f27c332b05db06bcfe6cc564f3c1c0f013)). - Filter submodules ([7b11095](https://github.com/pawamoy/mkdocstrings/commit/7b110959529c5fc0275fb98c6d97e7c71e205900)). ### Code Refactoring - Don't guess lang in generated docs ([db4f60a](https://github.com/pawamoy/mkdocstrings/commit/db4f60a13dd0d191d7515683d7d42ae374b39fae)). - Render at HTML step with custom markdown converter ([9b5a3e1](https://github.com/pawamoy/mkdocstrings/commit/9b5a3e126cd584893a8d0858ca9b67b8251e88f1)). ### Features - Change forward ref to ref, fix optional unions ([2f0bfaa](https://github.com/pawamoy/mkdocstrings/commit/2f0bfaabf367bfa513c20fb1230409306e43add2)). - Discover package submodules ([231062a](https://github.com/pawamoy/mkdocstrings/commit/231062a3a107abc02134f102a06693969cf603ad)). - Implement watched source code (hacks) ([4a67953](https://github.com/pawamoy/mkdocstrings/commit/4a67953c0af9da363d52ba058b3c51cf4cbfaabe)). ## [0.6.1](https://github.com/pawamoy/mkdocstrings/releases/tag/0.6.1) - 2020-01-02 [Compare with 0.6.0](https://github.com/pawamoy/mkdocstrings/compare/0.6.0...0.6.1) ### Bug Fixes - Break docstring discarding loop if found ([5a17fec](https://github.com/pawamoy/mkdocstrings/commit/5a17fec5beed2003d19ccdcb359b46b79bfcf469)). - Fix discarding docstring ([143f7cb](https://github.com/pawamoy/mkdocstrings/commit/143f7cb00f02a7d3179cc5606ed7903566250227)). - Fix getting annotation from nodes ([ecde72b](https://github.com/pawamoy/mkdocstrings/commit/ecde72bb22ccedb36aa847dd50504c63ad04498c)). - Fix various things ([affbf06](https://github.com/pawamoy/mkdocstrings/commit/affbf064d457d4b626e8f67d38e94d7919bc2df2)). ### Code Refactoring - Break as soon as we find the same attr in a parent class while trying to discard the docstring ([65d7908](https://github.com/pawamoy/mkdocstrings/commit/65d7908f489ec465b2803ea8f55c70d0f9d7586b)). - Split Docstring.parse method to improve readability ([2226e2d](https://github.com/pawamoy/mkdocstrings/commit/2226e2d55a6b9bbdd5a56183f1a9ba3c5f01b5ac)). ## [0.6.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.6.0) - 2019-12-28 [Compare with 0.5.0](https://github.com/pawamoy/mkdocstrings/compare/0.5.0...0.6.0) ### Bug Fixes - Fix GenericMeta import error on Python 3.7+ ([febf2b9](https://github.com/pawamoy/mkdocstrings/commit/febf2b9749d97cce80f5d20339372842fdffc908)). ### Code Refactoring - More classes. Still ugly code though :'( ([f41c119](https://github.com/pawamoy/mkdocstrings/commit/f41c11988d8d849a0310cca511c2d93a74cab86f)). - Split into more modules ([f1872a4](https://github.com/pawamoy/mkdocstrings/commit/f1872a4c8d41a0b9603b7f344de3186110a4e1bd)). - Use Object subclasses ([40dd106](https://github.com/pawamoy/mkdocstrings/commit/40dd1062188e6ad6ef6fbc12ddead2132fe6af1e)). ## [0.5.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.5.0) - 2019-12-22 [Compare with 0.4.0](https://github.com/pawamoy/mkdocstrings/compare/0.4.0...0.5.0) ### Features - Use divs in HTML contents to ease styling ([2a36a0e](https://github.com/pawamoy/mkdocstrings/commit/2a36a0eba7f52c43a3eba593ddd971acaa0a9c92)). ## [0.4.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.4.0) - 2019-12-22 [Compare with 0.3.0](https://github.com/pawamoy/mkdocstrings/compare/0.3.0...0.4.0) ### Features - Parse docstrings Google-style blocks, get types from signature ([5af0c7b](https://github.com/pawamoy/mkdocstrings/commit/5af0c7b766ea7158d603b44c6df278dbcd189864)). ## [0.3.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.3.0) - 2019-12-21 [Compare with 0.2.0](https://github.com/pawamoy/mkdocstrings/compare/0.2.0...0.3.0) ### Features - Allow object referencing in docstrings ([2dd50c0](https://github.com/pawamoy/mkdocstrings/commit/2dd50c06f96acaf0e2f969f217f0cbcfb1de2fd4)). ## [0.2.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.2.0) - 2019-12-15 [Compare with 0.1.0](https://github.com/pawamoy/mkdocstrings/compare/0.1.0...0.2.0) ### Misc - Refactor, features, etc. ([111fa85](https://github.com/pawamoy/mkdocstrings/commit/111fa85a6305a198ac4e19a75bb491b98683929c)). ## [0.1.0](https://github.com/pawamoy/mkdocstrings/releases/tag/0.1.0) - 2019-12-12 [Compare with first commit](https://github.com/pawamoy/mkdocstrings/compare/f1dd8fb2b4a4ae81f9144fe062ca9743ae82bd69...0.1.0) ### Misc - Clean up (delete unused files) ([c227043](https://github.com/pawamoy/mkdocstrings/commit/c227043814381b95031e426725e97106931f4ef9)). - Clean up unused makefile rules ([edc01e9](https://github.com/pawamoy/mkdocstrings/commit/edc01e99aa7b762e800d9ae25cd5b842812dc326)). - Initial commit ([f1dd8fb](https://github.com/pawamoy/mkdocstrings/commit/f1dd8fb2b4a4ae81f9144fe062ca9743ae82bd69)). - Update readme ([ae56bdd](https://github.com/pawamoy/mkdocstrings/commit/ae56bdd9ac5692665409e99eb0fd509d8dfc605e)). - Add plugin ([6ed5cb1](https://github.com/pawamoy/mkdocstrings/commit/6ed5cb1879b498ddc8d0fe1c04db7e3527f2ff81)). - First PoC, needs better theming ([18a00b9](https://github.com/pawamoy/mkdocstrings/commit/18a00b9405a94405256a1ad2ae45886da40296e4)). - Get attributes docstrings ([7838fff](https://github.com/pawamoy/mkdocstrings/commit/7838fffa5b1d5a481fd2ea5a94d305a96b06c321)). - Refactor ([f68f1a8](https://github.com/pawamoy/mkdocstrings/commit/f68f1a89d477a55a6e86a9eb4c92bd5d6416b5cc)). mkdocstrings-0.29.0/CODE_OF_CONDUCT.md000066400000000000000000000125361476356224100171310ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at dev@pawamoy.fr. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq [translations]: https://www.contributor-covenant.org/translations mkdocstrings-0.29.0/CONTRIBUTING.md000066400000000000000000000105011476356224100165510ustar00rootroot00000000000000# Contributing Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. ## Environment setup Nothing easier! Fork and clone the repository. The project uses dynamic versioning, so to get the correct package version when building, make sure to pull Git tags: ```bash cd mkdocstrings # Assuming you authenticate with SSH. git remote add upstream git@github.com:mkdocstrings/mkdocstrings git pull upstream --tags ``` Then: ```bash make setup ``` > NOTE: If it fails for some reason, you'll need to install [uv](https://github.com/astral-sh/uv) manually. > > You can install it with: > > ```bash > curl -LsSf https://astral.sh/uv/install.sh | sh > ``` > > Now you can try running `make setup` again, or simply `uv sync`. You now have the dependencies installed. Run `make help` to see all the available actions! ## Tasks The entry-point to run commands and tasks is the `make` Python script, located in the `scripts` directory. Try running `make` to show the available commands and tasks. The *commands* do not need the Python dependencies to be installed, while the *tasks* do. The cross-platform tasks are written in Python, thanks to [duty](https://github.com/pawamoy/duty). If you work in VSCode, we provide [an action to configure VSCode](https://pawamoy.github.io/copier-uv/work/#vscode-setup) for the project. ## Development As usual: 1. create a new branch: `git switch -c feature-or-bugfix-name` 1. edit the code and/or the documentation **Before committing:** 1. run `make format` to auto-format the code 1. run `make check` to check everything (fix any warning) 1. run `make test` to run the tests (fix any issue) 1. if you updated the documentation or the project dependencies: 1. run `make docs` 1. go to http://localhost:8000 and check that everything looks good 1. follow our [commit message convention](#commit-message-convention) If you are unsure about how to fix or ignore a warning, just let the continuous integration fail, and we will help you during review. Don't bother updating the changelog, we will take care of this. ## Commit message convention Commit messages must follow our convention based on the [Angular style](https://gist.github.com/stephenparish/9941e89d80e2bc58a153#format-of-the-commit-message) or the [Karma convention](https://karma-runner.github.io/4.0/dev/git-commit-msg.html): ``` [(scope)]: Subject [Body] ``` **Subject and body must be valid Markdown.** Subject must have proper casing (uppercase for first letter if it makes sense), but no dot at the end, and no punctuation in general. Scope and body are optional. Type can be: - `build`: About packaging, building wheels, etc. - `chore`: About packaging or repo/files management. - `ci`: About Continuous Integration. - `deps`: Dependencies update. - `docs`: About documentation. - `feat`: New feature. - `fix`: Bug fix. - `perf`: About performance. - `refactor`: Changes that are not features or bug fixes. - `style`: A change in code style/format. - `tests`: About tests. If you write a body, please add trailers at the end (for example issues and PR references, or co-authors), without relying on GitHub's flavored Markdown: ``` Body. Issue #10: https://github.com/namespace/project/issues/10 Related to PR namespace/other-project#15: https://github.com/namespace/other-project/pull/15 ``` These "trailers" must appear at the end of the body, without any blank lines between them. The trailer title can contain any character except colons `:`. We expect a full URI for each trailer, not just GitHub autolinks (for example, full GitHub URLs for commits and issues, not the hash or the #issue-number). We do not enforce a line length on commit messages summary and body, but please avoid very long summaries, and very long lines in the body, unless they are part of code blocks that must not be wrapped. ## Pull requests guidelines Link to any related issue in the Pull Request message. During the review, we recommend using fixups: ```bash # SHA is the SHA of the commit you want to fix git commit --fixup=SHA ``` Once all the changes are approved, you can squash your commits: ```bash git rebase -i --autosquash main ``` And force-push: ```bash git push -f ``` If this seems all too complicated, you can push or force-push each new commit, and we will squash them ourselves if needed, before merging. mkdocstrings-0.29.0/LICENSE000066400000000000000000000013621476356224100153320ustar00rootroot00000000000000ISC License Copyright (c) 2019, Timothée Mazzucotelli Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. mkdocstrings-0.29.0/Makefile000066400000000000000000000007601476356224100157660ustar00rootroot00000000000000# 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. actions = \ allrun \ changelog \ check \ check-api \ check-docs \ check-quality \ check-types \ clean \ coverage \ docs \ docs-deploy \ format \ help \ multirun \ release \ run \ setup \ test \ vscode .PHONY: $(actions) $(actions): @python scripts/make "$@" mkdocstrings-0.29.0/README.md000066400000000000000000000137341476356224100156120ustar00rootroot00000000000000# mkdocstrings [![ci](https://github.com/mkdocstrings/mkdocstrings/workflows/ci/badge.svg)](https://github.com/mkdocstrings/mkdocstrings/actions?query=workflow%3Aci) [![documentation](https://img.shields.io/badge/docs-mkdocs-708FCC.svg?style=flat)](https://mkdocstrings.github.io/) [![pypi version](https://img.shields.io/pypi/v/mkdocstrings.svg)](https://pypi.org/project/mkdocstrings/) [![conda version](https://img.shields.io/conda/vn/conda-forge/mkdocstrings)](https://anaconda.org/conda-forge/mkdocstrings) [![gitter](https://badges.gitter.im/join%20chat.svg)](https://app.gitter.im/#/room/#mkdocstrings:gitter.im) Automatic documentation from sources, for [MkDocs](https://www.mkdocs.org/). Come have a chat or ask questions on our [Gitter channel](https://gitter.im/mkdocstrings/community). --- **[Features](#features)** - **[Installation](#installation)** - **[Quick usage](#quick-usage)** ![mkdocstrings_gif1](https://user-images.githubusercontent.com/3999221/77157604-fb807480-6aa1-11ea-99e0-d092371d4de0.gif) ## Features - [**Language-agnostic:**](https://mkdocstrings.github.io/handlers/overview/) just like *MkDocs*, *mkdocstrings* is written in Python but is language-agnostic. 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 [C](https://mkdocstrings.github.io/c/), [Crystal](https://mkdocstrings.github.io/crystal/), [Python](https://mkdocstrings.github.io/python/), [TypeScript](https://mkdocstrings.github.io/typescript/), 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: - [**Multiple themes support:**](https://mkdocstrings.github.io/theming/) each handler can offer multiple themes. Currently, we offer the :star: [Material theme](https://squidfunk.github.io/mkdocs-material/) :star: as well as basic support for the ReadTheDocs and MkDocs themes for the Python handler. - [**Cross-references across pages:**](https://mkdocstrings.github.io/usage/#cross-references) *mkdocstrings* makes it possible to reference headings in other Markdown files with the classic Markdown linking syntax: `[identifier][]` or `[title][identifier]` -- and you don't need to remember which exact page this object was on. This works for any heading that's produced by a *mkdocstrings* language handler, and you can opt to include *any* Markdown heading into the global referencing scheme. **Note**: in versions prior to 0.15 *all* Markdown headers were included, but now you need to [opt in](https://mkdocstrings.github.io/usage/#cross-references-to-any-markdown-heading). - [**Cross-references across sites:**](https://mkdocstrings.github.io/usage/#cross-references-to-other-projects-inventories) similarly to [Sphinx's intersphinx extension](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html), *mkdocstrings* can reference API items from other libraries, given they provide an inventory and you load that inventory in your MkDocs configuration. - [**Inline injection in Markdown:**](https://mkdocstrings.github.io/usage/) instead of generating Markdown files, *mkdocstrings* allows you to inject documentation anywhere in your Markdown contents. The syntax is simple: `::: identifier` followed by a 4-spaces indented YAML block. The identifier and YAML configuration will be passed to the appropriate handler to collect and render documentation. - [**Global and local configuration:**](https://mkdocstrings.github.io/usage/#global-options) each handler can be configured globally in `mkdocs.yml`, and locally for each "autodoc" instruction. - **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/), [FastAPI](https://fastapi.tiangolo.com/reference/fastapi/), [Google](https://docs.kidger.site/jaxtyping/api/runtime-type-checking/), [IBM](https://ds4sd.github.io/docling/api_reference/document_converter/), [Jitsi](https://jitsi.github.io/jiwer/reference/alignment/), [Microsoft](https://microsoft.github.io/presidio/api/analyzer_python/), [NVIDIA](https://nvidia.github.io/bionemo-framework/API_reference/bionemo/core/api/), [Prefect](https://docs.prefect.io/2.10.12/api-ref/prefect/agent/), [Pydantic](https://docs.pydantic.dev/dev-v2/api/main/), [Textual](https://textual.textualize.io/api/app/), [and more...](https://github.com/mkdocstrings/mkdocstrings/network/dependents) ## Installation The `mkdocstrings` package doesn't provide support for any language: it's just a common base for language handlers. It means you likely want to install it with one or more official handlers, using [extras](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#extras). For example, to install it with Python support: ```bash pip install 'mkdocstrings[python]' ``` Alternatively, you can directly install the language handlers themselves, which depend on `mkdocstrings` anyway: ```bash pip install mkdocstrings-python ``` This will give you more control over the accepted range of versions for the handlers themselves. See the [official language handlers](https://mkdocstrings.github.io/handlers/overview/). --- With `conda`: ```bash conda install -c conda-forge mkdocstrings mkdocstrings-python ``` ## Quick usage In `mkdocs.yml`: ```yaml site_name: "My Library" theme: name: "material" plugins: - search - mkdocstrings ``` In one of your markdown files: ```markdown # Reference ::: my_library.my_module.my_class ``` See the [Usage](https://mkdocstrings.github.io/usage) section of the docs for more examples! mkdocstrings-0.29.0/config/000077500000000000000000000000001476356224100155705ustar00rootroot00000000000000mkdocstrings-0.29.0/config/coverage.ini000066400000000000000000000006361476356224100200710ustar00rootroot00000000000000[coverage:run] branch = true parallel = true source = src/ tests/ [coverage:paths] equivalent = src/ .venv/lib/*/site-packages/ .venvs/*/lib/*/site-packages/ [coverage:report] ignore_errors = True precision = 2 omit = src/*/__init__.py src/*/__main__.py tests/__init__.py tests/fixtures/*.py exclude_lines = pragma: no cover if TYPE_CHECKING [coverage:json] output = htmlcov/coverage.json mkdocstrings-0.29.0/config/git-changelog.toml000066400000000000000000000003501476356224100211730ustar00rootroot00000000000000bump = "auto" convention = "angular" in-place = true output = "CHANGELOG.md" parse-refs = false parse-trailers = true sections = ["build", "deps", "feat", "fix", "perf", "refactor"] template = "keepachangelog" versioning = "pep440" mkdocstrings-0.29.0/config/mypy.ini000066400000000000000000000001621476356224100172660ustar00rootroot00000000000000[mypy] ignore_missing_imports = true exclude = tests/fixtures/ warn_unused_ignores = true show_error_codes = true mkdocstrings-0.29.0/config/pytest.ini000066400000000000000000000005011476356224100176150ustar00rootroot00000000000000[pytest] python_files = test_*.py addopts = --cov --cov-config config/coverage.ini testpaths = tests # action:message_regex:warning_class:module_regex:line filterwarnings = error ignore:.*`get_anchors` method:DeprecationWarning:mkdocstrings ignore:.*Importing from:DeprecationWarning:mkdocstrings_handlers mkdocstrings-0.29.0/config/ruff.toml000066400000000000000000000044201476356224100174270ustar00rootroot00000000000000target-version = "py39" line-length = 120 [lint] exclude = [ "tests/fixtures/*.py", ] select = [ "A", "ANN", "ARG", "B", "BLE", "C", "C4", "COM", "D", "DTZ", "E", "ERA", "EXE", "F", "FBT", "G", "I", "ICN", "INP", "ISC", "N", "PGH", "PIE", "PL", "PLC", "PLE", "PLR", "PLW", "PT", "PYI", "Q", "RUF", "RSE", "RET", "S", "SIM", "SLF", "T", "T10", "T20", "TCH", "TID", "TRY", "UP", "W", "YTT", ] ignore = [ "A001", # Variable is shadowing a Python builtin "ANN101", # Missing type annotation for self "ANN102", # Missing type annotation for cls "ANN204", # Missing return type annotation for special method __str__ "ANN401", # Dynamically typed expressions (typing.Any) are disallowed "ARG005", # Unused lambda argument "C901", # Too complex "D105", # Missing docstring in magic method "D417", # Missing argument description in the docstring "E501", # Line too long "ERA001", # Commented out code "G004", # Logging statement uses f-string "PLR0911", # Too many return statements "PLR0912", # Too many branches "PLR0913", # Too many arguments to function call "PLR0915", # Too many statements "SLF001", # Private member accessed "TRY003", # Avoid specifying long messages outside the exception class ] [lint.per-file-ignores] "src/**/cli.py" = [ "T201", # Print statement ] "src/*/debug.py" = [ "T201", # Print statement ] "!src/*/*.py" = [ "D100", # Missing docstring in public module ] "!src/**.py" = [ "D101", # Missing docstring in public class "D103", # Missing docstring in public function ] "scripts/*.py" = [ "INP001", # File is part of an implicit namespace package "T201", # Print statement ] "tests/**.py" = [ "ARG005", # Unused lambda argument "FBT001", # Boolean positional arg in function definition "PLR2004", # Magic value used in comparison "S101", # Use of assert detected ] [lint.flake8-quotes] docstring-quotes = "double" [lint.flake8-tidy-imports] ban-relative-imports = "all" [lint.isort] known-first-party = ["mkdocstrings"] [lint.pydocstyle] convention = "google" [format] exclude = [ "tests/fixtures/*.py", ] docstring-code-format = true docstring-code-line-length = 80 mkdocstrings-0.29.0/config/vscode/000077500000000000000000000000001476356224100170535ustar00rootroot00000000000000mkdocstrings-0.29.0/config/vscode/launch.json000066400000000000000000000026701476356224100212250ustar00rootroot00000000000000{ "version": "0.2.0", "configurations": [ { "name": "python (current file)", "type": "debugpy", "request": "launch", "program": "${file}", "console": "integratedTerminal", "justMyCode": false, "args": "${command:pickArgs}" }, { "name": "run", "type": "debugpy", "request": "launch", "module": "mkdocstrings", "console": "integratedTerminal", "justMyCode": false, "args": "${command:pickArgs}" }, { "name": "docs", "type": "debugpy", "request": "launch", "module": "mkdocs", "justMyCode": false, "args": [ "serve", "-v" ] }, { "name": "test", "type": "debugpy", "request": "launch", "module": "pytest", "justMyCode": false, "args": [ "-c=config/pytest.ini", "-vvv", "--no-cov", "--dist=no", "tests", "-k=${input:tests_selection}" ] } ], "inputs": [ { "id": "tests_selection", "type": "promptString", "description": "Tests selection", "default": "" } ] }mkdocstrings-0.29.0/config/vscode/settings.json000066400000000000000000000017041476356224100216100ustar00rootroot00000000000000{ "files.watcherExclude": { "**/.venv*/**": true, "**/.venvs*/**": true, "**/venv*/**": true }, "mypy-type-checker.args": [ "--config-file=config/mypy.ini" ], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "python.testing.pytestArgs": [ "--config-file=config/pytest.ini" ], "ruff.enable": true, "ruff.format.args": [ "--config=config/ruff.toml" ], "ruff.lint.args": [ "--config=config/ruff.toml" ], "yaml.schemas": { "https://squidfunk.github.io/mkdocs-material/schema.json": "mkdocs.yml" }, "yaml.customTags": [ "!ENV scalar", "!ENV sequence", "!relative scalar", "tag:yaml.org,2002:python/name:materialx.emoji.to_svg", "tag:yaml.org,2002:python/name:materialx.emoji.twemoji", "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format" ] }mkdocstrings-0.29.0/config/vscode/tasks.json000066400000000000000000000046051476356224100211000ustar00rootroot00000000000000{ "version": "2.0.0", "tasks": [ { "label": "changelog", "type": "process", "command": "scripts/make", "args": ["changelog"] }, { "label": "check", "type": "process", "command": "scripts/make", "args": ["check"] }, { "label": "check-quality", "type": "process", "command": "scripts/make", "args": ["check-quality"] }, { "label": "check-types", "type": "process", "command": "scripts/make", "args": ["check-types"] }, { "label": "check-docs", "type": "process", "command": "scripts/make", "args": ["check-docs"] }, { "label": "check-api", "type": "process", "command": "scripts/make", "args": ["check-api"] }, { "label": "clean", "type": "process", "command": "scripts/make", "args": ["clean"] }, { "label": "docs", "type": "process", "command": "scripts/make", "args": ["docs"] }, { "label": "docs-deploy", "type": "process", "command": "scripts/make", "args": ["docs-deploy"] }, { "label": "format", "type": "process", "command": "scripts/make", "args": ["format"] }, { "label": "release", "type": "process", "command": "scripts/make", "args": ["release", "${input:version}"] }, { "label": "setup", "type": "process", "command": "scripts/make", "args": ["setup"] }, { "label": "test", "type": "process", "command": "scripts/make", "args": ["test", "coverage"], "group": "test" }, { "label": "vscode", "type": "process", "command": "scripts/make", "args": ["vscode"] } ], "inputs": [ { "id": "version", "type": "promptString", "description": "Version" } ] }mkdocstrings-0.29.0/docs/000077500000000000000000000000001476356224100152535ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/.overrides/000077500000000000000000000000001476356224100173335ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/.overrides/main.html000066400000000000000000000011041476356224100211410ustar00rootroot00000000000000{% extends "base.html" %} {% block announce %} Fund this project through sponsorship {% include ".icons/octicons/heart-fill-16.svg" %} — Follow @pawamoy on {% include ".icons/fontawesome/brands/mastodon.svg" %} Fosstodon for updates {% endblock %} mkdocstrings-0.29.0/docs/.overrides/partials/000077500000000000000000000000001476356224100211525ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/.overrides/partials/comments.html000066400000000000000000000041441476356224100236700ustar00rootroot00000000000000

mkdocstrings-0.29.0/docs/.overrides/partials/path-item.html000066400000000000000000000012111476356224100237230ustar00rootroot00000000000000{# Fix breadcrumbs for when mkdocs-section-index is used. #} {# See https://github.com/squidfunk/mkdocs-material/issues/7614. #} {% macro render_content(nav_item) %} {{ nav_item.title }} {% endmacro %} {% macro render(nav_item, ref=nav_item) %} {% if nav_item.is_page %}
  • {{ render_content(ref) }}
  • {% elif nav_item.children %} {{ render(nav_item.children | first, ref) }} {% endif %} {% endmacro %} mkdocstrings-0.29.0/docs/changelog.md000066400000000000000000000000601476356224100175200ustar00rootroot00000000000000--- title: Changelog --- --8<-- "CHANGELOG.md" mkdocstrings-0.29.0/docs/code_of_conduct.md000066400000000000000000000000741476356224100207130ustar00rootroot00000000000000--- title: Code of Conduct --- --8<-- "CODE_OF_CONDUCT.md" mkdocstrings-0.29.0/docs/contributing.md000066400000000000000000000000661476356224100203060ustar00rootroot00000000000000--- title: Contributing --- --8<-- "CONTRIBUTING.md" mkdocstrings-0.29.0/docs/credits.md000066400000000000000000000001351476356224100172310ustar00rootroot00000000000000--- title: Credits hide: - toc --- ```python exec="yes" --8<-- "scripts/gen_credits.py" ``` mkdocstrings-0.29.0/docs/css/000077500000000000000000000000001476356224100160435ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/css/insiders.css000066400000000000000000000037311476356224100204010ustar00rootroot00000000000000@keyframes heart { 0%, 40%, 80%, 100% { transform: scale(1); } 20%, 60% { transform: scale(1.15); } } @keyframes vibrate { 0%, 2%, 4%, 6%, 8%, 10%, 12%, 14%, 16%, 18% { -webkit-transform: translate3d(-2px, 0, 0); transform: translate3d(-2px, 0, 0); } 1%, 3%, 5%, 7%, 9%, 11%, 13%, 15%, 17%, 19% { -webkit-transform: translate3d(2px, 0, 0); transform: translate3d(2px, 0, 0); } 20%, 100% { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .heart { color: #e91e63; } .pulse { animation: heart 1000ms infinite; } .vibrate { animation: vibrate 2000ms infinite; } .new-feature svg { fill: var(--md-accent-fg-color) !important; } a.insiders { color: #e91e63; } .sponsorship-list { width: 100%; } .sponsorship-item { border-radius: 100%; display: inline-block; height: 1.6rem; margin: 0.1rem; overflow: hidden; width: 1.6rem; } .sponsorship-item:focus, .sponsorship-item:hover { transform: scale(1.1); } .sponsorship-item img { filter: grayscale(100%) opacity(75%); height: auto; width: 100%; } .sponsorship-item:focus img, .sponsorship-item:hover img { filter: grayscale(0); } .sponsorship-item.private { background: var(--md-default-fg-color--lightest); color: var(--md-default-fg-color); font-size: .6rem; font-weight: 700; line-height: 1.6rem; text-align: center; } .mastodon { color: #897ff8; border-radius: 100%; box-shadow: inset 0 0 0 .05rem currentcolor; display: inline-block; height: 1.2rem !important; padding: .25rem; 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; }mkdocstrings-0.29.0/docs/css/material.css000066400000000000000000000001311476356224100203460ustar00rootroot00000000000000/* More space at the bottom of the page. */ .md-main__inner { margin-bottom: 1.5rem; } mkdocstrings-0.29.0/docs/css/mkdocstrings.css000066400000000000000000000024041476356224100212640ustar00rootroot00000000000000/* Indentation. */ div.doc-contents:not(.first) { padding-left: 25px; border-left: .05rem solid var(--md-typeset-table-color); } /* Mark external links as such. */ a.external::after, a.autorefs-external::after { /* https://primer.style/octicons/arrow-up-right-24 */ mask-image: url('data:image/svg+xml,'); -webkit-mask-image: url('data:image/svg+xml,'); content: ' '; display: inline-block; vertical-align: middle; position: relative; height: 1em; width: 1em; background-color: currentColor; } a.external:hover::after, a.autorefs-external:hover::after { background-color: var(--md-accent-fg-color); } /* Avoid breaking parameters name, etc. in table cells. */ td code { word-break: normal !important; } /* Hide parameters in ToC. */ li.md-nav__item:has(> a[href*="("]) { display: none; } mkdocstrings-0.29.0/docs/css/style.css000066400000000000000000000020121476356224100177100ustar00rootroot00000000000000/* Increase logo size */ .md-header__button.md-logo { padding-bottom: 0.2rem; padding-right: 0; } .md-header__button.md-logo img { height: 1.5rem; } /* Mark external links as such (also in nav) */ a.external:hover::after, a.md-nav__link[href^="https:"]:hover::after { /* https://primer.style/octicons/link-external-16 */ background-image: url('data:image/svg+xml,'); height: 0.8em; width: 0.8em; margin-left: 0.2em; content: ' '; display: inline-block; } /* More space at the bottom of the page */ .md-main__inner { margin-bottom: 1.5rem; } mkdocstrings-0.29.0/docs/index.md000066400000000000000000000000751476356224100167060ustar00rootroot00000000000000--- title: Overview hide: - feedback --- --8<-- "README.md" mkdocstrings-0.29.0/docs/insiders/000077500000000000000000000000001476356224100170735ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/insiders/changelog.md000066400000000000000000000000461476356224100213440ustar00rootroot00000000000000# Changelog ## mkdocstrings Insiders mkdocstrings-0.29.0/docs/insiders/goals.yml000066400000000000000000000003761476356224100207310ustar00rootroot00000000000000goals: 500: name: PlasmaVac User Guide features: [] 1000: name: GraviFridge Fluid Renewal features: [] 1500: name: HyperLamp Navigation Tips features: [] 2000: name: FusionDrive Ejection Configuration features: [] mkdocstrings-0.29.0/docs/insiders/index.md000066400000000000000000000254761476356224100205420ustar00rootroot00000000000000--- title: Insiders --- # Insiders *mkdocstrings* follows the **sponsorware** release strategy, which means that new features are first exclusively released to sponsors as part of [Insiders][]. Read on to learn [what sponsorships achieve][sponsorship], [how to become a sponsor][sponsors] to get access to Insiders, and [what's in it for you][features]! ## What is Insiders? *mkdocstrings Insiders* is a private fork of *mkdocstrings*, hosted as a private GitHub repository. Almost[^1] [all new features][features] are developed as part of this fork, which means that they are immediately available to all eligible sponsors, as they are granted access to this private repository. [^1]: In general, every new feature is first exclusively released to sponsors, but sometimes upstream dependencies enhance existing features that must be supported by *mkdocstrings*. Every feature is tied to a [funding goal][funding] in monthly subscriptions. When a funding goal is hit, the features that are tied to it are merged back into *mkdocstrings* and released for general availability, making them available to all users. Bugfixes are always released in tandem. Sponsorships start as low as [**$10 a month**][sponsors].[^2] [^2]: Note that $10 a month is the minimum amount to become eligible for Insiders. While GitHub Sponsors also allows to sponsor lower amounts or one-time amounts, those can't be granted access to Insiders due to technical reasons. Such contributions are still very much welcome as they help ensuring the project's sustainability. ## What sponsorships achieve Sponsorships make this project sustainable, as they buy the maintainers of this project time – a very scarce resource – which is spent on the development of new features, bug fixing, stability improvement, issue triage and general support. The biggest bottleneck in Open Source is time.[^3] [^3]: Making an Open Source project sustainable is exceptionally hard: maintainers burn out, projects are abandoned. That's not great and very unpredictable. The sponsorware model ensures that if you decide to use *mkdocstrings*, you can be sure that bugs are fixed quickly and new features are added regularly. If you're unsure if you should sponsor this project, check out the list of [completed funding goals][goals completed] to learn whether you're already using features that were developed with the help of sponsorships. You're most likely using at least a handful of them, [thanks to our awesome sponsors][sponsors]! ## What's in it for me? ```python exec="1" session="insiders" data_source = [ "docs/insiders/goals.yml", ("griffe-pydantic", "https://mkdocstrings.github.io/griffe-pydantic/", "insiders/goals.yml"), ("griffe-typedoc", "https://mkdocstrings.github.io/griffe-typedoc/", "insiders/goals.yml"), ("griffe-warnings-deprecated", "https://mkdocstrings.github.io/griffe-warnings-deprecated/", "insiders/goals.yml"), ("mkdocstrings-c", "https://mkdocstrings.github.io/c/", "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" idprefix="" --8<-- "scripts/insiders.py" 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).**" ) ``` 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][backlog]. ## How to become a sponsor Thanks for your interest in sponsoring! In order to become an eligible sponsor with your GitHub account, visit [pawamoy's sponsor profile][github sponsor profile], and complete a sponsorship of **$10 a month or more**. You can use your individual or organization GitHub account for sponsoring. Sponsorships lower than $10 a month are also very much appreciated, and useful. They won't grant you access to Insiders, but they will be counted towards reaching sponsorship goals. Every sponsorship helps us implementing new features and releasing them to the public. **Important:** By default, when you're sponsoring **[@pawamoy][github sponsor profile]** through a GitHub organization, all the publicly visible members of the organization will be invited to join our private repositories. If you wish to only grant access to a subset of users, please send a short email to insiders@pawamoy.fr with the name of your organization and the GitHub accounts of the users that should be granted access. **Tip:** to ensure that access is not tied to a particular individual GitHub account, you can create a bot account (i.e. a GitHub account that is not tied to a specific individual), and use this account for the sponsoring. After being granted access to our private repositories, the bot account can create private forks of our private repositories into your own organization, which all members of your organization will have access to. You can cancel your sponsorship anytime.[^5] [^5]: If you cancel your sponsorship, GitHub schedules a cancellation request which will become effective at the end of the billing cycle. This means that even though you cancel your sponsorship, you will keep your access to Insiders as long as your cancellation isn't effective. All charges are processed by GitHub through Stripe. As we don't receive any information regarding your payment, and GitHub doesn't offer refunds, sponsorships are non-refundable. [:octicons-heart-fill-24:{ .pulse }   Join our awesome sponsors][github sponsor profile]{ .md-button .md-button--primary }

    If you sponsor publicly, you're automatically added here with a link to your profile and avatar to show your support for *mkdocstrings*. Alternatively, if you wish to keep your sponsorship private, you'll be a silent +1. You can select visibility during checkout and change it afterwards. ## Funding ### Goals The following section lists all funding goals. Each goal contains a list of features prefixed with a checkmark symbol, denoting whether a feature is :octicons-check-circle-fill-24:{ style="color: #00e676" } already available or :octicons-check-circle-fill-24:{ style="color: var(--md-default-fg-color--lightest)" } planned, but not yet implemented. When the funding goal is hit, the features are released for general availability. ```python exec="1" session="insiders" idprefix="" for goal in goals.values(): if not goal.complete: goal.render() ``` ### Goals completed This section lists all funding goals that were previously completed, which means that those features were part of Insiders, but are now generally available and can be used by all users. ```python exec="1" session="insiders" idprefix="" for goal in goals.values(): if goal.complete: goal.render() ``` ## Frequently asked questions ### Compatibility > We're building an open source project and want to allow outside collaborators to use *mkdocstrings* locally without having access to Insiders. Is this still possible? Yes. Insiders is compatible with *mkdocstrings*. Almost all new features and configuration options are either backward-compatible or implemented behind feature flags. Most Insiders features enhance the overall experience, though while these features add value for the users of your project, they shouldn't be necessary for previewing when making changes to content. ### Payment > We don't want to pay for sponsorship every month. Are there any other options? Yes. You can sponsor on a yearly basis by [switching your GitHub account to a yearly billing cycle][billing cycle]. If for some reason you cannot do that, you could also create a dedicated GitHub account with a yearly billing cycle, which you only use for sponsoring (some sponsors already do that). If you have any problems or further questions, please reach out to insiders@pawamoy.fr. ### Terms > Are we allowed to use Insiders under the same terms and conditions as *mkdocstrings*? Yes. Whether you're an individual or a company, you may use *mkdocstrings Insiders* precisely under the same terms as *mkdocstrings*, which are given by the [ISC license][license]. However, we kindly ask you to respect our **fair use policy**: - Please **don't distribute the source code** of Insiders. You may freely use it for public, private or commercial projects, privately fork or mirror it, but please don't make the source code public, as it would counteract the sponsorware strategy. - If you cancel your subscription, your access to the private repository is revoked, and you will miss out on all future updates of Insiders. However, you may **use the latest version** that's available to you **as long as you like**. Just remember that [GitHub deletes private forks][private forks]. [backlog]: https://pawamoy.github.io/backlog/ [insiders]: #what-is-insiders [sponsorship]: #what-sponsorships-achieve [sponsors]: #how-to-become-a-sponsor [features]: #whats-in-it-for-me [funding]: #funding [goals completed]: #goals-completed [github sponsor profile]: https://github.com/sponsors/pawamoy [billing cycle]: https://docs.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/changing-the-duration-of-your-billing-cycle [license]: ../license.md [private forks]: https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/removing-a-collaborator-from-a-personal-repository mkdocstrings-0.29.0/docs/insiders/installation.md000066400000000000000000000054731476356224100221270ustar00rootroot00000000000000--- title: Getting started with Insiders --- # Getting started with Insiders *mkdocstrings Insiders* is a compatible drop-in replacement for *mkdocstrings*, and can be installed similarly using `pip` or `git`. Note that in order to access the Insiders repository, you need to [become an eligible sponsor][] of @pawamoy on GitHub. ## Installation ### with the `insiders` tool [`insiders`][insiders-tool] is a tool that helps you keep up-to-date versions of Insiders projects in the PyPI index of your choice (self-hosted, Google registry, Artifactory, etc.). **We kindly ask that you do not upload the distributions to public registries, as it is against our [Terms of use][].** ### with pip (ssh/https) *mkdocstrings Insiders* can be installed with `pip` [using SSH][install-pip-ssh]: ```bash pip install git+ssh://git@github.com/pawamoy-insiders/mkdocstrings.git ``` Or using HTTPS: ```bash pip install git+https://${GH_TOKEN}@github.com/pawamoy-insiders/mkdocstrings.git ``` >? NOTE: **How to get a GitHub personal access token?** The `GH_TOKEN` environment variable is a GitHub token. It can be obtained by creating a [personal access token][github-pat] for your GitHub account. It will give you access to the Insiders repository, programmatically, from the command line or GitHub Actions workflows: > > 1. Go to https://github.com/settings/tokens > 2. Click on [Generate a new token][github-pat-new] > 3. Enter a name and select the [`repo`][scopes] scope > 4. Generate the token and store it in a safe place > > Note that the personal access token must be kept secret at all times, as it allows the owner to access your private repositories. ### with Git Of course, you can use *mkdocstrings Insiders* directly using Git: ``` git clone git@github.com:pawamoy-insiders/mkdocstrings ``` When cloning with Git, the package must be installed: ``` pip install -e mkdocstrings ``` ## Upgrading When upgrading Insiders, you should always check the version of *mkdocstrings* which makes up the first part of the version qualifier. For example, a version like `8.x.x.4.x.x` means that Insiders `4.x.x` is currently based on `8.x.x`. If the major version increased, it's a good idea to consult the [changelog][] and go through the steps to ensure your configuration is up to date and all necessary changes have been made. [become an eligible sponsor]: ./index.md#how-to-become-a-sponsor [changelog]: ./changelog.md [github-pat]: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token [github-pat-new]: https://github.com/settings/tokens/new [insiders-tool]: https://pawamoy.github.io/insiders-project/ [install-pip-ssh]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh [scopes]: https://docs.github.com/en/developers/apps/scopes-for-oauth-apps#available-scopes [terms of use]: ./index.md#terms mkdocstrings-0.29.0/docs/js/000077500000000000000000000000001476356224100156675ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/js/feedback.js000066400000000000000000000007751476356224100177620ustar00rootroot00000000000000const feedback = document.forms.feedback; feedback.hidden = false; feedback.addEventListener("submit", function(ev) { ev.preventDefault(); const commentElement = document.getElementById("feedback"); commentElement.style.display = "block"; feedback.firstElementChild.disabled = true; const data = ev.submitter.getAttribute("data-md-value"); const note = feedback.querySelector(".md-feedback__note [data-md-value='" + data + "']"); if (note) { note.hidden = false; } }) mkdocstrings-0.29.0/docs/js/insiders.js000066400000000000000000000054731476356224100200560ustar00rootroot00000000000000function humanReadableAmount(amount) { const strAmount = String(amount); if (strAmount.length >= 4) { return `${strAmount.slice(0, strAmount.length - 3)},${strAmount.slice(-3)}`; } return strAmount; } function getJSON(url, callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'json'; xhr.onload = function () { var status = xhr.status; if (status === 200) { callback(null, xhr.response); } else { callback(status, xhr.response); } }; xhr.send(); } function updatePremiumSponsors(dataURL, rank) { let capRank = rank.charAt(0).toUpperCase() + rank.slice(1); getJSON(dataURL + `/sponsors${capRank}.json`, function (err, sponsors) { const sponsorsDiv = document.getElementById(`${rank}-sponsors`); if (sponsors.length > 0) { let html = ''; html += `${capRank} sponsors

    ` sponsors.forEach(function (sponsor) { html += ` ${sponsor.name} ` }); html += '

    ' sponsorsDiv.innerHTML = html; } }); } function updateInsidersPage(author_username) { const sponsorURL = `https://github.com/sponsors/${author_username}` const dataURL = `https://raw.githubusercontent.com/${author_username}/sponsors/main`; getJSON(dataURL + '/numbers.json', function (err, numbers) { document.getElementById('sponsors-count').innerHTML = numbers.count; Array.from(document.getElementsByClassName('sponsors-total')).forEach(function (element) { element.innerHTML = '$ ' + humanReadableAmount(numbers.total); }); getJSON(dataURL + '/sponsors.json', function (err, sponsors) { const sponsorsElem = document.getElementById('sponsors'); const privateSponsors = numbers.count - sponsors.length; sponsors.forEach(function (sponsor) { sponsorsElem.innerHTML += ` `; }); if (privateSponsors > 0) { sponsorsElem.innerHTML += ` +${privateSponsors} `; } }); }); updatePremiumSponsors(dataURL, "gold"); updatePremiumSponsors(dataURL, "silver"); updatePremiumSponsors(dataURL, "bronze"); } mkdocstrings-0.29.0/docs/license.md000066400000000000000000000001151476356224100172140ustar00rootroot00000000000000--- title: License hide: - feedback --- # License ``` --8<-- "LICENSE" ``` mkdocstrings-0.29.0/docs/logo.svg000066400000000000000000000020561476356224100167370ustar00rootroot00000000000000 mkdocstrings-0.29.0/docs/recipes.md000066400000000000000000000331661476356224100172400ustar00rootroot00000000000000On this page you will find various recipes, tips and tricks for *mkdocstrings* and more generally Markdown documentation. ## Automatic code reference pages TIP: **[mkdocs-autoapi](https://github.com/jcayers20/mkdocs-autoapi) and [mkdocs-api-autonav](https://github.com/tlambert03/mkdocs-api-autonav) are MkDocs plugins that automatically generate API documentation from your project's source code. They were inspired by the recipe below.** *mkdocstrings* allows to inject documentation for any object into Markdown pages. But as the project grows, it quickly becomes quite tedious to keep the autodoc instructions, or even the dedicated Markdown files in sync with all your source files and objects. In this recipe, we will iteratively automate the process of generating these pages at each build of the documentation. --- Let say you have a project called `project`. This project has a lot of source files, or modules, which live in the `src` folder: ```tree repo/ src/ project/ lorem ipsum dolor sit amet ``` Without an automatic process, you will have to manually create a Markdown page for each one of these modules, with the corresponding autodoc instruction, for example `::: project.lorem`, and also add entry in MkDocs' navigation option (`nav` in `mkdocs.yml`). With a lot of modules, this is quickly getting cumbersome. Lets fix that. ### Generate pages on-the-fly In this recipe, we suggest to use the [mkdocs-gen-files plugin](https://github.com/oprypin/mkdocs-gen-files). This plugin exposes utilities to generate files at build time. These files won't be written to the docs directory: you don't have to track and version them. They are transparently generated each time you build your docs. This is perfect for our use-case! Add `mkdocs-gen-files` to your project's docs dependencies, and configure it like so: ```yaml title="mkdocs.yml" plugins: - search # (1)! - gen-files: scripts: - scripts/gen_ref_pages.py # (2)! - mkdocstrings ``` 1. Don't forget to load the `search` plugin when redefining the `plugins` item. 2. The magic happens here, see below how it works. mkdocs-gen-files is able to run Python scripts at build time. The Python script that we will execute lives in a scripts folder, and is named `gen_ref_pages.py`, like "generate code reference pages". ```tree repo/ docs/ index.md scripts/ gen_ref_pages.py src/ project/ mkdocs.yml ``` ```python title="scripts/gen_ref_pages.py" """Generate the code reference pages.""" from pathlib import Path import mkdocs_gen_files root = Path(__file__).parent.parent src = root / "src" # (1)! for path in sorted(src.rglob("*.py")): # (2)! module_path = path.relative_to(src).with_suffix("") # (3)! doc_path = path.relative_to(src).with_suffix(".md") # (4)! full_doc_path = Path("reference", doc_path) # (5)! parts = tuple(module_path.parts) if parts[-1] == "__init__": # (6)! parts = parts[:-1] elif parts[-1] == "__main__": continue with mkdocs_gen_files.open(full_doc_path, "w") as fd: # (7)! identifier = ".".join(parts) # (8)! print("::: " + identifier, file=fd) # (9)! mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root)) # (10)! ``` 1. It's important to build a path relative to the script itself, to make it possible to build the docs with MkDocs' [`-f` option](https://www.mkdocs.org/user-guide/cli/#mkdocs-build). 2. Here we recursively list all `.py` files, but you can adapt the code to list files with other extensions of course, supporting other languages than Python. 3. The module path will look like `project/lorem`. It will be used to build the *mkdocstrings* autodoc identifier. 4. This is the partial path of the Markdown page for the module. 5. This is the full path of the Markdown page within the docs. Here we put all reference pages into a `reference` folder. 6. This part is only relevant for Python modules. We skip `__main__` modules and remove `__init__` from the module parts as it's implicit during imports. 7. Magic! Add the file to MkDocs pages, without actually writing it in the docs folder. 8. Build the autodoc identifier. Here we document Python modules, so the identifier is a dot-separated path, like `project.lorem`. 9. Actually write to the magic file. 10. We can even set the `edit_uri` on the pages. > NOTE: > It is important to look out for correct edit page behaviour when using generated pages. > For example, if we have `edit_uri` set to `blob/master/docs/` and the following > file structure: > > ```tree > repo/ > mkdocs.yml > docs/ > index.md > scripts/ > gen_ref_pages.py > src/ > project/ > lorem.py > ipsum.py > dolor.py > sit.py > amet.py > ``` > > Then we will have to change our `set_edit_path` call to: > > ```python > mkdocs_gen_files.set_edit_path(full_doc_path, Path("../") / path) # (1)! > ``` > > 1. Path can be used to traverse the structure in any way you may need, but > remember to use relative paths! > > ...so that it correctly sets the edit path of (for example) `lorem.py` to > `/blob/master/src/project/lorem.py` instead of > `/blob/master/docs/src/project/lorem.py`. With this script, a `reference` folder is automatically created each time we build our docs. This folder contains a Markdown page for each of our source modules, and each of these pages contains a single line of the form `::: project.module` (module being `lorem`, `ipsum`, etc.). Great! But, we still have to actually add those pages into our MkDocs navigation: ```yaml title="mkdocs.yml" nav: # rest of the navigation... - Code Reference: - project: - lorem: reference/project/lorem.md - ipsum: reference/project/ipsum.md - dolor: reference/project/dolor.md - sit: reference/project/sit.md - amet: reference/project/amet.md # rest of the navigation... ``` Err... so this process is only semi-automatic? Yes, but don't worry, we can fully automate it. ### Generate a literate navigation file mkdocs-gen-files is able to generate a literate navigation file. But to make use of it, we will need an additional plugin: [mkdocs-literate-nav](https://github.com/oprypin/mkdocs-literate-nav). This plugin allows to specify the whole navigation, or parts of it, into Markdown pages, as plain Markdown lists. We use it here to specify the navigation for the code reference pages. First, add `mkdocs-literate-nav` to your project's docs dependencies, and configure the plugin in your MkDocs configuration: ```yaml title="mkdocs.yml" hl_lines="6 7" plugins: - search - gen-files: scripts: - scripts/gen_ref_pages.py - literate-nav: nav_file: SUMMARY.md - mkdocstrings ``` Then, the previous script is updated like so: ```python title="scripts/gen_ref_pages.py" hl_lines="7 24 32 33" """Generate the code reference pages and navigation.""" from pathlib import Path import mkdocs_gen_files nav = mkdocs_gen_files.Nav() root = Path(__file__).parent.parent src = root / "src" for path in sorted(src.rglob("*.py")): module_path = path.relative_to(src).with_suffix("") doc_path = path.relative_to(src).with_suffix(".md") full_doc_path = Path("reference", doc_path) parts = tuple(module_path.parts) if parts[-1] == "__init__": parts = parts[:-1] elif parts[-1] == "__main__": continue nav[parts] = doc_path.as_posix() # (1)! 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.relative_to(root)) with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: # (2)! nav_file.writelines(nav.build_literate_nav()) # (3)! ``` 1. Progressively build the navigation object. 2. At the end, create a magic, literate navigation file called `SUMMARY.md` in the `reference` folder. 3. Write the navigation as a Markdown list in the literate navigation file. Now we are able to remove our hard-coded navigation in `mkdocs.yml`, and replace it with a single line! ```yaml title="mkdocs.yml" nav: # rest of the navigation... # defer to gen-files + literate-nav - Code Reference: reference/ # (1)! # rest of the navigation... ``` 1. Note the trailing slash! It is needed so that `mkdocs-literate-nav` knows it has to look for a `SUMMARY.md` file in that folder. At this point, we should be able to see the tree of our modules in the navigation. ### Bind pages to sections themselves There's a last improvement we can do. With the current script, sections, corresponding to folders, will expand or collapse when you click on them, revealing `__init__` modules under them (or equivalent modules in other languages, if relevant). Since we are documenting a public API, and given users never explicitly import `__init__` modules, it would be nice if we could get rid of them and instead render their documentation inside the section itself. Well, this is possible thanks to a third plugin: [mkdocs-section-index](https://github.com/oprypin/mkdocs-section-index). Update the script like this: ```python title="scripts/gen_ref_pages.py" hl_lines="21 22" """Generate the code reference pages and navigation.""" from pathlib import Path import mkdocs_gen_files nav = mkdocs_gen_files.Nav() root = Path(__file__).parent.parent src = root / "src" for path in sorted(src.rglob("*.py")): module_path = path.relative_to(src).with_suffix("") doc_path = path.relative_to(src).with_suffix(".md") full_doc_path = Path("reference", doc_path) parts = tuple(module_path.parts) if parts[-1] == "__init__": parts = parts[:-1] doc_path = doc_path.with_name("index.md") full_doc_path = full_doc_path.with_name("index.md") elif parts[-1] == "__main__": continue nav[parts] = 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.relative_to(root)) with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: nav_file.writelines(nav.build_literate_nav()) ``` And update your MkDocs configuration to list the plugin: ```yaml title="mkdocs.yml" hl_lines="8" plugins: - search - gen-files: scripts: - scripts/gen_ref_pages.py - literate-nav: nav_file: SUMMARY.md - section-index - mkdocstrings ``` With this, `__init__` modules will be documented and bound to the sections themselves, better reflecting our public API. ## Prevent selection of prompts and output in Python code blocks To prevent the selection of `>>>`, `...` and output in Python "Console" code blocks, you can use the `pycon` syntax highlighting on your code blocks, and add global CSS rules to your site using MkDocs `extra_css` option: ````md ```pycon >>> for word in ("Hello", "mkdocstrings!"): ... print(word, end=" ") ... Hello mkdocstrings! ``` ```` ```css title="docs/css/code_select.css" .highlight .gp, .highlight .go { /* Generic.Prompt, Generic.Output */ user-select: none; } ``` ```yaml title="mkdocs.yml" extra_css: - css/code_select.css ``` > WARNING: > The `.highlight .gp, .highlight .go` CSS selector can have unintended side-effects. > To target `pycon` code blocks more specifically, you can configure the > `pymdownx.highlight` extension to use Pygments and set language classes > on code blocks: > > ```yaml title="mkdocs.yml" > markdown_extensions: > - pymdownx.highlight: > use_pygments: true > pygments_lang_class: true > ``` > > Then you can update the CSS selector like this: > > ```css title="docs/css/code_select.css" > .language-pycon .gp, .language-pycon .go { /* Generic.Prompt, Generic.Output */ > user-select: none; > } > ``` If you don't want to enable this globally, you can still use `style` tags in the relevant pages, with more accurate CSS selectors: ```html ``` Try to select the following code block's text: ```pycon >>> for word in ("Hello", "mkdocstrings!"): ... print(word, end=" ") Hello mkdocstrings! ``` ## Hide documentation strings from source code blocks Since documentation strings are rendered by handlers, it can sometimes feel redundant to show these same documentation strings in source code blocks (when handlers render those). There is a general workaround to hide these docstrings from source blocks using CSS: ```css /* These CSS classes depend on the handler. */ .doc-contents details .highlight code { line-height: 0; } .doc-contents details .highlight code > * { line-height: initial; } .doc-contents details .highlight code > .sd { /* Literal.String.Doc */ display: none; } ``` Note that this is considered a workaround and not a proper solution, because it has side-effects like also removing blank lines. ## Automatic highlighting for indented code blocks in docstrings Depending on the language used in your code base and the mkdocstrings handler used to document it, you might want to set a default syntax for code blocks added to your docstrings. For example, to default to the Python syntax: ```yaml title="mkdocs.yml" markdown_extensions: - pymdownx.highlight: default_lang: python ``` Then in your docstrings, indented code blocks will be highlighted as Python code: ```python def my_function(): """This is my function. The following code will be highlighted as Python: result = my_function() print(result) End of the docstring. """ pass ``` mkdocstrings-0.29.0/docs/reference/000077500000000000000000000000001476356224100172115ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/reference/mkdocstrings.md000066400000000000000000000001571476356224100222450ustar00rootroot00000000000000--- title: API reference hide: - navigation --- # ::: mkdocstrings options: show_submodules: true mkdocstrings-0.29.0/docs/schema.json000066400000000000000000000035601476356224100174120ustar00rootroot00000000000000{ "$schema": "https://json-schema.org/draft-07/schema", "title": "Automatic documentation from sources, for MkDocs.", "oneOf": [ { "markdownDescription": "https://mkdocstrings.github.io/", "enum": [ "mkdocstrings" ] }, { "type": "object", "properties": { "mkdocstrings": { "markdownDescription": "https://mkdocstrings.github.io/", "type": "object", "properties": { "custom_templates": { "title": "The path to a directory containing custom templates. The path is relative to the current working directory.", "markdownDescription": "https://mkdocstrings.github.io/theming/", "type": "string", "default": null, "format": "path" }, "default_handler": { "title": "The handler used by default when no handler is specified in autodoc instructions.", "markdownDescription": "https://mkdocstrings.github.io/usage/#global-options", "type": "string", "default": "python" }, "enable_inventory": { "title": "Whether to enable inventory file generation.", "markdownDescription": "https://mkdocstrings.github.io/usage/#cross-references-to-other-projects-inventories", "type": "boolean", "default": null }, "handlers": { "title": "The handlers global configuration.", "markdownDescription": "https://mkdocstrings.github.io/handlers/overview/", "anyOf": [ { "$ref": "https://mkdocstrings.github.io/python/schema.json" } ] } }, "additionalProperties": false } }, "additionalProperties": false } ] }mkdocstrings-0.29.0/docs/snippets/000077500000000000000000000000001476356224100171205ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/snippets/function_annotations_google.py000066400000000000000000000007501476356224100252720ustar00rootroot00000000000000from typing import Optional def my_function(param1: int, param2: Optional[str] = None) -> str: """A short description of this function. Arguments: param1: An integer? param2: A string? If you have a long description, you can split it on multiple lines. Just remember to indent those lines consistently. Complex markup is supported in sections items. I'm a code block! """ return f"{param2}{param1}" mkdocstrings-0.29.0/docs/snippets/function_annotations_rst.py000066400000000000000000000006331476356224100246260ustar00rootroot00000000000000from typing import Optional def my_function(param1: int, param2: Optional[str] = None) -> str: """A short description of this function. Complex markup is supported in the main description section. I'm a code block! :param param1: An integer? :param param2: A string? If you have a long description, you can split it on multiple lines. """ return f"{param2}{param1}" mkdocstrings-0.29.0/docs/troubleshooting.md000066400000000000000000000216461476356224100210350ustar00rootroot00000000000000# Troubleshooting ## Code blocks in admonitions (in docstrings or else) are not rendered correctly To render code blocks in admonitions, you need to add the `pymdownx.superfences` extensions to the list of Markdown extensions in `mkdocs.yml`. For example: ```markdown !!! note Some text. ```bash echo "some code" ``` ``` ```yaml title="mkdocs.yml" markdown_extensions: - admonition - codehilite - pymdownx.superfences ``` For code blocks in docstrings, make sure to escape newlines (`\n` -> `\\n`), or prefix the entire docstring with 'r' to make it a raw-docstring: `r"""`. Indeed, docstrings are still strings and therefore subject to how Python parses strings. ## Footnotes are duplicated or overridden Before version 0.14, footnotes could be duplicated over a page. Please upgrade to version 0.14 or higher. See also: - [Issue #186](https://github.com/mkdocstrings/mkdocstrings/issues/186) - [Tabs in docstrings (from `pymdownx.tabbed`) are not working properly](#tabs-in-docstrings-from-pymdownxtabbed-are-not-working-properly). ## MkDocs warns me about links to unfound documentation files A warning like this one: > WARNING - Documentation file 'reference/parsers/docstrings.md' contains a link to 'reference/parsers/pytkdocs.parsers.docstrings.Section' which is not found in the documentation files. ...generally means you used parentheses `()` instead of brackets `[]` for a cross-reference. Notice the dots in `reference/parsers/pytkdocs.parsers.docstrings.Section`? It shows that it's probably a cross-reference, not a direct link. It's probably written like `[Section](pytkdocs.parsers.docstrings.Section)` in the docs, when it should be `[Section][pytkdocs.parsers.docstrings.Section]`. ## Some objects are not rendered (they do not appear in the generated docs) - Make sure the configuration options of the handler are correct. Check the documentation for [Handlers](usage/handlers.md) to see the available options for each handler. - Also make sure your documentation in your source code is formatted correctly. For Python code, check the [supported docstring styles](https://mkdocstrings.github.io/python/usage/#supported-docstrings-styles) page. - Re-run the Mkdocs command with `-v`, and carefully read any traceback. ## Tabs in docstrings (from `pymdownx.tabbed`) are not working properly Before version 0.14, multiple tab blocks injected on the same page would result in broken links: clicking on a tab would bring the user to the wrong one. Please upgrade to version 0.14 or higher. See also: - [Issue #193](https://github.com/mkdocstrings/mkdocstrings/issues/193) - [Footnotes are duplicated or overridden](#footnotes-are-duplicated-or-overridden). If you are stuck on a version before 0.14, and want to use multiple tab blocks in one page, use this workaround. ??? example "JavaScript workaround" Put the following code in a .js file, and list it in MkDocs' `extra_javascript`: ```javascript // Credits to Nikolaos Zioulis (@zuru on GitHub) function setID(){ var tabs = document.getElementsByClassName("tabbed-set"); for (var i = 0; i < tabs.length; i++) { children = tabs[i].children; var counter = 0; var iscontent = 0; for(var j = 0; j < children.length;j++){ if(typeof children[j].htmlFor === 'undefined'){ if((iscontent + 1) % 2 == 0){ // check if it is content if(iscontent == 1){ btn = children[j].childNodes[1].getElementsByTagName("button"); } } else{ // if not change the id children[j].id = "__tabbed_" + String(i + 1) + "_" + String(counter + 1); children[j].name = "__tabbed_" + String(i + 1); // make default tab open if(j == 0) children[j].click(); } iscontent++; } else{ // link to the correct tab children[j].htmlFor = "__tabbed_" + String(i+1) + "_" + String(counter + 1); counter ++; } } } } setID(); ``` This code will correctly reset the IDs for tabs on a same page. ## The generated documentation does not look good Please open an ticket on the [bugtracker][bugtracker] with a detailed explanation and screenshots of the bad-looking parts. Note that you can always [customize the look](usage/theming.md) of *mkdocstrings* blocks -- through both HTML and CSS. ## Warning: could not find cross-reference target TIP: **New in version 0.15.** Cross-linking used to include any Markdown heading, but now it's only for *mkdocstrings* identifiers by default. See [Cross-references to any Markdown heading](usage/index.md#cross-references-to-any-markdown-heading) to opt back in. Make sure the referenced object is properly rendered: verify your configuration options. For false-positives, you can wrap the text in backticks (\`) to prevent `mkdocstrings` from trying to process it. --- ## Python specifics ### Nothing is rendered at all Is your package available in the Python path? See [Python handler: Finding modules](https://mkdocstrings.github.io/python/usage/#finding-modules). ### LaTeX in docstrings is not rendered correctly If you are using a Markdown extension like [Arithmatex Mathjax](https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown-extensions/#arithmatex) or [`markdown-katex`][markdown-katex] to render LaTeX, add `r` in front of your docstring to make sure nothing is escaped. You'll still maybe have to play with escaping to get things right. Example: ```python def math_function(x, y): r""" Look at these formulas: ```math f(x) = \int_{-\infty}^\infty \hat f(\xi)\,e^{2 \pi i \xi x} \,d\xi ``` """ ``` ### My docstrings in comments (`#:`) are not picked up We only support docstrings in comments through the [griffe-sphinx](https://mkdocstrings.github.io/griffe-sphinx) extension. Alternatively, instead of: ```python import enum class MyEnum(enum.Enum): v1 = 1 #: The first choice. v2 = 2 #: The second choice. ``` You can use: ```python import enum class MyEnum(enum.Enum): v1 = 1 """The first choice.""" v2 = 2 """The second choice.""" ``` Or: ```python import enum class MyEnum(enum.Enum): """My enum. Attributes: v1: The first choice. v2: The second choice. """ v1 = 1 v2 = 2 ``` ### My wrapped function shows documentation/code for its wrapper instead of its own Use [`functools.wraps()`](https://docs.python.org/3.6/library/functools.html#functools.wraps): ```python from functools import wraps def my_decorator(function): """The decorator docs.""" @wraps(function) def wrapped_function(*args, **kwargs): print("hello") function(*args, **kwargs) print("bye") return wrapped_function @my_decorator def my_function(*args, **kwargs): """The function docs.""" print(*args, **kwargs) ``` ### Footnotes do not render The library that parses docstrings, [Griffe](https://mkdocstrings.github.io/griffe/), splits docstrings in several "sections" (example: [Google-style sections syntax](https://mkdocstrings.github.io/griffe/reference/docstrings/#google-syntax)). If a footnote is used in a section, while referenced in another, mkdocstrings won't be able to render it correctly. The footnote and its reference must appear in the same section. ```python def my_function(): """Summary. This is the first section[^1]. Note: This is the second section[^2]. Note: This is the third section[^3]. References at the end are part of yet another section (fourth here)[^4]. [^1]: Some text. [^2]: Some text. [^3]: Some text. [^4]: Some text. """ ``` Here only the fourth footnote will work, because it is the only one that appear in the same section as its reference. To fix this, make sure all footnotes appear in the same section as their references: ```python def my_function(): """Summary. This is the first section[^1]. [^1]: Some text. Note: This is the second section[^2]. [^2]: Some text. Note: This is the third section[^3]. [^3]: Some text. References at the end are part of yet another section (fourth here)[^4]. [^4]: Some text. """ ``` ### Submodules are not rendered In previous versions of mkdocstrings-python, submodules were rendered by default. This was changed and you now need to set the following option: ```yaml title="mkdocs.yml" plugins: - mkdocstrings: handlers: python: options: show_submodules: true ``` [bugtracker]: https://github.com/mkdocstrings/mkdocstrings [markdown-katex]: https://gitlab.com/mbarkhau/markdown-katex mkdocstrings-0.29.0/docs/usage/000077500000000000000000000000001476356224100163575ustar00rootroot00000000000000mkdocstrings-0.29.0/docs/usage/handlers.md000066400000000000000000000307661476356224100205150ustar00rootroot00000000000000# Handlers A handler is what makes it possible to collect and render documentation for a particular language. ## Available handlers - [C](https://mkdocstrings.github.io/c/){ .external } [:octicons-heart-fill-24:{ .heart .pulse title="Sponsors only" }](../insiders/index.md) - [Crystal](https://mkdocstrings.github.io/crystal/){ .external } - [Python](https://mkdocstrings.github.io/python/){ .external } - [Python (Legacy)](https://mkdocstrings.github.io/python-legacy/){ .external } - [Shell](https://mkdocstrings.github.io/shell/){ .external } - [TypeScript](https://mkdocstrings.github.io/typescript/){ .external } [:octicons-heart-fill-24:{ .heart .pulse title="Sponsors only" }](../insiders/index.md) - [VBA](https://pypi.org/project/mkdocstrings-vba/){ .external } ## About the Python handlers Since version 0.18, a new Python handler is available. It is based on [Griffe](https://github.com/mkdocstrings/griffe), which is an improved version of [pytkdocs](https://github.com/mkdocstrings/pytkdocs). If you want to keep using the legacy handler as long as possible, you can depend on `mkdocstrings-python-legacy` directly, or specify the `python-legacy` extra when depending on *mkdocstrings*: ```toml title="pyproject.toml" # PEP 621 dependencies declaration # adapt to your dependencies manager [project] dependencies = [ "mkdocstrings[python-legacy]>=0.18", ] ``` The legacy handler will continue to "work" for many releases, as long as the new handler does not cover all previous use-cases. ### Migrate to the new Python handler To use the new Python handler, you can depend on `mkdocstrings-python` directly, or specify the `python` extra when depending on *mkdocstrings*: ```toml title="pyproject.toml" # PEP 621 dependencies declaration # adapt to your dependencies manager [project] dependencies = [ "mkdocstrings[python]>=0.18", ] ``` #### Selection options WARNING: Since *mkdocstrings* 0.19, the YAML `selection` key is merged into the `options` key. - [x] `filters` is implemented, and used as before. - [x] `members` is implemented, and used as before. - [x] `inherited_members` is implemented. - [x] `docstring_style` is implemented, and used as before, except for the `restructured-text` style which is renamed `sphinx`. Numpy-style is now built-in, so you can stop depending on `pytkdocs[numpy-style]` or `docstring_parser`. - [x] `docstring_options` is implemented, and used as before. Refer to the [`griffe` documentation](https://mkdocstrings.github.io/griffe/docstrings/#parsing-options) for the updated list of supported docstring options. - [x] `new_path_syntax` is irrelevant now. If you were setting it to True, remove the option and replace every colon (`:`) in your autodoc identifiers by dots (`.`). See [all the handler's options](https://mkdocstrings.github.io/python/usage/). #### Rendering options WARNING: Since *mkdocstrings* 0.19, the YAML `rendering` key is merged into the `options` key. Every previous option is supported. Additional options are available: - [x] `separate_signature`: Render the signature (or attribute value) in a code block below the heading, instead as inline code. Useful for long signatures. If Black is installed, the signature is formatted. Default: `False`. - [x] `line_length`: The maximum line length to use when formatting signatures. Default: `60`. - [x] `show_submodules`: Whether to render submodules of a module when iterating on children. Default: `False`. - [x] `docstring_section_style`: The style to use to render docstring sections such as attributes, parameters, etc. Available styles: `"table"` (default), `"list"` and `"spacy"`. The SpaCy style is a poor implementation of their [table style](https://spacy.io/api/doc/#init). We are open to improvements through PRs! See [all the handler's options](https://mkdocstrings.github.io/python/usage/). #### Templates Templates are mostly the same as before, but the file layout has changed, as well as some file names. See [the documentation about the Python handler templates](https://mkdocstrings.github.io/python/usage/customization/#templates). ## Custom handlers Since version 0.14, you can create and use custom handlers thanks to namespace packages. For more information about namespace packages, [see their documentation](https://packaging.python.org/guides/packaging-namespace-packages/). TIP: **TL;DR - Project template for handlers.** *mkdocstrings* provides a [Copier](https://github.com/copier-org/copier) template to kickstart new handlers: https://github.com/mkdocstrings/handler-template. To use it, install Copier (`pipx install copier`), then run `copier gh:mkdocstrings/handler-template my_handler` to generate a new project. See [its upstream documentation](https://pawamoy.github.io/copier-pdm/) to learn how to work on the generated project. ### Packaging For *mkdocstrings*, a custom handler package would have the following structure: ``` 📁 your_repository └─╴📁 mkdocstrings_handlers └─╴📁 custom_handler ├─╴📁 templates │  ├─╴📁 material │ ├─╴📁 mkdocs │ └─╴📁 readthedocs └─╴📄 __init__.py ``` NOTE: **Note the absence of `__init__.py` module in `mkdocstrings_handlers`!** ### Code A handler is a subclass of the base handler provided by *mkdocstrings*. See the documentation for the [`BaseHandler`][mkdocstrings.BaseHandler]. Subclasses of the base handler must declare a `name` and `domain` as class attributes, as well as implement the following methods: - `collect(identifier, options)` (**required**): method responsible for collecting and returning data (extracting documentation from source code, loading introspecting objects in memory, other sources? etc.) - `render(identifier, options)` (**required**): method responsible for actually rendering the data to HTML, using the Jinja templates provided by your package. - `get_options(local_options)` (**required**): method responsible for combining global options with local ones. - `get_aliases(identifier)` (**recommended**): method responsible for returning known aliases of object identifiers, in order to register cross-references in the autorefs plugin. - `get_inventory_urls()` (optional): method responsible for returning a list of URLs to download (object inventories) along with configuration options (for loading the inventory with `load_inventory`). - `load_inventory(in_file, url, **options)` (optional): method responsible for loading an inventory (binary file-handle) and yielding tuples of identifiers and URLs. - `update_env(config)` (optional): Gives you a chance to customize the Jinja environment used to render templates, for examples by adding/removing Jinja filters and global context variables. - `teardown()` (optional): Clean up / teardown anything that needs it at the end of the build. You must implement a `get_handler` method at the module level, which returns an instance of your handler. This function takes the following parameters: - `theme` (string, theme name) - `custom_templates` (optional string, path to custom templates directory) - `mdx` (list, Markdown extensions) - `mdx_config` (dict, extensions configuration) - `handler_config` (dict, handle configuration) - `tool_config` (dict, the whole MkDocs configuration) These arguments are all passed as keyword arguments, so you can ignore them by adding `**kwargs` or similar to your signature. You should not modify the MkDocs config but can use it to get information about the MkDocs instance such as where the current `site_dir` lives. See the [Mkdocs Configuration](https://www.mkdocs.org/user-guide/configuration/) for more info about what is accessible from it. Check out how the [Python handler](https://github.com/mkdocstrings/python/blob/master/src/mkdocstrings_handlers/python) is written for inspiration. ### Templates Your handler's implementation should normally be backed by templates, which go to the directory `mkdocstrings_handlers/custom_handler/templates/some_theme` (`custom_handler` here should be replaced with the actual name of your handler, and `some_theme` should be the name of an actual MkDocs theme that you support, e.g. `material`). With that structure, you can use `self.env.get_template("foo.html")` inside your `render` method. This already chooses the subdirectory based on the current MkDocs theme. If you wish to support *any* MkDocs theme, rather than a few specifically selected ones, you can pick one theme's subdirectory to be the fallback for when an unknown theme is encountered. Then you just need to set the `fallback_theme` variable on your handler subclass. The fallback directory can be used even for themes you explicitly support: you can omit some template from one of the other theme directories in case they're exactly the same as in the fallback theme. If your theme's HTML requires CSS to go along with it, put it into a file named `mkdocstrings_handlers/custom_handler/templates/some_theme/style.css`, then this will be included into the final site automatically if this handler is ever used. Alternatively, you can put the CSS as a string into the `extra_css` variable of your handler. Finally, it's possible to entirely omit templates, and tell *mkdocstrings* to use the templates of another handler. In you handler, override the `get_templates_dir()` method to return the other handlers templates path: ```python from pathlib import Path from mkdocstrings.handlers.base import BaseHandler class CobraHandler(BaseHandler): def get_templates_dir(self, handler: str | None = None) -> Path: # use the python handler templates # (it assumes the python handler is installed) return super().get_templates_dir("python") ``` ### Usage When a custom handler is installed, it is then available to *mkdocstrings*. You can configure it as usual: ```yaml title="mkdocs.yml" plugins: - mkdocstrings: handlers: custom_handler: handler_config_option: yes options: some_config_option: "a" other_config_option: 0 ``` ...and use it in your autodoc instructions: ```md title="docs/some_page.md" # Documentation for an object ::: some.objects.path handler: custom_handler options: some_config_option: "b" other_config_option: 1 ``` ## Handler extensions *mkdocstrings* provides a way for third-party packages to extend or alter the behavior of handlers. For example, an extension of the Python handler could add specific support for another Python library. NOTE: This feature is intended for developers. If you are a user and want to customize how objects are rendered, see [Theming / Customization](theming.md#customization). Such extensions can register additional template folders that will be used when rendering collected data. Extensions are responsible for synchronizing with the handler itself so that it uses the additional templates. An extension is a Python package that defines an entry-point for a specific handler: ```toml title="pyproject.toml" [project.entry-points."mkdocstrings.python.templates"] # (1)! extension-name = "extension_package:get_templates_path" # (2)! ``` 1. Replace `python` by the name of the handler you want to add templates to. 1. Replace `extension-name` by any name you want, and replace `extension_package:get_templates_path` by the actual module path and function name in your package. This entry-point assumes that the extension provides a `get_templates_path` function directly under the `extension_package` package: ```tree pyproject.toml extension_package/ __init__.py templates/ ``` ```python title="extension_package/__init__.py" from pathlib import Path def get_templates_path() -> Path: return Path(__file__).parent / "templates" ``` This function doesn't accept any argument and returns the path ([`pathlib.Path`][] or [`str`][]) to a directory containing templates. The directory must contain one subfolder for each supported theme, even if empty (see "fallback theme" in [custom handlers templates](#templates_1)). For example: ```tree pyproject.toml extension_package/ __init__.py templates/ material/ readthedocs/ mkdocs/ ``` *mkdocstrings* will add the folders corresponding to the user-selected theme, and to the handler's defined fallback theme, as usual. The names of the extension templates must not overlap with the handler's original templates. The extension is then responsible, in collaboration with its target handler, for mutating the collected data in order to instruct the handler to use one of the extension template when rendering particular objects. See each handler's docs to see if they support extensions, and how. mkdocstrings-0.29.0/docs/usage/index.md000066400000000000000000000254441476356224100200210ustar00rootroot00000000000000# Usage ## Autodoc syntax *mkdocstrings* works by processing special expressions in your Markdown files. The syntax is as follows: ```md ::: identifier YAML block ``` > NOTE: **Resources on YAML.** > YAML can sometimes be a bit tricky, particularly on indentation. > Here are some resources that other users found useful to better > understand YAML's peculiarities. > > - [YAML idiosyncrasies](https://docs.saltproject.io/en/3000/topics/troubleshooting/yaml_idiosyncrasies.html) > - [YAML multiline](https://yaml-multiline.info/) The `identifier` is a string identifying the object you want to document. The format of an identifier can vary from one handler to another. For example, the Python handler expects the full dotted-path to a Python object: `my_package.my_module.MyClass.my_method`. The YAML block is optional, and contains some configuration options: - `handler`: the name of the handler to use to collect and render this object. By default, it will use the value defined in the [Global options](#global-options)'s `default_handler` key, or `"python"`. - `options`: a dictionary of options passed to the handler's methods responsible both for collecting and rendering the documentation. These options can be defined globally (in `mkdocs.yml`, see [Global options](#global-options)), locally (as described here), or both. !!! example "Example with the Python handler" === "docs/my_page.md" ```md # Documentation for `MyClass` ::: my_package.my_module.MyClass handler: python options: members: - method_a - method_b show_root_heading: false show_source: false ``` === "mkdocs.yml" ```yaml nav: - "My page": my_page.md ``` === "src/my_package/my_module.py" ```python class MyClass: """Print print print!""" def method_a(self): """Print A!""" print("A!") def method_b(self): """Print B!""" print("B!") def method_c(self): """Print C!""" print("C!") ``` === "Result"

    Documentation for MyClass

    Print print print!

    method_a(self)

    Print A!

    method_b(self)

    Print B!

    It is also possible to integrate a mkdocstrings identifier into a Markdown header: ```md ## ::: my_package.my_module.MyClass options: show_source: false ``` The above is equivalent to: ```md ::: my_package.my_module.MyClass options: show_source: false heading_level: 2 ``` ## Global options *mkdocstrings* accepts a few top-level configuration options in `mkdocs.yml`: - `default_handler`: The handler that is used by default when no handler is specified. - `custom_templates`: The path to a directory containing custom templates. The path is relative to the MkDocs configuration file. See [Theming](theming.md). - `handlers`: The handlers' global configuration. - `enable_inventory`: Whether to enable inventory file generation. See [Cross-references to other projects / inventories](#cross-references-to-other-projects-inventories) - `enabled` **(New in version 0.20)**: Whether to enable the plugin. Defaults to `true`. Can be used to reduce build times when doing local development. Especially useful when used with environment variables (see example below). !!! example ```yaml title="mkdocs.yml" plugins: - mkdocstrings: enabled: !ENV [ENABLE_MKDOCSTRINGS, true] custom_templates: templates default_handler: python handlers: python: options: show_source: false ``` The handlers global configuration can then be overridden by local configurations: ```yaml title="docs/some_page.md" ::: my_package.my_module.MyClass options: show_source: true ``` Some handlers accept additional global configuration. Check the documentation for your handler of interest in [Handlers](handlers.md). ## Cross-references Cross-references are written as Markdown *reference-style* links: === "Markdown" ```md With a custom title: [`Object 1`][full.path.object1] With the identifier as title: [full.path.object2][] ``` === "HTML Result" ```html

    With a custom title: Object 1

    With the identifier as title: full.path.object2

    ``` Any item that was inserted using the [autodoc syntax](#autodoc-syntax) (e.g. `::: full.path.object1`) is possible to link to by using the same identifier with the cross-reference syntax (`[example][full.path.object1]`). But the cross-references are also applicable to the items' children that get pulled in. ### Finding out the anchor If you're not sure which exact identifier a doc item uses, you can look at its "anchor", which your Web browser will show in the URL bar when clicking an item's entry in the table of contents. If the URL is `https://example.com/some/page.html#full.path.object1` then you know that this item is possible to link to with `[example][full.path.object1]`, regardless of the current page. ### Cross-references to any Markdown heading TIP: **Changed in version 0.15.** Linking to any Markdown heading used to be the default, but now opt-in is required. If you want to link to *any* Markdown heading, not just *mkdocstrings*-inserted items, please enable the [*autorefs* plugin for *MkDocs*](https://github.com/mkdocstrings/autorefs) by adding `autorefs` to `plugins`: ```yaml title="mkdocs.yml" hl_lines="3" plugins: - search - autorefs - mkdocstrings: [...] ``` Note that you don't need to (`pip`) install anything more; this plugin is guaranteed to be pulled in with *mkdocstrings*. !!! example === "doc1.md" ```md ## Hello, world! Testing ``` === "doc2.md" ```md ## Something else Please see the [Hello, World!][hello-world] section. ``` === "Result HTML for doc2" ```html

    Please see the Hello, World! section.

    ``` ### Cross-references to a sub-heading in a docstring TIP: **New in version 0.14.** If you have a Markdown heading *inside* your docstring, you can also link directly to it. In the example below you see the identifier to be linked is `foo.bar--tips`, because it's the "Tips" heading that's part of the `foo.bar` object, joined with "`--`". !!! example === "foo.py" ```python def bar(): """Hello, world! # Tips - Stay hydrated. """ ``` === "doc1.md" ```md ::: foo.bar ``` === "doc2.md" ```md Check out the [tips][foo.bar--tips] ``` === "HTML result for doc2" ```html

    Check out the tips

    ``` The above tip about [Finding out the anchor](#finding-out-the-anchor) also applies the same way here. You may also notice that such a heading does not get rendered as a `

    ` element directly, but rather the level gets shifted to fit the encompassing document structure. If you're curious about the implementation, check out [mkdocstrings.HeadingShiftingTreeprocessor][] and others. ### Cross-references to other projects / inventories TIP: **New in version 0.16.** Python developers coming from Sphinx might know about its `intersphinx` extension, that allows to cross-reference items between several projects. *mkdocstrings* has a similar feature. To reference an item from another project, you must first tell *mkdocstrings* to load the inventory it provides. Each handler will be responsible of loading inventories specific to its language. For example, the Python handler can load Sphinx-generated inventories (`objects.inv`). In the following snippet, we load the inventory provided by `installer`: ```yaml title="mkdocs.yml" plugins: - mkdocstrings: handlers: python: inventories: - https://installer.readthedocs.io/en/stable/objects.inv ``` Now it is possible to cross-reference `installer`'s items. For example: === "Markdown" ```md See [installer.records][] to learn about records. ``` === "Result (HTML)" ```html

    See installer.records to learn about records.

    ``` === "Result (displayed)" See [installer.records][] to learn about records. You can of course select another version of the inventory, for example: ```yaml plugins: - mkdocstrings: handlers: python: inventories: # latest instead of stable - https://installer.readthedocs.io/en/latest/objects.inv ``` In case the inventory file is not served under the base documentation URL, you can explicitly specify both URLs: ```yaml plugins: - mkdocstrings: handlers: python: inventories: - url: https://cdn.example.com/version/objects.inv base_url: https://docs.example.com/version ``` Absolute URLs to cross-referenced items will then be based on `https://docs.example.com/version/` instead of `https://cdn.example.com/version/`. If you need authentication to access the inventory file, you can provide the credentials in the URL, either as `username:password`: ```yaml - url: https://username:password@private.example.com/version/objects.inv ``` ...or with token authentication: ```yaml - url: https://token123@private.example.com/version/objects.inv ``` The credentials can also be specified using environment variables in the form `${ENV_VAR}`: ```yaml - url: https://${USERNAME}:${PASSWORD}@private.example.com/version/objects.inv ``` Reciprocally, *mkdocstrings* also allows to *generate* an inventory file in the Sphinx format. It will be enabled by default if the Python handler is used, and generated as `objects.inv` in the final site directory. Other projects will be able to cross-reference items from your project. To explicitly enable or disable the generation of the inventory file, use the global `enable_inventory` option: ```yaml plugins: - mkdocstrings: enable_inventory: false ``` mkdocstrings-0.29.0/docs/usage/theming.md000066400000000000000000000072371476356224100203450ustar00rootroot00000000000000# Themes *mkdocstrings* can support multiple MkDocs themes. It currently supports the *[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)* theme and, partially, the built-in MkDocs and ReadTheDocs themes. Each handler can fallback to a particular theme when the user selected theme is not supported. For example, the Python handler will fallback to the *Material for MkDocs* templates. ## Customization There is some degree of customization possible in *mkdocstrings*. First, you can write custom templates to override the theme templates. Second, the provided templates make use of CSS classes, so you can tweak the look and feel with extra CSS rules. ### Templates To use custom templates and override the theme ones, specify the relative path from your configuration file to your templates directory with the `custom_templates` global configuration option: ```yaml title="mkdocs.yml" plugins: - mkdocstrings: custom_templates: templates ``` Your directory structure must be identical to the provided templates one: ``` 📁 templates/ ├─╴📁 / │ ├── 📁 / │ └── 📁 / └── 📁 / ├── 📁 / └── 📁 / ``` For example, check out the Python [template tree](https://github.com/mkdocstrings/python/tree/master/src/mkdocstrings_handlers/python/templates/) on GitHub. You don't have to replicate the whole tree, only the handlers, themes or templates you want to override. For example, to override some templates of the *Material* theme for Python: ``` 📁 templates/ └── 📁 python/ └── 📁 material/ ├── 📄 parameters.html └── 📄 exceptions.html ``` In the HTML files, replace the original contents with your modified version. In the future, the templates will use Jinja blocks, so it will be easier to modify small part of the templates without copy-pasting the whole files. See the documentation about templates for: - the Crystal handler: https://mkdocstrings.github.io/crystal/styling.html - the Python handler: https://mkdocstrings.github.io/python/usage/customization/#templates #### Debugging Every template has access to a `log` function, allowing to log messages as usual: ```jinja {{ log.debug("A DEBUG message.") }} {{ log.info("An INFO message.") }} {{ log.warning("A WARNING message.") }} {{ log.error("An ERROR message.") }} {{ log.critical("A CRITICAL message.") }} ``` ### CSS classes Since each handler provides its own set of templates, with their own CSS classes, we cannot list them all here. See the documentation about CSS classes for: - the Crystal handler: https://mkdocstrings.github.io/crystal/styling.html#custom-styles - the Python handler: https://mkdocstrings.github.io/python/usage/customization/#css-classes ### Syntax highlighting Code blocks that occur in the docstring of an item inserted with *mkdocstrings*, as well as code blocks (such as *Source code*) that *mkdocstrings* inserts itself, are syntax-highlighted according to the same rules as other normal code blocks in your document. See more details in [mkdocstrings.Highlighter][]. As for the CSS class used for code blocks -- it will also match the "normal" config, so the default (`.codehilite` or `.highlight`) will match your chosen Markdown extension for highlighting. IMPORTANT: **Changed in version 0.15.** The CSS class used to always be `.highlight`, but now it depends on the configuration. Long story short, you probably should add `pymdownx.highlight` to your `markdown_extensions`, and then use `.doc-contents .highlight` as the CSS selector in case you want to change something about *mkdocstrings'* code blocks specifically. mkdocstrings-0.29.0/duties.py000066400000000000000000000177101476356224100162000ustar00rootroot00000000000000"""Development tasks.""" from __future__ import annotations import os import re import sys from contextlib import contextmanager from functools import wraps from importlib.metadata import version as pkgversion from pathlib import Path from typing import TYPE_CHECKING, Any, Callable from duty import duty, tools if TYPE_CHECKING: from collections.abc import Iterator from duty.context import Context PY_SRC_PATHS = (Path(_) for _ in ("src", "tests", "duties.py", "scripts")) PY_SRC_LIST = tuple(str(_) for _ in PY_SRC_PATHS) PY_SRC = " ".join(PY_SRC_LIST) CI = os.environ.get("CI", "0") in {"1", "true", "yes", ""} WINDOWS = os.name == "nt" PTY = not WINDOWS and not CI MULTIRUN = os.environ.get("MULTIRUN", "0") == "1" def pyprefix(title: str) -> str: if MULTIRUN: prefix = f"(python{sys.version_info.major}.{sys.version_info.minor})" return f"{prefix:14}{title}" return title def not_from_insiders(func: Callable) -> Callable: @wraps(func) def wrapper(ctx: Context, *args: Any, **kwargs: Any) -> None: origin = ctx.run("git config --get remote.origin.url", silent=True) if "pawamoy-insiders/griffe" in origin: ctx.run( lambda: False, title="Not running this task from insiders repository (do that from public repo instead!)", ) return func(ctx, *args, **kwargs) return wrapper @contextmanager def material_insiders() -> Iterator[bool]: if "+insiders" in pkgversion("mkdocs-material"): os.environ["MATERIAL_INSIDERS"] = "true" try: yield True finally: os.environ.pop("MATERIAL_INSIDERS") else: yield False def _get_changelog_version() -> str: changelog_version_re = re.compile(r"^## \[(\d+\.\d+\.\d+)\].*$") with Path(__file__).parent.joinpath("CHANGELOG.md").open("r", encoding="utf8") as file: return next(filter(bool, map(changelog_version_re.match, file))).group(1) # type: ignore[union-attr] @duty def changelog(ctx: Context, bump: str = "") -> None: """Update the changelog in-place with latest commits. Parameters: bump: Bump option passed to git-changelog. """ ctx.run(tools.git_changelog(bump=bump or None), title="Updating changelog") ctx.run(tools.yore.check(bump=bump or _get_changelog_version()), title="Checking legacy code") @duty(pre=["check-quality", "check-types", "check-docs", "check-api"]) def check(ctx: Context) -> None: """Check it all!""" @duty def check_quality(ctx: Context) -> None: """Check the code quality.""" ctx.run( tools.ruff.check(*PY_SRC_LIST, config="config/ruff.toml"), title=pyprefix("Checking code quality"), ) @duty def check_docs(ctx: Context) -> None: """Check if the documentation builds correctly.""" Path("htmlcov").mkdir(parents=True, exist_ok=True) Path("htmlcov/index.html").touch(exist_ok=True) with material_insiders(): ctx.run( tools.mkdocs.build(strict=True, verbose=True), title=pyprefix("Building documentation"), ) @duty def check_types(ctx: Context) -> None: """Check that the code is correctly typed.""" os.environ["MYPYPATH"] = "src" os.environ["FORCE_COLOR"] = "1" ctx.run( tools.mypy(*PY_SRC_LIST, config_file="config/mypy.ini"), title=pyprefix("Type-checking"), ) @duty def check_api(ctx: Context, *cli_args: str) -> None: """Check for API breaking changes.""" ctx.run( tools.griffe.check("mkdocstrings", search=["src"], color=True).add_args(*cli_args), title="Checking for API breaking changes", nofail=True, ) @duty def docs(ctx: Context, *cli_args: str, host: str = "127.0.0.1", port: int = 8000) -> None: """Serve the documentation (localhost:8000). Parameters: host: The host to serve the docs from. port: The port to serve the docs on. """ with material_insiders(): ctx.run( tools.mkdocs.serve(dev_addr=f"{host}:{port}").add_args(*cli_args), title="Serving documentation", capture=False, ) @duty def docs_deploy(ctx: Context, *, force: bool = False) -> None: """Deploy the documentation to GitHub pages. Parameters: force: Whether to force deployment, even from non-Insiders version. """ os.environ["DEPLOY"] = "true" with material_insiders() as insiders: if not insiders: ctx.run(lambda: False, title="Not deploying docs without Material for MkDocs Insiders!") origin = ctx.run("git config --get remote.origin.url", silent=True, allow_overrides=False) if "pawamoy-insiders/mkdocstrings" in origin: ctx.run( "git remote add org-pages git@github.com:mkdocstrings/mkdocstrings.github.io", silent=True, nofail=True, allow_overrides=False, ) ctx.run( tools.mkdocs.gh_deploy(remote_name="org-pages", force=True), title="Deploying documentation", ) elif force: ctx.run( tools.mkdocs.gh_deploy(remote_name="org-pages", force=True), title="Deploying documentation", ) else: ctx.run( lambda: False, title="Not deploying docs from public repository (do that from insiders instead!)", nofail=True, ) @duty def format(ctx: Context) -> None: """Run formatting tools on the code.""" ctx.run( tools.ruff.check(*PY_SRC_LIST, config="config/ruff.toml", fix_only=True, exit_zero=True), title="Auto-fixing code", ) ctx.run(tools.ruff.format(*PY_SRC_LIST, config="config/ruff.toml"), title="Formatting code") @duty def build(ctx: Context) -> None: """Build source and wheel distributions.""" ctx.run( tools.build(), title="Building source and wheel distributions", pty=PTY, ) @duty @not_from_insiders def publish(ctx: Context) -> None: """Publish source and wheel distributions to PyPI.""" if not Path("dist").exists(): ctx.run("false", title="No distribution files found") dists = [str(dist) for dist in Path("dist").iterdir()] ctx.run( tools.twine.upload(*dists, skip_existing=True), title="Publishing source and wheel distributions to PyPI", pty=PTY, ) @duty(post=["build", "publish", "docs-deploy"]) @not_from_insiders def release(ctx: Context, version: str = "") -> None: """Release a new Python package. Parameters: version: The new version number to use. """ if not (version := (version or input("> Version to release: ")).strip()): ctx.run("false", title="A version must be provided") ctx.run("git add pyproject.toml CHANGELOG.md", title="Staging files", pty=PTY) ctx.run(["git", "commit", "-m", f"chore: Prepare release {version}"], title="Committing changes", pty=PTY) ctx.run(f"git tag {version}", title="Tagging commit", pty=PTY) ctx.run("git push", title="Pushing commits", pty=False) ctx.run("git push --tags", title="Pushing tags", pty=False) @duty(silent=True, aliases=["cov"]) def coverage(ctx: Context) -> None: """Report coverage as text and HTML.""" ctx.run(tools.coverage.combine(), nofail=True) ctx.run(tools.coverage.report(rcfile="config/coverage.ini"), capture=False) ctx.run(tools.coverage.html(rcfile="config/coverage.ini")) @duty def test(ctx: Context, *cli_args: str, match: str = "") -> None: """Run the test suite. Parameters: match: A pytest expression to filter selected tests. """ py_version = f"{sys.version_info.major}{sys.version_info.minor}" os.environ["COVERAGE_FILE"] = f".coverage.{py_version}" ctx.run( tools.pytest( "tests", config_file="config/pytest.ini", select=match, color="yes", ).add_args("-n", "auto", *cli_args), title=pyprefix("Running tests"), ) mkdocstrings-0.29.0/mkdocs.yml000066400000000000000000000145421476356224100163340ustar00rootroot00000000000000site_name: "mkdocstrings" site_description: "Automatic documentation from sources, for MkDocs." site_url: "https://mkdocstrings.github.io/" repo_url: "https://github.com/mkdocstrings/mkdocstrings" repo_name: "mkdocstrings/mkdocstrings" site_dir: "site" watch: [mkdocs.yml, README.md, CONTRIBUTING.md, CHANGELOG.md, src/mkdocstrings] copyright: Copyright © 2019 Timothée Mazzucotelli edit_uri: edit/main/docs/ validation: omitted_files: warn absolute_links: warn unrecognized_links: warn nav: - Home: - Overview: index.md - Changelog: changelog.md - Credits: credits.md - License: license.md - Usage: - usage/index.md - Theming: usage/theming.md - Handlers: usage/handlers.md - All handlers: - C: https://mkdocstrings.github.io/c/ - Crystal: https://mkdocstrings.github.io/crystal/ - Python: https://mkdocstrings.github.io/python/ - Python (Legacy): https://mkdocstrings.github.io/python-legacy/ - Shell: https://mkdocstrings.github.io/shell/ - TypeScript: https://mkdocstrings.github.io/typescript/ - VBA: https://pypi.org/project/mkdocstrings-vba - Guides: - Recipes: recipes.md - Troubleshooting: troubleshooting.md - API reference: reference/mkdocstrings.md - Development: - Contributing: contributing.md - Code of Conduct: code_of_conduct.md - Coverage report: coverage.md - Insiders: - insiders/index.md - Getting started: - Installation: insiders/installation.md - Changelog: insiders/changelog.md - Author's website: https://pawamoy.github.io/ theme: name: material logo: logo.svg custom_dir: docs/.overrides features: - announce.dismiss - content.action.edit - content.action.view - content.code.annotate - content.code.copy - content.tooltips - navigation.footer - navigation.instant.preview - navigation.path - navigation.sections - navigation.tabs - navigation.tabs.sticky - navigation.top - search.highlight - search.suggest - toc.follow palette: - media: "(prefers-color-scheme)" toggle: icon: material/brightness-auto name: Switch to light mode - media: "(prefers-color-scheme: light)" scheme: default primary: teal accent: purple toggle: icon: material/weather-sunny name: Switch to dark mode - media: "(prefers-color-scheme: dark)" scheme: slate primary: black accent: lime toggle: icon: material/weather-night name: Switch to system preference extra_css: - css/style.css - css/material.css - css/mkdocstrings.css - css/insiders.css extra_javascript: - js/feedback.js markdown_extensions: - attr_list - admonition - callouts: strip_period: false - footnotes - pymdownx.details - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg - pymdownx.highlight: pygments_lang_class: true - pymdownx.magiclink - pymdownx.snippets: base_path: [!relative $config_dir] check_paths: true - pymdownx.superfences - pymdownx.tabbed: alternate_style: true slugify: !!python/object/apply:pymdownx.slugs.slugify kwds: case: lower - pymdownx.tasklist: custom_checkbox: true - pymdownx.tilde - toc: permalink: "¤" plugins: - search - autorefs - markdown-exec - section-index - coverage - mkdocstrings: handlers: python: inventories: - https://docs.python.org/3/objects.inv - https://installer.readthedocs.io/en/stable/objects.inv # demonstration purpose in the docs - https://mkdocstrings.github.io/autorefs/objects.inv - https://www.mkdocs.org/objects.inv - https://python-markdown.github.io/objects.inv - https://jinja.palletsprojects.com/en/stable/objects.inv - https://markupsafe.palletsprojects.com/en/stable/objects.inv paths: [src] options: docstring_options: ignore_init_summary: true docstring_section_style: list filters: ["!^_"] heading_level: 1 inherited_members: true merge_init_into_class: true parameter_headings: true separate_signature: true show_root_heading: true show_root_full_path: false show_signature_annotations: true show_source: false show_symbol_type_heading: true show_symbol_type_toc: true signature_crossrefs: true summary: true - llmstxt: files: - output: llms-full.txt inputs: - index.md - usage/index.md - usage/handlers.md - usage/theming.md - recipes.md - troubleshooting.md - reference/**.md - git-revision-date-localized: enabled: !ENV [DEPLOY, false] enable_creation_date: true type: timeago - redirects: redirect_maps: theming.md: usage/theming.md handlers/overview.md: usage/handlers.md reference/index.md: reference/mkdocstrings.md#mkdocstrings reference/extension.md: reference/mkdocstrings.md#mkdocstrings.extension reference/handlers/index.md: reference/mkdocstrings.md#mkdocstrings.handlers reference/handlers/base.md: reference/mkdocstrings.md#mkdocstrings.handlers.base reference/handlers/rendering.md: reference/mkdocstrings.md#mkdocstrings.handlers.rendering reference/inventory.md: reference/mkdocstrings.md#mkdocstrings.inventory reference/loggers.md: reference/mkdocstrings.md#mkdocstrings.loggers reference/plugin.md: reference/mkdocstrings.md#mkdocstrings.plugin - minify: minify_html: !ENV [DEPLOY, false] - group: enabled: !ENV [MATERIAL_INSIDERS, false] plugins: - typeset extra: social: - icon: fontawesome/brands/github link: https://github.com/pawamoy - icon: fontawesome/brands/mastodon link: https://fosstodon.org/@pawamoy - icon: fontawesome/brands/twitter link: https://twitter.com/pawamoy - icon: fontawesome/brands/gitter link: https://gitter.im/mkdocstrings/community - icon: fontawesome/brands/python link: https://pypi.org/project/mkdocstrings/ analytics: feedback: title: Was this page helpful? ratings: - icon: material/emoticon-happy-outline name: This page was helpful data: 1 note: Thanks for your feedback! - icon: material/emoticon-sad-outline name: This page could be improved data: 0 note: Let us know how we can improve this page. mkdocstrings-0.29.0/pyproject.toml000066400000000000000000000070121476356224100172370ustar00rootroot00000000000000[build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" [project] name = "mkdocstrings" description = "Automatic documentation from sources, for MkDocs." authors = [{name = "Timothée Mazzucotelli", email = "dev@pawamoy.fr"}] license = "ISC" license-files = ["LICENSE"] readme = "README.md" requires-python = ">=3.9" keywords = ["mkdocs", "mkdocs-plugin", "docstrings", "autodoc", "documentation"] dynamic = ["version"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Documentation", "Topic :: Software Development", "Topic :: Software Development :: Documentation", "Topic :: Utilities", "Typing :: Typed", ] dependencies = [ "Jinja2>=2.11.1", "Markdown>=3.6", "MarkupSafe>=1.1", "mkdocs>=1.6", "mkdocs-autorefs>=1.4", "pymdown-extensions>=6.3", "importlib-metadata>=4.6; python_version < '3.10'", "typing-extensions>=4.1; python_version < '3.10'", ] [project.optional-dependencies] crystal = ["mkdocstrings-crystal>=0.3.4"] python-legacy = ["mkdocstrings-python-legacy>=0.2.1"] python = ["mkdocstrings-python>=1.16.2"] [project.urls] Homepage = "https://mkdocstrings.github.io" Documentation = "https://mkdocstrings.github.io" Changelog = "https://mkdocstrings.github.io/changelog" Repository = "https://github.com/mkdocstrings/mkdocstrings" Issues = "https://github.com/mkdocstrings/mkdocstrings/issues" Discussions = "https://github.com/mkdocstrings/mkdocstrings/discussions" Gitter = "https://gitter.im/mkdocstrings/community" Funding = "https://github.com/sponsors/pawamoy" [project.entry-points."mkdocs.plugins"] mkdocstrings = "mkdocstrings:MkdocstringsPlugin" [tool.pdm.version] source = "call" getter = "scripts.get_version:get_version" [tool.pdm.build] # Include as much as possible in the source distribution, to help redistributors. excludes = ["**/.pytest_cache"] source-includes = [ "config", "docs", "scripts", "share", "tests", "duties.py", "mkdocs.yml", "*.md", "LICENSE", ] [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 = "."}, ] [dependency-groups] maintain = [ "build>=1.2", "git-changelog>=2.5", "twine>=5.1", "yore>=0.3.3", ] ci = [ "dirty-equals>=0.9", "duty>=1.6", "ruff>=0.4", "pytest>=8.2", "pytest-cov>=5.0", "pytest-randomly>=3.15", "pytest-xdist>=3.6", "mypy>=1.10", "types-markdown>=3.6", "types-pyyaml>=6.0", ] docs = [ "markdown-callouts>=0.4", "markdown-exec>=1.8", "mkdocs>=1.6", "mkdocs-coverage>=1.0", "mkdocs-git-revision-date-localized-plugin>=1.2", "mkdocs-llmstxt>=0.1", "mkdocs-material>=9.5", "mkdocs-minify-plugin>=0.8", "mkdocs-redirects>=1.2.1", "mkdocs-section-index>=0.3", "mkdocstrings-python>=1.16.2", # YORE: EOL 3.10: Remove line. "tomli>=2.0; python_version < '3.11'", ] [tool.uv] default-groups = ["maintain", "ci", "docs"] mkdocstrings-0.29.0/scripts/000077500000000000000000000000001476356224100160125ustar00rootroot00000000000000mkdocstrings-0.29.0/scripts/gen_credits.py000066400000000000000000000147711476356224100206640ustar00rootroot00000000000000# Script to generate the project's credits. from __future__ import annotations import os import sys from collections import defaultdict from collections.abc import Iterable from importlib.metadata import distributions from itertools import chain from pathlib import Path from textwrap import dedent from typing import Union from jinja2 import StrictUndefined from jinja2.sandbox import SandboxedEnvironment from packaging.requirements import Requirement # YORE: EOL 3.10: Replace block with line 2. if sys.version_info >= (3, 11): import tomllib else: import tomli as tomllib project_dir = Path(os.getenv("MKDOCS_CONFIG_DIR", ".")) with project_dir.joinpath("pyproject.toml").open("rb") as pyproject_file: pyproject = tomllib.load(pyproject_file) project = pyproject["project"] project_name = project["name"] devdeps = [dep for group in pyproject["dependency-groups"].values() for dep in group if not dep.startswith("-e")] PackageMetadata = dict[str, Union[str, Iterable[str]]] Metadata = dict[str, PackageMetadata] def _merge_fields(metadata: dict) -> PackageMetadata: fields = defaultdict(list) for header, value in metadata.items(): fields[header.lower()].append(value.strip()) return { field: value if len(value) > 1 or field in ("classifier", "requires-dist") else value[0] for field, value in fields.items() } def _norm_name(name: str) -> str: return name.replace("_", "-").replace(".", "-").lower() def _requirements(deps: list[str]) -> dict[str, Requirement]: return {_norm_name((req := Requirement(dep)).name): req for dep in deps} def _extra_marker(req: Requirement) -> str | None: if not req.marker: return None try: return next(marker[2].value for marker in req.marker._markers if getattr(marker[0], "value", None) == "extra") except StopIteration: return None def _get_metadata() -> Metadata: metadata = {} for pkg in distributions(): name = _norm_name(pkg.name) # type: ignore[attr-defined,unused-ignore] metadata[name] = _merge_fields(pkg.metadata) # type: ignore[arg-type] metadata[name]["spec"] = set() metadata[name]["extras"] = set() metadata[name].setdefault("summary", "") _set_license(metadata[name]) return metadata def _set_license(metadata: PackageMetadata) -> None: license_field = metadata.get("license-expression", metadata.get("license", "")) license_name = license_field if isinstance(license_field, str) else " + ".join(license_field) check_classifiers = license_name in ("UNKNOWN", "Dual License", "") or license_name.count("\n") if check_classifiers: license_names = [] for classifier in metadata["classifier"]: if classifier.startswith("License ::"): license_names.append(classifier.rsplit("::", 1)[1].strip()) license_name = " + ".join(license_names) metadata["license"] = license_name or "?" def _get_deps(base_deps: dict[str, Requirement], metadata: Metadata) -> Metadata: deps = {} for dep_name, dep_req in base_deps.items(): if dep_name not in metadata or dep_name == "mkdocstrings": continue metadata[dep_name]["spec"] |= {str(spec) for spec in dep_req.specifier} # type: ignore[operator] metadata[dep_name]["extras"] |= dep_req.extras # type: ignore[operator] deps[dep_name] = metadata[dep_name] again = True while again: again = False for pkg_name in metadata: if pkg_name in deps: for pkg_dependency in metadata[pkg_name].get("requires-dist", []): requirement = Requirement(pkg_dependency) dep_name = _norm_name(requirement.name) extra_marker = _extra_marker(requirement) if ( dep_name in metadata and dep_name not in deps and dep_name != project["name"] and (not extra_marker or extra_marker in deps[pkg_name]["extras"]) ): metadata[dep_name]["spec"] |= {str(spec) for spec in requirement.specifier} # type: ignore[operator] deps[dep_name] = metadata[dep_name] again = True return deps def _render_credits() -> str: metadata = _get_metadata() dev_dependencies = _get_deps(_requirements(devdeps), metadata) prod_dependencies = _get_deps( _requirements( chain( # type: ignore[arg-type] project.get("dependencies", []), chain(*project.get("optional-dependencies", {}).values()), ), ), metadata, ) template_data = { "project_name": project_name, "prod_dependencies": sorted(prod_dependencies.values(), key=lambda dep: str(dep["name"]).lower()), "dev_dependencies": sorted(dev_dependencies.values(), key=lambda dep: str(dep["name"]).lower()), "more_credits": "http://pawamoy.github.io/credits/", } template_text = dedent( """ # Credits These projects were used to build *{{ project_name }}*. **Thank you!** [Python](https://www.python.org/) | [uv](https://github.com/astral-sh/uv) | [copier-uv](https://github.com/pawamoy/copier-uv) {% macro dep_line(dep) -%} [{{ dep.name }}](https://pypi.org/project/{{ dep.name }}/) | {{ dep.summary }} | {{ ("`" ~ dep.spec|sort(reverse=True)|join(", ") ~ "`") if dep.spec else "" }} | `{{ dep.version }}` | {{ dep.license }} {%- endmacro %} {% if prod_dependencies -%} ### Runtime dependencies Project | Summary | Version (accepted) | Version (last resolved) | License ------- | ------- | ------------------ | ----------------------- | ------- {% for dep in prod_dependencies -%} {{ dep_line(dep) }} {% endfor %} {% endif -%} {% if dev_dependencies -%} ### Development dependencies Project | Summary | Version (accepted) | Version (last resolved) | License ------- | ------- | ------------------ | ----------------------- | ------- {% for dep in dev_dependencies -%} {{ dep_line(dep) }} {% endfor %} {% endif -%} {% if more_credits %}**[More credits from the author]({{ more_credits }})**{% endif %} """, ) jinja_env = SandboxedEnvironment(undefined=StrictUndefined) return jinja_env.from_string(template_text).render(**template_data) print(_render_credits()) mkdocstrings-0.29.0/scripts/get_version.py000066400000000000000000000020061476356224100207060ustar00rootroot00000000000000# Get current project version from Git tags or changelog. import re from contextlib import suppress from pathlib import Path from pdm.backend.hooks.version import SCMVersion, Version, default_version_formatter, get_version_from_scm _root = Path(__file__).parent.parent _changelog = _root / "CHANGELOG.md" _changelog_version_re = re.compile(r"^## \[(\d+\.\d+\.\d+)\].*$") _default_scm_version = SCMVersion(Version("0.0.0"), None, False, None, None) # noqa: FBT003 def get_version() -> str: scm_version = get_version_from_scm(_root) or _default_scm_version if scm_version.version <= Version("0.1"): # Missing Git tags? with suppress(OSError, StopIteration): # noqa: SIM117 with _changelog.open("r", encoding="utf8") as file: match = next(filter(None, map(_changelog_version_re.match, file))) scm_version = scm_version._replace(version=Version(match.group(1))) return default_version_formatter(scm_version) if __name__ == "__main__": print(get_version()) mkdocstrings-0.29.0/scripts/insiders.py000066400000000000000000000136321476356224100202110ustar00rootroot00000000000000# Functions related to Insiders funding goals. from __future__ import annotations import json import logging import os import posixpath from dataclasses import dataclass from datetime import date, datetime, timedelta from itertools import chain from pathlib import Path from typing import TYPE_CHECKING, cast from urllib.error import HTTPError from urllib.parse import urljoin from urllib.request import urlopen import yaml if TYPE_CHECKING: from collections.abc import Iterable logger = logging.getLogger(f"mkdocs.logs.{__name__}") def human_readable_amount(amount: int) -> str: str_amount = str(amount) if len(str_amount) >= 4: # noqa: PLR2004 return f"{str_amount[: len(str_amount) - 3]},{str_amount[-3:]}" return str_amount @dataclass class Project: name: str url: str @dataclass class Feature: name: str ref: str | None since: date | None project: Project | None def url(self, rel_base: str = "..") -> str | None: # noqa: D102 if not self.ref: return None if self.project: rel_base = self.project.url return posixpath.join(rel_base, self.ref.lstrip("/")) def render(self, rel_base: str = "..", *, badge: bool = False) -> None: # noqa: D102 new = "" if badge: recent = self.since and date.today() - self.since <= timedelta(days=60) # noqa: DTZ011 if recent: ft_date = self.since.strftime("%B %d, %Y") # type: ignore[union-attr] new = f' :material-alert-decagram:{{ .new-feature .vibrate title="Added on {ft_date}" }}' project = f"[{self.project.name}]({self.project.url}) — " if self.project else "" feature = f"[{self.name}]({self.url(rel_base)})" if self.ref else self.name print(f"- [{'x' if self.since else ' '}] {project}{feature}{new}") @dataclass class Goal: name: str amount: int features: list[Feature] complete: bool = False @property def human_readable_amount(self) -> str: # noqa: D102 return human_readable_amount(self.amount) def render(self, rel_base: str = "..") -> None: # noqa: D102 print(f"#### $ {self.human_readable_amount} — {self.name}\n") 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]: goals_data = yaml.safe_load(data)["goals"] return { amount: Goal( name=goal_data["name"], amount=amount, complete=funding >= amount, features=[ Feature( name=feature_data["name"], ref=feature_data.get("ref"), since=feature_data.get("since") and datetime.strptime(feature_data["since"], "%Y/%m/%d").date(), # noqa: DTZ007 project=project, ) for feature_data in goal_data["features"] ], ) for amount, goal_data in goals_data.items() } def _load_goals_from_disk(path: str, funding: int = 0) -> dict[int, Goal]: project_dir = os.getenv("MKDOCS_CONFIG_DIR", ".") try: data = Path(project_dir, path).read_text() except OSError as error: raise RuntimeError(f"Could not load data from disk: {path}") from error return load_goals(data, funding) def _load_goals_from_url(source_data: tuple[str, str, str], funding: int = 0) -> dict[int, Goal]: project_name, project_url, data_fragment = source_data data_url = urljoin(project_url, data_fragment) try: with urlopen(data_url) as response: # noqa: S310 data = response.read() except HTTPError as error: raise RuntimeError(f"Could not load data from network: {data_url}") from error return load_goals(data, funding, project=Project(name=project_name, url=project_url)) def _load_goals(source: str | tuple[str, str, str], funding: int = 0) -> dict[int, Goal]: if isinstance(source, str): return _load_goals_from_disk(source, funding) return _load_goals_from_url(source, funding) def funding_goals(source: str | list[str | tuple[str, str, str]], funding: int = 0) -> dict[int, Goal]: if isinstance(source, str): return _load_goals_from_disk(source, funding) goals = {} for src in source: source_goals = _load_goals(src, funding) for amount, goal in source_goals.items(): if amount not in goals: goals[amount] = goal else: goals[amount].features.extend(goal.features) return {amount: goals[amount] for amount in sorted(goals)} def feature_list(goals: Iterable[Goal]) -> list[Feature]: return list(chain.from_iterable(goal.features for goal in goals)) def load_json(url: str) -> str | list | dict: with urlopen(url) as response: # noqa: S310 return json.loads(response.read().decode()) data_source = globals()["data_source"] sponsor_url = "https://github.com/sponsors/pawamoy" data_url = "https://raw.githubusercontent.com/pawamoy/sponsors/main" numbers: dict[str, int] = load_json(f"{data_url}/numbers.json") # type: ignore[assignment] sponsors: list[dict] = load_json(f"{data_url}/sponsors.json") # type: ignore[assignment] current_funding = numbers["total"] sponsors_count = numbers["count"] goals = funding_goals(data_source, funding=current_funding) 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, ) mkdocstrings-0.29.0/scripts/make000077700000000000000000000000001476356224100201342make.pyustar00rootroot00000000000000mkdocstrings-0.29.0/scripts/make.py000077500000000000000000000141721476356224100173110ustar00rootroot00000000000000#!/usr/bin/env python3 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) mkdocstrings-0.29.0/src/000077500000000000000000000000001476356224100151125ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/000077500000000000000000000000001476356224100176215ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/__init__.py000066400000000000000000000031161476356224100217330ustar00rootroot00000000000000"""mkdocstrings package. Automatic documentation from sources, for MkDocs. """ from __future__ import annotations from mkdocstrings._internal.extension import AutoDocProcessor, MkdocstringsExtension from mkdocstrings._internal.handlers.base import ( BaseHandler, CollectionError, CollectorItem, HandlerConfig, HandlerOptions, Handlers, ThemeNotSupported, do_any, ) from mkdocstrings._internal.handlers.rendering import ( HeadingShiftingTreeprocessor, Highlighter, IdPrependingTreeprocessor, MkdocstringsInnerExtension, ParagraphStrippingTreeprocessor, ) from mkdocstrings._internal.inventory import Inventory, InventoryItem from mkdocstrings._internal.loggers import ( TEMPLATES_DIRS, LoggerAdapter, TemplateLogger, get_logger, get_template_logger, get_template_logger_function, get_template_path, ) from mkdocstrings._internal.plugin import MkdocstringsPlugin, PluginConfig __all__: list[str] = [ "TEMPLATES_DIRS", "AutoDocProcessor", "BaseHandler", "CollectionError", "CollectorItem", "HandlerConfig", "HandlerOptions", "Handlers", "HeadingShiftingTreeprocessor", "Highlighter", "IdPrependingTreeprocessor", "Inventory", "InventoryItem", "LoggerAdapter", "MkdocstringsExtension", "MkdocstringsInnerExtension", "MkdocstringsPlugin", "ParagraphStrippingTreeprocessor", "PluginConfig", "TemplateLogger", "ThemeNotSupported", "do_any", "get_logger", "get_template_logger", "get_template_logger_function", "get_template_path", ] mkdocstrings-0.29.0/src/mkdocstrings/_internal/000077500000000000000000000000001476356224100215745ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/_internal/__init__.py000066400000000000000000000000001476356224100236730ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/_internal/debug.py000066400000000000000000000054101476356224100232340ustar00rootroot00000000000000from __future__ import annotations import os import platform import sys from dataclasses import dataclass from importlib import metadata @dataclass class _Variable: """Dataclass describing an environment variable.""" name: str """Variable name.""" value: str """Variable value.""" @dataclass class _Package: """Dataclass describing a Python package.""" name: str """Package name.""" version: str """Package version.""" @dataclass class _Environment: """Dataclass to store environment information.""" interpreter_name: str """Python interpreter name.""" interpreter_version: str """Python interpreter version.""" interpreter_path: str """Path to Python executable.""" platform: str """Operating System.""" packages: list[_Package] """Installed packages.""" variables: list[_Variable] """Environment variables.""" def _interpreter_name_version() -> tuple[str, str]: if hasattr(sys, "implementation"): impl = sys.implementation.version version = f"{impl.major}.{impl.minor}.{impl.micro}" kind = impl.releaselevel if kind != "final": version += kind[0] + str(impl.serial) return sys.implementation.name, version return "", "0.0.0" def _get_version(dist: str = "mkdocstrings") -> str: """Get version of the given distribution. Parameters: dist: A distribution name. Returns: A version number. """ try: return metadata.version(dist) except metadata.PackageNotFoundError: return "0.0.0" def _get_debug_info() -> _Environment: """Get debug/environment information. Returns: Environment information. """ py_name, py_version = _interpreter_name_version() packages = ["mkdocstrings"] variables = ["PYTHONPATH", *[var for var in os.environ if var.startswith("MKDOCSTRINGS")]] 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], ) 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} ({info.interpreter_path})") print("- __Environment variables__:") for var in info.variables: print(f" - `{var.name}`: `{var.value}`") print("- __Installed packages__:") for pkg in info.packages: print(f" - `{pkg.name}` v{pkg.version}") if __name__ == "__main__": _print_debug_info() mkdocstrings-0.29.0/src/mkdocstrings/_internal/download.py000066400000000000000000000055711476356224100237650ustar00rootroot00000000000000import base64 import gzip import os import re import urllib.parse import urllib.request from collections.abc import Mapping from typing import BinaryIO, Optional from mkdocstrings._internal.loggers import get_logger _logger = get_logger(__name__) # Regex pattern for an environment variable in the form ${ENV_VAR}. _ENV_VAR_PATTERN = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}") def _download_url_with_gz(url: str) -> bytes: url, auth_header = _extract_auth_from_url(url) req = urllib.request.Request( # noqa: S310 url, headers={"Accept-Encoding": "gzip", "User-Agent": "mkdocstrings/0.15.0", **auth_header}, ) with urllib.request.urlopen(req) as resp: # noqa: S310 content: BinaryIO = resp if "gzip" in resp.headers.get("content-encoding", ""): content = gzip.GzipFile(fileobj=resp) # type: ignore[assignment] return content.read() def _expand_env_vars(credential: str, url: str, env: Optional[Mapping[str, str]] = None) -> str: """A safe implementation of environment variable substitution. It only supports the following forms: `${ENV_VAR}`. Neither `$ENV_VAR` or `%ENV_VAR` are supported. """ if env is None: env = os.environ def replace_func(match: re.Match) -> str: try: return env[match.group(1)] except KeyError: _logger.warning( "Environment variable '%s' is not set, but is used in inventory URL %s", match.group(1), url, ) return match.group(0) return re.sub(_ENV_VAR_PATTERN, replace_func, credential) # Implementation adapted from PDM: https://github.com/pdm-project/pdm. def _extract_auth_from_url(url: str) -> tuple[str, dict[str, str]]: """Extract credentials from the URL if present, and return the URL and the appropriate auth header for the credentials.""" if "@" not in url: return url, {} scheme, netloc, *rest = urllib.parse.urlparse(url) auth, host = netloc.split("@", 1) auth = _expand_env_vars(credential=auth, url=url) auth_header = _create_auth_header(credential=auth, url=url) url = urllib.parse.urlunparse((scheme, host, *rest)) return url, auth_header def _create_auth_header(credential: str, url: str) -> dict[str, str]: """Create the Authorization header for basic or bearer authentication, depending on credential.""" if ":" not in credential: # We assume that the user is using a token. _logger.debug("Using bearer token authentication for %s", url) return {"Authorization": f"Bearer {credential}"} # Else, we assume that the user is using user:password. user, pwd = credential.split(":", 1) _logger.debug("Using basic authentication for %s", url) credentials = base64.encodebytes(f"{user}:{pwd}".encode()).decode().strip() return {"Authorization": f"Basic {credentials}"} mkdocstrings-0.29.0/src/mkdocstrings/_internal/extension.py000066400000000000000000000345631476356224100241750ustar00rootroot00000000000000# This module holds the code of the Markdown extension responsible for matching "autodoc" instructions. # # The extension is composed of a Markdown [block processor](https://python-markdown.github.io/extensions/api/#blockparser) # that matches indented blocks starting with a line like `::: identifier`. # # For each of these blocks, it uses a [handler][mkdocstrings.BaseHandler] to collect documentation about # the given identifier and render it with Jinja templates. # # Both the collection and rendering process can be configured by adding YAML configuration under the "autodoc" # instruction: # # ```yaml # ::: some.identifier # handler: python # options: # option1: value1 # option2: # - value2a # - value2b # option_x: etc # ``` from __future__ import annotations import re from typing import TYPE_CHECKING, Any from warnings import warn from xml.etree.ElementTree import Element import yaml from jinja2.exceptions import TemplateNotFound from markdown.blockprocessors import BlockProcessor from markdown.extensions import Extension from markdown.treeprocessors import Treeprocessor from mkdocs.exceptions import PluginError from mkdocstrings._internal.handlers.base import BaseHandler, CollectionError, CollectorItem, Handlers from mkdocstrings._internal.loggers import get_logger if TYPE_CHECKING: from collections.abc import MutableSequence from markdown import Markdown from mkdocs_autorefs import AutorefsPlugin _logger = get_logger(__name__) class AutoDocProcessor(BlockProcessor): """Our "autodoc" Markdown block processor. It has a [`test` method][mkdocstrings.AutoDocProcessor.test] that tells if a block matches a criterion, and a [`run` method][mkdocstrings.AutoDocProcessor.run] that processes it. It also has utility methods allowing to get handlers and their configuration easily, useful when processing a matched block. """ regex = re.compile(r"^(?P#{1,6} *|)::: ?(?P.+?) *$", flags=re.MULTILINE) """The regular expression to match our autodoc instructions.""" def __init__( self, md: Markdown, *, handlers: Handlers, autorefs: AutorefsPlugin, ) -> None: """Initialize the object. Arguments: md: A `markdown.Markdown` instance. handlers: The handlers container. autorefs: The autorefs plugin instance. """ super().__init__(parser=md.parser) self.md = md """The Markdown instance.""" self._handlers = handlers self._autorefs = autorefs self._updated_envs: set = set() def test(self, parent: Element, block: str) -> bool: # noqa: ARG002 """Match our autodoc instructions. Arguments: parent: The parent element in the XML tree. block: The block to be tested. Returns: Whether this block should be processed or not. """ return bool(self.regex.search(block)) def run(self, parent: Element, blocks: MutableSequence[str]) -> None: """Run code on the matched blocks. The identifier and configuration lines are retrieved from a matched block and used to collect and render an object. Arguments: parent: The parent element in the XML tree. blocks: The rest of the blocks to be processed. """ block = blocks.pop(0) match = self.regex.search(block) if match: if match.start() > 0: self.parser.parseBlocks(parent, [block[: match.start()]]) # removes the first line block = block[match.end() :] block, the_rest = self.detab(block) if not block and blocks and blocks[0].startswith((" handler:", " options:")): # YAML options were separated from the `:::` line by a blank line. block = blocks.pop(0) if match: identifier = match["name"] heading_level = match["heading"].count("#") _logger.debug("Matched '::: %s'", identifier) html, handler, data = self._process_block(identifier, block, heading_level) el = Element("div", {"class": "mkdocstrings"}) # The final HTML is inserted as opaque to subsequent processing, and only revealed at the end. el.text = self.md.htmlStash.store(html) if handler.outer_layer: self._process_headings(handler, el) parent.append(el) if the_rest: # This block contained unindented line(s) after the first indented # line. Insert these lines as the first block of the master blocks # list for future processing. blocks.insert(0, the_rest) def _process_block( self, identifier: str, yaml_block: str, heading_level: int = 0, ) -> tuple[str, BaseHandler, CollectorItem]: """Process an autodoc block. Arguments: identifier: The identifier of the object to collect and render. yaml_block: The YAML configuration. heading_level: Suggested level of the heading to insert (0 to ignore). Raises: PluginError: When something wrong happened during collection. TemplateNotFound: When a template used for rendering could not be found. Returns: Rendered HTML, the handler that was used, and the collected item. """ local_config = yaml.safe_load(yaml_block) or {} handler_name = self._handlers.get_handler_name(local_config) _logger.debug("Using handler '%s'", handler_name) handler = self._handlers.get_handler(handler_name) local_options = local_config.get("options", {}) if heading_level: # Heading level obtained from Markdown (`##`) takes precedence. local_options["heading_level"] = heading_level # YORE: Bump 1: Replace block with line 2. if handler.get_options.__func__ is not BaseHandler.get_options: # type: ignore[attr-defined] options = handler.get_options(local_options) else: warn( "mkdocstrings v1 will start using your handler's `get_options` method to build options " "instead of merging the global and local options (dictionaries). ", DeprecationWarning, stacklevel=1, ) handler_config = self._handlers.get_handler_config(handler_name) global_options = handler_config.get("options", {}) options = {**global_options, **local_options} _logger.debug("Collecting data") try: data: CollectorItem = handler.collect(identifier, options) except CollectionError as exception: _logger.error("%s", exception) # noqa: TRY400 raise PluginError(f"Could not collect '{identifier}'") from exception if handler_name not in self._updated_envs: # We haven't seen this handler before on this document. _logger.debug("Updating handler's rendering env") handler._update_env(self.md, config=self._handlers._tool_config) self._updated_envs.add(handler_name) _logger.debug("Rendering templates") try: rendered = handler.render(data, options) except TemplateNotFound as exc: _logger.error( # noqa: TRY400 "Template '%s' not found for '%s' handler and theme '%s'.", exc.name, handler_name, self._handlers._theme, ) raise return rendered, handler, data def _process_headings(self, handler: BaseHandler, element: Element) -> None: # We're in the outer handler layer, as well as the outer extension layer. # # The "handler layer" tracks the nesting of the autodoc blocks, which can appear in docstrings. # # - Render ::: Object1 # Outer handler layer # - Render Object1's docstring # Outer handler layer # - Docstring renders ::: Object2 # Inner handler layers # - etc. # Inner handler layers # # The "extension layer" tracks whether we're converting an autodoc instruction # or nested content within it, like docstrings. Markdown conversion within Markdown conversion. # # - Render ::: Object1 # Outer extension layer # - Render Object1's docstring # Inner extension layer # # The generated HTML was just stashed, and the `toc` extension won't be able to see headings. # We need to duplicate the headings directly, just so `toc` can pick them up, # otherwise they wouldn't appear in the final table of contents. # # These headings are generated by the `BaseHandler.do_heading` method (Jinja filter), # which runs in the inner extension layer, and not in the outer one where we are now. headings = handler.get_headings() element.extend(headings) # These duplicated headings will later be removed by our `_HeadingsPostProcessor` processor, # which runs right after `toc` (see `MkdocstringsExtension.extendMarkdown`). # # If we were in an inner handler layer, we wouldn't do any of this # and would just let headings bubble up to the outer handler layer. if (page := self._autorefs.current_page) is None: return for heading in headings: rendered_id = heading.attrib["id"] # The title is registered to be used as tooltip by autorefs. self._autorefs.register_anchor(page, rendered_id, title=heading.text, primary=True) # Register all identifiers for this object # both in the autorefs plugin and in the inventory. aliases: tuple[str, ...] # YORE: Bump 1: Replace block with line 16. if hasattr(handler, "get_anchors"): warn( "The `get_anchors` method is deprecated. " "Declare a `get_aliases` method instead, accepting a string (identifier) " "instead of a collected object.", DeprecationWarning, stacklevel=1, ) try: data_object = handler.collect(rendered_id, getattr(handler, "fallback_config", {})) except CollectionError: aliases = () else: aliases = handler.get_anchors(data_object) else: aliases = handler.get_aliases(rendered_id) for alias in aliases: if alias != rendered_id: self._autorefs.register_anchor(page, alias, rendered_id, primary=False) if "data-role" in heading.attrib: self._handlers.inventory.register( name=rendered_id, domain=handler.domain, role=heading.attrib["data-role"], priority=1, # Register with standard priority. uri=f"{page.url}#{rendered_id}", ) for alias in aliases: if alias not in self._handlers.inventory: self._handlers.inventory.register( name=alias, domain=handler.domain, role=heading.attrib["data-role"], priority=2, # Register with lower priority. uri=f"{page.url}#{rendered_id}", ) class _HeadingsPostProcessor(Treeprocessor): def run(self, root: Element) -> None: self._remove_duplicated_headings(root) def _remove_duplicated_headings(self, parent: Element) -> None: carry_text = "" for el in reversed(parent): # Reversed mainly for the ability to mutate during iteration. if el.tag == "div" and el.get("class") == "mkdocstrings": # Delete the duplicated headings along with their container, but keep the text (i.e. the actual HTML). carry_text = (el.text or "") + carry_text parent.remove(el) else: if carry_text: el.tail = (el.tail or "") + carry_text carry_text = "" self._remove_duplicated_headings(el) if carry_text: 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. It cannot work outside of `mkdocstrings`. """ def __init__(self, handlers: Handlers, autorefs: AutorefsPlugin, **kwargs: Any) -> None: """Initialize the object. Arguments: handlers: The handlers container. autorefs: The autorefs plugin instance. **kwargs: Keyword arguments used by `markdown.extensions.Extension`. """ super().__init__(**kwargs) self._handlers = handlers self._autorefs = autorefs def extendMarkdown(self, md: Markdown) -> None: # noqa: N802 (casing: parent method's name) """Register the extension. Add an instance of our [`AutoDocProcessor`][mkdocstrings.AutoDocProcessor] to the Markdown parser. Arguments: md: A `markdown.Markdown` instance. """ md.parser.blockprocessors.register( AutoDocProcessor(md, handlers=self._handlers, autorefs=self._autorefs), "mkdocstrings", priority=75, # Right before markdown.blockprocessors.HashHeaderProcessor ) md.treeprocessors.register( _HeadingsPostProcessor(md), "mkdocstrings_post_headings", priority=4, # Right after 'toc'. ) md.treeprocessors.register( _TocLabelsTreeProcessor(md), "mkdocstrings_post_toc_labels", priority=4, # Right after 'toc'. ) mkdocstrings-0.29.0/src/mkdocstrings/_internal/handlers/000077500000000000000000000000001476356224100233745ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/_internal/handlers/__init__.py000066400000000000000000000000001476356224100254730ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/_internal/handlers/base.py000066400000000000000000000762101476356224100246660ustar00rootroot00000000000000# Base module for handlers. # # This module contains the base classes for implementing handlers. from __future__ import annotations import datetime import importlib import inspect import sys from concurrent import futures from io import BytesIO from pathlib import Path from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, cast from warnings import warn from xml.etree.ElementTree import Element, tostring from jinja2 import Environment, FileSystemLoader from markdown import Markdown from markdown.extensions.toc import TocTreeprocessor from markupsafe import Markup from mkdocs.utils.cache import download_and_cache_url from mkdocs_autorefs import AutorefsInlineProcessor, BacklinksTreeProcessor from mkdocstrings._internal.download import _download_url_with_gz from mkdocstrings._internal.handlers.rendering import ( HeadingShiftingTreeprocessor, Highlighter, IdPrependingTreeprocessor, MkdocstringsInnerExtension, ParagraphStrippingTreeprocessor, ) from mkdocstrings._internal.inventory import Inventory from mkdocstrings._internal.loggers import get_logger, get_template_logger # TODO: remove once support for Python 3.9 is dropped if sys.version_info < (3, 10): from importlib_metadata import entry_points else: from importlib.metadata import entry_points if TYPE_CHECKING: from collections.abc import Iterable, Iterator, Mapping, Sequence from markdown import Extension from mkdocs_autorefs import AutorefsHookInterface, Backlink _logger = get_logger(__name__) CollectorItem = Any """The type of the item returned by the `collect` method of a handler.""" HandlerConfig = Any """The type of the configuration of a handler.""" HandlerOptions = Any """The type of the options passed to a handler.""" # Autodoc instructions can appear in nested Markdown, # so we need to keep track of the Markdown conversion layer we're in. # Since any handler can be called from any Markdown conversion layer, # we need to keep track of the layer globally. # This global variable is incremented/decremented in `do_convert_markdown`, # and used in `outer_layer`. _markdown_conversion_layer: int = 0 class CollectionError(Exception): """An exception raised when some collection of data failed.""" class ThemeNotSupported(Exception): # noqa: N818 """An exception raised to tell a theme is not supported.""" def do_any(seq: Sequence, attribute: str | None = None) -> bool: """Check if at least one of the item in the sequence evaluates to true. The `any` builtin as a filter for Jinja templates. Arguments: seq: An iterable object. attribute: The attribute name to use on each object of the iterable. Returns: A boolean telling if any object of the iterable evaluated to True. """ if attribute is None: return any(seq) return any(_[attribute] for _ in seq) class BaseHandler: """The base handler class. Inherit from this class to implement a handler. You will have to implement the `collect` and `render` methods. You can also implement the `teardown` method, and override the `update_env` method, to add more filters to the Jinja environment, making them available in your Jinja templates. To define a fallback theme, add a `fallback_theme` class-variable. To add custom CSS, add an `extra_css` variable or create an 'style.css' file beside the templates. """ # YORE: Bump 1: Replace ` = ""` with `` within line. name: ClassVar[str] = "" """The handler's name, for example "python".""" # YORE: Bump 1: Replace ` = ""` with `` within line. domain: ClassVar[str] = "" """The handler's domain, used to register objects in the inventory, for example "py".""" enable_inventory: ClassVar[bool] = False """Whether the inventory creation is enabled.""" # YORE: Bump 1: Remove block. fallback_config: ClassVar[dict] = {} """Fallback configuration when searching anchors for identifiers.""" fallback_theme: ClassVar[str] = "" """Fallback theme to use when a template isn't found in the configured theme.""" extra_css: str = "" """Extra CSS.""" def __init__( self, # YORE: Bump 1: Remove line. *args: Any, # YORE: Bump 1: Remove line. **kwargs: Any, # YORE: Bump 1: Replace `# ` with `` within block. # *, # theme: str, # custom_templates: str | None, # mdx: Sequence[str | Extension], # mdx_config: Mapping[str, Any], ) -> None: """Initialize the object. If the given theme is not supported (it does not exist), it will look for a `fallback_theme` attribute in `self` to use as a fallback theme. Keyword Arguments: theme (str): The theme to use. custom_templates (str | None): The path to custom templates. mdx (list[str | Extension]): A list of Markdown extensions to use. mdx_config (Mapping[str, Mapping[str, Any]]): Configuration for the Markdown extensions. """ # YORE: Bump 1: Remove block. handler = "" theme = "" custom_templates = None if args: handler, args = args[0], args[1:] if args: theme, args = args[0], args[1:] warn( "The `theme` argument must be passed as a keyword argument.", DeprecationWarning, stacklevel=2, ) if args: custom_templates, args = args[0], args[1:] warn( "The `custom_templates` argument must be passed as a keyword argument.", DeprecationWarning, stacklevel=2, ) handler = kwargs.pop("handler", handler) theme = kwargs.pop("theme", theme) custom_templates = kwargs.pop("custom_templates", custom_templates) mdx = kwargs.pop("mdx", None) mdx_config = kwargs.pop("mdx_config", None) if handler: if not self.name: type(self).name = handler warn( "The `handler` argument is deprecated. The handler name must be specified as a class attribute.", DeprecationWarning, stacklevel=2, ) if not self.domain: warn( "The `domain` attribute must be specified as a class attribute.", DeprecationWarning, stacklevel=2, ) if mdx is None: warn( "The `mdx` argument must be provided (as a keyword argument).", DeprecationWarning, stacklevel=2, ) if mdx_config is None: warn( "The `mdx_config` argument must be provided (as a keyword argument).", DeprecationWarning, stacklevel=2, ) self.theme = theme """The selected theme.""" self.custom_templates = custom_templates """The path to custom templates.""" self.mdx = mdx """The Markdown extensions to use.""" self.mdx_config = mdx_config """The configuration for the Markdown extensions.""" self._md: Markdown | None = None self._headings: list[Element] = [] paths = [] # add selected theme templates themes_dir = self.get_templates_dir(self.name) paths.append(themes_dir / self.theme) # add extended theme templates extended_templates_dirs = self.get_extended_templates_dirs(self.name) for templates_dir in extended_templates_dirs: paths.append(templates_dir / self.theme) # add fallback theme templates if self.fallback_theme and self.fallback_theme != self.theme: paths.append(themes_dir / self.fallback_theme) # add fallback theme of extended templates for templates_dir in extended_templates_dirs: paths.append(templates_dir / self.fallback_theme) for path in paths: css_path = path / "style.css" if css_path.is_file(): self.extra_css += "\n" + css_path.read_text(encoding="utf-8") break if self.custom_templates is not None: paths.insert(0, Path(self.custom_templates) / self.name / self.theme) self.env = Environment( autoescape=True, loader=FileSystemLoader(paths), auto_reload=False, # Editing a template in the middle of a build is not useful. ) """The Jinja environment.""" self.env.filters["convert_markdown"] = self.do_convert_markdown self.env.filters["heading"] = self.do_heading self.env.filters["any"] = do_any self.env.globals["log"] = get_template_logger(self.name) @property def md(self) -> Markdown: """The Markdown instance. Raises: RuntimeError: When the Markdown instance is not set yet. """ if self._md is None: raise RuntimeError("Markdown instance not set yet") return self._md def get_inventory_urls(self) -> list[tuple[str, dict[str, Any]]]: """Return the URLs (and configuration options) of the inventory files to download.""" return [] @classmethod def load_inventory( cls, in_file: BinaryIO, # noqa: ARG003 url: str, # noqa: ARG003 base_url: str | None = None, # noqa: ARG003 **kwargs: Any, # noqa: ARG003 ) -> Iterator[tuple[str, str]]: """Yield items and their URLs from an inventory file streamed from `in_file`. Arguments: in_file: The binary file-like object to read the inventory from. url: The URL that this file is being streamed from (used to guess `base_url`). base_url: The URL that this inventory's sub-paths are relative to. **kwargs: Ignore additional arguments passed from the config. Yields: Tuples of (item identifier, item URL). """ yield from () def get_options(self, local_options: Mapping[str, Any]) -> HandlerOptions: """Get combined options. Override this method to customize how options are combined, for example by merging the global options with the local options. By combining options here, you don't have to do it twice in `collect` and `render`. Arguments: local_options: The local options. Returns: The combined options. """ return local_options def collect(self, identifier: str, options: HandlerOptions) -> CollectorItem: """Collect data given an identifier and user configuration. In the implementation, you typically call a subprocess that returns JSON, and load that JSON again into a Python dictionary for example, though the implementation is completely free. Arguments: identifier: An identifier for which to collect data. For example, in Python, it would be 'mkdocstrings.handlers' to collect documentation about the handlers module. It can be anything that you can feed to the tool of your choice. options: The final configuration options. Returns: Anything you want, as long as you can feed it to the handler's `render` method. """ raise NotImplementedError def render(self, data: CollectorItem, options: HandlerOptions) -> str: """Render a template using provided data and configuration options. Arguments: data: The collected data to render. options: The final configuration options. Returns: The rendered template as HTML. """ raise NotImplementedError def render_backlinks(self, backlinks: Mapping[str, Iterable[Backlink]]) -> str: # noqa: ARG002 """Render backlinks.""" return "" def teardown(self) -> None: """Teardown the handler. This method should be implemented to, for example, terminate a subprocess that was started when creating the handler instance. """ def get_templates_dir(self, handler: str | None = None) -> Path: """Return the path to the handler's templates directory. Override to customize how the templates directory is found. Arguments: handler: The name of the handler to get the templates directory of. Raises: ModuleNotFoundError: When no such handler is installed. FileNotFoundError: When the templates directory cannot be found. Returns: The templates directory path. """ handler = handler or self.name try: import mkdocstrings_handlers except ModuleNotFoundError as error: raise ModuleNotFoundError(f"Handler '{handler}' not found, is it installed?") from error for path in mkdocstrings_handlers.__path__: theme_path = Path(path, handler, "templates") if theme_path.exists(): return theme_path raise FileNotFoundError(f"Can't find 'templates' folder for handler '{handler}'") def get_extended_templates_dirs(self, handler: str) -> list[Path]: """Load template extensions for the given handler, return their templates directories. Arguments: handler: The name of the handler to get the extended templates directory of. Returns: The extensions templates directories. """ discovered_extensions = entry_points(group=f"mkdocstrings.{handler}.templates") return [extension.load()() for extension in discovered_extensions] def get_aliases(self, identifier: str) -> tuple[str, ...]: # noqa: ARG002 """Return the possible aliases for a given identifier. Arguments: identifier: The identifier to get the aliases of. Returns: A tuple of strings - aliases. """ return () @property def outer_layer(self) -> bool: """Whether we're in the outer Markdown conversion layer.""" return _markdown_conversion_layer == 0 def do_convert_markdown( self, text: str, heading_level: int, html_id: str = "", *, strip_paragraph: bool = False, autoref_hook: AutorefsHookInterface | None = None, ) -> Markup: """Render Markdown text; for use inside templates. Arguments: text: The text to convert. heading_level: The base heading level to start all Markdown headings from. html_id: The HTML id of the element that's considered the parent of this element. strip_paragraph: Whether to exclude the `

    ` tag from around the whole output. Returns: An HTML string. """ global _markdown_conversion_layer # noqa: PLW0603 _markdown_conversion_layer += 1 treeprocessors = self.md.treeprocessors treeprocessors[HeadingShiftingTreeprocessor.name].shift_by = heading_level # type: ignore[attr-defined] treeprocessors[IdPrependingTreeprocessor.name].id_prefix = html_id and html_id + "--" # type: ignore[attr-defined] treeprocessors[ParagraphStrippingTreeprocessor.name].strip = strip_paragraph # type: ignore[attr-defined] if BacklinksTreeProcessor.name in treeprocessors: treeprocessors[BacklinksTreeProcessor.name].initial_id = html_id # type: ignore[attr-defined] if autoref_hook: self.md.inlinePatterns[AutorefsInlineProcessor.name].hook = autoref_hook # type: ignore[attr-defined] try: return Markup(self.md.convert(text)) finally: treeprocessors[HeadingShiftingTreeprocessor.name].shift_by = 0 # type: ignore[attr-defined] treeprocessors[IdPrependingTreeprocessor.name].id_prefix = "" # type: ignore[attr-defined] treeprocessors[ParagraphStrippingTreeprocessor.name].strip = False # type: ignore[attr-defined] if BacklinksTreeProcessor.name in treeprocessors: treeprocessors[BacklinksTreeProcessor.name].initial_id = None # type: ignore[attr-defined] self.md.inlinePatterns[AutorefsInlineProcessor.name].hook = None # type: ignore[attr-defined] self.md.reset() _markdown_conversion_layer -= 1 def do_heading( self, content: Markup, heading_level: int, *, role: str | None = None, hidden: bool = False, toc_label: str | None = None, **attributes: str, ) -> Markup: """Render an HTML heading and register it for the table of contents. For use inside templates. Arguments: content: The HTML within the heading. heading_level: The level of heading (e.g. 3 -> `h3`). role: An optional role for the object bound to this heading. hidden: If True, only register it for the table of contents, don't render anything. toc_label: The title to use in the table of contents ('data-toc-label' attribute). **attributes: Any extra HTML attributes of the heading. Returns: An HTML string. """ # Produce a heading element that will be used later, in `AutoDocProcessor.run`, to: # - register it in the ToC: right now we're in the inner Markdown conversion layer, # so we have to bubble up the information to the outer Markdown conversion layer, # for the ToC extension to pick it up. # - register it in autorefs: right now we don't know what page is being rendered, # so we bubble up the information again to where autorefs knows the page, # and can correctly register the heading anchor (id) to its full URL. # - register it in the objects inventory: same as for autorefs, # we don't know the page here, or the handler (and its domain), # so we bubble up the information to where the mkdocstrings extension knows that. el = Element(f"h{heading_level}", attributes) if toc_label is None: toc_label = content.unescape() if isinstance(content, Markup) else content el.set("data-toc-label", toc_label) if role: el.set("data-role", role) if content: el.text = str(content).strip() self._headings.append(el) if hidden: return Markup('').format(attributes["id"]) # Now produce the actual HTML to be rendered. The goal is to wrap the HTML content into a heading. # Start with a heading that has just attributes (no text), and add a placeholder into it. el = Element(f"h{heading_level}", attributes) el.append(Element("mkdocstrings-placeholder")) # Tell the inner 'toc' extension to make its additions if configured so. toc = cast(TocTreeprocessor, self.md.treeprocessors["toc"]) if toc.use_anchors: toc.add_anchor(el, attributes["id"]) if toc.use_permalinks: toc.add_permalink(el, attributes["id"]) # The content we received is HTML, so it can't just be inserted into the tree. We had marked the middle # of the heading with a placeholder that can never occur (text can't directly contain angle brackets). # Now this HTML wrapper can be "filled" by replacing the placeholder. html_with_placeholder = tostring(el, encoding="unicode") assert ( # noqa: S101 html_with_placeholder.count("") == 1 ), f"Bug in mkdocstrings: failed to replace in {html_with_placeholder!r}" html = html_with_placeholder.replace("", content) return Markup(html) def get_headings(self) -> Sequence[Element]: """Return and clear the headings gathered so far. Returns: A list of HTML elements. """ result = list(self._headings) self._headings.clear() return result # YORE: Bump 1: Replace `*args: Any, **kwargs: Any` with `config: Any`. def update_env(self, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 """Update the Jinja environment.""" # YORE: Bump 1: Remove line. warn("No need to call `super().update_env()` anymore.", DeprecationWarning, stacklevel=2) def _update_env(self, md: Markdown, *, config: Any | None = None) -> None: """Update our handler to point to our configured Markdown instance, grabbing some of the config from `md`.""" # YORE: Bump 1: Remove block. if self.mdx is None and config is not None: self.mdx = config.get("mdx", None) or config.get("markdown_extensions", None) or () if self.mdx_config is None and config is not None: self.mdx_config = config.get("mdx_config", None) or config.get("mdx_configs", None) or {} extensions: list[str | Extension] = [*self.mdx, MkdocstringsInnerExtension(self._headings)] new_md = Markdown(extensions=extensions, extension_configs=self.mdx_config) # MkDocs adds its own (required) extension that's not part of the config. Propagate it. if "relpath" in md.treeprocessors: relpath = md.treeprocessors["relpath"] new_relpath = type(relpath)(relpath.file, relpath.files, relpath.config) # type: ignore[attr-defined,call-arg] new_md.treeprocessors.register(new_relpath, "relpath", priority=0) self._md = new_md self.env.filters["highlight"] = Highlighter(new_md).highlight # YORE: Bump 1: Replace block with `self.update_env(config)`. parameters = inspect.signature(self.update_env).parameters if "md" in parameters: warn( "The `update_env(md)` parameter is deprecated. Use `self.md` instead.", DeprecationWarning, stacklevel=1, ) self.update_env(new_md, config) elif "config" in parameters: self.update_env(config) class Handlers: """A collection of handlers. Do not instantiate this directly. [The plugin][mkdocstrings.MkdocstringsPlugin] will keep one instance of this for the purpose of caching. Use [mkdocstrings.MkdocstringsPlugin.get_handler][] for convenient access. """ def __init__( self, *, theme: str, default: str, inventory_project: str, inventory_version: str = "0.0.0", handlers_config: dict[str, HandlerConfig] | None = None, custom_templates: str | None = None, mdx: Sequence[str | Extension] | None = None, mdx_config: Mapping[str, Any] | None = None, tool_config: Any, ) -> None: """Initialize the object. Arguments: theme: The theme to use. default: The default handler to use. inventory_project: The project name to use in the inventory. inventory_version: The project version to use in the inventory. handlers_config: The handlers configuration. custom_templates: The path to custom templates. mdx: A list of Markdown extensions to use. mdx_config: Configuration for the Markdown extensions. tool_config: Tool configuration to pass down to handlers. """ self._theme = theme self._default = default self._handlers_config = handlers_config or {} self._custom_templates = custom_templates self._mdx = mdx or [] self._mdx_config = mdx_config or {} self._handlers: dict[str, BaseHandler] = {} self._tool_config = tool_config self.inventory: Inventory = Inventory(project=inventory_project, version=inventory_version) """The objects inventory.""" self._inv_futures: dict[futures.Future, tuple[BaseHandler, str, Any]] = {} # YORE: Bump 1: Remove block. def get_anchors(self, identifier: str) -> tuple[str, ...]: """Return the canonical HTML anchor for the identifier, if any of the seen handlers can collect it. Arguments: identifier: The identifier (one that [collect][mkdocstrings.BaseHandler.collect] can accept). Returns: A tuple of strings - anchors without '#', or an empty tuple if there isn't any identifier familiar with it. """ for handler in self._handlers.values(): try: if hasattr(handler, "get_anchors"): warn( "The `get_anchors` method is deprecated. " "Declare a `get_aliases` method instead, accepting a string (identifier) " "instead of a collected object.", DeprecationWarning, stacklevel=1, ) aliases = handler.get_anchors(handler.collect(identifier, getattr(handler, "fallback_config", {}))) else: aliases = handler.get_aliases(identifier) except CollectionError: continue if aliases: return aliases return () def get_handler_name(self, config: dict) -> str: """Return the handler name defined in an "autodoc" instruction YAML configuration, or the global default handler. Arguments: config: A configuration dictionary, obtained from YAML below the "autodoc" instruction. Returns: The name of the handler to use. """ return config.get("handler", self._default) def get_handler_config(self, name: str) -> dict: """Return the global configuration of the given handler. Arguments: name: The name of the handler to get the global configuration of. Returns: The global configuration of the given handler. It can be an empty dictionary. """ return self._handlers_config.get(name, None) or {} def get_handler(self, name: str, handler_config: dict | None = None) -> BaseHandler: """Get a handler thanks to its name. This function dynamically imports a module named "mkdocstrings.handlers.NAME", calls its `get_handler` method to get an instance of a handler, and caches it in dictionary. It means that during one run (for each reload when serving, or once when building), a handler is instantiated only once, and reused for each "autodoc" instruction asking for it. Arguments: name: The name of the handler. Really, it's the name of the Python module holding it. handler_config: Configuration passed to the handler. Returns: An instance of a subclass of [`BaseHandler`][mkdocstrings.BaseHandler], as instantiated by the `get_handler` method of the handler's module. """ if name not in self._handlers: if handler_config is None: handler_config = self._handlers_config.get(name, {}) module = importlib.import_module(f"mkdocstrings_handlers.{name}") # YORE: Bump 1: Remove block. kwargs = { "theme": self._theme, "custom_templates": self._custom_templates, "mdx": self._mdx, "mdx_config": self._mdx_config, "handler_config": handler_config, "tool_config": self._tool_config, } if "config_file_path" in inspect.signature(module.get_handler).parameters: kwargs["config_file_path"] = self._tool_config.get("config_file_path") warn( "The `config_file_path` argument in `get_handler` functions is deprecated. " "Use `tool_config.get('config_file_path')` instead.", DeprecationWarning, stacklevel=1, ) self._handlers[name] = module.get_handler(**kwargs) # YORE: Bump 1: Replace `# ` with `` within block. # self._handlers[name] = module.get_handler( # theme=self._theme, # custom_templates=self._custom_templates, # mdx=self._mdx, # mdx_config=self._mdx_config, # handler_config=handler_config, # tool_config=self._tool_config, # ) return self._handlers[name] def _download_inventories(self) -> None: """Download an inventory file from an URL. Arguments: url: The URL of the inventory. """ to_download: list[tuple[BaseHandler, str, Any]] = [] for handler_name, conf in self._handlers_config.items(): handler = self.get_handler(handler_name) if handler.get_inventory_urls.__func__ is BaseHandler.get_inventory_urls: # type: ignore[attr-defined] if inv_configs := conf.pop("import", ()): warn( "mkdocstrings v1 will stop handling 'import' in handlers configuration. " "Instead your handler must define a `get_inventory_urls` method " "that returns a list of URLs to download. ", DeprecationWarning, stacklevel=1, ) inv_configs = [{"url": inv} if isinstance(inv, str) else inv for inv in inv_configs] inv_configs = [(inv.pop("url"), inv) for inv in inv_configs] else: inv_configs = handler.get_inventory_urls() to_download.extend((handler, url, conf) for url, conf in inv_configs) if to_download: thread_pool = futures.ThreadPoolExecutor(4) for handler, url, conf in to_download: _logger.debug("Downloading inventory from %s", url) future = thread_pool.submit( download_and_cache_url, url, datetime.timedelta(days=1), download=_download_url_with_gz, ) self._inv_futures[future] = (handler, url, conf) thread_pool.shutdown(wait=False) def _yield_inventory_items(self) -> Iterator[tuple[str, str]]: if self._inv_futures: _logger.debug("Waiting for %s inventory download(s)", len(self._inv_futures)) futures.wait(self._inv_futures, timeout=30) # Reversed order so that pages from first futures take precedence: for fut, (handler, url, conf) in reversed(self._inv_futures.items()): try: yield from handler.load_inventory(BytesIO(fut.result()), url, **conf) except Exception as error: # noqa: BLE001 _logger.error("Couldn't load inventory %s through handler '%s': %s", url, handler.name, error) # noqa: TRY400 self._inv_futures = {} @property def seen_handlers(self) -> Iterable[BaseHandler]: """Get the handlers that were encountered so far throughout the build. Returns: An iterable of instances of [`BaseHandler`][mkdocstrings.BaseHandler] (usable only to loop through it). """ return self._handlers.values() def teardown(self) -> None: """Teardown all cached handlers and clear the cache.""" for future in self._inv_futures: future.cancel() for handler in self.seen_handlers: handler.teardown() self._handlers.clear() mkdocstrings-0.29.0/src/mkdocstrings/_internal/handlers/rendering.py000066400000000000000000000273601476356224100257330ustar00rootroot00000000000000# This module holds helpers responsible for augmentations to the Markdown sub-documents produced by handlers. from __future__ import annotations import copy import re import textwrap from typing import TYPE_CHECKING, Any from markdown.extensions import Extension from markdown.extensions.codehilite import CodeHiliteExtension from markdown.treeprocessors import Treeprocessor from markupsafe import Markup from pymdownx.highlight import Highlight, HighlightExtension if TYPE_CHECKING: from xml.etree.ElementTree import Element from markdown import Markdown class Highlighter(Highlight): """Code highlighter that tries to match the Markdown configuration. Picking up the global config and defaults works only if you use the `codehilite` or `pymdownx.highlight` (recommended) Markdown extension. - If you use `pymdownx.highlight`, highlighting settings are picked up from it, and the default CSS class is `.highlight`. This also means the default of `guess_lang: false`. - Otherwise, if you use the `codehilite` extension, settings are picked up from it, and the default CSS class is `.codehilite`. Also consider setting `guess_lang: false`. - If neither are added to `markdown_extensions`, highlighting is enabled anyway. This is for backwards compatibility. If you really want to disable highlighting even in *mkdocstrings*, add one of these extensions anyway and set `use_pygments: false`. The underlying implementation is `pymdownx.highlight` regardless. """ # https://raw.githubusercontent.com/facelessuser/pymdown-extensions/main/docs/src/markdown/extensions/highlight.md _highlight_config_keys = frozenset( ( "css_class", "guess_lang", "default_lang", "pygments_style", "noclasses", "use_pygments", "linenums", "linenums_special", "linenums_style", "linenums_class", "extend_pygments_lang", "language_prefix", "code_attr_on_pre", "auto_title", "auto_title_map", "line_spans", "anchor_linenums", "line_anchors", "pygments_lang_class", "stripnl", ), ) def __init__(self, md: Markdown): """Configure to match a `markdown.Markdown` instance. Arguments: md: The Markdown instance to read configs from. """ config: dict[str, Any] = {} self._highlighter: str | None = None for ext in md.registeredExtensions: if isinstance(ext, HighlightExtension) and (ext.enabled or not config): self._highlighter = "highlight" config = ext.getConfigs() break # This one takes priority, no need to continue looking if isinstance(ext, CodeHiliteExtension) and not config: self._highlighter = "codehilite" config = ext.getConfigs() config["language_prefix"] = config["lang_prefix"] self._css_class = config.pop("css_class", "highlight") super().__init__(**{name: opt for name, opt in config.items() if name in self._highlight_config_keys}) def highlight( self, src: str, language: str | None = None, *, inline: bool = False, dedent: bool = True, linenums: bool | None = None, **kwargs: Any, ) -> str: """Highlight a code-snippet. Arguments: src: The code to highlight. language: Explicitly tell what language to use for highlighting. inline: Whether to highlight as inline. dedent: Whether to dedent the code before highlighting it or not. linenums: Whether to add line numbers in the result. **kwargs: Pass on to `pymdownx.highlight.Highlight.highlight`. Returns: The highlighted code as HTML text, marked safe (not escaped for HTML). """ if isinstance(src, Markup): src = src.unescape() if dedent: src = textwrap.dedent(src) kwargs.setdefault("css_class", self._css_class) old_linenums = self.linenums # type: ignore[has-type] if linenums is not None: self.linenums = linenums try: result = super().highlight(src, language, inline=inline, **kwargs) finally: self.linenums = old_linenums if inline: # 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) class IdPrependingTreeprocessor(Treeprocessor): """Prepend the configured prefix to IDs of all HTML elements.""" name: str = "mkdocstrings_ids" """The name of the treeprocessor.""" id_prefix: str """The prefix to add to every ID. It is prepended without any separator; specify your own separator if needed.""" def __init__(self, md: Markdown, id_prefix: str): """Initialize the object. Arguments: md: A `markdown.Markdown` instance. id_prefix: The prefix to add to every ID. It is prepended without any separator. """ super().__init__(md) self.id_prefix = id_prefix def run(self, root: Element) -> None: """Prepend the configured prefix to all IDs in the document.""" if self.id_prefix: self._prefix_ids(root) def _prefix_ids(self, root: Element) -> None: index = len(root) for el in reversed(root): # Reversed mainly for the ability to mutate during iteration. index -= 1 self._prefix_ids(el) href_attr = el.get("href") if id_attr := el.get("id"): if el.tag == "a" and not href_attr: # An anchor with id and no href is used by autorefs: # leave it untouched and insert a copy with updated id after it. new_el = copy.deepcopy(el) new_el.set("id", self.id_prefix + id_attr) root.insert(index + 1, new_el) else: # Anchors with id and href are not used by autorefs: # update in place. el.set("id", self.id_prefix + id_attr) # Always update hrefs, names and labels-for: # there will always be a corresponding id. if href_attr and href_attr.startswith("#"): el.set("href", "#" + self.id_prefix + href_attr[1:]) if name_attr := el.get("name"): el.set("name", self.id_prefix + name_attr) if el.tag == "label": for_attr = el.get("for") if for_attr: el.set("for", self.id_prefix + for_attr) class HeadingShiftingTreeprocessor(Treeprocessor): """Shift levels of all Markdown headings according to the configured base level.""" name: str = "mkdocstrings_headings" """The name of the treeprocessor.""" regex: re.Pattern = re.compile(r"([Hh])([1-6])") """The regex to match heading tags.""" shift_by: int """The number of heading "levels" to add to every heading. `

    ` with `shift_by = 3` becomes `

    `.""" def __init__(self, md: Markdown, shift_by: int): """Initialize the object. Arguments: md: A `markdown.Markdown` instance. shift_by: The number of heading "levels" to add to every heading. """ super().__init__(md) self.shift_by = shift_by def run(self, root: Element) -> None: """Shift the levels of all headings in the document.""" if not self.shift_by: return for el in root.iter(): match = self.regex.fullmatch(el.tag) if match: level = int(match[2]) + self.shift_by level = max(1, min(level, 6)) el.tag = f"{match[1]}{level}" class _HeadingReportingTreeprocessor(Treeprocessor): """Records the heading elements encountered in the document.""" name: str = "mkdocstrings_headings_list" """The name of the treeprocessor.""" regex: re.Pattern = re.compile(r"[Hh][1-6]") """The regex to match heading tags.""" headings: list[Element] """The list (the one passed in the initializer) that is used to record the heading elements (by appending to it).""" def __init__(self, md: Markdown, headings: list[Element]): super().__init__(md) self.headings = headings def run(self, root: Element) -> None: """Record all heading elements encountered in the document.""" permalink_class = self.md.treeprocessors["toc"].permalink_class # type: ignore[attr-defined] for el in root.iter(): if self.regex.fullmatch(el.tag): el = copy.copy(el) # noqa: PLW2901 # 'toc' extension's first pass (which we require to build heading stubs/ids) also edits the HTML. # Undo the permalink edit so we can pass this heading to the outer pass of the 'toc' extension. if len(el) > 0 and el[-1].get("class") == permalink_class: del el[-1] self.headings.append(el) class ParagraphStrippingTreeprocessor(Treeprocessor): """Unwraps the `

    ` element around the whole output.""" name: str = "mkdocstrings_strip_paragraph" """The name of the treeprocessor.""" strip: bool = False """Whether to strip `

    ` elements or not.""" def run(self, root: Element) -> Element | None: """Unwrap the root element if it's a single `

    ` element.""" if self.strip and len(root) == 1 and root[0].tag == "p": # Turn the single `

    ` element into the root element and inherit its tag name (it's significant!) root[0].tag = root.tag return root[0] return None class MkdocstringsInnerExtension(Extension): """Extension that should always be added to Markdown sub-documents that handlers request (and *only* them).""" def __init__(self, headings: list[Element]): """Initialize the object. Arguments: headings: A list that will be populated with all HTML heading elements encountered in the document. """ super().__init__() self.headings = headings """The list that will be populated with all HTML heading elements encountered in the document.""" def extendMarkdown(self, md: Markdown) -> None: # noqa: N802 (casing: parent method's name) """Register the extension. Arguments: md: A `markdown.Markdown` instance. """ md.registerExtension(self) md.treeprocessors.register( HeadingShiftingTreeprocessor(md, 0), HeadingShiftingTreeprocessor.name, priority=12, ) md.treeprocessors.register( IdPrependingTreeprocessor(md, ""), IdPrependingTreeprocessor.name, priority=4, # Right after 'toc' (needed because that extension adds ids to headers). ) md.treeprocessors.register( _HeadingReportingTreeprocessor(md, self.headings), _HeadingReportingTreeprocessor.name, priority=1, # Close to the end. ) md.treeprocessors.register( ParagraphStrippingTreeprocessor(md), ParagraphStrippingTreeprocessor.name, priority=0.99, # Close to the end. ) mkdocstrings-0.29.0/src/mkdocstrings/_internal/inventory.py000066400000000000000000000125221476356224100242050ustar00rootroot00000000000000# Module responsible for the objects inventory. # # Credits to Brian Skinn and the sphobjinv project: # https://github.com/bskinn/sphobjinv. from __future__ import annotations import re import zlib from textwrap import dedent from typing import TYPE_CHECKING, BinaryIO if TYPE_CHECKING: from collections.abc import Collection class InventoryItem: """Inventory item.""" def __init__( self, name: str, domain: str, role: str, uri: str, priority: int = 1, dispname: str | None = None, ): """Initialize the object. Arguments: 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. """ self.name: str = name """The item name.""" self.domain: str = domain """The item domain.""" self.role: str = role """The item role.""" self.uri: str = uri """The item URI.""" self.priority: int = priority """The item priority.""" self.dispname: str = dispname or name """The item display name.""" def format_sphinx(self) -> str: """Format this item as a Sphinx inventory line. Returns: A line formatted for an `objects.inv` file. """ dispname = self.dispname if dispname == self.name: dispname = "-" uri = self.uri if uri.endswith(self.name): uri = uri[: -len(self.name)] + "$" return f"{self.name} {self.domain}:{self.role} {self.priority} {uri} {dispname}" sphinx_item_regex = re.compile(r"^(.+?)\s+(\S+):(\S+)\s+(-?\d+)\s+(\S+)\s*(.*)$") """Regex to parse a Sphinx v2 inventory line.""" @classmethod def parse_sphinx(cls, line: str) -> InventoryItem: """Parse a line from a Sphinx v2 inventory file and return an `InventoryItem` from it.""" match = cls.sphinx_item_regex.search(line) if not match: raise ValueError(line) name, domain, role, priority, uri, dispname = match.groups() if uri.endswith("$"): uri = uri[:-1] + name if dispname == "-": dispname = name return cls(name, domain, role, uri, int(priority), dispname) class Inventory(dict): """Inventory of collected and rendered objects.""" def __init__(self, items: list[InventoryItem] | None = None, project: str = "project", version: str = "0.0.0"): """Initialize the object. Arguments: items: A list of items. project: The project name. version: The project version. """ super().__init__() items = items or [] for item in items: self[item.name] = item self.project = project """The project name.""" self.version = version """The project version.""" 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: 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. """ 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. Returns: The inventory as bytes. """ header = ( dedent( f""" # Sphinx inventory version 2 # Project: {self.project} # Version: {self.version} # The remainder of this file is compressed using zlib. """, ) .lstrip() .encode("utf8") ) 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 def parse_sphinx(cls, in_file: BinaryIO, *, domain_filter: Collection[str] = ()) -> Inventory: """Parse a Sphinx v2 inventory file and return an `Inventory` from it. Arguments: in_file: The binary file-like object to read from. domain_filter: A collection of domain values to allow (and filter out all other ones). Returns: An inventory containing the collected items. """ for _ in range(4): in_file.readline() lines = zlib.decompress(in_file.read()).splitlines() items = [InventoryItem.parse_sphinx(line.decode("utf8")) for line in lines] if domain_filter: items = [item for item in items if item.domain in domain_filter] return cls(items) mkdocstrings-0.29.0/src/mkdocstrings/_internal/loggers.py000066400000000000000000000146761476356224100236260ustar00rootroot00000000000000# Logging functions. from __future__ import annotations import logging from contextlib import suppress from pathlib import Path from typing import TYPE_CHECKING, Any, Callable try: from jinja2 import pass_context except ImportError: # TODO: remove once Jinja2 < 3.1 is dropped from jinja2 import contextfunction as pass_context # type: ignore[attr-defined,no-redef] if TYPE_CHECKING: from collections.abc import MutableMapping, Sequence from jinja2.runtime import Context try: import mkdocstrings_handlers except ImportError: TEMPLATES_DIRS: Sequence[Path] = () else: TEMPLATES_DIRS = tuple(mkdocstrings_handlers.__path__) """The directories where the handler templates are located.""" class LoggerAdapter(logging.LoggerAdapter): """A logger adapter to prefix messages. This adapter also adds an additional parameter to logging methods called `once`: if `True`, the message will only be logged once. Examples: In Python code: >>> logger = get_logger("myplugin") >>> logger.debug("This is a debug message.") >>> logger.info("This is an info message.", once=True) In Jinja templates (logger available in context as `log`): ```jinja {{ log.debug("This is a debug message.") }} {{ log.info("This is an info message.", once=True) }} ``` """ def __init__(self, prefix: str, logger: logging.Logger): """Initialize the object. Arguments: prefix: The string to insert in front of every message. logger: The logger instance. """ super().__init__(logger, {}) self.prefix = prefix """The prefix to insert in front of every message.""" self._logged: set[tuple[LoggerAdapter, str]] = set() def process(self, msg: str, kwargs: MutableMapping[str, Any]) -> tuple[str, Any]: """Process the message. Arguments: msg: The message: kwargs: Remaining arguments. Returns: The processed message. """ return f"{self.prefix}: {msg}", kwargs def log(self, level: int, msg: object, *args: object, **kwargs: object) -> None: """Log a message. Arguments: level: The logging level. msg: The message. *args: Additional arguments passed to parent method. **kwargs: Additional keyword arguments passed to parent method. """ if kwargs.pop("once", False): if (key := (self, str(msg))) in self._logged: return self._logged.add(key) super().log(level, msg, *args, **kwargs) # type: ignore[arg-type] class TemplateLogger: """A wrapper class to allow logging in templates. The logging methods provided by this class all accept two parameters: - `msg`: The message to log. - `once`: If `True`, the message will only be logged once. Methods: debug: Function to log a DEBUG message. info: Function to log an INFO message. warning: Function to log a WARNING message. error: Function to log an ERROR message. critical: Function to log a CRITICAL message. """ def __init__(self, logger: LoggerAdapter): """Initialize the object. Arguments: logger: A logger adapter. """ self.debug = get_template_logger_function(logger.debug) """Log a DEBUG message.""" self.info = get_template_logger_function(logger.info) """Log an INFO message.""" self.warning = get_template_logger_function(logger.warning) """Log a WARNING message.""" self.error = get_template_logger_function(logger.error) """Log an ERROR message.""" self.critical = get_template_logger_function(logger.critical) """Log a CRITICAL message.""" class _Lazy: unset = object() def __init__(self, func: Callable, *args: Any, **kwargs: Any): self.func = func self.args = args self.kwargs = kwargs self.result = self.unset def __call__(self): if self.result is self.unset: self.result = self.func(*self.args, **self.kwargs) return self.result def __str__(self) -> str: return str(self()) def __repr__(self) -> str: return repr(self()) def get_template_logger_function(logger_func: Callable) -> Callable: """Create a wrapper function that automatically receives the Jinja template context. Arguments: logger_func: The logger function to use within the wrapper. Returns: A function. """ @pass_context def wrapper(context: Context, msg: str | None = None, *args: Any, **kwargs: Any) -> str: """Log a message. Arguments: context: The template context, automatically provided by Jinja. msg: The message to log. **kwargs: Additional arguments passed to the logger function. Returns: An empty string. """ logger_func(f"%s: {msg or 'Rendering'}", _Lazy(get_template_path, context), *args, **kwargs) return "" return wrapper def get_template_path(context: Context) -> str: """Return the path to the template currently using the given context. Arguments: context: The template context. Returns: The relative path to the template. """ context_name: str = str(context.name) filename = context.environment.get_template(context_name).filename if filename: for template_dir in TEMPLATES_DIRS: with suppress(ValueError): return str(Path(filename).relative_to(template_dir)) with suppress(ValueError): return str(Path(filename).relative_to(Path.cwd())) return filename return context_name def get_logger(name: str) -> LoggerAdapter: """Return a pre-configured logger. Arguments: name: The name to use with `logging.getLogger`. Returns: A logger configured to work well in MkDocs. """ logger = logging.getLogger(f"mkdocs.plugins.{name}") return LoggerAdapter(name.split(".", 1)[0], logger) def get_template_logger(handler_name: str | None = None) -> TemplateLogger: """Return a logger usable in templates. Parameters: handler_name: The name of the handler. Returns: A template logger. """ handler_name = handler_name or "base" return TemplateLogger(get_logger(f"mkdocstrings_handlers.{handler_name}.templates")) mkdocstrings-0.29.0/src/mkdocstrings/_internal/plugin.py000066400000000000000000000274051476356224100234540ustar00rootroot00000000000000# This module contains the "mkdocstrings" plugin for MkDocs. # # The plugin instantiates a Markdown extension ([`MkdocstringsExtension`][mkdocstrings.MkdocstringsExtension]), # and adds it to the list of Markdown extensions used by `mkdocs` # during the [`on_config` event hook](https://www.mkdocs.org/user-guide/plugins/#on_config). # # Once the documentation is built, the [`on_post_build` event hook](https://www.mkdocs.org/user-guide/plugins/#on_post_build) # is triggered and calls the [`handlers.teardown()` method][mkdocstrings.Handlers.teardown]. This method is # used to teardown the handlers that were instantiated during documentation buildup. # # Finally, when serving the documentation, it can add directories to watch # during the [`on_serve` event hook](https://www.mkdocs.org/user-guide/plugins/#on_serve). from __future__ import annotations import os import re from re import Match from typing import TYPE_CHECKING, Any from warnings import catch_warnings, simplefilter from mkdocs.config import Config from mkdocs.config import config_options as opt from mkdocs.plugins import BasePlugin, CombinedEvent, event_priority from mkdocs.utils import write_file from mkdocs_autorefs import AutorefsConfig, AutorefsPlugin from mkdocstrings._internal.extension import MkdocstringsExtension from mkdocstrings._internal.handlers.base import BaseHandler, Handlers from mkdocstrings._internal.loggers import get_logger if TYPE_CHECKING: from jinja2.environment import Environment from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.files import Files _logger = get_logger(__name__) class PluginConfig(Config): """The configuration options of `mkdocstrings`, written in `mkdocs.yml`.""" handlers = opt.Type(dict, default={}) """ Global configuration of handlers. You can set global configuration per handler, applied everywhere, but overridable in each "autodoc" instruction. Example: ```yaml plugins: - mkdocstrings: handlers: python: options: option1: true option2: "value" rust: options: option9: 2 ``` """ default_handler = opt.Type(str, default="python") """The default handler to use. The value is the name of the handler module. Default is "python".""" custom_templates = opt.Optional(opt.Dir(exists=True)) """Location of custom templates to use when rendering API objects. Value should be the path of a directory relative to the MkDocs configuration file. """ enable_inventory = opt.Optional(opt.Type(bool)) """Whether to enable object inventory creation.""" enabled = opt.Type(bool, default=True) """Whether to enable the plugin. Default is true. If false, *mkdocstrings* will not collect or render anything.""" class MkdocstringsPlugin(BasePlugin[PluginConfig]): """An `mkdocs` plugin. This plugin defines the following event hooks: - `on_config` - `on_env` - `on_post_build` Check the [Developing Plugins](https://www.mkdocs.org/user-guide/plugins/#developing-plugins) page of `mkdocs` for more information about its plugin system. """ css_filename: str = "assets/_mkdocstrings.css" """The path of the CSS file to write in the site directory.""" def __init__(self) -> None: """Initialize the object.""" super().__init__() self._handlers: Handlers | None = None @property def handlers(self) -> Handlers: """Get the instance of [mkdocstrings.Handlers][] for this plugin/build. Raises: RuntimeError: If the plugin hasn't been initialized with a config. Returns: An instance of [mkdocstrings.Handlers][] (the same throughout the build). """ if not self._handlers: raise RuntimeError("The plugin hasn't been initialized with a config yet") return self._handlers 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). In this hook, we instantiate our [`MkdocstringsExtension`][mkdocstrings.MkdocstringsExtension] and add it to the list of Markdown extensions used by `mkdocs`. We pass this plugin's configuration dictionary to the extension when instantiating it (it will need it later when processing markdown to get handlers and their global configurations). Arguments: config: The MkDocs config object. Returns: The modified config. """ if not self.plugin_enabled: _logger.debug("Plugin is not enabled. Skipping.") return config _logger.debug("Adding extension to the list") handlers = Handlers( default=self.config.default_handler, handlers_config=self.config.handlers, theme=config.theme.name or os.path.dirname(config.theme.dirs[0]), custom_templates=self.config.custom_templates, mdx=config.markdown_extensions, mdx_config=config.mdx_configs, inventory_project=config.site_name, inventory_version="0.0.0", # TODO: Find a way to get actual version. tool_config=config, ) handlers._download_inventories() AutorefsPlugin.record_backlinks = True autorefs: AutorefsPlugin try: # If autorefs plugin is explicitly enabled, just use it. autorefs = config.plugins["autorefs"] # type: ignore[assignment] _logger.debug("Picked up existing autorefs instance %r", autorefs) except KeyError: # Otherwise, add a limited instance of it that acts only on what's added through `register_anchor`. autorefs = AutorefsPlugin() autorefs.config = AutorefsConfig() autorefs.scan_toc = False config.plugins["autorefs"] = autorefs _logger.debug("Added a subdued autorefs instance %r", autorefs) # YORE: Bump 1: Remove block. with catch_warnings(): simplefilter("ignore", category=DeprecationWarning) autorefs.get_fallback_anchor = handlers.get_anchors mkdocstrings_extension = MkdocstringsExtension(handlers, autorefs) config.markdown_extensions.append(mkdocstrings_extension) # type: ignore[arg-type] config.extra_css.insert(0, self.css_filename) # So that it has lower priority than user files. self._autorefs = autorefs self._handlers = handlers return config @property def inventory_enabled(self) -> bool: """Tell if the inventory is enabled or not. Returns: Whether the inventory is enabled. """ inventory_enabled = self.config.enable_inventory if inventory_enabled is None: inventory_enabled = any(handler.enable_inventory for handler in self.handlers.seen_handlers) return inventory_enabled @property def plugin_enabled(self) -> bool: """Tell if the plugin is enabled or not. Returns: Whether the plugin is enabled. """ return self.config.enabled @event_priority(50) # Early, before autorefs' starts applying cross-refs and collecting backlinks. def _on_env_load_inventories(self, env: Environment, config: MkDocsConfig, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 if self.plugin_enabled and self._handlers: register = config.plugins["autorefs"].register_url # type: ignore[attr-defined] for identifier, url in self._handlers._yield_inventory_items(): register(identifier, url) @event_priority(-20) # Late, not important. def _on_env_add_css(self, env: Environment, config: MkDocsConfig, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 if self.plugin_enabled and self._handlers: css_content = "\n".join(handler.extra_css for handler in self.handlers.seen_handlers) write_file(css_content.encode("utf-8"), os.path.join(config.site_dir, self.css_filename)) @event_priority(-20) # Late, not important. def _on_env_write_inventory(self, env: Environment, config: MkDocsConfig, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 if self.plugin_enabled and self._handlers and self.inventory_enabled: _logger.debug("Creating inventory file objects.inv") inv_contents = self.handlers.inventory.format_sphinx() write_file(inv_contents, os.path.join(config.site_dir, "objects.inv")) @event_priority(-100) # Last, after autorefs has finished applying cross-refs and collecting backlinks. def _on_env_apply_backlinks(self, env: Environment, /, *, config: MkDocsConfig, files: Files) -> Environment: # noqa: ARG002 regex = re.compile(r"") def repl(match: Match) -> str: handler_name = match.group(2) handler = self.handlers.get_handler(handler_name) # The handler doesn't implement backlinks, # return early to avoid computing them. if handler.render_backlinks.__func__ is BaseHandler.render_backlinks: # type: ignore[attr-defined] return "" identifier = match.group(1) aliases = handler.get_aliases(identifier) backlinks = self._autorefs.get_backlinks(identifier, *aliases, from_url=file.page.url) # type: ignore[union-attr] # No backlinks, avoid calling the handler's method. if not backlinks: return "" return handler.render_backlinks(backlinks) for file in files: if file.page and file.page.content: _logger.debug("Applying backlinks in page %s", file.page.file.src_path) file.page.content = regex.sub(repl, file.page.content) return env on_env = CombinedEvent(_on_env_load_inventories, _on_env_add_css, _on_env_write_inventory, _on_env_apply_backlinks) """Extra actions that need to happen after all Markdown-to-HTML page rendering. Hook for the [`on_env` event](https://www.mkdocs.org/user-guide/plugins/#on_env). - Gather results from background inventory download tasks. - Write mkdocstrings' extra files (CSS, inventory) into the site directory. - Apply backlinks to the HTML output of each page. """ def on_post_build( self, config: MkDocsConfig, # noqa: ARG002 **kwargs: Any, # noqa: ARG002 ) -> None: """Teardown the handlers. Hook for the [`on_post_build` event](https://www.mkdocs.org/user-guide/plugins/#on_post_build). This hook is used to teardown all the handlers that were instantiated and cached during documentation buildup. 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 handler's `teardown` method, which is indirectly called by this hook. Arguments: config: The MkDocs config object. **kwargs: Additional arguments passed by MkDocs. """ if not self.plugin_enabled: return if self._handlers: _logger.debug("Tearing handlers down") self.handlers.teardown() def get_handler(self, handler_name: str) -> BaseHandler: """Get a handler by its name. See [mkdocstrings.Handlers.get_handler][]. Arguments: handler_name: The name of the handler. Returns: An instance of a subclass of [`BaseHandler`][mkdocstrings.BaseHandler]. """ return self.handlers.get_handler(handler_name) mkdocstrings-0.29.0/src/mkdocstrings/extension.py000066400000000000000000000006101476356224100222040ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" import warnings from typing import Any from mkdocstrings._internal import extension def __getattr__(name: str) -> Any: warnings.warn( "Importing from `mkdocstrings.extension` is deprecated. Import from `mkdocstrings` directly.", DeprecationWarning, stacklevel=2, ) return getattr(extension, name) mkdocstrings-0.29.0/src/mkdocstrings/handlers/000077500000000000000000000000001476356224100214215ustar00rootroot00000000000000mkdocstrings-0.29.0/src/mkdocstrings/handlers/__init__.py000066400000000000000000000000671476356224100235350ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" mkdocstrings-0.29.0/src/mkdocstrings/handlers/base.py000066400000000000000000000006131476356224100227050ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" import warnings from typing import Any from mkdocstrings._internal.handlers import base def __getattr__(name: str) -> Any: warnings.warn( "Importing from `mkdocstrings.handlers.base` is deprecated. Import from `mkdocstrings` directly.", DeprecationWarning, stacklevel=2, ) return getattr(base, name) mkdocstrings-0.29.0/src/mkdocstrings/handlers/rendering.py000066400000000000000000000006321476356224100237510ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" import warnings from typing import Any from mkdocstrings._internal.handlers import rendering def __getattr__(name: str) -> Any: warnings.warn( "Importing from `mkdocstrings.handlers.rendering` is deprecated. Import from `mkdocstrings` directly.", DeprecationWarning, stacklevel=2, ) return getattr(rendering, name) mkdocstrings-0.29.0/src/mkdocstrings/inventory.py000066400000000000000000000006101476356224100222250ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" import warnings from typing import Any from mkdocstrings._internal import inventory def __getattr__(name: str) -> Any: warnings.warn( "Importing from `mkdocstrings.inventory` is deprecated. Import from `mkdocstrings` directly.", DeprecationWarning, stacklevel=2, ) return getattr(inventory, name) mkdocstrings-0.29.0/src/mkdocstrings/loggers.py000066400000000000000000000006021476356224100216330ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" import warnings from typing import Any from mkdocstrings._internal import loggers def __getattr__(name: str) -> Any: warnings.warn( "Importing from `mkdocstrings.loggers` is deprecated. Import from `mkdocstrings` directly.", DeprecationWarning, stacklevel=2, ) return getattr(loggers, name) mkdocstrings-0.29.0/src/mkdocstrings/plugin.py000066400000000000000000000005771476356224100215020ustar00rootroot00000000000000"""Deprecated. Import from `mkdocstrings` directly.""" import warnings from typing import Any from mkdocstrings._internal import plugin def __getattr__(name: str) -> Any: warnings.warn( "Importing from `mkdocstrings.plugin` is deprecated. Import from `mkdocstrings` directly.", DeprecationWarning, stacklevel=2, ) return getattr(plugin, name) mkdocstrings-0.29.0/src/mkdocstrings/py.typed000066400000000000000000000000001476356224100213060ustar00rootroot00000000000000mkdocstrings-0.29.0/tests/000077500000000000000000000000001476356224100154655ustar00rootroot00000000000000mkdocstrings-0.29.0/tests/__init__.py000066400000000000000000000002451476356224100175770ustar00rootroot00000000000000"""Tests suite for `mkdocstrings`.""" from pathlib import Path TESTS_DIR = Path(__file__).parent TMP_DIR = TESTS_DIR / "tmp" FIXTURES_DIR = TESTS_DIR / "fixtures" mkdocstrings-0.29.0/tests/conftest.py000066400000000000000000000040331476356224100176640ustar00rootroot00000000000000"""Configuration for the pytest test suite.""" from __future__ import annotations from collections import ChainMap from typing import TYPE_CHECKING, Any import pytest from markdown.core import Markdown from mkdocs.config.defaults import MkDocsConfig if TYPE_CHECKING: from collections.abc import Iterator from pathlib import Path from mkdocs import config from mkdocstrings._internal.plugin import MkdocstringsPlugin @pytest.fixture(name="mkdocs_conf") def fixture_mkdocs_conf(request: pytest.FixtureRequest, tmp_path: Path) -> Iterator[config.Config]: """Yield a MkDocs configuration object.""" conf = MkDocsConfig() while hasattr(request, "_parent_request") and hasattr(request._parent_request, "_parent_request"): request = request._parent_request 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[str, Any] = 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: config.Config) -> MkdocstringsPlugin: """Return a plugin instance.""" return mkdocs_conf["plugins"]["mkdocstrings"] @pytest.fixture(name="ext_markdown") def fixture_ext_markdown(mkdocs_conf: MkDocsConfig) -> Markdown: """Return a Markdown instance with MkdocstringsExtension.""" return Markdown(extensions=mkdocs_conf["markdown_extensions"], extension_configs=mkdocs_conf["mdx_configs"]) mkdocstrings-0.29.0/tests/fixtures/000077500000000000000000000000001476356224100173365ustar00rootroot00000000000000mkdocstrings-0.29.0/tests/fixtures/__init__.py000066400000000000000000000000371476356224100214470ustar00rootroot00000000000000"""Some fixtures for tests.""" mkdocstrings-0.29.0/tests/fixtures/cross_reference.py000066400000000000000000000000441476356224100230550ustar00rootroot00000000000000""" Link to [something.Else][]. """ mkdocstrings-0.29.0/tests/fixtures/footnotes.py000066400000000000000000000002531476356224100217300ustar00rootroot00000000000000def func_a(): """func_a[^1]. [^1]: Footnote\x20A """ def func_b(): """func_b[^x]. [^x]: Footnote\x20B """ def func_c(): """func_c. """ mkdocstrings-0.29.0/tests/fixtures/headings.py000066400000000000000000000000451476356224100214710ustar00rootroot00000000000000""" Foo === ### Bar ###### Baz """ mkdocstrings-0.29.0/tests/fixtures/headings_many.py000066400000000000000000000002071476356224100225150ustar00rootroot00000000000000def heading_1(): """## Heading one""" def heading_2(): """### Heading two""" def heading_3(): """#### Heading three""" mkdocstrings-0.29.0/tests/fixtures/html_tokens.py000066400000000000000000000000571476356224100222410ustar00rootroot00000000000000def func(foo="

    HELLO

    "): """test""" mkdocstrings-0.29.0/tests/fixtures/markdown_anchors.py000066400000000000000000000002731476356224100232510ustar00rootroot00000000000000"""Module docstring. [](){#anchor} Paragraph. [](){#heading-anchor-1} [](){#heading-anchor-2} [](){#heading-anchor-3} ## Heading [](#has-href1) [](#has-href2){#with-id} Pararaph. """mkdocstrings-0.29.0/tests/fixtures/nesting.py000066400000000000000000000003051476356224100213550ustar00rootroot00000000000000class Class: """A class. ## ::: tests.fixtures.nesting.Class.method options: show_root_heading: true """ def method(self) -> None: """A method.""" mkdocstrings-0.29.0/tests/fixtures/string_annotation.py000066400000000000000000000001671476356224100234540ustar00rootroot00000000000000from typing import Literal class Foo: @property def foo() -> Literal["hi"]: "hi" return "hi" mkdocstrings-0.29.0/tests/test_api.py000066400000000000000000000161561476356224100176600ustar00rootroot00000000000000"""Tests for our own API exposition.""" from __future__ import annotations from collections import defaultdict from pathlib import Path from typing import TYPE_CHECKING import griffe import pytest import mkdocstrings from mkdocstrings import Inventory if TYPE_CHECKING: from collections.abc import Iterator @pytest.fixture(name="loader", scope="module") def _fixture_loader() -> griffe.GriffeLoader: loader = griffe.GriffeLoader() loader.load("mkdocstrings") loader.resolve_aliases() return loader @pytest.fixture(name="internal_api", scope="module") def _fixture_internal_api(loader: griffe.GriffeLoader) -> griffe.Module: return loader.modules_collection["mkdocstrings._internal"] @pytest.fixture(name="public_api", scope="module") def _fixture_public_api(loader: griffe.GriffeLoader) -> griffe.Module: return loader.modules_collection["mkdocstrings"] def _yield_public_objects( obj: griffe.Module | griffe.Class, *, modules: bool = False, modulelevel: bool = True, inherited: bool = False, special: bool = False, ) -> Iterator[griffe.Object | griffe.Alias]: for member in obj.all_members.values() if inherited else obj.members.values(): try: if member.is_module: if member.is_alias or not member.is_public: continue if modules: yield member yield from _yield_public_objects( member, # type: ignore[arg-type] modules=modules, modulelevel=modulelevel, inherited=inherited, special=special, ) elif member.is_public and (special or not member.is_special): yield member else: continue if member.is_class and not modulelevel: yield from _yield_public_objects( member, # type: ignore[arg-type] modules=modules, modulelevel=False, inherited=inherited, special=special, ) except (griffe.AliasResolutionError, griffe.CyclicAliasError): continue @pytest.fixture(name="modulelevel_internal_objects", scope="module") def _fixture_modulelevel_internal_objects(internal_api: griffe.Module) -> list[griffe.Object | griffe.Alias]: return list(_yield_public_objects(internal_api, modulelevel=True)) @pytest.fixture(name="internal_objects", scope="module") def _fixture_internal_objects(internal_api: griffe.Module) -> list[griffe.Object | griffe.Alias]: return list(_yield_public_objects(internal_api, modulelevel=False, special=True)) @pytest.fixture(name="public_objects", scope="module") def _fixture_public_objects(public_api: griffe.Module) -> list[griffe.Object | griffe.Alias]: return list(_yield_public_objects(public_api, modulelevel=False, inherited=True, special=True)) @pytest.fixture(name="inventory", scope="module") def _fixture_inventory() -> Inventory: inventory_file = Path(__file__).parent.parent / "site" / "objects.inv" if not inventory_file.exists(): raise pytest.skip("The objects inventory is not available.") with inventory_file.open("rb") as file: return Inventory.parse_sphinx(file) def test_exposed_objects(modulelevel_internal_objects: list[griffe.Object | griffe.Alias]) -> None: """All public objects in the internal API are exposed under `mkdocstrings`.""" not_exposed = [ obj.path for obj in modulelevel_internal_objects if obj.name not in mkdocstrings.__all__ or not hasattr(mkdocstrings, obj.name) ] assert not not_exposed, "Objects not exposed:\n" + "\n".join(sorted(not_exposed)) def test_unique_names(modulelevel_internal_objects: list[griffe.Object | griffe.Alias]) -> None: """All internal objects have unique names.""" names_to_paths = defaultdict(list) for obj in modulelevel_internal_objects: names_to_paths[obj.name].append(obj.path) non_unique = [paths for paths in names_to_paths.values() if len(paths) > 1] assert not non_unique, "Non-unique names:\n" + "\n".join(str(paths) for paths in non_unique) def test_single_locations(public_api: griffe.Module) -> None: """All objects have a single public location.""" def _public_path(obj: griffe.Object | griffe.Alias) -> bool: return obj.is_public and (obj.parent is None or _public_path(obj.parent)) multiple_locations = {} for obj_name in mkdocstrings.__all__: obj = public_api[obj_name] if obj.aliases and ( public_aliases := [path for path, alias in obj.aliases.items() if path != obj.path and _public_path(alias)] ): multiple_locations[obj.path] = public_aliases assert not multiple_locations, "Multiple public locations:\n" + "\n".join( f"{path}: {aliases}" for path, aliases in multiple_locations.items() ) def test_api_matches_inventory(inventory: Inventory, public_objects: list[griffe.Object | griffe.Alias]) -> None: """All public objects are added to the inventory.""" ignore_names = {"__getattr__", "__init__", "__repr__", "__str__", "__post_init__"} not_in_inventory = [ obj.path for obj in public_objects if obj.name not in ignore_names and obj.path not in inventory ] msg = "Objects not in the inventory (try running `make run mkdocs build`):\n{paths}" assert not not_in_inventory, msg.format(paths="\n".join(sorted(not_in_inventory))) def test_inventory_matches_api( inventory: Inventory, public_objects: list[griffe.Object | griffe.Alias], loader: griffe.GriffeLoader, ) -> None: """The inventory doesn't contain any additional Python object.""" not_in_api = [] # YORE: Bump 1: Remove line. deprecated_modules = {"extension", "handlers", "inventory", "loggers", "plugin"} public_api_paths = {obj.path for obj in public_objects} public_api_paths.add("mkdocstrings") for item in inventory.values(): if item.domain == "py" and "(" not in item.name: obj = loader.modules_collection[item.name] # YORE: Bump 1: Remove block. if any(obj.path.startswith(f"mkdocstrings.{module}") for module in deprecated_modules): continue if obj.path not in public_api_paths and not any(path in public_api_paths for path in obj.aliases): not_in_api.append(item.name) msg = "Inventory objects not in public API (try running `make run mkdocs build`):\n{paths}" assert not not_in_api, msg.format(paths="\n".join(sorted(not_in_api))) def test_no_module_docstrings_in_internal_api(internal_api: griffe.Module) -> None: """No module docstrings should be written in our internal API. The reasoning is that docstrings are addressed to users of the public API, but internal modules are not exposed to users, so they should not have docstrings. """ def _modules(obj: griffe.Module) -> Iterator[griffe.Module]: for member in obj.modules.values(): yield member yield from _modules(member) for obj in _modules(internal_api): assert not obj.docstring mkdocstrings-0.29.0/tests/test_download.py000066400000000000000000000075251476356224100207160ustar00rootroot00000000000000"""Tests for the internal mkdocstrings _download module.""" from __future__ import annotations import logging from typing import TYPE_CHECKING import pytest from mkdocstrings._internal import download if TYPE_CHECKING: from collections.abc import Mapping @pytest.mark.parametrize( ("credential", "expected", "env"), [ ("USER", "USER", {"USER": "testuser"}), ("$USER", "$USER", {"USER": "testuser"}), ("${USER", "${USER", {"USER": "testuser"}), ("$USER}", "$USER}", {"USER": "testuser"}), ("${TOKEN}", "testtoken", {"TOKEN": "testtoken"}), ("${USER}:${PASSWORD}", "${USER}:testpass", {"PASSWORD": "testpass"}), ("${USER}:${PASSWORD}", "testuser:testpass", {"USER": "testuser", "PASSWORD": "testpass"}), ( "user_prefix_${USER}_user_$uffix:pwd_prefix_${PASSWORD}_pwd_${uffix", "user_prefix_testuser_user_$uffix:pwd_prefix_testpass_pwd_${uffix", {"USER": "testuser", "PASSWORD": "testpass"}, ), ], ) def test_expand_env_vars(credential: str, expected: str, env: Mapping[str, str]) -> None: """Test expanding environment variables.""" assert download._expand_env_vars(credential, url="https://test.example.com", env=env) == expected def test_expand_env_vars_with_missing_env_var(caplog: pytest.LogCaptureFixture) -> None: """Test expanding environment variables with a missing environment variable.""" caplog.set_level(logging.WARNING, logger="mkdocs.plugins.mkdocstrings._download") credential = "${USER}" env: dict[str, str] = {} assert download._expand_env_vars(credential, url="https://test.example.com", env=env) == "${USER}" output = caplog.records[0].getMessage() assert "'USER' is not set" in output @pytest.mark.parametrize( ("url", "expected_url"), [ ("http://host/path", "http://host/path"), ("http://token@host/path", "http://host/path"), ("http://${token}@host/path", "http://host/path"), ("http://username:password@host/path", "http://host/path"), ("http://username:${PASSWORD}@host/path", "http://host/path"), ("http://${USERNAME}:${PASSWORD}@host/path", "http://host/path"), ("http://prefix${USERNAME}suffix:prefix${PASSWORD}suffix@host/path", "http://host/path"), ], ) def test_extract_auth_from_url(monkeypatch: pytest.MonkeyPatch, url: str, expected_url: str) -> None: """Test extracting the auth part from the URL.""" monkeypatch.setattr(download, "_create_auth_header", lambda *args, **kwargs: {}) result_url, _result_auth_header = download._extract_auth_from_url(url) assert result_url == expected_url def test_create_auth_header_basic_auth() -> None: """Test creating the Authorization header for basic authentication.""" auth_header = download._create_auth_header(credential="testuser:testpass", url="https://test.example.com") assert auth_header == {"Authorization": "Basic dGVzdHVzZXI6dGVzdHBhc3M="} def test_create_auth_header_bearer_auth() -> None: """Test creating the Authorization header for bearer token authentication.""" auth_header = download._create_auth_header(credential="token123", url="https://test.example.com") assert auth_header == {"Authorization": "Bearer token123"} @pytest.mark.parametrize( ("var", "match"), [ ("${var}", "var"), ("${VAR}", "VAR"), ("${_}", "_"), ("${_VAR}", "_VAR"), ("${VAR123}", "VAR123"), ("${VAR123_}", "VAR123_"), ("VAR", None), ("$1VAR", None), ("${1VAR}", None), ("${}", None), ("${ }", None), ], ) def test_env_var_pattern(var: str, match: str | None) -> None: """Test the environment variable regex pattern.""" _match = download._ENV_VAR_PATTERN.match(var) if _match is None: assert match is _match else: assert _match.group(1) == match mkdocstrings-0.29.0/tests/test_extension.py000066400000000000000000000214211476356224100211120ustar00rootroot00000000000000"""Tests for the extension module.""" from __future__ import annotations import re import sys from textwrap import dedent from typing import TYPE_CHECKING import pytest if TYPE_CHECKING: from markdown import Markdown from mkdocstrings import MkdocstringsPlugin @pytest.mark.parametrize("ext_markdown", [{"markdown_extensions": [{"footnotes": {}}]}], indirect=["ext_markdown"]) def test_multiple_footnotes(ext_markdown: Markdown) -> None: """Assert footnotes don't get added to subsequent docstrings.""" output = ext_markdown.convert( dedent( """ Top.[^aaa] ::: tests.fixtures.footnotes.func_a ::: tests.fixtures.footnotes.func_b ::: tests.fixtures.footnotes.func_c [^aaa]: Top footnote """, ), ) assert output.count("Footnote A") == 1 assert output.count("Footnote B") == 1 assert output.count("Top footnote") == 1 def test_markdown_heading_level(ext_markdown: Markdown) -> None: """Assert that Markdown headings' level doesn't exceed heading_level.""" output = ext_markdown.convert("::: tests.fixtures.headings\n options:\n show_root_heading: true") assert ">Foo

    " in output assert ">Bar" in output assert ">Baz" in output def test_keeps_preceding_text(ext_markdown: Markdown) -> None: """Assert that autodoc is recognized in the middle of a block and preceding text is kept.""" output = ext_markdown.convert("**preceding**\n::: tests.fixtures.headings") assert "preceding" in output assert ">Foo" in output assert ":::" not in output def test_reference_inside_autodoc(ext_markdown: Markdown) -> None: """Assert cross-reference Markdown extension works correctly.""" output = ext_markdown.convert("::: tests.fixtures.cross_reference") assert re.search(r"Link to <.*something\.Else.*>something\.Else<.*>\.", output) @pytest.mark.skipif(sys.version_info < (3, 8), reason="typing.Literal requires Python 3.8") def test_quote_inside_annotation(ext_markdown: Markdown) -> None: """Assert that inline highlighting doesn't double-escape HTML.""" output = ext_markdown.convert("::: tests.fixtures.string_annotation.Foo") assert ";hi&" in output assert "&" not in output def test_html_inside_heading(ext_markdown: Markdown) -> None: """Assert that headings don't double-escape HTML.""" output = ext_markdown.convert("::: tests.fixtures.html_tokens") assert "'<" in output assert "&" not in output @pytest.mark.parametrize( ("ext_markdown", "expect_permalink"), [ ({"markdown_extensions": [{"toc": {"permalink": "@@@"}}]}, "@@@"), ({"markdown_extensions": [{"toc": {"permalink": "TeSt"}}]}, "TeSt"), ({"markdown_extensions": [{"toc": {"permalink": True}}]}, "¶"), ], indirect=["ext_markdown"], ) def test_no_double_toc(ext_markdown: Markdown, expect_permalink: str) -> None: """Assert that the 'toc' extension doesn't apply its modification twice.""" output = ext_markdown.convert( dedent( """ # aa ::: tests.fixtures.headings options: show_root_toc_entry: false # bb """, ), ) assert output.count(expect_permalink) == 5 assert 'id="tests.fixtures.headings--foo"' in output assert ext_markdown.toc_tokens == [ # type: ignore[attr-defined] # the member gets populated only with 'toc' extension { "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", "html": "Baz", "name": "Baz", "data-toc-label": "", "children": [], }, ], }, ], }, ], }, { "level": 1, "id": "bb", "html": "bb", "name": "bb", "data-toc-label": "", "children": [], }, ] def test_use_custom_handler(ext_markdown: Markdown) -> None: """Assert that we use the custom handler declared in an individual autodoc instruction.""" with pytest.raises(ModuleNotFoundError): ext_markdown.convert("::: tests.fixtures.headings\n handler: not_here") def test_register_every_identifier_alias(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") handler.get_aliases = lambda _: ids # type: ignore[method-assign] autorefs = ext_markdown.parser.blockprocessors["mkdocstrings"]._autorefs # type: ignore[attr-defined] class Page: url = "foo" autorefs.current_page = Page() ext_markdown.convert("::: tests.fixtures.headings") for identifier in ids: assert identifier in autorefs._secondary_url_map 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") def test_use_yaml_options_after_blank_line(ext_markdown: Markdown) -> None: """Check that YAML options are detected even after a blank line.""" assert "h1" not in ext_markdown.convert("::: tests.fixtures.headings\n\n options:\n heading_level: 2") @pytest.mark.parametrize("ext_markdown", [{"markdown_extensions": [{"admonition": {}}]}], indirect=["ext_markdown"]) def test_removing_duplicated_headings(ext_markdown: Markdown) -> None: """Assert duplicated headings are removed from the output.""" output = ext_markdown.convert( dedent( """ ::: tests.fixtures.headings_many.heading_1 !!! note ::: tests.fixtures.headings_many.heading_2 ::: tests.fixtures.headings_many.heading_3 """, ), ) assert output.count(">Heading one<") == 1 assert output.count(">Heading two<") == 1 assert output.count(">Heading three<") == 1 assert output.count('class="mkdocstrings') == 0 def _assert_contains_in_order(items: list[str], string: str) -> None: index = 0 for item in items: assert item in string[index:] index = string.index(item, index) + len(item) @pytest.mark.parametrize("ext_markdown", [{"markdown_extensions": [{"attr_list": {}}]}], indirect=["ext_markdown"]) def test_backup_of_anchors(ext_markdown: Markdown) -> None: """Anchors with empty `href` are backed up.""" output = ext_markdown.convert("::: tests.fixtures.markdown_anchors") # Anchors with id and no href have been backed up and updated. _assert_contains_in_order( [ 'id="anchor"', 'id="tests.fixtures.markdown_anchors--anchor"', 'id="heading-anchor-1"', 'id="tests.fixtures.markdown_anchors--heading-anchor-1"', 'id="heading-anchor-2"', 'id="tests.fixtures.markdown_anchors--heading-anchor-2"', 'id="heading-anchor-3"', 'id="tests.fixtures.markdown_anchors--heading-anchor-3"', ], output, ) # Anchors with href and with or without id have been updated but not backed up. _assert_contains_in_order( [ 'id="tests.fixtures.markdown_anchors--with-id"', ], output, ) assert 'id="with-id"' not in output _assert_contains_in_order( [ 'href="#tests.fixtures.markdown_anchors--has-href1"', 'href="#tests.fixtures.markdown_anchors--has-href2"', ], output, ) assert 'href="#has-href1"' not in output assert 'href="#has-href2"' not in output mkdocstrings-0.29.0/tests/test_handlers.py000066400000000000000000000116211476356224100206770ustar00rootroot00000000000000"""Tests for the handlers.base module.""" from __future__ import annotations from textwrap import dedent from typing import TYPE_CHECKING import pytest from dirty_equals import IsStr from jinja2.exceptions import TemplateNotFound from markdown import Markdown from mkdocstrings import Highlighter if TYPE_CHECKING: from pathlib import Path from mkdocstrings import MkdocstringsPlugin @pytest.mark.parametrize("extension_name", ["codehilite", "pymdownx.highlight"]) def test_highlighter_without_pygments(extension_name: str) -> None: """Assert that it's possible to disable Pygments highlighting. Arguments: extension_name: The "user-chosen" Markdown extension for syntax highlighting. """ configs = {extension_name: {"use_pygments": False, "css_class": "hiiii"}} md = Markdown(extensions=[extension_name], extension_configs=configs) hl = Highlighter(md) assert ( hl.highlight("import foo", language="python") == '
    import foo
    ' ) assert ( hl.highlight("import foo", language="python", inline=True) == f'import foo' ) @pytest.mark.parametrize("extension_name", [None, "codehilite", "pymdownx.highlight"]) @pytest.mark.parametrize("inline", [False, True]) def test_highlighter_basic(extension_name: str | None, inline: bool) -> None: """Assert that Pygments syntax highlighting works. Arguments: extension_name: The "user-chosen" Markdown extension for syntax highlighting. inline: Whether the highlighting was inline. """ md = Markdown(extensions=[extension_name], extension_configs={extension_name: {}}) if extension_name else Markdown() hl = Highlighter(md) actual = hl.highlight("import foo", language="python", inline=inline) assert "import" in actual assert "import foo" not in actual # Highlighting has split it up. def test_extended_templates(tmp_path: Path, plugin: MkdocstringsPlugin) -> None: """Test the extended templates functionality. Parameters: tmp_path: Temporary folder. plugin: Instance of our plugin. """ handler = plugin._handlers.get_handler("python") # type: ignore[union-attr] # 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 with pytest.raises(expected_exception=TemplateNotFound): handler.env.get_template("new.html") # check precedence: base theme, base fallback theme, extended theme, extended fallback theme # start with last one and go back up handler.env.cache = None 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.mkdir() extended_theme.joinpath("new.html").write_text("extended new") assert handler.env.get_template("new.html").render() == "extended new" 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.mkdir() base_theme.joinpath("new.html").write_text("base new") assert handler.env.get_template("new.html").render() == "base new" @pytest.mark.parametrize( "ext_markdown", [{"markdown_extensions": [{"toc": {"permalink": True}}]}], indirect=["ext_markdown"], ) def test_nested_autodoc(ext_markdown: Markdown) -> None: """Assert that nested autodocs render well and do not mess up the TOC.""" output = ext_markdown.convert( dedent( """ # ::: tests.fixtures.nesting.Class options: members: false show_root_heading: true """, ), ) assert 'id="tests.fixtures.nesting.Class"' in output assert 'id="tests.fixtures.nesting.Class.method"' in output assert ext_markdown.toc_tokens == [ # type: ignore[attr-defined] { "level": 1, "id": "tests.fixtures.nesting.Class", "html": IsStr(), "name": "Class", "data-toc-label": "Class", "children": [ { "level": 2, "id": "tests.fixtures.nesting.Class.method", "html": IsStr(), "name": "method", "data-toc-label": "method", "children": [], }, ], }, ] mkdocstrings-0.29.0/tests/test_inventory.py000066400000000000000000000040461476356224100211370ustar00rootroot00000000000000"""Tests for the inventory module.""" from __future__ import annotations import sys from io import BytesIO from os.path import join import pytest from mkdocs.commands.build import build from mkdocs.config import load_config from mkdocstrings import Inventory, InventoryItem sphinx = pytest.importorskip("sphinx.util.inventory", reason="Sphinx is not installed") @pytest.mark.parametrize( "our_inv", [ Inventory(), Inventory([InventoryItem(name="object_path", domain="py", role="obj", uri="page_url")]), Inventory([InventoryItem(name="object_path", domain="py", role="obj", uri="page_url#object_path")]), Inventory([InventoryItem(name="object_path", domain="py", role="obj", uri="page_url#other_anchor")]), ], ) def test_sphinx_load_inventory_file(our_inv: Inventory) -> None: """Perform the 'live' inventory load test.""" buffer = BytesIO(our_inv.format_sphinx()) sphinx_inv = sphinx.InventoryFile.load(buffer, "", join) sphinx_inv_length = sum(len(sphinx_inv[key]) for key in sphinx_inv) assert sphinx_inv_length == len(our_inv.values()) for item in our_inv.values(): assert item.name in sphinx_inv[f"{item.domain}:{item.role}"] @pytest.mark.skipif(sys.version_info < (3, 7), reason="using plugins that require Python 3.7") def test_sphinx_load_mkdocstrings_inventory_file() -> None: """Perform the 'live' inventory load test on mkdocstrings own inventory.""" mkdocs_config = load_config() mkdocs_config["plugins"].run_event("startup", command="build", dirty=False) try: build(mkdocs_config) finally: mkdocs_config["plugins"].run_event("shutdown") own_inv = mkdocs_config["plugins"]["mkdocstrings"].handlers.inventory with open("site/objects.inv", "rb") as fp: sphinx_inv = sphinx.InventoryFile.load(fp, "", join) sphinx_inv_length = sum(len(sphinx_inv[key]) for key in sphinx_inv) assert sphinx_inv_length == len(own_inv.values()) for item in own_inv.values(): assert item.name in sphinx_inv[f"{item.domain}:{item.role}"] mkdocstrings-0.29.0/tests/test_loggers.py000066400000000000000000000033421476356224100205420ustar00rootroot00000000000000"""Tests for the loggers module.""" from unittest.mock import MagicMock import pytest from mkdocstrings import get_logger, get_template_logger @pytest.mark.parametrize( "kwargs", [ {}, {"once": False}, {"once": True}, ], ) def test_logger(kwargs: dict, caplog: pytest.LogCaptureFixture) -> None: """Test logger methods. Parameters: kwargs: Keyword arguments passed to the logger methods. """ logger = get_logger("mkdocstrings.test") caplog.set_level(0) for _ in range(2): logger.debug("Debug message", **kwargs) logger.info("Info message", **kwargs) logger.warning("Warning message", **kwargs) logger.error("Error message", **kwargs) logger.critical("Critical message", **kwargs) if kwargs.get("once", False): assert len(caplog.records) == 5 else: assert len(caplog.records) == 10 @pytest.mark.parametrize( "kwargs", [ {}, {"once": False}, {"once": True}, ], ) def test_template_logger(kwargs: dict, caplog: pytest.LogCaptureFixture) -> None: """Test template logger methods. Parameters: kwargs: Keyword arguments passed to the template logger methods. """ logger = get_template_logger() mock = MagicMock() caplog.set_level(0) for _ in range(2): logger.debug(mock, "Debug message", **kwargs) logger.info(mock, "Info message", **kwargs) logger.warning(mock, "Warning message", **kwargs) logger.error(mock, "Error message", **kwargs) logger.critical(mock, "Critical message", **kwargs) if kwargs.get("once", False): assert len(caplog.records) == 5 else: assert len(caplog.records) == 10 mkdocstrings-0.29.0/tests/test_plugin.py000066400000000000000000000047021476356224100203770ustar00rootroot00000000000000"""Tests for the mkdocstrings plugin.""" from __future__ import annotations from typing import TYPE_CHECKING from mkdocs.commands.build import build from mkdocs.config import load_config from mkdocstrings import MkdocstringsPlugin if TYPE_CHECKING: from pathlib import Path def test_disabling_plugin(tmp_path: Path) -> None: """Test disabling plugin.""" docs_dir = tmp_path / "docs" site_dir = tmp_path / "site" docs_dir.mkdir() site_dir.mkdir() docs_dir.joinpath("index.md").write_text("::: mkdocstrings") config_file = tmp_path / "mkdocs.yml" config_file.write_text( """ site_name: Test theme: mkdocs plugins: - mkdocstrings: enabled: false """, ) mkdocs_config = load_config(str(config_file)) mkdocs_config["docs_dir"] = str(docs_dir) mkdocs_config["site_dir"] = str(site_dir) mkdocs_config["plugins"].run_event("startup", command="build", dirty=False) try: build(mkdocs_config) finally: mkdocs_config["plugins"].run_event("shutdown") # make sure the instruction was not processed assert "::: mkdocstrings" in site_dir.joinpath("index.html").read_text() def test_plugin_default_config(tmp_path: Path) -> None: """Test default config options are set for Plugin.""" config_file_path = tmp_path / "mkdocs.yml" plugin = MkdocstringsPlugin() errors, warnings = plugin.load_config({}, config_file_path=str(config_file_path)) assert errors == [] assert warnings == [] assert plugin.config == { "handlers": {}, "default_handler": "python", "custom_templates": None, "enable_inventory": None, "enabled": True, } def test_plugin_config_custom_templates(tmp_path: Path) -> None: """Test custom_templates option is relative to config file.""" config_file_path = tmp_path / "mkdocs.yml" options = {"custom_templates": "docs/templates"} template_dir = tmp_path / options["custom_templates"] # Path must exist or config validation will fail. template_dir.mkdir(parents=True) plugin = MkdocstringsPlugin() errors, warnings = plugin.load_config(options, config_file_path=str(config_file_path)) assert errors == [] assert warnings == [] assert plugin.config == { "handlers": {}, "default_handler": "python", "custom_templates": str(template_dir), "enable_inventory": None, "enabled": True, } mkdocstrings-0.29.0/tests/tmp/000077500000000000000000000000001476356224100162655ustar00rootroot00000000000000mkdocstrings-0.29.0/tests/tmp/.gitkeep000066400000000000000000000000001476356224100177040ustar00rootroot00000000000000