CLI wrapper¶
Click Extra’s wrap subcommand applies its help colorization to any installed Click CLI, without modifying the target’s source code. This is useful for previewing how a third-party CLI would look with Click Extra’s keyword highlighting and themed styling.
Usage¶
The wrap subcommand is the default when no known subcommand is given, so both forms work:
$ click-extra wrap flask --help
$ click-extra flask --help
$ wrap --help
Usage: wrap [OPTIONS] SCRIPT [ARGS]...
Aliases: run
Apply Click Extra help colorization to any Click CLI.
Wraps SCRIPT with keyword highlighting and themed styling for help screens.
The target CLI is not modified.
Resolution order for SCRIPT: installed console_scripts entry point,
module:function notation, Python file path, or Python module name.
Options:
--theme [dark|light] Color theme preset.
-h, --help Show this message and exit.
Tip
run is an alias for wrap, so you can also use:
$ click-extra run flask --help
Wrapping a Click CLI¶
Pass the target CLI name (or path) as the first argument. Everything after it is forwarded to the target:
$ click-extra flask --help
$ click-extra black --help
$ click-extra ./my_script.py --help
$ click-extra my_package.cli:main --help
Tip
An optional -- separator is available which you can use for visually separating Click Extra from the target CLI:
$ click-extra --no-color -- flask --help
Execution timing¶
The group-level --time flag measures the total execution time of the wrapped CLI, including import and patching overhead:
$ click-extra --time flask routes
Execution time: 0.342 seconds.
Color control¶
--color / --no-color (--ansi / --no-ansi) controls whether ANSI codes are emitted. The flag also respects environment variables like NO_COLOR, CLICOLOR, and FORCE_COLOR:
$ click-extra --no-color flask --help
$ NO_COLOR=1 click-extra flask --help
The --theme option on wrap selects a color preset:
$ click-extra wrap --theme light flask --help
Configuration¶
Click Extra’s configuration file support works alongside the wrapper. Group-level options like verbosity can be set in pyproject.toml:
[tool.click-extra]
verbosity = "DEBUG"
$ click-extra flask --help
debug: Set <Logger click_extra (DEBUG)> to DEBUG.
...
Defaults for the wrapped CLI¶
The [tool.click-extra.wrap.<script>] section sets persistent defaults for a specific target CLI. All keys are converted to CLI arguments and prepended to the target’s invocation:
[tool.click-extra.wrap.flask]
app = "myapp:create_app"
debug = true
$ click-extra flask routes
# Equivalent to: flask --app myapp:create_app --debug routes
The section name must match the script name you pass on the command line. Multiple targets can each have their own section:
[tool.click-extra.wrap.flask]
app = "myapp:create_app"
[tool.click-extra.wrap.quart]
app = "otherapp:create_app"
Explicit CLI arguments always override config values:
$ click-extra flask --app otherapp routes
# CLI --app wins over config
Invalid option names are caught by the target CLI itself with standard Click error messages, so typos are surfaced immediately.
Script resolution¶
The SCRIPT argument is resolved in this order:
Console scripts entry point: any package installed with
pip installoruv addthat registers aconsole_scriptsentry point. This covers most CLI tools.module:functionnotation: explicit import path likemy_app.cli:main..pyfile path: a local Python script.Python module name: a bare module or package name invocable via
python -m.
Ephemeral wrapping with uvx¶
The wrapper is particularly useful with uvx for one-shot colorization of any Click CLI without permanently installing Click Extra:
$ uvx click-extra -- flask --help
$ uvx click-extra -- black --help
How it works¶
The wrapper monkey-patches Click at two levels before importing the target module:
Decorator defaults:
@click.command()and@click.group()produce colorized commands when no explicitcls=is given.Method patching:
click.Command.get_helpandclick.Command.format_helpare patched to inject the colorized formatter and keyword collection on all commands, including those with custom classes (like Flask’sFlaskGroup).
CLIs already built with Click Extra or Cloup are unaffected by the patching (they already have their own help formatting) but still run correctly through the wrapper.
Introspecting external CLIs¶
The show-params subcommand inspects the parameters of any Click CLI without running it. It displays a table with each parameter’s ID, spec, class, type, hidden status, environment variables, and default value.
$ click-extra show-params --help
Usage: show-params [OPTIONS] SCRIPT [SUBCOMMAND]...
Show parameters of an external Click CLI.
Resolves SCRIPT as a console_scripts entry point, module:function notation,
.py file path, or Python module name. Loads the Click command and prints its
parameter table.
Extra arguments after SCRIPT navigate into nested command groups.
Options:
--table-format [aligned|asciidoc|colon-grid|csv|csv-excel|csv-excel-tab|csv-unix|double-grid|double-outline|fancy-grid|fancy-outline|github|grid|heavy-grid|heavy-outline|hjson|html|jira|json|json5|jsonc|latex|latex-booktabs|latex-longtable|latex-raw|mediawiki|mixed-grid|mixed-outline|moinmoin|orgtbl|outline|pipe|plain|presto|pretty|psql|rounded-grid|rounded-outline|rst|simple|simple-grid|simple-outline|textile|toml|tsv|unsafehtml|vertical|xml|yaml|youtrack]
Rendering style of tables. [default: ROUNDED_OUTLINE]
-h, --help Show this message and exit.
Here is an example introspecting Flask’s run subcommand with the vertical table format:
$ click-extra show-params --table-format vertical flask run
***************************[ 1. row ]***************************
ID | run.cert
Spec. | --cert PATH
Class | click.core.Option
Param type | flask.cli.CertParamType
Python type | str
Hidden | ✘
Env. vars. |
Default | Sentinel.UNSET
***************************[ 2. row ]***************************
ID | run.debug
Spec. | --debug / --no-debug
Class | click.core.Option
Param type | click.types.BoolParamType
Python type | bool
Hidden | ✘
Env. vars. |
Default | False
***************************[ 3. row ]***************************
ID | run.debugger
Spec. | --debugger / --no-debugger
Class | click.core.Option
Param type | click.types.BoolParamType
Python type | bool
Hidden | ✘
Env. vars. |
Default | None
***************************[ 4. row ]***************************
ID | run.exclude_patterns
Spec. | --exclude-patterns PATH
Class | click.core.Option
Param type | flask.cli.SeparatedPathType
Python type | str
Hidden | ✘
Env. vars. |
Default | None
***************************[ 5. row ]***************************
ID | run.extra_files
Spec. | --extra-files PATH
Class | click.core.Option
Param type | flask.cli.SeparatedPathType
Python type | str
Hidden | ✘
Env. vars. |
Default | None
***************************[ 6. row ]***************************
ID | run.help
Spec. | --help
Class | click.core.Option
Param type | click.types.BoolParamType
Python type | bool
Hidden | ✘
Env. vars. |
Default | False
***************************[ 7. row ]***************************
ID | run.host
Spec. | -h, --host TEXT
Class | click.core.Option
Param type | click.types.StringParamType
Python type | str
Hidden | ✘
Env. vars. |
Default | '127.0.0.1'
***************************[ 8. row ]***************************
ID | run.key
Spec. | --key FILE
Class | click.core.Option
Param type | click.types.Path
Python type | str
Hidden | ✘
Env. vars. |
Default | Sentinel.UNSET
***************************[ 9. row ]***************************
ID | run.port
Spec. | -p, --port INTEGER
Class | click.core.Option
Param type | click.types.IntParamType
Python type | int
Hidden | ✘
Env. vars. |
Default | 5000
***************************[ 10. row ]***************************
ID | run.reload
Spec. | --reload / --no-reload
Class | click.core.Option
Param type | click.types.BoolParamType
Python type | bool
Hidden | ✘
Env. vars. |
Default | None
***************************[ 11. row ]***************************
ID | run.with_threads
Spec. | --with-threads / --without-threads
Class | click.core.Option
Param type | click.types.BoolParamType
Python type | bool
Hidden | ✘
Env. vars. |
Default | True
All --table-format renderings are supported. JSON output is useful for programmatic consumption:
$ click-extra show-params --table-format json flask run
[
{
"ID": "run.cert",
"Spec.": "--cert PATH",
"Class": "click.core.Option",
"Param type": "flask.cli.CertParamType",
"Python type": "str",
"Hidden": false,
"Env. vars.": [],
"Default": "Sentinel.UNSET"
},
{
"ID": "run.debug",
"Spec.": "--debug / --no-debug",
"Class": "click.core.Option",
"Param type": "click.types.BoolParamType",
"Python type": "bool",
"Hidden": false,
"Env. vars.": [],
"Default": false
},
{
"ID": "run.debugger",
"Spec.": "--debugger / --no-debugger",
"Class": "click.core.Option",
"Param type": "click.types.BoolParamType",
"Python type": "bool",
"Hidden": false,
"Env. vars.": [],
"Default": null
},
{
"ID": "run.exclude_patterns",
"Spec.": "--exclude-patterns PATH",
"Class": "click.core.Option",
"Param type": "flask.cli.SeparatedPathType",
"Python type": "str",
"Hidden": false,
"Env. vars.": [],
"Default": null
},
{
"ID": "run.extra_files",
"Spec.": "--extra-files PATH",
"Class": "click.core.Option",
"Param type": "flask.cli.SeparatedPathType",
"Python type": "str",
"Hidden": false,
"Env. vars.": [],
"Default": null
},
{
"ID": "run.help",
"Spec.": "--help",
"Class": "click.core.Option",
"Param type": "click.types.BoolParamType",
"Python type": "bool",
"Hidden": false,
"Env. vars.": [],
"Default": false
},
{
"ID": "run.host",
"Spec.": "-h, --host TEXT",
"Class": "click.core.Option",
"Param type": "click.types.StringParamType",
"Python type": "str",
"Hidden": false,
"Env. vars.": [],
"Default": "127.0.0.1"
},
{
"ID": "run.key",
"Spec.": "--key FILE",
"Class": "click.core.Option",
"Param type": "click.types.Path",
"Python type": "str",
"Hidden": false,
"Env. vars.": [],
"Default": "Sentinel.UNSET"
},
{
"ID": "run.port",
"Spec.": "-p, --port INTEGER",
"Class": "click.core.Option",
"Param type": "click.types.IntParamType",
"Python type": "int",
"Hidden": false,
"Env. vars.": [],
"Default": 5000
},
{
"ID": "run.reload",
"Spec.": "--reload / --no-reload",
"Class": "click.core.Option",
"Param type": "click.types.BoolParamType",
"Python type": "bool",
"Hidden": false,
"Env. vars.": [],
"Default": null
},
{
"ID": "run.with_threads",
"Spec.": "--with-threads / --without-threads",
"Class": "click.core.Option",
"Param type": "click.types.BoolParamType",
"Python type": "bool",
"Hidden": false,
"Env. vars.": [],
"Default": true
}
]
Subcommand drilling¶
Extra arguments after SCRIPT navigate into nested command groups:
$ click-extra show-params -- flask run
$ click-extra show-params -- flask routes
Target resolution¶
Target resolution follows the same order as wrap: console_scripts entry points, module:function notation, .py file paths, and Python module names.
When the resolved entry point is a wrapper function (not a Click command), the module is scanned for Click command instances. If a single command group is found, it is used automatically. If multiple candidates exist, the error message lists them so you can use explicit module:name notation:
$ click-extra show-params -- flask.cli:cli
click_extra.wrap API¶
classDiagram
Command <|-- _WrapCommand
ExtraGroup <|-- WrapperGroup
ExtraHelpColorsMixin <|-- _WrapCommand
Wrap any Click CLI with Click Extra’s help colorization.
Monkey-patches Click’s decorator functions before importing the target module
so @click.command() and @click.group() produce colorized variants with
keyword highlighting and themed styling.
- class click_extra.wrap.WrapperGroup(*args, help_command=True, **kwargs)[source]¶
Bases:
ExtraGroupExtraGroup that falls back to the
wrapsubcommand for unknown names.Known subcommands and their aliases are dispatched normally. Anything else is treated as a target script and forwarded to
wrap.Like
ExtraCommand.__init__, but auto-injects ahelpsubcommand.- Parameters:
help_command (
bool) – whenTrue(the default), ahelpsubcommand is automatically registered. Set toFalseto suppress it, or register your ownhelpsubcommand to override it.
- click_extra.wrap.patch_click(theme=None, color=True)[source]¶
Replace Click’s decorator functions with colorized variants.
Must be called before importing the target CLI module so that
@click.command()and@click.group()decorators produce colorized commands.Note
Only the decorator functions are replaced, not the class names (
click.Command,click.Group). Replacing class names would breakisinstanceandissubclasschecks in Click internals (_param_memo) and Cloup’s decorator validators.- Parameters:
theme (
HelpExtraTheme|None) – Color theme to use.Nonekeeps the current default.color (
bool) – WhenFalse, the patched context disables ANSI output.
- Return type:
- click_extra.wrap.unpatch_click()[source]¶
Restore Click’s original decorator functions and methods.
Reverses the changes made by
patch_click(). Useful in tests to avoid leaking global state between test cases.- Return type:
- click_extra.wrap.resolve_target(script)[source]¶
Resolve a script name to a module path and function name.
Resolution order:
console_scriptsentry points from installed packages.Explicit
module:functionnotation..pyfile path.Bare Python module or package name.
- Return type:
- Returns:
(module_path, function_name)tuple. function_name is empty when the target should be invoked as a module or script file.- Raises:
click.ClickException – If the script cannot be resolved.