0
# sphinx-click
1
2
A Sphinx extension that automatically extracts documentation from Click-based command-line applications and integrates it into Sphinx documentation systems. It enables developers to document their CLI tools by automatically generating formatted help text, command descriptions, and option details directly from the Click application code.
3
4
## Package Information
5
6
- **Package Name**: sphinx-click
7
- **Language**: Python
8
- **Installation**: `pip install sphinx-click`
9
- **Requires**: Python >=3.8
10
11
## Core Imports
12
13
```python
14
import sphinx_click
15
```
16
17
For Sphinx extension setup:
18
19
```python
20
# In your Sphinx conf.py
21
extensions = ['sphinx_click']
22
```
23
24
## Basic Usage
25
26
### 1. Enable the Extension
27
28
Add sphinx-click to your Sphinx configuration file (`conf.py`):
29
30
```python
31
extensions = ['sphinx_click']
32
```
33
34
### 2. Document a Click Application
35
36
Use the `.. click::` directive in your documentation:
37
38
```rst
39
.. click:: mypackage.cli:main
40
:prog: my-cli-tool
41
:nested: full
42
```
43
44
### 3. Complete Example
45
46
Given a Click application like this:
47
48
```python
49
# mypackage/cli.py
50
import click
51
52
@click.group()
53
def main():
54
"""A sample CLI application."""
55
pass
56
57
@main.command()
58
@click.option('--name', '-n', help='Name to greet')
59
@click.option('--count', default=1, help='Number of greetings')
60
def hello(name, count):
61
"""Say hello to someone."""
62
for _ in range(count):
63
click.echo(f'Hello {name}!')
64
65
@main.command()
66
def goodbye():
67
"""Say goodbye."""
68
click.echo('Goodbye!')
69
```
70
71
Document it with:
72
73
```rst
74
.. click:: mypackage.cli:main
75
:prog: my-cli-tool
76
:nested: full
77
```
78
79
This automatically generates formatted documentation showing the command structure, options, arguments, and help text.
80
81
## Capabilities
82
83
### Sphinx Extension Setup
84
85
Register the extension with Sphinx and configure its behavior.
86
87
```python { .api }
88
def setup(app: Sphinx) -> Dict[str, Any]:
89
"""
90
Set up the sphinx-click extension.
91
92
Args:
93
app: The Sphinx application instance
94
95
Returns:
96
Dict containing extension metadata with keys:
97
- 'parallel_read_safe': True
98
- 'parallel_write_safe': True
99
"""
100
```
101
102
### Click Directive
103
104
The main Sphinx directive for documenting Click applications.
105
106
```python { .api }
107
class ClickDirective(rst.Directive):
108
"""
109
A Sphinx directive for documenting Click commands.
110
111
Usage:
112
.. click:: module:parser
113
:prog: program-name
114
:nested: full|short|none
115
:commands: cmd1,cmd2,cmd3
116
"""
117
118
has_content = False
119
required_arguments = 1
120
option_spec = {
121
'prog': 'directives.unchanged_required',
122
'nested': 'nested', # Custom validation function
123
'commands': 'directives.unchanged',
124
'show-nested': 'directives.flag'
125
}
126
127
def _load_module(self, module_path: str) -> Union[click.Command, click.Group]:
128
"""Load the module and return the Click command/group."""
129
130
def _generate_nodes(
131
self,
132
name: str,
133
command: click.Command,
134
parent: Optional[click.Context],
135
nested: NestedT,
136
commands: Optional[List[str]] = None,
137
semantic_group: bool = False,
138
) -> List[nodes.section]:
139
"""Generate the relevant Sphinx nodes for documentation."""
140
141
def run(self) -> Sequence[nodes.section]:
142
"""Execute the directive and return documentation nodes."""
143
```
144
145
### Configuration
146
147
Extension configuration options available in Sphinx conf.py.
148
149
```python { .api }
150
# Configuration value for mocking imports during documentation build
151
sphinx_click_mock_imports: List[str]
152
"""
153
List of module names to mock during import.
154
Defaults to autodoc_mock_imports if not specified.
155
156
Example in conf.py:
157
sphinx_click_mock_imports = ['some_module', 'another_module']
158
"""
159
```
160
161
### Events
162
163
Custom Sphinx events emitted during documentation generation for customization.
164
165
```python { .api }
166
# Event: sphinx-click-process-description
167
def on_process_description(ctx: click.Context, lines: List[str]) -> None:
168
"""
169
Emitted when processing command descriptions.
170
171
Args:
172
ctx: Click context for the command
173
lines: List of description lines (modifiable)
174
"""
175
176
# Event: sphinx-click-process-usage
177
def on_process_usage(ctx: click.Context, lines: List[str]) -> None:
178
"""
179
Emitted when processing usage information.
180
181
Args:
182
ctx: Click context for the command
183
lines: List of usage lines (modifiable)
184
"""
185
186
# Event: sphinx-click-process-options
187
def on_process_options(ctx: click.Context, lines: List[str]) -> None:
188
"""
189
Emitted when processing command options.
190
191
Args:
192
ctx: Click context for the command
193
lines: List of option lines (modifiable)
194
"""
195
196
# Event: sphinx-click-process-arguments
197
def on_process_arguments(ctx: click.Context, lines: List[str]) -> None:
198
"""
199
Emitted when processing command arguments.
200
201
Args:
202
ctx: Click context for the command
203
lines: List of argument lines (modifiable)
204
"""
205
206
# Event: sphinx-click-process-envars
207
def on_process_envvars(ctx: click.Context, lines: List[str]) -> None:
208
"""
209
Emitted when processing environment variables.
210
211
Args:
212
ctx: Click context for the command
213
lines: List of environment variable lines (modifiable)
214
"""
215
216
# Event: sphinx-click-process-epilog
217
def on_process_epilog(ctx: click.Context, lines: List[str]) -> None:
218
"""
219
Emitted when processing command epilog text.
220
221
Args:
222
ctx: Click context for the command
223
lines: List of epilog lines (modifiable)
224
"""
225
```
226
227
## Directive Options
228
229
### Required Options
230
231
```python { .api }
232
# :prog: option (required)
233
prog: str
234
"""
235
The program name to display in usage examples.
236
237
Example:
238
.. click:: mypackage.cli:main
239
:prog: my-tool
240
"""
241
```
242
243
### Validation Functions
244
245
```python { .api }
246
def nested(argument: Optional[str]) -> NestedT:
247
"""
248
Validate nested directive option values.
249
250
Args:
251
argument: The option value from the directive
252
253
Returns:
254
Validated nested option value
255
256
Raises:
257
ValueError: If argument is not a valid nested value
258
"""
259
```
260
261
### Optional Options
262
263
```python { .api }
264
# :nested: option
265
nested: Literal['full', 'short', 'none', None]
266
"""
267
Control the level of nested command documentation.
268
269
Values:
270
- 'full': Show complete documentation for all subcommands
271
- 'short': Show only command names and short descriptions
272
- 'none': Don't show subcommands at all
273
- None: Default behavior (same as 'short')
274
275
Example:
276
.. click:: mypackage.cli:main
277
:prog: my-tool
278
:nested: full
279
"""
280
281
# :commands: option
282
commands: str
283
"""
284
Comma-separated list of specific commands to document.
285
If not specified, all commands are documented.
286
287
Example:
288
.. click:: mypackage.cli:main
289
:prog: my-tool
290
:commands: hello,goodbye
291
"""
292
293
# :show-nested: option (deprecated)
294
show_nested: bool
295
"""
296
Deprecated: Use :nested: full instead.
297
When present, shows full nested command documentation.
298
299
Example (deprecated):
300
.. click:: mypackage.cli:main
301
:prog: my-tool
302
:show-nested:
303
"""
304
```
305
306
### Utility Functions
307
308
Helper functions for formatting and processing Click command data.
309
310
```python { .api }
311
def _get_usage(ctx: click.Context) -> str:
312
"""
313
Alternative, non-prefixed version of 'get_usage'.
314
315
Args:
316
ctx: Click context for the command
317
318
Returns:
319
Usage string without command name prefix
320
"""
321
322
def _get_help_record(ctx: click.Context, opt: click.core.Option) -> Tuple[str, str]:
323
"""
324
Re-implementation of click.Option.get_help_record compatible with Sphinx.
325
326
Formats option arguments using angle brackets instead of uppercase,
327
and uses comma-separated opts instead of slashes for Sphinx compatibility.
328
329
Args:
330
ctx: Click context for the command
331
opt: Click option to format
332
333
Returns:
334
Tuple of (option_signature, help_text)
335
"""
336
337
def _format_help(help_string: str) -> Generator[str, None, None]:
338
"""
339
Format help string by cleaning ANSI sequences and processing special markers.
340
341
Args:
342
help_string: Raw help text from Click command
343
344
Yields:
345
Formatted help lines
346
"""
347
348
def _indent(text: str, level: int = 1) -> str:
349
"""
350
Indent text by specified number of levels (4 spaces per level).
351
352
Args:
353
text: Text to indent
354
level: Number of indentation levels
355
356
Returns:
357
Indented text
358
"""
359
360
def _filter_commands(
361
ctx: click.Context,
362
commands: Optional[List[str]] = None,
363
) -> List[click.Command]:
364
"""
365
Return filtered list of commands from a Click group.
366
367
Args:
368
ctx: Click context for the command group
369
commands: Optional list of specific command names to include
370
371
Returns:
372
List of Click commands, sorted by name
373
"""
374
375
def _get_lazyload_commands(ctx: click.Context) -> Dict[str, click.Command]:
376
"""
377
Get lazy-loaded commands from a Click multi-command.
378
379
Args:
380
ctx: Click context for the multi-command
381
382
Returns:
383
Dictionary mapping command names to command objects
384
"""
385
386
def _process_lines(event_name: str) -> Callable[[_T_Formatter], _T_Formatter]:
387
"""
388
Decorator that emits Sphinx events during line processing.
389
390
Args:
391
event_name: Name of the event to emit
392
393
Returns:
394
Decorator function for formatter functions
395
"""
396
```
397
398
### Formatter Functions
399
400
Internal functions that generate reStructuredText for different parts of Click commands.
401
402
```python { .api }
403
def _format_description(ctx: click.Context) -> Generator[str, None, None]:
404
"""
405
Format the description for a given Click Command.
406
407
Parses help text as reStructuredText, allowing rich information
408
in help messages.
409
410
Args:
411
ctx: Click context for the command
412
413
Yields:
414
Formatted description lines
415
"""
416
417
def _format_usage(ctx: click.Context) -> Generator[str, None, None]:
418
"""
419
Format the usage for a Click Command.
420
421
Args:
422
ctx: Click context for the command
423
424
Yields:
425
Formatted usage lines as code block
426
"""
427
428
def _format_options(ctx: click.Context) -> Generator[str, None, None]:
429
"""
430
Format all Click Options for a Click Command.
431
432
Args:
433
ctx: Click context for the command
434
435
Yields:
436
Formatted option documentation lines
437
"""
438
439
def _format_arguments(ctx: click.Context) -> Generator[str, None, None]:
440
"""
441
Format all Click Arguments for a Click Command.
442
443
Args:
444
ctx: Click context for the command
445
446
Yields:
447
Formatted argument documentation lines
448
"""
449
450
def _format_envvars(ctx: click.Context) -> Generator[str, None, None]:
451
"""
452
Format all environment variables for a Click Command.
453
454
Args:
455
ctx: Click context for the command
456
457
Yields:
458
Formatted environment variable documentation lines
459
"""
460
461
def _format_epilog(ctx: click.Context) -> Generator[str, None, None]:
462
"""
463
Format the epilog for a given Click Command.
464
465
Parses epilog text as reStructuredText.
466
467
Args:
468
ctx: Click context for the command
469
470
Yields:
471
Formatted epilog lines
472
"""
473
474
def _format_command(
475
ctx: click.Context,
476
nested: NestedT,
477
commands: Optional[List[str]] = None,
478
) -> Generator[str, None, None]:
479
"""
480
Format the complete output of a Click Command.
481
482
Args:
483
ctx: Click context for the command
484
nested: The granularity of subcommand details
485
commands: Optional list of specific commands to document
486
487
Yields:
488
Complete formatted command documentation lines
489
"""
490
491
def _format_option(
492
ctx: click.Context, opt: click.core.Option
493
) -> Generator[str, None, None]:
494
"""
495
Format the output for a single Click Option.
496
497
Args:
498
ctx: Click context for the command
499
opt: Click option to format
500
501
Yields:
502
Formatted option lines
503
"""
504
505
def _format_argument(arg: click.Argument) -> Generator[str, None, None]:
506
"""
507
Format the output of a Click Argument.
508
509
Args:
510
arg: Click argument to format
511
512
Yields:
513
Formatted argument lines
514
"""
515
516
def _format_envvar(
517
param: Union[click.core.Option, click.Argument]
518
) -> Generator[str, None, None]:
519
"""
520
Format the environment variables of a Click Option or Argument.
521
522
Args:
523
param: Click parameter with environment variable
524
525
Yields:
526
Formatted environment variable lines
527
"""
528
529
def _format_subcommand(command: click.Command) -> Generator[str, None, None]:
530
"""
531
Format a sub-command of a Click Command or Group.
532
533
Args:
534
command: Click subcommand to format
535
536
Yields:
537
Formatted subcommand lines
538
"""
539
```
540
541
## Types
542
543
```python { .api }
544
from typing import Literal, Sequence, Dict, Any, List, Optional, Union, Callable, Generator, Pattern, Tuple
545
from sphinx.application import Sphinx
546
from docutils import nodes
547
from docutils.parsers.rst import Directive
548
import click
549
import logging
550
551
# Type aliases used in the API
552
NestedT = Literal['full', 'short', 'none', None]
553
_T_Formatter = Callable[[click.Context], Generator[str, None, None]]
554
555
# Constants for nested option values
556
NESTED_FULL: str = 'full'
557
NESTED_SHORT: str = 'short'
558
NESTED_NONE: str = 'none'
559
560
# Pattern for removing ANSI escape sequences
561
ANSI_ESC_SEQ_RE: Pattern[str]
562
563
# Logger instance
564
LOG: logging.Logger
565
```
566
567
## Error Handling
568
569
The extension handles several common error conditions:
570
571
### Import Errors
572
573
```python
574
# Module import failures are caught and reported with helpful messages
575
# Example error messages:
576
# - "Failed to import 'parser' from 'mymodule'. The following exception was raised: ..."
577
# - "Module 'mymodule' has no attribute 'parser'"
578
# - "The module appeared to call sys.exit()"
579
```
580
581
### Invalid Click Objects
582
583
```python
584
# Validates that imported objects are Click commands or groups
585
# Example error message:
586
# - "'<type>' of type 'str' is not click.Command or click.Group"
587
```
588
589
### Directive Option Errors
590
591
```python
592
# Validates directive options and provides clear error messages
593
# Example error messages:
594
# - ":prog: must be specified"
595
# - "'invalid' is not a valid value for ':nested:'; allowed values: full, short, none, None"
596
# - "':nested:' and ':show-nested:' are mutually exclusive"
597
```
598
599
## Dependencies
600
601
- **click** or **asyncclick**: For Click command/group support
602
- **sphinx**: Core documentation system (requires sphinx.ext.autodoc)
603
- **docutils**: reStructuredText processing utilities
604
605
## Advanced Usage
606
607
### Event Customization
608
609
Register event handlers to customize the generated documentation:
610
611
```python
612
# In your Sphinx conf.py
613
def customize_description(ctx, lines):
614
"""Modify command descriptions during processing."""
615
if ctx.command.name == 'special-command':
616
lines.insert(0, '**This is a special command!**')
617
lines.append('')
618
619
def setup(app):
620
app.connect('sphinx-click-process-description', customize_description)
621
```
622
623
### Mock Imports
624
625
Handle missing dependencies during documentation builds:
626
627
```python
628
# In your Sphinx conf.py
629
sphinx_click_mock_imports = [
630
'expensive_dependency',
631
'optional_module',
632
'development_only_package'
633
]
634
```
635
636
### Complex Command Structures
637
638
Document multi-level command groups:
639
640
```rst
641
.. click:: mypackage.cli:main
642
:prog: my-complex-tool
643
:nested: full
644
645
.. click:: mypackage.admin:admin_cli
646
:prog: my-complex-tool admin
647
:nested: short
648
:commands: user,permissions
649
```