cyclopts icon indicating copy to clipboard operation
cyclopts copied to clipboard

mkdocs plugin

Open BrianPugh opened this issue 2 months ago • 24 comments

Addresses #617

@relativityhd @danielgafni testing and feedback would be appreciated!

BrianPugh avatar Oct 23 '25 00:10 BrianPugh

Codecov Report

:x: Patch coverage is 79.80769% with 189 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 89.37%. Comparing base (9b3a1db) to head (08265f8). :warning: Report is 41 commits behind head on main.

Files with missing lines Patch % Lines
cyclopts/docs/markdown.py 79.03% 31 Missing and 17 partials :warning:
cyclopts/ext/sphinx.py 78.60% 32 Missing and 8 partials :warning:
cyclopts/docs/base.py 82.22% 15 Missing and 9 partials :warning:
cyclopts/docs/rst.py 80.00% 8 Missing and 16 partials :warning:
cyclopts/help/formatters/markdown.py 64.44% 14 Missing and 2 partials :warning:
cyclopts/help/formatters/rst.py 20.00% 8 Missing :warning:
cyclopts/utils.py 69.23% 6 Missing and 2 partials :warning:
cyclopts/help/formatters/html.py 63.15% 4 Missing and 3 partials :warning:
cyclopts/ext/mkdocs.py 93.81% 2 Missing and 4 partials :warning:
cyclopts/help/help.py 80.95% 2 Missing and 2 partials :warning:
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #621      +/-   ##
==========================================
+ Coverage   88.10%   89.37%   +1.26%     
==========================================
  Files          69       70       +1     
  Lines        7820     7934     +114     
  Branches     1791     1802      +11     
==========================================
+ Hits         6890     7091     +201     
+ Misses        556      479      -77     
+ Partials      374      364      -10     
Flag Coverage Δ
unittests 89.31% <79.80%> (+1.26%) :arrow_up:

Flags with carried forward coverage won't be shown. Click here to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov[bot] avatar Oct 23 '25 00:10 codecov[bot]

Seems to work! I have tested it with our rather complex CLI which has a meta app, dataclasses and super nested commands.

I would suggest you get in contact with squidfunk to add cyclopts in the plugins schema file: https://squidfunk.github.io/mkdocs-material/schema/plugins.json so that yaml language server dont say that cyclopts is not a valid plugin

I've found one thing which is odd: Some of my commands have two "Options" headers where one is also present in the toc:

image image

Same thing happens with arguments.

image

Always the second "Option" or "Argument" is without a ":" and is instead marked as a header.

This seems to only occur on commands which are part of double-nested apps. E.g. in my screenshots you can see that I have an app inside an app inside an app -> 3 subcommands

relativityhd avatar Oct 23 '25 12:10 relativityhd

Ah, and the filtering commands dont seem to work as I would expect:


    :commands: training
    :exclude-commands: training.create-dataset

Will show all training commands, including the create-dataset command and subcommands. On the other side:

    :commands: training.create-dataset
/* no exclude */

Will hide the create-dataset sub-commands but show all other training commands.

relativityhd avatar Oct 23 '25 12:10 relativityhd

thanks for the testing! I'll try and address these tomorrow.

BrianPugh avatar Oct 24 '25 00:10 BrianPugh

I will be testing it with my CLI tomorrow.

danielgafni avatar Oct 28 '25 01:10 danielgafni

@relativityhd @danielgafni can you guys give this another round of testing? thanks!

BrianPugh avatar Nov 03 '25 20:11 BrianPugh

Definitely an improvement for env vars and the TOC entries!

image

I think the last issue to address is the Markdown TOC which is still weird image

danielgafni avatar Nov 03 '25 21:11 danielgafni

I'll get on it! Thanks for testing!

BrianPugh avatar Nov 03 '25 21:11 BrianPugh

Actually sorry, I was still running the old version. And confused positional arguments with env docs :man_facepalming:

TOC is fine, only the missing env vars is an issue for me.

danielgafni avatar Nov 04 '25 09:11 danielgafni

Markdown TOC is actually fine now, sorry for the confusion.

image

danielgafni avatar Nov 04 '25 09:11 danielgafni

Thanks! I'm going to do a bit of a refactor (including your suggestions). I'm saving the env-var stuff for a separate PR because this is already quite a large PR, and it'll make it easier to review that functionality.

Once i have these changes in, i think we should have one more round of testing then merge. Then i'll work on the env var stuff!

BrianPugh avatar Nov 04 '25 13:11 BrianPugh

Understood! Thanks for your efforts Brian

danielgafni avatar Nov 04 '25 14:11 danielgafni

My previous reported bugs seem to be correct now.

But I found now several other problems, I tried to show them in this screenshot: image

The mkdocs code for this is basically

## Create Dataset Commands

::: cyclopts
    :module: darts.cli:app
    :commands: training.create_dataset
    :generate-toc: false
    :flatten-commands: true
    :heading-level: 3

Where training.create_dataset is a further subapp with multiple commands inside.

I know that we have a super nested CLI, it is awesome that it is possible to have such nesting, and it makes our lives so much easier! I understand that this makes debugging of this PR super hard. So if you like, I can create a minimal reproducible version of our CLI if you need one. Or also help writing Code for it.

Either way: Thanks for your efforts Brian!

relativityhd avatar Nov 04 '25 16:11 relativityhd

@danielgafni @relativityhd I'm kind of a noob at mkdocs, but i'm getting the vibe that the sphinx-like plugin syntax isn't idiomatic? Is it more common/prefered to use yaml syntax within the directive block? Because if so, i can easily switch to that (rather than emulating sphinx syntax).

BrianPugh avatar Nov 04 '25 22:11 BrianPugh

I think you can use MkDocsStrings-Python as an example, it is quite commonly used in the Python community as far as I can tell. Stuff in the directive block looks e.g. like this:

::: package.module.class
    options:
      do_something: false

But at the end, I think as long as you document how to do stuff, it doesn't matter a lot. I didn't notice the difference in declaration-syntax until you asked me about it. :D

relativityhd avatar Nov 05 '25 07:11 relativityhd

While it doesn't matter technically, it's better to conform to the current widespread style, IMO.

danielgafni avatar Nov 05 '25 10:11 danielgafni

Yaml it is! I'll update this.

BrianPugh avatar Nov 05 '25 11:11 BrianPugh

@danielgafni can you give this another round of testing?

@relativityhd same for you. Is there a branch of darts that I can play with to manually test some document generation? Thanks!

BrianPugh avatar Nov 10 '25 00:11 BrianPugh

Hi Brian, I've pushed my local changes to this branch: https://github.com/awi-response/darts-nextgen/tree/feature/cycloptsv4

You would need to sync stuff with uv sync --extra cpu --extra training --all-groups to ensure all dependencies are loaded correctly.

Currently, we're still doing a lot of imports in the functions themselves to avoid long load times when calling --help on the CLI. I know that the new lazy-loading feature should help with that, but unfortunately this only works for nested subcommands, at least on another test I did. ("Lazy commands are resolved/imported in these situations: [...] Help Generation - When displaying help that includes the command") Maybe I will open another issue after having a closer look at this problem.

relativityhd avatar Nov 12 '25 10:11 relativityhd

thanks for posting! I'll play around with doc-generation in the darts-nextgen repo.

As for the lazy-loading stuff, yes lets handle that separately in another issue/pr later!

BrianPugh avatar Nov 12 '25 14:11 BrianPugh

@relativityhd I think we're getting closer; i'll continue to fiddle around with it, but I tweaked it to definitely be more in-line with what you would want.

BrianPugh avatar Nov 13 '25 03:11 BrianPugh

Hey Brian, I noticed these dataclass options are all rendered as both position arguments (UPPERCASE) and options (--lower-case), is this expected?

In fact they are all optional.

image

danielgafni avatar Nov 17 '25 23:11 danielgafni

probably intentional! you probably want to mark your dataclass kw_only=True (or use KW_ONLY)

BrianPugh avatar Nov 18 '25 01:11 BrianPugh

Any idea if we could use mkdocstrings from Cyclopts docstrings or parameters help?

Better treatment for newlines in "long" help docstrings

I've attempted to do something like this:

@app.command()
def my_command():
    """My short description. 

    My long description. 

    Example:
    
        $ my-command ...
    """

But the example got stripped from the generated markdown since the second newline ends the long description.

Any idea if this behavior could be changed for markdown help format?

Document parameter types

I have this dict[str, str] argument but it's impossible to tell whether it accepts a dot-notation dict from the docs. I have to document this myself in the parameter help.

image

Same issue stands with other types. Seems more like a general cyclopts problem since the CLI help is missing this info as well? Am I missing some configuration option here?

Enable relative links to other docs

Ideally I want to be able to link to my main docs from the CLI docs. This is typically done via relative links:

[learn more here](../learn/concept)

However, this would break the urls displayed in CLI --hepl.

It sounds like this could be solved by allowing the user to specify a base URL pointing to the actual docs website and prefix the relative links with this base URL? Example:

app = cyclopts.App("app", docs_site_url="https://my.docs")

@app.command()
def my_command():
    """Learn more in [my docs](./learn/my-command)"""
$ app my-command --help
...
Learn more in [my docs](https://my.docs/learn/my-command)

danielgafni avatar Nov 20 '25 00:11 danielgafni

Hey @BrianPugh , could you please make a dev release from this branch?

danielgafni avatar Dec 03 '25 15:12 danielgafni

sure! just a moment; I'm finally a bit more available after Thanksgiving madness, so I'll refocus on this PR!

BrianPugh avatar Dec 03 '25 15:12 BrianPugh

this is now available as v4.4.0a1! I'll have to review your above message soon and see what kind of improvements i can make.

BrianPugh avatar Dec 03 '25 15:12 BrianPugh

Thanks!

I didn't realize until now this PR wasn't based on the 5.0.0 version of Cyclopts.

danielgafni avatar Dec 03 '25 15:12 danielgafni

@danielgafni sorry for the slower iterations this time around, but here's what I'll be working on this morning:

Any idea if we could use mkdocstrings from Cyclopts docstrings or parameters help?

Not really (unless I'm completely misunderstanding); in order to work with everything else in Cyclopts, we have to be using our parsing system.


But the example got stripped from the generated markdown since the second newline ends the long description.

I also share this frustration; this is because docstring_parser parses the section and we would somehow have to "unparse" it. We explore it a bit in #477. We also explore it in the docstring_parser repo a bit here; but I honestly don't really have the will-power to deal with it. We could sort of hack-in support by find/replacing these section titles prior to docstring-parser, and then undo the find/replace afterwards; just seems quite fragile.

TLDR I agree!


it's impossible to tell whether it accepts a dot-notation dict from the docs

hmmm, yes this definitely does seem like a valid issue. What would be a good programmatic output? I agree it is a bit cumbersome to have to manually present an example. What if instead it instead displayed -t.<KEY> --tags.<KEY>? I'll tackle this in a separate, independent PR since it's a fairly independent issue.


Ideally I want to be able to link to my main docs from the CLI docs.

I'll try and implement this feature now. It might be difficult, but I think it would be a good value add.

My TODO list for this PR

Given all of the above, I think this PR is in a "good enough" state for a merge; we can continue to refine the idea in subsequent releases. However, I'll try and sneak in the docs-linking feature. What do you think @danielgafni @relativityhd ?

BrianPugh avatar Dec 08 '25 15:12 BrianPugh

Not really (unless I'm completely misunderstanding); in order to work with everything else in Cyclopts, we have to be using our parsing system.

I mean this was an introduction to the rest of my post :)

Being able to write mkdocstrings-compatible markdown is all we'd need, but the beeline issue makes it quite challenging.

In general, I just want a way to attach mkdocs markdown to CLI commands in order for it to be rendered in the docs automatically. It doesn't necessarily need to be present in the Cli help (probably better if it's not since it can be large and confusing).

Ideally I'd have CLI docs attached to CLI commands definitions so information stays local and automatically injected into the website.

danielgafni avatar Dec 08 '25 16:12 danielgafni