Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add annotation links in signature #65

Closed
dustinlagoy opened this issue Mar 24, 2023 · 4 comments
Closed

Add annotation links in signature #65

dustinlagoy opened this issue Mar 24, 2023 · 4 comments
Assignees

Comments

@dustinlagoy
Copy link

Is your feature request related to a problem? Please describe.
I often write functions/classes/etc which (I hope) are self-describing enough to exist without a docstring, or which have a docstring that doesn't describe all of the parameters. In this case the only place the parameters are shown are in the signature but their annotations do not contain links (when the annotation exists somewhere else in the codebase).

Describe the solution you'd like
It would be nice if there were an option to auto-generate these links similarly to how they are handled in the "Parameters" section created from the docstring. For example in the following signature:

def foo(baz: other_module.Baz) -> str:

I would like if the generated html contained a link to other_module.Baz.

Describe alternatives you've considered
Another option could be to create/update the docstring to add parameters based on the signature, similarly to how auto-docstring generators work but in this case leaving the original code untouched. I implemented a quick hack for this in griffe but I think it would require more work to make it a usable feature.

Additional context
I made a proof-of-concept patch (see below) to the function and signature templates to include links in a similar way to the docstring template. If this feature seems useful I could try to complete in a pull request (maybe adding a flag to turn it on/off and applying it to more than just the function template). The current released version makes a signature like:

original

And with my patch it looks like (the blue text has two correctly generated links):

patched

diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/function.html b/src/mkdocstrings_handlers/python/templates/material/_base/function.html
index b9b1696..cc1dacd 100644
--- a/src/mkdocstrings_handlers/python/templates/material/_base/function.html
+++ b/src/mkdocstrings_handlers/python/templates/material/_base/function.html
@@ -24,10 +24,10 @@
       {% if config.separate_signature %}
         <span class="doc doc-object-name doc-function-name">{% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %}</span>
       {% else %}
-        {% filter highlight(language="python", inline=True) %}
+        <span class="doc doc-object-name doc-function-name">
           {% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %}
           {% include "signature.html" with context %}
-        {% endfilter %}
+        </span>
       {% endif %}
 
       {% with labels = function.labels %}
diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/signature.html b/src/mkdocstrings_handlers/python/templates/material/_base/signature.html
index bc24ea3..40b7b4b 100644
--- a/src/mkdocstrings_handlers/python/templates/material/_base/signature.html
+++ b/src/mkdocstrings_handlers/python/templates/material/_base/signature.html
@@ -24,11 +24,21 @@
           {%- endif -%}
 
           {%- if config.show_signature_annotations and parameter.annotation is not none -%}
-            {%- set annotation = ": " + parameter.annotation|safe -%}
+            {%- set annotation -%}
+              {% with expression = parameter.annotation %}
+                {% include "expression.html" with context %}
+              {% endwith %}
+            {%- endset -%}
+            {%- set annotation = ": " + annotation -%}
           {%- endif -%}
 
           {%- if parameter.default is not none and parameter.kind.value != "variadic positional" and parameter.kind.value != "variadic keyword" -%}
-            {%- set default = ns.equal + parameter.default|safe -%}
+            {%- set default -%}
+              {% with expression = parameter.default %}
+                {% include "expression.html" with context %}
+              {% endwith %}
+            {%- endset -%}
+            {%- set default = ns.equal + default -%}
           {%- endif -%}
 
           {%- if parameter.kind.value == "variadic positional" -%}
@@ -42,7 +52,11 @@
         {%- endif -%}
       {%- endfor -%}
     )
-    {%- if config.show_signature_annotations and function.annotation %} -> {{ function.annotation|safe }}{%- endif -%}
+    {%- if config.show_signature_annotations and function.annotation %}
+      {% with expression = function.annotation %}
+        -> {% include "expression.html" with context %}
+      {% endwith %}
+    {%- endif -%}
 
   {%- endwith -%}
 {%- endif -%}
\ No newline at end of file
@pawamoy
Copy link
Member

pawamoy commented Apr 3, 2023

Hello! Thanks for the detailed feature request and proof-of-concept! It would indeed be nice to add links to corresponding objects in signature annotations. However, and as you can see, it's not trivial as we must be able to do three things on a same signature:

  • format it with Black
  • highlight it with Pygments
  • add cross-reference links

There's no straight-forward solution to this: there's no order that allow the three operations without breaking one.
Obviously Black can always be run first. But then we can't syntax highlight code with cross-ref spans in it, and once it is syntax highlighted it's too late to add cross-ref spans.

Still, I thought about it and I think it's doable with a more complex Jinja filter: the idea is to write cross-ref spans first, then stash and replace them with unique ids, that get replaced back with the stashed cross-ref after the highlighting process. I'll have time to work on this soon 🙂

@rodrigogiraoserrao
Copy link

rodrigogiraoserrao commented Apr 25, 2023

I was coming here to request this same feature.
Another great use case is for properties that you can usually just document with a single-line docstring:

@property
def some_property(self) -> SomeType:
    """The description of what you're getting."""
    ...

Typically, the type SomeType is an important part of the documentation of the property, but you'll only get a link to it if you expand the docstring to this:

@property
def some_property(self) -> SomeType:
    """The description of what you're getting.

    Returns:
        What you are getting.
    """
    ...

But now you have two duplicated sentences. If you remove the first, you are getting rid of the "most important part of the docstring".
I actually tried collapsing the Returns section into a single line:

@property
def some_property(self) -> SomeType:
    """Returns: Description of what you are getting."""
    ...

But then griffe will report an empty Returns section.

To add links to signatures, I tried modifying the .html templates and make use of expression.html to get the links but then I was breaking black formatting, as pawamoy mentioned.

Let me know if I can do anything to help you move this forward, although I have very limited knowledge of how this handler works internally.

rodrigogiraoserrao added a commit to Textualize/textual that referenced this issue Apr 25, 2023
We need to have explicit 'Returns:' sections in properties if we want to link to the return type while mkdocstrings/python#65 is open.
rodrigogiraoserrao added a commit to Textualize/textual that referenced this issue May 2, 2023
* Export types used in app.py

* Export more linked types/errors/classes.

* Remove custom template.

* Address review comments.

We need to have explicit 'Returns:' sections in properties if we want to link to the return type while mkdocstrings/python#65 is open.

* Improve docs.
@pawamoy pawamoy self-assigned this May 8, 2023
@pawamoy
Copy link
Member

pawamoy commented May 11, 2023

This feature is implemented as part of the insiders version of the Python handler, see https://mkdocstrings.github.io/python/usage/configuration/signatures/#signature_crossrefs

@pawamoy pawamoy closed this as completed May 11, 2023
@rodrigogiraoserrao
Copy link

This feature is implemented as part of the insiders version of the Python handler, see https://mkdocstrings.github.io/python/usage/configuration/signatures/#signature_crossrefs

Yup, I saw the fosstodon announcement! Thanks for your work.
I'll see you on the other side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants