Skip to content

docs: Add Python to the generated Markdown tool doc #5490

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

Merged
merged 6 commits into from
Apr 10, 2025

Conversation

wenzeslaus
Copy link
Member

@wenzeslaus wenzeslaus commented Apr 1, 2025

This completely revamps the generated header for tool documentation pages, and it adds Python syntax for the tool and Python-oriented parameter description. The Python part is similar, but not the same to what is generated by Sphinx autodoc. I tried to make like it while accommodating the metadata we have (key desc strings, label and description for flags), while working with the Markdown syntax (we generate pure and simple Markdown which is only later translated to HTML in generic way, not knowing about the context or language).

Most of the headings are removed for both CLI and Python, key-value parameters go before flags for both, and the idea makes heavy use of synchronized tabs.

Top of the page

Current New: CLI New: Python
image image image
Note what is (not) visible right at the beginning... ...and what is visible here. Python has the same pieces with changes to syntax as appropriate.
(no language indicated) Command line Python (grass.script)

Generated example Python calls

gs.run_command("r.neighbors", input="name", output="name")
gs.run_command("r.watershed", elevation="name", accumulation="name")
gs.parse_command("v.db.select", map="name", format="json")
gs.parse_command("r.univar", map="name", format="json")
gs.run_command("r.slope.aspect", elevation="name", slope="name")  # with a local fix for rules
gs.run_command("r.stats", input="name")
gs.run_command("r.what.color", input="name")  # with a local fix for input
gs.run_command("r.category", map="name", output_format="plain")
gs.run_command("r.null", map="name")
gs.run_command("g.copy")  # the rules don't allow dynamic parameters like g.copy has

This completely revamps the generated header for tool documentation pages, and it adds Python syntax for the tool and Python-oriented parameter description. The Python part is similar, but not the same to what is generated by Sphinx autodoc. I tried to make like it while accomodating the metadata we have (key desc strings, label and description for flags), while working with the Markdown syntax (we generate pure and simple Markdown which is only later translated to HTML in generic way, not knowing about the context or language).

Most of the headings are removed for both CLI and Python, key-value parameters go before flags for both, and the idea makes heavy use of synchronized tabs.
@echoix
Copy link
Member

echoix commented Apr 1, 2025

For the example part, since I imagine it being difficult to be right in all cases, would there be a possibility to override the example manually with a valid example?

@echoix
Copy link
Member

echoix commented Apr 1, 2025

Overall it's really nice, especially for the CLI one (are the flags still there in the case of the middle picture?)!

@wenzeslaus
Copy link
Member Author

Adding more info to the metadata is possible. It would be useful at other places too. We can keep a list of ideas. I was thinking about overriding the run_command vs parse_command choice even for the general syntax block.

For this PR, we need to come up with rules which will give good results with the existing metadata. There is already a lot of info available. For example, the additional rules are not touched at all.

@github-actions github-actions bot added C Related code is in C libraries docs labels Apr 2, 2025
@hellik
Copy link
Member

hellik commented Apr 2, 2025

Very nice!

It is called

Command Line (bash)

though in winGRASS we don't have a bash, only a Windows command line

@neteler
Copy link
Member

neteler commented Apr 2, 2025

Very nice!

though in winGRASS we don't have a bash, only a Windows command line

Perhaps remove the "(bash)" as there are also other shells like zsh, etc. Or call it "(shell)"?

@wenzeslaus
Copy link
Member Author

Command line seems good here. It should be shell-neutral. What about later, in the examples? There we often use Bash specifically. Note that the tabs are synced like you can see e.g. in GitHub doc.

The story for Python may also be more complicated with the examples section.

@wenzeslaus
Copy link
Member Author

...it's really nice, especially for the CLI one

I'm interested, what do you like with the CLI and why you give Python a lower ranking?

(are the flags still there in the case of the middle picture?)!

The flags are there at the end. For Python, the short flags are treated in a special way, differently from how allowed values with description would be treated (think e.g. format), although that's what they are from Python perspective.

Flags in CLI and Python

image

@wenzeslaus
Copy link
Member Author

Any suggestions how to show the type information in Python? ...or any of the other info.

r.neighbors: input, output, size, method, ...

image

g.copy: raster, raster_3d

image

r.watershed: memory

image

@echoix
Copy link
Member

echoix commented Apr 2, 2025

I'm interested, what do you like with the CLI and why you give Python a lower ranking?

I don't know, the way it was spaced out, not too much on the line that showed the name of argument, so it was kinda smooth visually to find the structure of what is indented.

But it's kinda similar when I look today.

The Python full signature is kinda hard to follow as it is jammed, but probably required to be shown exhaustively at least once, as source of truth.

@echoix
Copy link
Member

echoix commented Apr 2, 2025

The flags are there at the end. For Python, the short flags are treated in a special way, differently from how allowed values with description would be treated (think e.g. format), although that's what they are from Python perspective.

The flags layout for Python is quite easy to follow (visually) without even reading!

@echoix
Copy link
Member

echoix commented Apr 2, 2025

Any suggestions how to show the type information in Python? ...or any of the other info.

Using Python type annotations maybe? How does mkdocsstrings through griffe present it with markdown? Or even sphinx? https://mkdocstrings.github.io/griffe/
https://github.com/mkdocstrings/mkdocstrings

r.neighbors: input, output, size, method, ...

image

g.copy: raster, raster_3d

image

I don't understand what from, to is as an annotation with code markup.

r.watershed: memory

image

Memory in MB, where does it come from? Is it a Python module (tool) that has this info in the parser metadata?

@wenzeslaus
Copy link
Member Author

Using Python type annotations maybe?

That's what I was thinking, but I started with what I saw in pandoc doc.

How does mkdocsstrings through griffe present it with markdown? Or even sphinx? https://mkdocstrings.github.io/griffe/ https://github.com/mkdocstrings/mkdocstrings

mkdocstrings may be something which we end up using for the Python part (but that's a migration for another time).

On the other hand, just having the same thing as what we will have in the source code makes sense. Also something readable by non-experts like list[str] vs Iterable[Str]. I just didn't do much research on this.

I don't understand what from, to is as an annotation with code markup.

Memory in MB, where does it come from? Is it a Python module (tool) that has this info in the parser metadata?

Both from,to and memory in MB are key_desc which is what goes after the key_name= in command line doc. See the current g.copy doc as an example. It would be nice to have that additional info there, but it is also very unspecific. from,to can be "old_name,new_name" in Python, but also ("old_name", "new_name"). However, for display tool, it would likely be "10,50" or (10, 50). On the other hand, memory in MB would be 300. This is another place to extent the tool metadata, but for now, this is what we have.

… output aka new prompt) and show first parameter from a group of 'at least one required'. Fix C warnings.
@wenzeslaus
Copy link
Member Author

I added the generated Python examples to the description. While I hit some limitations, it is pretty impressive what we can do with the current tool metadata. I have two open questions here:

  1. How the detailed description in Python should look like? (esp types, but also the key_desc, both discussed above)
  2. Should command line also have an example and how that example should look like? (it should be easier to create than for Python)

Then I need to organize the code better and it will be good to go.

Assuming this builds, if you download the artifact from Documentation workflow, you should get the full version including addons.

…xample for CLI. Add function parameter file instead of hardcoding stdout. Fix CLI synopsis for tools without flags.
…ameter as tuple, so the basic type is actually wrong (e.g. string or iterable of ints rather than int). Even the synopsis for Python is wrong without this info as ints or floats can just be comma-separated without that info because default answer (values) will include multiple values for tuples. Now tuples in default values are represented as strings in synopsis (aka short version) which is the simpler solution, but I used the more complicated code only for the actual type in the parameters section (aka long version). The key_desc to tuple comes from parser.c code which is little different and requires a separate change.
@wenzeslaus
Copy link
Member Author

Tuples of ints and floats in Python are no longer just the numbers and commas, but they are now strings (which happens to be actually how the underlying implementation works, but I'm made that choice mostly to keep the code simple):

image

For the types, I used the same info to show the type as tuple rather than int or float. It gets complicated when multiple values are allowed. The parameter can be tuple, list of tuples, list, or a comma-separated string. I don't show all the options a this point, but I show most.

For simple multiple, we don't have a way of expressing "this can have more than one item, but usually it has one item" versus "this is expected to be more than one item" versus "this is required to be more than one item". Consequently, I consider "multiple" to expect one item by default (the first case), so r.univar gives expected result (str as first type) while r.series is suboptimal (list type is only a second type listed).

g.copy - classic tuples

image

r.univar - classic multiple

image

m.nviz.image - long tuple

image

@wenzeslaus wenzeslaus marked this pull request as ready for review April 4, 2025 20:13
@wenzeslaus
Copy link
Member Author

I added the generated example for the command line and used only str, float, int, list, tuple (possibly nested) in the Python types (but no Iterable).

This is now ready ready for review.

wenzeslaus added a commit to wenzeslaus/grass that referenced this pull request Apr 4, 2025
This uses a function to get the required number of items in a tuple if the parameter value is defined as a tuple using key_desc. This is a first step to providing this information in the API and tool metadata which is important because it has implications for type (tool option parameter of type int with key_desc with comma has to have the comma, so it is actually not an int in e.g. Python).

There is little more what can be done here and that's not doing the check when there is no tuple, but this would be better done with some tests in place for this parser feature.

The function is actually already in OSGeo#5490 so this is a draft also for this reason, but the logic should be reviewable.
@echoix
Copy link
Member

echoix commented Apr 4, 2025

Separating union of different types with a comma, but also separating the elements of a tuple with a comma, and also using the comma in between the types, the key descr from metadata, and between the optional indicator is probably confusing, at least for me, especially on a same line. If we are to show Python types, we might as well present it using a valid Python syntax. (The latest Python syntax for types is using the pipe as the union operator (this OR that type)).

Generally, my opinion for reference docs is to have true information, even if incomplete, rather than more info, but could be false. I don't mind if a section is marked experimental and warns if something might not work.

… contexts for precise tuple-multiple cases. Separate types by pipe. Make optional/required in italics to make it more distinct. Introduce a 'Used as' line which shows age (as input/output) and desc/prompt from gisprompt followed by key_desc in italics. Make flags parameter and long flags more like the other parameters.
@wenzeslaus
Copy link
Member Author

Separating union of different types with a comma, but also separating the elements of a tuple with a comma, and also using the comma in between the types, the key descr from metadata, and between the optional indicator is probably confusing, at least for me, especially on a same line.

Now using Python's pipe to separate types. Key desc is not moved under "Used as". Optional indicator and tuple items are still both separated by comma, but tuple items are inside parentheses and the optional indicator is now newly in emphasis/italics.

Generally, my opinion for reference docs is to have true information, even if incomplete, rather than more info, but could be false.

As far as I can tell, it is pretty clear overall, although we were not really showing most of that info in the past or using in the doc.

I don't mind if a section is marked experimental and warns if something might not work.

The example piece is the one closest to being experimental. While the heuristic is relatively straightforward, it needs to be tested more (evaluated in the wild). Not enough to warrant marking it experimental.

@wenzeslaus
Copy link
Member Author

This r.slope.aspect example shows how the new "Used as" works for the most common case, input and output raster:

image

This m.nviz.image example shows a long type description and several examples of "Used as":

image

This r.watershed example shows (short) flags and long flags, now more aligned with how other parameters are represented:

image

@wenzeslaus
Copy link
Member Author

Here is a link to the artifact if that makes it easier for anyone to review.

Copy link
Contributor

@petrasovaa petrasovaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#5358 (md to man) will need to be updated.

@wenzeslaus wenzeslaus changed the title docs: Add Python to generated Markdown tool doc docs: Add Python to the generated Markdown tool doc Apr 10, 2025
@wenzeslaus wenzeslaus merged commit f48be67 into OSGeo:main Apr 10, 2025
30 of 31 checks passed
@wenzeslaus wenzeslaus deleted the add-python-to-tool-doc branch April 10, 2025 14:15
@github-project-automation github-project-automation bot moved this from In Progress to Done in GRASS Markdown Documentation Apr 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C Related code is in C docs libraries
Projects
Development

Successfully merging this pull request may close these issues.

5 participants