Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docstring support #719

Open
garthk opened this issue Feb 2, 2024 · 2 comments
Open

docstring support #719

garthk opened this issue Feb 2, 2024 · 2 comments
Labels
enhancement New feature or request

Comments

@garthk
Copy link

garthk commented Feb 2, 2024

Description

Please render Python docstrings in cells as Markdown above the cell.

"The functions in this cell..."

I'm coming to Marimo as an old time Python programmer. I'm loving the predictable execution order—thanks!—but it feels odd to have to create dedicated cells to provide narrative text before some code.

Python, you see, has long provided a method for exactly this purpose: the humble docstring (Pandas docs).

def __():
    """This text is a function's docstring."""
    return

Please render my docstrings as Markdown above the code whenever the code is hidden.

Suggested solution

I dug into the app.cell decorator, and confirmed it could take the function's docstring and put it somewhere useful. I tried hacking it in as a replacement for an empty last_expr, but that's a terrible idea. What if you need both? You'll know what to do. It might even be quick, and fun.

Alternative

Marimo could support plain Markdown cells with always-hidden code, provide a WYSIWYG editor for them, and provide an upgrade path by spotting the characteristic shape of the older way of doing it:

@app.cell(hide_code=True)
def __(mo):
    mo.md("Automatic Markdown would be _so nice_.")
    return

That's has less of your "everything you type is Python" vibe, though.

Additional context

If you put a string at the top of a Python file, that string becomes that module's documentation, available as __doc__. You'll see it if you run help on the REPL, and it's the basis for the automatically rendered docs for the Python standard library and other Python packages.

You can also get to it from inside your Python code:

>>> import os, sys, inspect, textwrap
>>> doc = inspect.cleandoc(sys.__doc__)
>>> print(textwrap.fill(doc, 78, max_lines=2))
This module provides access to some objects used or maintained by the
interpreter and to functions that interact strongly with the [...]
>>>

The same is true of a function:

>>> import marimo
>>> app = marimo.App()
>>> @app.cell
... def __():
...     """This would be awesome rendered to Markdown and displayed
...     above the cell."""
...
>>> doc = inspect.cleandoc(__.__doc__)
>>> print(textwrap.fill(doc, 78))
This would be awesome rendered to Markdown and displayed above the cell.
>>>

Ruff's Black-compatible formatter can handle Markdown fenced code in docstrings as of astral-sh/ruff#9030. So, this change would go particularly well with #546 to cover the edge case of someone putting Python code in their Python docstrings.

The MyST Markdown parser includes support for LaTeX markup for math and equations, and can be used across any project's documentation including its docstrings with sphinx-autodoc2's autodoc2-docstring and other supported extensions. Imagine, out of the box, being able to type the following into the top of a cell:

"""
Since Pythagoras, we know that {math}`a^2 + b^2 = c^2`.

```{math}
:label: mymath
(a + b)^2 = a^2 + 2ab + b^2

(a + b)^2  &=  (a + b)(a + b) \\
        &=  a^2 + 2ab + b^2
```

The equation {eq}`mymath` is a quadratic equation.
"""

… and have it come out like this:

oh, that's lovely

@akshayka
Copy link
Contributor

akshayka commented Feb 2, 2024

Thanks for taking the time to write such a thoughtful feature request.

Re: rendering docstrings as markdown

We may be able to support something like this; an implementation quirk of our runtime is that cells are represented as just a block of code, not wrapped in a function ... but we could keep them as functions, which would let us easily access the docstring and include it as part of the cell's output.

Stepping back, as a user, which would you prefer: rendering docstrings as markdown, or a WISYWIG markdown editor?

@akshayka akshayka added the enhancement New feature or request label Apr 12, 2024
@dmadisetti
Copy link
Contributor

I thought about this recently because I have the pattern

@app.cell
def _my_fn(np, other_libs):
  def fn(a,b,c):
    """doc string"""
    # logic
    return whatever
  return fn

and then in my __init__

def unwrap_mo(fn):
  return fn()
from notebook import  _my_fn
my_fn = unwrap(_my_fn)

to enable easier importing from another notebook and using fn directly. Proposal for less friction:

@app.fn
def my_fn(a, b, c, *, np, other_libs): # Abuse * to separate user vs graph arguments
    """doc string"""
    # logic
    return whatever

Which is much cleaner than the nested functions for off editor changes.
In editor, the cell could render the doc string as markdown output. Need a bit of thought into how to make args editable, but name is already present, so maybe cue off name? Allow the user to set name to something like my_fn(a,b,c) which is then appropriately parsed. This is nice because it'll be instantly compatible with the markdown format too, since name is already carried. Plus doesn't need any UI change.

Implementation-wise, @app.fn could just make a cell under the hood, wrap the function in a formatter as output, and then declare my_fn as the only def.

assertions

  • name does not contain a , *, since that's used for graph defs
  • args do not interfere with global defs (potentially lead to confusion)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants