Skip to content

IndentationError when using a multi-line decorator for a class method #246

@mrossinek

Description

@mrossinek

Problem Description

I encounter an IndentationError when trying to generate the documentation of a class which contains a multi-line decorator on a class method.

I believe that this is a limitation of the _dedent method but I do not have a good proposal for a solution yet. If we can discuss and figure out a good approach on how to resolve this I am happy to help with fixing the issue 👍
What would need to happen is that the actual function definition also gets dedented rather than simply the line following the decorator. See the example below.

Steps to reproduce the behavior:

I was able to break down the issue to the following example:

import pytest


class TestDummy:
    """Test Dummy."""

    @pytest.mark.parametrize(
        "arg,string",
        [
            ["hello", "world"],
        ],
    )
    def test_dummy(self, arg, string):
        """Dummy test method."""
        assert arg != string
Using `pdoc -o tmp example.py` generates the following error:
Traceback (most recent call last):
  File "/home/max/Git/cobib/.direnv/python-3.9.2/bin/pdoc", line 33, in <module>
    sys.exit(load_entry_point('pdoc', 'console_scripts', 'pdoc')())
  File "/home/max/Git/pdoc/pdoc/__main__.py", line 153, in cli
    pdoc.pdoc(
  File "/home/max/Git/pdoc/pdoc/__init__.py", line 386, in pdoc
    write(doc.Module(m))
  File "/home/max/Git/pdoc/pdoc/__init__.py", line 355, in write
    outfile.write_bytes(r(mod).encode())
  File "/home/max/Git/pdoc/pdoc/__init__.py", line 367, in r
    return render.html_module(module=mod, all_modules=all_modules)
  File "/home/max/Git/pdoc/pdoc/render.py", line 70, in html_module
    return env.select_template(
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "/home/max/Git/pdoc/pdoc/templates/default/module.html.jinja2", line 650, in top-level template code
    {%- if loop.nextitem %}.{% endif -%}
  File "/home/max/Git/pdoc/pdoc/templates/frame.html.jinja2", line 18, in top-level template code
    <body>{% block body %}{% endblock %}</body>
  File "/home/max/Git/pdoc/pdoc/templates/default/module.html.jinja2", line 722, in block "body"
    {% block module_contents %}
  File "/home/max/Git/pdoc/pdoc/templates/default/module.html.jinja2", line 729, in block "module_contents"
    {{ member(m) }}
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/runtime.py", line 679, in _invoke
    rv = self._func(*arguments)
  File "/home/max/Git/pdoc/pdoc/templates/default/module.html.jinja2", line 557, in template
    {{ function(doc) }}
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/runtime.py", line 679, in _invoke
    rv = self._func(*arguments)
  File "/home/max/Git/pdoc/pdoc/templates/default/module.html.jinja2", line 523, in template
    {{ decorators(fn) }}
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/runtime.py", line 679, in _invoke
    rv = self._func(*arguments)
  File "/home/max/Git/pdoc/pdoc/templates/default/module.html.jinja2", line 514, in template
    {% for d in doc.decorators if not d.startswith("@_") %}
  File "/home/max/Git/cobib/.direnv/python-3.9.2/lib/python3.9/site-packages/jinja2/environment.py", line 471, in getattr
    return getattr(obj, attribute)
  File "/usr/lib/python3.9/functools.py", line 969, in __get__
    val = self.func(instance)
  File "/home/max/Git/pdoc/pdoc/doc.py", line 767, in decorators
    for t in doc_ast.parse(obj).decorator_list:
  File "/home/max/Git/pdoc/pdoc/doc_ast.py", line 60, in parse
    return _parse_function(src)
  File "/home/max/Git/pdoc/pdoc/doc_ast.py", line 196, in _parse_function
    tree = ast.parse(_dedent(source))
  File "/usr/lib/python3.9/ast.py", line 50, in parse
    return compile(source, filename, mode, flags,
  File "<unknown>", line 7
    def test_dummy(self, arg, string):
IndentationError: unexpected indent

For additional details, this is what _dedent generates at the moment:

@pytest.mark.parametrize(
"arg,string",
        [
            ["hello", "world"],
        ],
    )
    def test_dummy(self, arg, string):
        """Dummy test method."""
        assert arg != string

The dedented string is not causing any problems but the remaining indent of the def test_dummy line eventually causes the error to arise.

System Information

A fresh checkout of main:

% pdoc --version
pdoc: 6.4.2 (+15, commit 8d133d2)
Python: 3.9.2
Platform: Linux-5.11.11-arch1-1-x86_64-with-glibc2.33

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions