mkdocstrings / griffe-pydantic

Griffe extension for Pydantic.
https://mkdocstrings.github.io/griffe-pydantic/
ISC License
7 stars 2 forks source link

bug: griffe-pydantic crashes when mode='before' is added to field_validator #2

Closed Benjamin-T closed 6 months ago

Benjamin-T commented 6 months ago

Description of the bug

When the example model is modified to have a field_validator with keyword argument mode='before' griffe crashes.

To Reproduce

class ExampleModel(BaseModel):
    """An example {info}."""

    model_config = ConfigDict(frozen=False)

    field_without_default: str
    """Shows the *[Required]* marker in the signature."""

    field_plain_with_validator: int = 100
    """Show standard field with type annotation."""

    field_with_validator_and_alias: str = Field("FooBar", alias="BarFoo", validation_alias="BarFoo")
    """Shows corresponding validator with link/anchor."""

    field_with_constraints_and_description: int = Field(
        default=5, ge=0, le=100, description="Shows constraints within doc string."
    )

    @field_validator("field_with_validator_and_alias", "field_without_default", mode="before") # <<-- mind the 'mode='before'
    @classmethod
    def check_max_length_ten(cls, v) -> str:
        """Show corresponding field with link/anchor."""
        if len(v) >= 10:
            raise ValueError("No more than 10 characters allowed")
        return v

Full traceback

(c:\gitlab\mkdocs_experiments\.conda) PS C:\gitlab\mkdocs_experiments> mkdocs serve
INFO    -  Building documentation...
INFO    -  Cleaning site directory
INFO    -  mkdocstrings_handlers: .conda\Lib\site-packages\griffe_pydantic\templates\material\pydantic_model.html: DeprecationWarning: Extending '_base/class.html' is deprecated, extend '_base/class.html.jinja'           instead. After some time, this message will be logged as a warning, causing strict builds to fail.
INFO    -  Documentation built in 0.88 seconds
INFO    -  [21:16:41] Watching paths for changes: 'docs', 'mkdocs.yml'
INFO    -  [21:16:41] Serving on http://127.0.0.1:8000/
INFO    -  [21:17:11] Detected file changes
INFO    -  Building documentation...
INFO    -  mkdocstrings_handlers: .conda\Lib\site-packages\griffe_pydantic\templates\material\pydantic_model.html: DeprecationWarning: Extending '_base/class.html' is deprecated, extend '_base/class.html.jinja'           instead. After some time, this message will be logged as a warning, causing strict builds to fail.
INFO    -  Documentation built in 1.03 seconds
INFO    -  [21:17:12] Reloading browsers
INFO    -  [21:17:29] Detected file changes
INFO    -  Building documentation...
ERROR   -  Error reading page 'index.md': malformed node or string: ExprKeyword(name='mode', value="'before'", function=ExprName(name='field_validator', parent=Class('ExampleModel', 37, 61)))
Traceback (most recent call last):
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocs\livereload\__init__.py", line 211, in _build_loop
    self.builder()
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocs\commands\serve.py", line 67, in builder
    build(config, serve_url=None if is_clean else serve_url, dirty=is_dirty)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocs\commands\build.py", line 310, in build
    _populate_page(file.page, config, files, dirty)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocs\commands\build.py", line 167, in _populate_page
    page.render(config, files)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocs\structure\pages.py", line 285, in render
    self.content = md.convert(self.markdown)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\markdown\core.py", line 357, in convert
    root = self.parser.parseDocument(self.lines).getroot()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\markdown\blockparser.py", line 117, in parseDocument
    self.parseChunk(self.root, '\n'.join(lines))
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\markdown\blockparser.py", line 136, in parseChunk
    self.parseBlocks(parent, text.split('\n\n'))
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\markdown\blockparser.py", line 158, in parseBlocks
    if processor.run(parent, blocks) is not False:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocstrings\extension.py", line 128, in run
    html, handler, data = self._process_block(identifier, block, heading_level)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocstrings\extension.py", line 210, in _process_block
    data: CollectorItem = handler.collect(identifier, options)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\mkdocstrings_handlers\python\handler.py", line 315, in collect
    loader.load(
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe\loader.py", line 233, in load
    self.extensions.call("on_package_loaded", pkg=obj)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe\extensions\base.py", line 345, in call
    getattr(extension, event)(**kwargs)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe_pydantic\extension.py", line 42, in on_package_loaded
    static.process_module(pkg, processed=self.processed, schema=self.schema)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe_pydantic\static.py", line 165, in process_module
    process_module(submodule, processed=processed, schema=schema)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe_pydantic\static.py", line 162, in process_module
    process_class(cls, processed=processed, schema=schema)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe_pydantic\static.py", line 145, in process_class
    process_function(member, cls, processed=processed)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe_pydantic\static.py", line 111, in process_function
    fields = [ast.literal_eval(field) for field in decorator.arguments]  # type: ignore[arg-type]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\site-packages\griffe_pydantic\static.py", line 111, in <listcomp>
    fields = [ast.literal_eval(field) for field in decorator.arguments]  # type: ignore[arg-type]
              ^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\ast.py", line 110, in literal_eval
    return _convert(node_or_string)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\ast.py", line 109, in _convert
    return _convert_signed_num(node)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\ast.py", line 83, in _convert_signed_num
    return _convert_num(node)
           ^^^^^^^^^^^^^^^^^^
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\ast.py", line 74, in _convert_num
    _raise_malformed_node(node)
  File "c:\gitlab\mkdocs_experiments\.conda\Lib\ast.py", line 71, in _raise_malformed_node
    raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string: ExprKeyword(name='mode', value="'before'", function=ExprName(name='field_validator', parent=Class('ExampleModel', 37, 61)))
ERROR   -  [21:17:30] An error happened during the rebuild. The server will appear stuck until build errors are resolved.

Expected behavior

render correctly

Environment information

[tool.poetry.dependencies]
python = "^3.11"
pydantic = "^2.7.1"
griffe = "0.45.2"
mkdocs = "^1.6.0"
mkdocs-material = "^9.5.24"
mkdocstrings = "^0.25.1"
mkdocstrings-python = "^1.10.3"
ruamel-yaml = "^0.18.6"
pydantic-yaml = "^1.3.0"
pawamoy commented 6 months ago

Hi @Benjamin-T, thanks a lot for the report! I see what's going wrong (griffe-pydantic simply didn't expect to see non-strings arguments inside @field_validator decorators). I should be able to fix this before next week :slightly_smiling_face:

pawamoy commented 6 months ago

Fixed, tackling next issue before release.