Skip to content

bug: RecursionError when subclass is attribute #368

Closed
@patrick-kidger

Description

@patrick-kidger

Description of the bug

Code of the following form produces a RecursionError in griffe:

class X:
    pass

class Y(X):
    pass

X.Y = Y

To Reproduce

https://github.com/patrick-kidger/griffe-error

FWIW I'm providing this via mkdocs, as I didn't quite piece together the correct griffe.load(...) invocation to obtain this error. A simple griffe.load("mylib", force_inspection=True) does not raise the error.

Full traceback

Full traceback
INFO    -  Building documentation...
INFO    -  Cleaning site directory
ERROR   -  Error reading page 'foo.md': maximum recursion depth exceeded
Traceback (most recent call last):
  File ".../.venv/lib/python3.12/site-packages/click/core.py", line 1161, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/click/core.py", line 1082, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/click/core.py", line 1443, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocs/__main__.py", line 272, in serve_command
    serve.serve(**kwargs)
  File ".../.venv/lib/python3.12/site-packages/mkdocs/commands/serve.py", line 85, in serve
    builder(config)
  File ".../.venv/lib/python3.12/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 ".../.venv/lib/python3.12/site-packages/mkdocs/commands/build.py", line 310, in build
    _populate_page(file.page, config, files, dirty)
  File ".../.venv/lib/python3.12/site-packages/mkdocs/commands/build.py", line 167, in _populate_page
    page.render(config, files)
  File ".../.venv/lib/python3.12/site-packages/mkdocs/structure/pages.py", line 285, in render
    self.content = md.convert(self.markdown)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/markdown/core.py", line 357, in convert
    root = self.parser.parseDocument(self.lines).getroot()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/markdown/blockparser.py", line 117, in parseDocument
    self.parseChunk(self.root, '\n'.join(lines))
  File ".../.venv/lib/python3.12/site-packages/markdown/blockparser.py", line 136, in parseChunk
    self.parseBlocks(parent, text.split('\n\n'))
  File ".../.venv/lib/python3.12/site-packages/markdown/blockparser.py", line 158, in parseBlocks
    if processor.run(parent, blocks) is not False:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings/_internal/extension.py", line 126, in run
    html, handler, data = self._process_block(identifier, block, heading_level)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings/_internal/extension.py", line 201, in _process_block
    rendered = handler.render(data, options)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings_handlers/python/_internal/handler.py", line 294, in render
    return template.render(
           ^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/jinja2/environment.py", line 1295, in render
    self.environment.handle_exception()
  File ".../.venv/lib/python3.12/site-packages/jinja2/environment.py", line 942, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings_handlers/python/templates/material/class.html.jinja", line 1, in top-level template code
    {% extends "_base/class.html.jinja" %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja", line 120, in top-level template code
    {% block contents scoped %}
^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja", line 220, in block 'contents'
    {% block children scoped %}


... some thousand lines from jinja templating removed for brevity ...


  File ".../.venv/lib/python3.12/site-packages/mkdocstrings_handlers/python/templates/material/children.html.jinja", line 1, in top-level template code
    {% extends "_base/children.html.jinja" %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/mkdocstrings_handlers/python/templates/material/_base/children.html.jinja", line 13, in top-level template code
    {% if obj.all_members %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/jinja2/environment.py", line 490, in getattr
    return getattr(obj, attribute)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/mixins.py", line 299, in all_members
    if self.is_class:  # type: ignore[attr-defined]
       ^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 1345, in is_class
    return self.final_target.is_class
           ^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 1693, in final_target
    if target.path in paths_seen:
       ^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 1152, in path
    return f"{self.parent.path}.{self.name}"  # type: ignore[union-attr]
              ^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 1152, in path
    return f"{self.parent.path}.{self.name}"  # type: ignore[union-attr]
              ^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 1152, in path
    return f"{self.parent.path}.{self.name}"  # type: ignore[union-attr]
              ^^^^^^^^^^^^^^^^
  [Previous line repeated 134 more times]
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 856, in path
    return self.canonical_path
           ^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 868, in canonical_path
    return f"{self.parent.path}.{self.name}"
              ^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 856, in path
    return self.canonical_path
           ^^^^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 868, in canonical_path
    return f"{self.parent.path}.{self.name}"
              ^^^^^^^^^^^^^^^^
  File ".../.venv/lib/python3.12/site-packages/_griffe/models.py", line 856, in path
    return self.canonical_path
           ^^^^^^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded

Expected behavior

No crash :)

Environment information

- __System__: macOS-15.3.2-arm64-arm-64bit
- __Python__: cpython 3.12.0 (.../.venv/bin/python3)
- __Environment variables__:
- __Installed packages__:
  - `griffe` v1.6.2

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions