diff --git a/docs/insiders/changelog.md b/docs/insiders/changelog.md index ab70887a..a6c7b907 100644 --- a/docs/insiders/changelog.md +++ b/docs/insiders/changelog.md @@ -2,6 +2,11 @@ ## mkdocstrings-python Insiders +### 1.9.0 September 03, 2024 { id="1.9.0" } + +- [Relative cross-references][relative_crossrefs] +- [Scoped cross-references][scoped_crossrefs] + ### 1.8.3 June 19, 2024 { id="1.8.3" } - Update code for Griffe 0.46+ to avoid deprecation warnings diff --git a/docs/insiders/goals.yml b/docs/insiders/goals.yml index 57985eae..16d1d507 100644 --- a/docs/insiders/goals.yml +++ b/docs/insiders/goals.yml @@ -37,3 +37,8 @@ goals: name: FusionDrive Ejection Configuration features: - name: Relative cross-references + ref: /usage/configuration/docstrings/#relative_crossrefs + since: 2024/09/03 + - name: Scoped cross-references + ref: /usage/configuration/docstrings/#scoped_crossrefs + since: 2024/09/03 diff --git a/docs/usage/configuration/docstrings.md b/docs/usage/configuration/docstrings.md index 027ebaed..d88cbbfb 100644 --- a/docs/usage/configuration/docstrings.md +++ b/docs/usage/configuration/docstrings.md @@ -317,6 +317,226 @@ class Thing: //// /// +## `relative_crossrefs` + +[:octicons-heart-fill-24:{ .pulse } Sponsors only](../../insiders/index.md){ .insiders } — +[:octicons-tag-24: Insiders 1.9.0](../../insiders/changelog.md#1.9.0) + +- **:octicons-package-24: Type [`bool`][] :material-equal: `False`{ title="default value" }** + + +Whether to enable the relative-crossref syntax. + +The relative-crossref syntax lets you reference the current object or its parent by prefixing a crossref identifier with dots. For example, to cross-reference the current object's `name` member, you can write `[link to name attribute][.name]`. The "current object" is the object containing the docstring being rendered. + + +```yaml title="in mkdocs.yml (global configuration)" +plugins: +- mkdocstrings: + handlers: + python: + options: + relative_crossrefs: false +``` + +```md title="or in docs/some_page.md (local configuration)" +::: path.to.module + options: + relative_crossrefs: true +``` + +/// admonition | Examples + type: preview + +```python title="pkg/module.py" +"""Summary. + +- Link to [`module`][.]. +- Link to [`module_attribute`][.module_attribute]. +- Link to [`Class`][.Class]. +- Link to [`class_attribute`][.Class.class_attribute]. +- Link to [`instance_attribute`][.Class.instance_attribute]. +- Link to [`method`][.Class.method]. +""" + +module_attribute = 0 +"""Summary. + +- Link to [`module`][..]. +- Link to [`module_attribute`][.]. +- Link to [`Class`][..Class]. +- Link to [`class_attribute`][..Class.class_attribute]. +- Link to [`instance_attribute`][..Class.instance_attribute]. +- Link to [`method`][..Class.method]. +""" + +class Class: + """Summary. + + - Link to [`module`][..]. + - Link to [`module_attribute`][..module_attribute]. + - Link to [`Class`][.]. + - Link to [`class_attribute`][.class_attribute]. + - Link to [`instance_attribute`][.instance_attribute]. + - Link to [`method`][.method]. + """ + + class_attribute = 0 + """Summary. + + - Link to [`module`][...]. + - Link to [`module_attribute`][...module_attribute]. + - Link to [`Class`][..]. + - Link to [`class_attribute`][.]. + - Link to [`instance_attribute`][..instance_attribute]. + - Link to [`method`][..method]. + """ + + def __init__(self): + """Summary. + + - Link to [`module`][...]. + - Link to [`module_attribute`][...module_attribute]. + - Link to [`Class`][..]. + - Link to [`class_attribute`][..class_attribute]. + - Link to [`instance_attribute`][..instance_attribute]. + - Link to [`method`][..method]. + """ + self.instance_attribute = 0 + """Summary. + + - Link to [`module`][...]. + - Link to [`module_attribute`][...module_attribute]. + - Link to [`Class`][..]. + - Link to [`class_attribute`][..class_attribute]. + - Link to [`instance_attribute`][.]. + - Link to [`method`][..method]. + """ + + def method(self): + """Summary. + + - Link to [`module`][...]. + - Link to [`module_attribute`][...module_attribute]. + - Link to [`Class`][..]. + - Link to [`class_attribute`][..class_attribute]. + - Link to [`instance_attribute`][..instance_attribute]. + - Link to [`method`][.]. + """ +``` + +/// + + +## `scoped_crossrefs` + +[:octicons-heart-fill-24:{ .pulse } Sponsors only](../../insiders/index.md){ .insiders } — +[:octicons-tag-24: Insiders 1.9.0](../../insiders/changelog.md#1.9.0) + +- **:octicons-package-24: Type [`bool`][] :material-equal: `False`{ title="default value" }** + + +Whether to enable scoped cross-references. + +With scoped cross-references, you can write identifiers as if you wanted to access them from the current object's scope. The scoping rules do not exactly match Python's: you can reference members and siblings too, without prefixing with `self.` or `cls.`. + +The following order is applied when resolving a name in a given scope: + +1. member of the current object +2. parent class +3. repeat 1-2 within parent's scope + +In practice, it means that the name is first looked up in members, then it is compared against the parent name (only if it's a class), then it is looked up in siblings. It continues climbing up the object tree until there's no parent, in which case it raises a name resolution error. + +Cross-referencing an imported object will directly link to this object if the objects inventory of the project it comes from was [loaded][import]. You won't be able to cross-reference it within your own documentation with scoped references, if you happen to be rendering this external object too. In that case, you can use an absolute reference or a [relative][relative_crossrefs] one instead. + +Another limitation is that you won't be able to reference an external package if its name can be resolved in the current object's scope. + +```yaml title="in mkdocs.yml (global configuration)" +plugins: +- mkdocstrings: + handlers: + python: + options: + scoped_crossrefs: false +``` + +```md title="or in docs/some_page.md (local configuration)" +::: path.to.module + options: + scoped_crossrefs: true +``` + +/// admonition | Examples + type: preview + +```python title="pkg/module.py" +"""Summary. + +- Link to [`module_attribute`][module_attribute]. +- Link to [`Class`][Class]. +- Link to [`class_attribute`][Class.class_attribute]. +- Link to [`instance_attribute`][Class.instance_attribute]. +- Link to [`method`][Class.method]. +""" + +module_attribute = 0 +"""Summary. + +- Link to [`Class`][Class]. +- Link to [`class_attribute`][Class.class_attribute]. +- Link to [`instance_attribute`][Class.instance_attribute]. +- Link to [`method`][Class.method]. +""" + +class Class: + """Summary. + + - Link to [`module_attribute`][module_attribute]. + - Link to [`class_attribute`][class_attribute]. + - Link to [`instance_attribute`][instance_attribute]. + - Link to [`method`][method]. + """ + + class_attribute = 0 + """Summary. + + - Link to [`module_attribute`][module_attribute]. + - Link to [`Class`][Class]. + - Link to [`instance_attribute`][instance_attribute]. + - Link to [`method`][method]. + """ + + def __init__(self): + """Summary. + + - Link to [`module_attribute`][module_attribute]. + - Link to [`Class`][Class]. + - Link to [`class_attribute`][class_attribute]. + - Link to [`instance_attribute`][instance_attribute]. + - Link to [`method`][method]. + """ + self.instance_attribute = 0 + """Summary. + + - Link to [`module_attribute`][module_attribute]. + - Link to [`Class`][Class]. + - Link to [`class_attribute`][class_attribute]. + - Link to [`method`][method]. + """ + + def method(self): + """Summary. + + - Link to [`module_attribute`][module_attribute]. + - Link to [`Class`][Class]. + - Link to [`class_attribute`][class_attribute]. + - Link to [`instance_attribute`][instance_attribute]. + """ +``` + +/// + ## `show_if_no_docstring` - **:octicons-package-24: Type [`bool`][] :material-equal: `False`{ title="default value" }** diff --git a/src/mkdocstrings_handlers/python/handler.py b/src/mkdocstrings_handlers/python/handler.py index eb1d73c7..ef93ee3b 100644 --- a/src/mkdocstrings_handlers/python/handler.py +++ b/src/mkdocstrings_handlers/python/handler.py @@ -85,6 +85,8 @@ class PythonHandler(BaseHandler): "separate_signature": False, "line_length": 60, "merge_init_into_class": False, + "relative_crossrefs": False, + "scoped_crossrefs": False, "show_docstring_attributes": True, "show_docstring_functions": True, "show_docstring_classes": True, @@ -168,6 +170,8 @@ class PythonHandler(BaseHandler): docstring_options (dict): The options for the docstring parser. See [docstring parsers](https://mkdocstrings.github.io/griffe/reference/docstrings/) and their options in Griffe docs. docstring_section_style (str): The style used to render docstring sections. Options: `table`, `list`, `spacy`. Default: `"table"`. merge_init_into_class (bool): Whether to merge the `__init__` method into the class' signature and docstring. Default: `False`. + relative_crossrefs (bool): Whether to enable the relative crossref syntax. Default: `False`. + scoped_crossrefs (bool): Whether to enable the scoped crossref ability. Default: `False`. show_if_no_docstring (bool): Show the object heading even if it has no docstring or children with docstrings. Default: `False`. show_docstring_attributes (bool): Whether to display the "Attributes" section in the object's docstring. Default: `True`. show_docstring_functions (bool): Whether to display the "Functions" or "Methods" sections in the object's docstring. Default: `True`. diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja index 27a91d13..fd13661b 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja @@ -133,8 +133,10 @@ Context: {% endwith %} {% if config.merge_init_into_class %} {% if "__init__" in class.all_members and class.all_members["__init__"].has_docstring %} - {% with docstring_sections = class.all_members["__init__"].docstring.parsed %} - {% include "docstring"|get_template with context %} + {% with function = class.all_members["__init__"] %} + {% with obj = function, docstring_sections = function.docstring.parsed %} + {% include "docstring"|get_template with context %} + {% endwith %} {% endwith %} {% endif %} {% endif %}