NiklasRosenstein / pydoc-markdown

Create Python API documentation in Markdown format.
http://niklasrosenstein.github.io/pydoc-markdown/
Other
449 stars 104 forks source link

Render Python DocTest correctly #327

Open Hocnonsense opened 1 month ago

Hocnonsense commented 1 month ago

Thanks for this usefull software!

Is your feature request related to a problem? Please describe.

I'm using pydoc-markdown to generate markdown files. However, all things in docstring will be write to markdown almost as-is, and when there is a function:

def iter_rsplit(s: str, sep=";"):
    """
    >>> list(iter_rsplit("a;b;c;d;e;f;g", ";"))
   ['a;b;c;d;e;f;g', 'a;b;c;d;e;f', 'a;b;c;d;e', 'a;b;c;d', 'a;b;c', 'a;b', 'a']
    """
   ...

However, it is not a clear way to view it

Describe the solution you'd like

I would like pydoc-markdown find >>> in docstring and render like this:

<a id="taxon.iter_rsplit"></a>

#### iter\_rsplit

\```python
def iter_rsplit(s: str, sep=";")
\```

example:
\```python
>>> list(iter_rsplit("a;b;c;d;e;f;g", ";"))
['a;b;c;d;e;f;g', 'a;b;c;d;e;f', 'a;b;c;d;e', 'a;b;c;d', 'a;b;c', 'a;b', 'a']
\```

Additional context

All backslashes preceding backquotes within code blocks solely serve to prevent Markdown formatting issues.

lraubuch commented 2 weeks ago

I have found a quick solution for myself for this particular problem. Since I have not tested it though I am not going to propose the change.

This is clearly a google style format, so I checked the contrib/processors/google.py file. My changes are only in two places of the _process method. I included the changed method below:

def _process(self, node: docspec.ApiObject):
        if not node.docstring:
            return

        lines = []
        current_lines: t.List[str] = []
        in_codeblock = False
        keyword = None

        def _commit():
            if keyword:
                generate_sections_markdown(lines, {keyword: current_lines})
            else:
                lines.extend(current_lines)
            current_lines.clear()

        for line in node.docstring.content.split("\n"):
            if line.lstrip().startswith("```"):
                in_codeblock = not in_codeblock
                current_lines.append(line)
                continue

            if in_codeblock:
                current_lines.append(line)
                continue

            line = line.strip()
            if line in self._keywords_map:
                _commit()
                keyword = self._keywords_map[line]
# new start
                if keyword == 'Examples':
                    current_lines.append('```python')
# new end
                continue

            if keyword is None:
                lines.append(line)
                continue

            for param_re in self._param_res:
                param_match = param_re.match(line)
                if param_match:
                    if "type" in param_match.groupdict():
                        current_lines.append("- `{param}` _{type}_ - {desc}".format(**param_match.groupdict()))
                    else:
                        current_lines.append("- `{param}` - {desc}".format(**param_match.groupdict()))
                    break

            if not param_match:
                current_lines.append("  {line}".format(line=line))
# new start
        if keyword == 'Examples':
            current_lines.append('```')
# new end
        _commit()
        node.docstring.content = "\n".join(lines)

I hope this helps in finding a solution that fits not only my problem

Hocnonsense commented 1 week ago

Thanks for your suggestion! However, after adding the two if keyword == 'Examples': block, nothing happened to my generated markdown files.