44import traceback
55import typing as ty
66import warnings
7+ from __future__ import annotations
78
89try :
9- import asyncclick as click
10+ import asyncclick
11+
12+ ASYNCCLICK_SUPPORT = True
1013except ImportError :
14+ ASYNCCLICK_SUPPORT = False
15+ try :
1116 import click
12- import click .core
17+
18+ CLICK_SUPPORT = True
19+ except ImportError as err :
20+ CLICK_SUPPORT = False
21+ if ASYNCCLICK_SUPPORT :
22+ pass
23+ else :
24+ raise err
1325from docutils import nodes
1426from docutils .parsers import rst
1527from docutils .parsers .rst import directives
2840
2941ANSI_ESC_SEQ_RE = re .compile (r'\x1B\[\d+(;\d+){0,2}m' , flags = re .MULTILINE )
3042
31- _T_Formatter = ty .Callable [[click .Context ], ty .Generator [str , None , None ]]
43+ if ASYNCCLICK_SUPPORT and CLICK_SUPPORT :
44+ click_context_type = asyncclick .Context | click .Context
45+ click_option_type = asyncclick .core .Option | click .core .Option
46+ click_choice_type = asyncclick .Choice | click .Choice
47+ click_argument_type = asyncclick .Argument | click .Argument
48+ click_command_type = asyncclick .Command | click .Command
49+ click_multicommand_type = asyncclick .MultiCommand | click .MultiCommand
50+ click_group_type = asyncclick .Group | click .Group
51+ click_command_collection_type = (
52+ asyncclick .CommandCollection | click .CommandCollection
53+ )
54+ join_options = click .formatting .join_options
55+ elif ASYNCCLICK_SUPPORT :
56+ click_context_type = asyncclick .Context
57+ click_option_type = asyncclick .core .Option
58+ click_choice_type = asyncclick .Choice
59+ click_argument_type = asyncclick .Argument
60+ click_command_type = asyncclick .Command
61+ click_multicommand_type = asyncclick .MultiCommand
62+ click_group_type = asyncclick .Group
63+ click_command_collection_type = asyncclick .CommandCollection
64+ join_options = asyncclick .formatting .join_options
65+ else :
66+ click_context_type = click .Context
67+ click_option_type = click .core .Option
68+ click_choice_type = click .Choice
69+ click_argument_type = click .Argument
70+ click_command_type = click .Command
71+ click_multicommand_type = click .MultiCommand
72+ click_group_type = click .Group
73+ click_command_collection_type = click .CommandCollection
74+ join_options = click .formatting .join_options
75+
76+ _T_Formatter = ty .Callable [[click_context_type ], ty .Generator [str , None , None ]]
3277
3378
3479def _process_lines (event_name : str ) -> ty .Callable [[_T_Formatter ], _T_Formatter ]:
3580 def decorator (func : _T_Formatter ) -> _T_Formatter :
3681 @functools .wraps (func )
37- def process_lines (ctx : click .Context ) -> ty .Generator [str , None , None ]:
82+ def process_lines (
83+ ctx : click_context_type ,
84+ ) -> ty .Generator [str , None , None ]:
3885 lines = list (func (ctx ))
3986 if "sphinx-click-env" in ctx .meta :
4087 ctx .meta ["sphinx-click-env" ].app .events .emit (event_name , ctx , lines )
@@ -56,15 +103,18 @@ def prefixed_lines() -> ty.Generator[str, None, None]:
56103 return '' .join (prefixed_lines ())
57104
58105
59- def _get_usage (ctx : click . Context ) -> str :
106+ def _get_usage (ctx : click_context_type ) -> str :
60107 """Alternative, non-prefixed version of 'get_usage'."""
61108 formatter = ctx .make_formatter ()
62109 pieces = ctx .command .collect_usage_pieces (ctx )
63110 formatter .write_usage (ctx .command_path , ' ' .join (pieces ), prefix = '' )
64111 return formatter .getvalue ().rstrip ('\n ' ) # type: ignore
65112
66113
67- def _get_help_record (ctx : click .Context , opt : click .core .Option ) -> ty .Tuple [str , str ]:
114+ def _get_help_record (
115+ ctx : click_context_type ,
116+ opt : click_option_type ,
117+ ) -> ty .Tuple [str , str ]:
68118 """Re-implementation of click.Opt.get_help_record.
69119
70120 The variant of 'get_help_record' found in Click makes uses of slashes to
@@ -76,7 +126,7 @@ def _get_help_record(ctx: click.Context, opt: click.core.Option) -> ty.Tuple[str
76126 """
77127
78128 def _write_opts (opts : ty .List [str ]) -> str :
79- rv , _ = click . formatting . join_options (opts )
129+ rv , _ = join_options (opts )
80130 if not opt .is_flag and not opt .count :
81131 name = opt .name
82132 if opt .metavar :
@@ -120,7 +170,7 @@ def _write_opts(opts: ty.List[str]) -> str:
120170 )
121171 )
122172
123- if isinstance (opt .type , click . Choice ):
173+ if isinstance (opt .type , click_choice_type ):
124174 extras .append (':options: %s' % ' | ' .join (str (x ) for x in opt .type .choices ))
125175
126176 if extras :
@@ -150,7 +200,9 @@ def _format_help(help_string: str) -> ty.Generator[str, None, None]:
150200
151201
152202@_process_lines ("sphinx-click-process-description" )
153- def _format_description (ctx : click .Context ) -> ty .Generator [str , None , None ]:
203+ def _format_description (
204+ ctx : click_context_type ,
205+ ) -> ty .Generator [str , None , None ]:
154206 """Format the description for a given `click.Command`.
155207
156208 We parse this as reStructuredText, allowing users to embed rich
@@ -162,7 +214,9 @@ def _format_description(ctx: click.Context) -> ty.Generator[str, None, None]:
162214
163215
164216@_process_lines ("sphinx-click-process-usage" )
165- def _format_usage (ctx : click .Context ) -> ty .Generator [str , None , None ]:
217+ def _format_usage (
218+ ctx : click_context_type ,
219+ ) -> ty .Generator [str , None , None ]:
166220 """Format the usage for a `click.Command`."""
167221 yield '.. code-block:: shell'
168222 yield ''
@@ -172,7 +226,8 @@ def _format_usage(ctx: click.Context) -> ty.Generator[str, None, None]:
172226
173227
174228def _format_option (
175- ctx : click .Context , opt : click .core .Option
229+ ctx : click_context_type ,
230+ opt : click_option_type ,
176231) -> ty .Generator [str , None , None ]:
177232 """Format the output for a `click.core.Option`."""
178233 opt_help = _get_help_record (ctx , opt )
@@ -194,13 +249,15 @@ def _format_option(
194249
195250
196251@_process_lines ("sphinx-click-process-options" )
197- def _format_options (ctx : click .Context ) -> ty .Generator [str , None , None ]:
252+ def _format_options (
253+ ctx : click_context_type ,
254+ ) -> ty .Generator [str , None , None ]:
198255 """Format all `click.Option` for a `click.Command`."""
199256 # the hidden attribute is part of click 7.x only hence use of getattr
200257 params = [
201258 param
202259 for param in ctx .command .params
203- if isinstance (param , click . core . Option ) and not getattr (param , 'hidden' , False )
260+ if isinstance (param , click_option_type ) and not getattr (param , 'hidden' , False )
204261 ]
205262
206263 for param in params :
@@ -209,7 +266,9 @@ def _format_options(ctx: click.Context) -> ty.Generator[str, None, None]:
209266 yield ''
210267
211268
212- def _format_argument (arg : click .Argument ) -> ty .Generator [str , None , None ]:
269+ def _format_argument (
270+ arg : click_argument_type ,
271+ ) -> ty .Generator [str , None , None ]:
213272 """Format the output of a `click.Argument`."""
214273 yield '.. option:: {}' .format (arg .human_readable_name )
215274 yield ''
@@ -228,9 +287,11 @@ def _format_argument(arg: click.Argument) -> ty.Generator[str, None, None]:
228287
229288
230289@_process_lines ("sphinx-click-process-arguments" )
231- def _format_arguments (ctx : click .Context ) -> ty .Generator [str , None , None ]:
290+ def _format_arguments (
291+ ctx : click_context_type ,
292+ ) -> ty .Generator [str , None , None ]:
232293 """Format all `click.Argument` for a `click.Command`."""
233- params = [x for x in ctx .command .params if isinstance (x , click . Argument )]
294+ params = [x for x in ctx .command .params if isinstance (x , click_argument_type )]
234295
235296 for param in params :
236297 for line in _format_argument (param ):
@@ -239,13 +300,13 @@ def _format_arguments(ctx: click.Context) -> ty.Generator[str, None, None]:
239300
240301
241302def _format_envvar (
242- param : ty . Union [ click . core . Option , click . Argument ] ,
303+ param : click_option_type | click_argument_type ,
243304) -> ty .Generator [str , None , None ]:
244305 """Format the envvars of a `click.Option` or `click.Argument`."""
245306 yield '.. envvar:: {}' .format (param .envvar )
246307 yield ' :noindex:'
247308 yield ''
248- if isinstance (param , click . Argument ):
309+ if isinstance (param , click_argument_type ):
249310 param_ref = param .human_readable_name
250311 else :
251312 # if a user has defined an opt with multiple "aliases", always use the
@@ -256,7 +317,9 @@ def _format_envvar(
256317
257318
258319@_process_lines ("sphinx-click-process-envars" )
259- def _format_envvars (ctx : click .Context ) -> ty .Generator [str , None , None ]:
320+ def _format_envvars (
321+ ctx : click_context_type ,
322+ ) -> ty .Generator [str , None , None ]:
260323 """Format all envvars for a `click.Command`."""
261324
262325 auto_envvar_prefix = ctx .auto_envvar_prefix
@@ -281,7 +344,9 @@ def _format_envvars(ctx: click.Context) -> ty.Generator[str, None, None]:
281344 yield ''
282345
283346
284- def _format_subcommand (command : click .Command ) -> ty .Generator [str , None , None ]:
347+ def _format_subcommand (
348+ command : click_command_type ,
349+ ) -> ty .Generator [str , None , None ]:
285350 """Format a sub-command of a `click.Command` or `click.Group`."""
286351 yield '.. object:: {}' .format (command .name )
287352
@@ -296,7 +361,9 @@ def _format_subcommand(command: click.Command) -> ty.Generator[str, None, None]:
296361
297362
298363@_process_lines ("sphinx-click-process-epilog" )
299- def _format_epilog (ctx : click .Context ) -> ty .Generator [str , None , None ]:
364+ def _format_epilog (
365+ ctx : click_context_type ,
366+ ) -> ty .Generator [str , None , None ]:
300367 """Format the epilog for a given `click.Command`.
301368
302369 We parse this as reStructuredText, allowing users to embed rich
@@ -306,7 +373,9 @@ def _format_epilog(ctx: click.Context) -> ty.Generator[str, None, None]:
306373 yield from _format_help (ctx .command .epilog )
307374
308375
309- def _get_lazyload_commands (ctx : click .Context ) -> ty .Dict [str , click .Command ]:
376+ def _get_lazyload_commands (
377+ ctx : click_context_type ,
378+ ) -> ty .Dict [str , click_command_type ]:
310379 commands = {}
311380 for command in ctx .command .list_commands (ctx ):
312381 commands [command ] = ctx .command .get_command (ctx , command )
@@ -315,12 +384,12 @@ def _get_lazyload_commands(ctx: click.Context) -> ty.Dict[str, click.Command]:
315384
316385
317386def _filter_commands (
318- ctx : click . Context ,
387+ ctx : click_context_type ,
319388 commands : ty .Optional [ty .List [str ]] = None ,
320- ) -> ty .List [click . Command ]:
389+ ) -> ty .List [click_command_type ]:
321390 """Return list of used commands."""
322391 lookup = getattr (ctx .command , 'commands' , {})
323- if not lookup and isinstance (ctx .command , click . MultiCommand ):
392+ if not lookup and isinstance (ctx .command , click_multicommand_type ):
324393 lookup = _get_lazyload_commands (ctx )
325394
326395 if commands is None :
@@ -330,7 +399,7 @@ def _filter_commands(
330399
331400
332401def _format_command (
333- ctx : click . Context ,
402+ ctx : click_context_type ,
334403 nested : NestedT ,
335404 commands : ty .Optional [ty .List [str ]] = None ,
336405) -> ty .Generator [str , None , None ]:
@@ -429,7 +498,7 @@ class ClickDirective(rst.Directive):
429498 'show-nested' : directives .flag ,
430499 }
431500
432- def _load_module (self , module_path : str ) -> ty . Union [ click . Command , click . Group ] :
501+ def _load_module (self , module_path : str ) -> click_command_type | click_group_type :
433502 """Load the module."""
434503
435504 try :
@@ -460,7 +529,7 @@ def _load_module(self, module_path: str) -> ty.Union[click.Command, click.Group]
460529
461530 parser = getattr (mod , attr_name )
462531
463- if not isinstance (parser , ( click . Command , click . Group ) ):
532+ if not isinstance (parser , click_command_type | click_group_type ):
464533 raise self .error (
465534 '"{}" of type "{}" is not click.Command or click.Group.'
466535 '"click.BaseCommand"' .format (type (parser ), module_path )
@@ -470,8 +539,8 @@ def _load_module(self, module_path: str) -> ty.Union[click.Command, click.Group]
470539 def _generate_nodes (
471540 self ,
472541 name : str ,
473- command : click . Command ,
474- parent : ty .Optional [click . Context ],
542+ command : click_command_type ,
543+ parent : ty .Optional [click_context_type ],
475544 nested : NestedT ,
476545 commands : ty .Optional [ty .List [str ]] = None ,
477546 semantic_group : bool = False ,
@@ -490,7 +559,10 @@ def _generate_nodes(
490559 `click.CommandCollection`.
491560 :returns: A list of nested docutil nodes
492561 """
493- ctx = click .Context (command , info_name = name , parent = parent )
562+ if ASYNCCLICK_SUPPORT and isinstance (command , asyncclick .Command ):
563+ ctx = asyncclick .Context (command , info_name = name , parent = parent )
564+ else :
565+ ctx = click .Context (command , info_name = name , parent = parent )
494566
495567 if command .hidden :
496568 return []
@@ -523,7 +595,7 @@ def _generate_nodes(
523595 # Subcommands
524596
525597 if nested == NESTED_FULL :
526- if isinstance (command , click . CommandCollection ):
598+ if isinstance (command , click_command_collection_type ):
527599 for source in command .sources :
528600 section .extend (
529601 self ._generate_nodes (
0 commit comments