mkdocstrings / python

A Python handler for mkdocstrings.
https://mkdocstrings.github.io/python
ISC License
191 stars 36 forks source link

`invalid syntax` error on function with docstring using `Annotated[]` #80

Closed johnthagen closed 1 year ago

johnthagen commented 1 year ago

Describe the bug

mkdocstrings-python/griffe fails to build documentation if function uses Annotated[] type annotation.

To Reproduce

strict: true
site_name: My Docs
nav:
  - index.md
  - "My page": my_page.md
plugins:
  - search
  - mkdocstrings
::: main.main
    handler: python
      show_root_heading: false
      show_source: false

Create a Typer application using Annotated[], which is the preferred way to use it:

# main.py
import typer
from typing_extensions import Annotated

def main(name: Annotated[str, typer.Argument(help="My Name")]):
    """Test"""
    print(f"Hello {name}")

if __name__ == "__main__":
    typer.run(main)
$ mkdocs serve
INFO     -  Building documentation...
INFO     -  Cleaning site directory
ERROR    -  griffe: main.py:5: Failed to get annotation expression from Subscript: invalid syntax (<string-annotation>, line
            1)

Aborted with 1 errors in strict mode!

Expected behavior

No warnings or errors generated and documentation builds/renders successfully.

System (please complete the following information):

Additional context

$ python -m pip list 
Package             Version
------------------- -------
click               8.1.3
colorama            0.4.6
ghp-import          2.1.0
griffe              0.29.0
Jinja2              3.1.2
Markdown            3.3.7
MarkupSafe          2.1.3
mergedeep           1.3.4
mkdocs              1.4.3
mkdocs-autorefs     0.4.1
mkdocstrings        0.22.0
mkdocstrings-python 1.1.2
packaging           23.1
pip                 23.1.2
pymdown-extensions  10.0.1
python-dateutil     2.8.2
PyYAML              6.0
pyyaml_env_tag      0.1
six                 1.16.0
typer               0.9.0
typing_extensions   4.6.3
watchdog            3.0.0
wheel               0.40.0
pawamoy commented 1 year ago

Immediate workaround: add from __future__ import annotations at the top of your module.

Explanation: The issue is that we have to support forward references and explicit string annotations:

class A:
    def method(self) -> "A": ...

def func() -> "tuple[Any, ...]": ...

...while also supporting string literals:

def func() -> Literal["hello"]: ...

...which is not as easy as it seems.

Adding from __future__ import annotations at the top helps, because we detect it and then can avoid trying to (re)parse strings in annotations.

In your case, without this import, we try to parse "My name", which obviously fails with a syntax error.

Possible solution: instead of failing on the syntax error and logging a warning, we could fallback to just use this part of the annotation as a string.

johnthagen commented 1 year ago

@pawamoy Thank you for the prompt response and explanation!

Just wanted to confirm that when 53827c8 is released onto PyPI, will this issue be fixed, or will from __future__ import annotations still be required?

pawamoy commented 1 year ago

Thanks for asking: no, you won't need from __future__ import annotations :)

johnthagen commented 1 year ago

Okay, great. Thanks for the great package!

johnthagen commented 1 year ago

Wanted to confirm that this issue was fixed after updating to griffe 0.29.1.