mkdocs / mkdocs-click Goto Github PK
View Code? Open in Web Editor NEWAn MkDocs extension to generate documentation for Click command line applications
Home Page: https://pypi.org/project/mkdocs-click
License: Apache License 2.0
An MkDocs extension to generate documentation for Click command line applications
Home Page: https://pypi.org/project/mkdocs-click
License: Apache License 2.0
mkdocs-click doesn't seem to generate toc entries that can be used by mkdocs-material. This means that themes that use this information like mkdocs-material doesn't show the entries, which is a bit of a drawback for big/nested commands:
Compare mkdocstrings:
https://frankier.github.io/skelshop/io/
mkdocs-click:
https://frankier.github.io/skelshop/cli/
Is this where mkdocstrings does it? https://github.com/pawamoy/mkdocstrings/blob/6453026fac287387090a67cce70c078377d107dd/src/mkdocstrings/plugin.py#L172
I suppose that again it's not possible with only a markdown extension, but a full mkdocs extension is needed.
:remove_ascii_art: True
"""
Replace titles names from anidb.
The result will be copied to the clipboard.
\b
>>> 1 The Prince`s New Clothes
<<< e1: EP1 «The Prince`s New Clothes»
"""
It would be great to allow for the CLI commands generated to be loaded as well into the objects.inv
that's generated alongside something like mkdocstrings
. This would let me use the native cross-referencing of something like [my-entrypoint subprogram][]
to generate a cross-reference, rather than [my-entrypoint subprogram](references#my-entrypoint-subprogram)
at the moment.
Options are currently documented in a plain format as if they were copy-pasted from a terminal emulator. I'd be happy if they are rendered in a human-readable HTML table.
I'm writing docs with i18n support.
There are two places where it should be done:
@click.option('--quiet/--verbose', '-q/-v', flag_value=True, default=False, help=_("Disable processing output"))
@doc(_("""Help text of subcommand."""))
def subcommand(quiet):
...
docs
directory. I'm using mkdocs-static-i18n
plugin. So I've created index.XX.md
for each supported language.I want to pass different language code to mkdocs-click
plugin in each cli.XX.md
.
I think it will includes reloading of module each time with changing LANG
variable.
Following this click multi-command example:
Context is being passed around the multi-commands properly when on the command line.
So I know my coding is proper.
However, help_option_names
¸for example, isn't being picked up by mkdocs-click
.
This tool's subcommands are loaded from a plugin folder dynamically.
Usage:
wbscc [OPTIONS] COMMAND [ARGS]...
Options:
Name | Type | Description | Default |
---|---|---|---|
--help | boolean | Show this message and exit. | False |
CONTEXT_SETTINGS = {
"token_normalize_func": lambda x: x.lower(),
"help_option_names": ["-h", "--help"],
}
$ wbscc --help
Usage: wbscc [OPTIONS] COMMAND [ARGS]...
This tool's subcommands are loaded from a plugin folder dynamically.
Options:
-h, --help Show this message and exit.
Commands:
hello Prints hello.
This tool's subcommands are loaded from a plugin folder dynamically.
Usage:
wbscc [OPTIONS] COMMAND [ARGS]...
Options:
Name | Type | Description | Default |
---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
I'm not sure if I'm doing something wrong, but nothing is being generated at all. And the mkdocs command doesn't raise any errors either.
Here is the block that I use:
::: mkdocs-click
:module: package.module.cli
:command: click_command
And my mkdocs extensions list:
markdown_extensions:
# Python Markdown
- abbr
- admonition
- attr_list
- def_list
- footnotes
- md_in_html
- mkdocs-click
- toc:
permalink: true
# Python Markdown Extensions
- pymdownx.arithmatex:
generic: true
- pymdownx.betterem:
smart_enable: all
- pymdownx.caret
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.highlight
- pymdownx.inlinehilite
- pymdownx.keys
- pymdownx.magiclink
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
I'm a new user to mkdocs-click
so apologies if I'm doing something wrong but I've been stuck trying to get even the basic Readme example working. I found this comment in issue #46 which referred to the issue changing when "hitting enter." As it turns out, the CLI documentation will only render for me if there are at least two spaces at the end of the markdown file, otherwise it renders the header but not CLI documentation.
e.g. this will only render the heading CLI Reference
# CLI Reference
::: mkdocs-click
:module: app.cli
:command: cli
but this will render the heading and generated documentation.
# CLI Reference
::: mkdocs-click
:module: app.cli
:command: cli
<newline>
<newline>
It's a particular challenge for new users where they are likely to copy / paste the readme example into a new text file in order to begin testing and immediately hit a deadend. In my case, I assumed there was something arcane about the :module: reference (does it follow standard library import hierarchies, are they directory hierarchies, something else, etc...)
Hey! Thanks for the develop of mkdocs-click
, it'll save me a lot of time on documentation 💚
One thing that I would like to suggest is to have a left border on commands description to better organize the docs. I use mkdocstrings
for Python documentation that has div
structure inside, and it can be easily personalised with a custom.css
file (example on the image bellow).
It would be great to do the same here! :)
\b
:
https://click.palletsprojects.com/en/8.1.x/documentation/#preventing-rewrapping
Rewrapping can be disabled on a per-paragraph basis by adding a line with solely the \b escape marker in it.
\f
:
https://click.palletsprojects.com/en/8.1.x/documentation/#truncating-help-texts
You can use the \f escape marker to have Click truncate the help text after the marker.
Hi,
Is there any way to generate documentation for the CLI without first having to install the Python package and dependencies? One of the dependencies takes a while to build and install, and I don't want to bloat my documentation build time if I don't have to. Thank you!
Hi, I installed it in my virtual env, getting this error when running mkdocs serve
:
ERROR - Config value: 'markdown_extensions'. Error: Failed to load extension 'mkdocs-click'.
ModuleNotFoundError: No module named 'mkdocs-click'
Aborted with 1 Configuration Errors!
The package in installed in the venv and shown when running pip list
.
Could it be because I'm using a different theme (material) than in the instructions?
Environment variables can be used to set option values:-
@click.option(
"--debug/--no-debug",
default=False,
envvar="PRODUCT_DEBUG",
help="Output debugging logging",
)
However these are not exposed in the CLI documentation.
It has to be admitted that Click's help text also does not expose these at all, so manual addition of this mapping to the docstrings may be needed anyhow.
Many thanks for this plugin for mkdocs - much appreciated
Hi there,
it would be great if this could also support asyncclick. The changes involved would be fairly minimal, just replacing the click import with:
try:
import asyncclick as click
except:
import click
in _loader.py
would suffice. This would assume that when asyncclick is installed, it should be used (since there is no other reason to install it alongside 'normal' click I can imagine. If that is considered not good enough, it would only be a few more lines to add an instance test against asyncclick.BaseCommand
alongside the one against click.BaseCommand
.
Thanks for considering!
The following does not appear to have any effect on the title:
---
title: CLI reference
---
::: mkdocs-click
:module: hatch.cli
:command: hatch
:depth: 0
:style: table
:remove_ascii_art: true
Nice plugin!
I actually wish I'd discovered it earlier. Can I suggest you add the plugin to the overview here: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins. It will help visibility :)
Perhaps useful for this plugin as well, the approach I took is using mkdocs-macros to insert the output of some_click_command --help into my mkdocs folder. Relevant code bits:
I would like to set the depth to 1
and prevent the generated h1 so I can set my own to CLI reference
. Alternatively, an option to explicitly set the first header would suffice but I would prefer the other option I mentioned.
When documenting CLI, one can choose to document all the commands in a single file, or to split the documentation to multiple files by subgroups.
Right now, if I want to document only the subcommand I need to specify the subcommand as my command in the block. However, in that way the parent command isn't shown in the command path. This might cause some confusion
consider that I have a group named my_cli
and a subcommands my_sub1
and my_sub2
and I want to document only my_sub1
.
If I write:
::: mkdocs-click
:module: app.cli
:command: my_sub1
The path printed is my_sub1 [OPTIONS] COMMAND
and not the entire path my_cli my_sub1 [OPTIONS] COMMAND
.
The only way is to write:
::: mkdocs-click
:module: app.cli
:command: my_cli
And to document everything in the same file.
One should be able to specify which subcommands to display, not just depth. that means that the block should look like:
::: mkdocs-click
:module: <module>
:command: <command>
:subcommands: [<list of subcommands>]
Hi! The mkdocs-click
works great for me, thanks 🙇
But I have encountered one problem: mkdocs-click
does not take into account the Click's hidden
flag. I have some groups of commands that are hidden from the --help
page and in turn, I would like to also exclude them from the docs.
Click supports hidden
both in Command
and Option
. We could add a flag to mkdocs-click
that would filter them out during docs generation.
I could contribute such a feature, but first I would like to discuss that with you.
Our CI currently runs on Python 3.7 and 3.8, let's get it onboard with 3.9 as well.
There's a problem with a multi command module.
I've use demisto-sdk and found it.
When importing a command, the module is not in the command name.
using the module above:
format command:
filename: docs/commands/format.md
::: mkdocs-click
:module: demisto_sdk.__main__
:command: format
The usage should be demisto-sdk format
. Is there a way to explicit the name of the command?
I can't use prog_name
as it not accepting spaces.
Prompted by discussion in #25 (comment)
Currently we drop the --help
option from the output of command reference:
We should probably keep it in for explicitness and simplicity. (Users may have renamed it to something else, readers might think it's actually not present, etc.)
I am getting a ModuleNotFoundError
exception thrown when trying to start the mkdocs serve
development server and even trying to do mkdocs build
.
I'm not sure why it can't find my module called open_bandage
as I understand it uses relative path finding and I'm executing the mkdocs serve
command from my overall Intellij directory. (i.e. same level as my docs
, mkdocs.yml
, etc.)
ERROR - Error reading page 'index.md': No module named 'open_bandage'
Traceback (most recent call last):
File "/home/aspea002/miniconda3/envs/open_bandage/bin/mkdocs", line 8, in <module>
sys.exit(cli())
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs/__main__.py", line 136, in serve_command
**kwargs
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs/commands/serve.py", line 141, in serve
config = builder()
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs/commands/serve.py", line 136, in builder
build(config, live_server=live_server, dirty=dirty)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs/commands/build.py", line 271, in build
_populate_page(file.page, config, files, dirty)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs/commands/build.py", line 171, in _populate_page
page.render(config, files)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs/structure/pages.py", line 175, in render
self.content = md.convert(self.markdown)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/markdown/core.py", line 261, in convert
self.lines = prep.run(self.lines)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs_click/_extension.py", line 46, in run
replace=lambda **options: replace_command_docs(has_attr_list=self._has_attr_list, **options),
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs_click/_processing.py", line 35, in replace_blocks
yield from replace(**options)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs_click/_extension.py", line 46, in <lambda>
replace=lambda **options: replace_command_docs(has_attr_list=self._has_attr_list, **options),
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs_click/_extension.py", line 27, in replace_command_docs
command_obj = load_command(module, command)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs_click/_loader.py", line 15, in load_command
command = _load_obj(module, attribute)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/site-packages/mkdocs_click/_loader.py", line 25, in _load_obj
mod = importlib.import_module(module)
File "/home/aspea002/miniconda3/envs/open_bandage/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 965, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'open_bandage'
mkdocs.yml
site_name: Open Bandage
site_author: 'Andrew Spear'
site_url: 'https://xxxxxxxxxxxxxxxxxxxx'
theme:
name: 'material'
palette:
# Light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: light green
accent: deep orange
toggle:
icon: material/weather-night
name: Switch to dark mode
# Dark Mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: deep orange
accent: lime
toggle:
icon: material/weather-sunny
name: Switch to light mode
icon:
logo: material/bandage
favicon: images/uscc_logo.png
features:
- navigation.tabs
- navigation.sections
- navigation.top
# - toc.integrate
markdown_extensions:
- admonition
- pymdownx.highlight:
linenums: true
- pymdownx.inlinehilite
- pymdownx.superfences
- pymdownx.smartsymbols
- pymdownx.details
- pymdownx.caret
- pymdownx.mark
- pymdownx.tilde
- pymdownx.betterem:
smart_enable: all
- def_list
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.tabbed
- attr_list
- mkdocs-click
- toc:
toc_depth: 4
nav:
- Home: index.md
- Developer Info: development.md
index.md
::: mkdocs-click
:module: open_bandage.scripts.cli
:command: cli
:prog_name: openbandage
:depth: 2
:style: table
Project Directory structure
Consider a nested CLI, ie one group with one or more nested commands or groups.
Right now the TOC looks like this:
This is nice and clean, as it allows visualizing the
But… In the page content itself, the hierarchy is only represented by heading styles (more or less big/bold text), like this:
root
Usage: ...
Options: ...
subgroup1
Usage: ...
Options:...
subcommand1
Usage: ...
Options: ...
subcommand2
Usage: ...
Options: ...
subcommand3
Usage: ...
Options: ...
When looking at a given section, it is not obvious to know whether a given command
belongs to a parent group (and which one) (see subcommand1
and subcommand2
), or if it's just a standalone command (see subcommand3
).
Besides, permalinks only contain eg /#subcommand2
, which again doesn't convey the actual hierarchy.
command_path
, eg ## root subgroup1 subcommand2
/#root-subgroup1-subcommand2
(see custom labels)Hi,
Is this project still active and has anyone tested this project with the material theme?
Thanks a lot for this package! We are implementing in our SDK docs and it's working great.
We have, however, a small issue that we believe you could help with. In the setup.py
in our package we use:
entry_points="""
[console_scripts]
up42=up42.cli:main
"""
Which means that the main
function of the up42/cli.py
script is used as the entry point for the click CLI, but the main
name gets replaced with the up42
name, so that you can call up42 authenticate
instead of main authenticate
. In the generated docs with mkdocs-click
we see the main
name instead, which can be confusing for users.
It would be great if we could somehow in the mkdocs-click
setup add an entry_point
, i.e.:
::: mkdocs-click
:module: up42.cli
:command: main
:entry_point: up42
:depth: 2
And then in the generated docs all the main
references would be replaced with up42
.
I believe this could be quite useful since a number of click
CLIs are using mechanisms similar to this. Happy to hear any alternative suggestions/comments/questions you have!
Hi and thanks for this beautiful library.
I am happily using it but I see that the help for the --help option is present in every command by default.
Is it possible to disable it and show it to the user only once?
Users of mkdocstrings noticed that indented mkdocs-click blocks are not picked up and handled by mkdocs-click, and later (block processors) mkdocstrings picks it up (we use the same syntax :::
) and errors out since it do not support the rest of the syntax.
Would it be possible to loosen a bit the regex to match blocks starting with spaces?
The alternative is to implement the processor as a block processor rather than a pre-processor, and indentation will be handled for you automatically. You'd just have to make sure to keep using a higher priority than mkdocstrings, since you match the contents after :::
more specifically (strictly equal to mkdocs-click
in your case, while mkdocstrings matches anything).
For reference, our block processor implementation:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.