1+ from __future__ import annotations
2+
13import inspect
24import functools
35import re
68import warnings
79
810try :
9- import asyncclick as click
11+ import asyncclick
12+
13+ ASYNCCLICK_SUPPORT = True
1014except ImportError :
15+ ASYNCCLICK_SUPPORT = False
16+ try :
1117 import click
12- import click .core
18+
19+ CLICK_SUPPORT = True
20+ except ImportError as err :
21+ CLICK_SUPPORT = False
22+ if ASYNCCLICK_SUPPORT :
23+ pass
24+ else :
25+ raise err
1326from docutils import nodes
1427from docutils .parsers import rst
1528from docutils .parsers .rst import directives
2841
2942ANSI_ESC_SEQ_RE = re .compile (r'\x1B\[\d+(;\d+){0,2}m' , flags = re .MULTILINE )
3043
31- _T_Formatter = ty .Callable [[click .Context ], ty .Generator [str , None , None ]]
44+ if ASYNCCLICK_SUPPORT and CLICK_SUPPORT :
45+ click_context_type = asyncclick .Context | click .Context
46+ click_option_type = asyncclick .core .Option | click .core .Option
47+ click_choice_type = asyncclick .Choice | click .Choice
48+ click_argument_type = asyncclick .Argument | click .Argument
49+ click_command_type = asyncclick .Command | click .Command
50+ click_multicommand_type = asyncclick .MultiCommand | click .MultiCommand
51+ click_group_type = asyncclick .Group | click .Group
52+ click_command_collection_type = (
53+ asyncclick .CommandCollection | click .CommandCollection
54+ )
55+ join_options = click .formatting .join_options
56+ elif ASYNCCLICK_SUPPORT :
57+ click_context_type = asyncclick .Context
58+ click_option_type = asyncclick .core .Option
59+ click_choice_type = asyncclick .Choice
60+ click_argument_type = asyncclick .Argument
61+ click_command_type = asyncclick .Command
62+ click_multicommand_type = asyncclick .MultiCommand
63+ click_group_type = asyncclick .Group
64+ click_command_collection_type = asyncclick .CommandCollection
65+ join_options = asyncclick .formatting .join_options
66+ else :
67+ click_context_type = click .Context
68+ click_option_type = click .core .Option
69+ click_choice_type = click .Choice
70+ click_argument_type = click .Argument
71+ click_command_type = click .Command
72+ click_multicommand_type = click .MultiCommand
73+ click_group_type = click .Group
74+ click_command_collection_type = click .CommandCollection
75+ join_options = click .formatting .join_options
76+
77+ _T_Formatter = ty .Callable [[click_context_type ], ty .Generator [str , None , None ]]
3278
3379
3480def _process_lines (event_name : str ) -> ty .Callable [[_T_Formatter ], _T_Formatter ]:
3581 def decorator (func : _T_Formatter ) -> _T_Formatter :
3682 @functools .wraps (func )
37- def process_lines (ctx : click .Context ) -> ty .Generator [str , None , None ]:
83+ def process_lines (
84+ ctx : click_context_type ,
85+ ) -> ty .Generator [str , None , None ]:
3886 lines = list (func (ctx ))
3987 if "sphinx-click-env" in ctx .meta :
4088 ctx .meta ["sphinx-click-env" ].app .events .emit (event_name , ctx , lines )
@@ -56,15 +104,18 @@ def prefixed_lines() -> ty.Generator[str, None, None]:
56104 return '' .join (prefixed_lines ())
57105
58106
59- def _get_usage (ctx : click . Context ) -> str :
107+ def _get_usage (ctx : click_context_type ) -> str :
60108 """Alternative, non-prefixed version of 'get_usage'."""
61109 formatter = ctx .make_formatter ()
62110 pieces = ctx .command .collect_usage_pieces (ctx )
63111 formatter .write_usage (ctx .command_path , ' ' .join (pieces ), prefix = '' )
64112 return formatter .getvalue ().rstrip ('\n ' ) # type: ignore
65113
66114
67- def _get_help_record (ctx : click .Context , opt : click .core .Option ) -> ty .Tuple [str , str ]:
115+ def _get_help_record (
116+ ctx : click_context_type ,
117+ opt : click_option_type ,
118+ ) -> ty .Tuple [str , str ]:
68119 """Re-implementation of click.Opt.get_help_record.
69120
70121 The variant of 'get_help_record' found in Click makes uses of slashes to
@@ -76,7 +127,7 @@ def _get_help_record(ctx: click.Context, opt: click.core.Option) -> ty.Tuple[str
76127 """
77128
78129 def _write_opts (opts : ty .List [str ]) -> str :
79- rv , _ = click . formatting . join_options (opts )
130+ rv , _ = join_options (opts )
80131 if not opt .is_flag and not opt .count :
81132 name = opt .name
82133 if opt .metavar :
@@ -120,7 +171,7 @@ def _write_opts(opts: ty.List[str]) -> str:
120171 )
121172 )
122173
123- if isinstance (opt .type , click . Choice ):
174+ if isinstance (opt .type , click_choice_type ):
124175 extras .append (':options: %s' % ' | ' .join (str (x ) for x in opt .type .choices ))
125176
126177 if extras :
@@ -150,7 +201,9 @@ def _format_help(help_string: str) -> ty.Generator[str, None, None]:
150201
151202
152203@_process_lines ("sphinx-click-process-description" )
153- def _format_description (ctx : click .Context ) -> ty .Generator [str , None , None ]:
204+ def _format_description (
205+ ctx : click_context_type ,
206+ ) -> ty .Generator [str , None , None ]:
154207 """Format the description for a given `click.Command`.
155208
156209 We parse this as reStructuredText, allowing users to embed rich
@@ -162,7 +215,9 @@ def _format_description(ctx: click.Context) -> ty.Generator[str, None, None]:
162215
163216
164217@_process_lines ("sphinx-click-process-usage" )
165- def _format_usage (ctx : click .Context ) -> ty .Generator [str , None , None ]:
218+ def _format_usage (
219+ ctx : click_context_type ,
220+ ) -> ty .Generator [str , None , None ]:
166221 """Format the usage for a `click.Command`."""
167222 yield '.. code-block:: shell'
168223 yield ''
@@ -172,7 +227,8 @@ def _format_usage(ctx: click.Context) -> ty.Generator[str, None, None]:
172227
173228
174229def _format_option (
175- ctx : click .Context , opt : click .core .Option
230+ ctx : click_context_type ,
231+ opt : click_option_type ,
176232) -> ty .Generator [str , None , None ]:
177233 """Format the output for a `click.core.Option`."""
178234 opt_help = _get_help_record (ctx , opt )
@@ -194,13 +250,15 @@ def _format_option(
194250
195251
196252@_process_lines ("sphinx-click-process-options" )
197- def _format_options (ctx : click .Context ) -> ty .Generator [str , None , None ]:
253+ def _format_options (
254+ ctx : click_context_type ,
255+ ) -> ty .Generator [str , None , None ]:
198256 """Format all `click.Option` for a `click.Command`."""
199257 # the hidden attribute is part of click 7.x only hence use of getattr
200258 params = [
201259 param
202260 for param in ctx .command .params
203- if isinstance (param , click . core . Option ) and not getattr (param , 'hidden' , False )
261+ if isinstance (param , click_option_type ) and not getattr (param , 'hidden' , False )
204262 ]
205263
206264 for param in params :
@@ -209,7 +267,9 @@ def _format_options(ctx: click.Context) -> ty.Generator[str, None, None]:
209267 yield ''
210268
211269
212- def _format_argument (arg : click .Argument ) -> ty .Generator [str , None , None ]:
270+ def _format_argument (
271+ arg : click_argument_type ,
272+ ) -> ty .Generator [str , None , None ]:
213273 """Format the output of a `click.Argument`."""
214274 yield '.. option:: {}' .format (arg .human_readable_name )
215275 yield ''
@@ -228,9 +288,11 @@ def _format_argument(arg: click.Argument) -> ty.Generator[str, None, None]:
228288
229289
230290@_process_lines ("sphinx-click-process-arguments" )
231- def _format_arguments (ctx : click .Context ) -> ty .Generator [str , None , None ]:
291+ def _format_arguments (
292+ ctx : click_context_type ,
293+ ) -> ty .Generator [str , None , None ]:
232294 """Format all `click.Argument` for a `click.Command`."""
233- params = [x for x in ctx .command .params if isinstance (x , click . Argument )]
295+ params = [x for x in ctx .command .params if isinstance (x , click_argument_type )]
234296
235297 for param in params :
236298 for line in _format_argument (param ):
@@ -239,13 +301,13 @@ def _format_arguments(ctx: click.Context) -> ty.Generator[str, None, None]:
239301
240302
241303def _format_envvar (
242- param : ty . Union [ click . core . Option , click . Argument ] ,
304+ param : click_option_type | click_argument_type ,
243305) -> ty .Generator [str , None , None ]:
244306 """Format the envvars of a `click.Option` or `click.Argument`."""
245307 yield '.. envvar:: {}' .format (param .envvar )
246308 yield ' :noindex:'
247309 yield ''
248- if isinstance (param , click . Argument ):
310+ if isinstance (param , click_argument_type ):
249311 param_ref = param .human_readable_name
250312 else :
251313 # if a user has defined an opt with multiple "aliases", always use the
@@ -256,7 +318,9 @@ def _format_envvar(
256318
257319
258320@_process_lines ("sphinx-click-process-envars" )
259- def _format_envvars (ctx : click .Context ) -> ty .Generator [str , None , None ]:
321+ def _format_envvars (
322+ ctx : click_context_type ,
323+ ) -> ty .Generator [str , None , None ]:
260324 """Format all envvars for a `click.Command`."""
261325
262326 auto_envvar_prefix = ctx .auto_envvar_prefix
@@ -281,7 +345,9 @@ def _format_envvars(ctx: click.Context) -> ty.Generator[str, None, None]:
281345 yield ''
282346
283347
284- def _format_subcommand (command : click .Command ) -> ty .Generator [str , None , None ]:
348+ def _format_subcommand (
349+ command : click_command_type ,
350+ ) -> ty .Generator [str , None , None ]:
285351 """Format a sub-command of a `click.Command` or `click.Group`."""
286352 yield '.. object:: {}' .format (command .name )
287353
@@ -296,7 +362,9 @@ def _format_subcommand(command: click.Command) -> ty.Generator[str, None, None]:
296362
297363
298364@_process_lines ("sphinx-click-process-epilog" )
299- def _format_epilog (ctx : click .Context ) -> ty .Generator [str , None , None ]:
365+ def _format_epilog (
366+ ctx : click_context_type ,
367+ ) -> ty .Generator [str , None , None ]:
300368 """Format the epilog for a given `click.Command`.
301369
302370 We parse this as reStructuredText, allowing users to embed rich
@@ -306,7 +374,9 @@ def _format_epilog(ctx: click.Context) -> ty.Generator[str, None, None]:
306374 yield from _format_help (ctx .command .epilog )
307375
308376
309- def _get_lazyload_commands (ctx : click .Context ) -> ty .Dict [str , click .Command ]:
377+ def _get_lazyload_commands (
378+ ctx : click_context_type ,
379+ ) -> ty .Dict [str , click_command_type ]:
310380 commands = {}
311381 for command in ctx .command .list_commands (ctx ):
312382 commands [command ] = ctx .command .get_command (ctx , command )
@@ -315,12 +385,12 @@ def _get_lazyload_commands(ctx: click.Context) -> ty.Dict[str, click.Command]:
315385
316386
317387def _filter_commands (
318- ctx : click . Context ,
388+ ctx : click_context_type ,
319389 commands : ty .Optional [ty .List [str ]] = None ,
320- ) -> ty .List [click . Command ]:
390+ ) -> ty .List [click_command_type ]:
321391 """Return list of used commands."""
322392 lookup = getattr (ctx .command , 'commands' , {})
323- if not lookup and isinstance (ctx .command , click . MultiCommand ):
393+ if not lookup and isinstance (ctx .command , click_multicommand_type ):
324394 lookup = _get_lazyload_commands (ctx )
325395
326396 if commands is None :
@@ -330,7 +400,7 @@ def _filter_commands(
330400
331401
332402def _format_command (
333- ctx : click . Context ,
403+ ctx : click_context_type ,
334404 nested : NestedT ,
335405 commands : ty .Optional [ty .List [str ]] = None ,
336406) -> ty .Generator [str , None , None ]:
@@ -429,7 +499,7 @@ class ClickDirective(rst.Directive):
429499 'show-nested' : directives .flag ,
430500 }
431501
432- def _load_module (self , module_path : str ) -> ty . Union [ click . Command , click . Group ] :
502+ def _load_module (self , module_path : str ) -> click_command_type | click_group_type :
433503 """Load the module."""
434504
435505 try :
@@ -460,7 +530,7 @@ def _load_module(self, module_path: str) -> ty.Union[click.Command, click.Group]
460530
461531 parser = getattr (mod , attr_name )
462532
463- if not isinstance (parser , ( click . Command , click . Group ) ):
533+ if not isinstance (parser , click_command_type | click_group_type ):
464534 raise self .error (
465535 '"{}" of type "{}" is not click.Command or click.Group.'
466536 '"click.BaseCommand"' .format (type (parser ), module_path )
@@ -470,8 +540,8 @@ def _load_module(self, module_path: str) -> ty.Union[click.Command, click.Group]
470540 def _generate_nodes (
471541 self ,
472542 name : str ,
473- command : click . Command ,
474- parent : ty .Optional [click . Context ],
543+ command : click_command_type ,
544+ parent : ty .Optional [click_context_type ],
475545 nested : NestedT ,
476546 commands : ty .Optional [ty .List [str ]] = None ,
477547 semantic_group : bool = False ,
@@ -490,7 +560,10 @@ def _generate_nodes(
490560 `click.CommandCollection`.
491561 :returns: A list of nested docutil nodes
492562 """
493- ctx = click .Context (command , info_name = name , parent = parent )
563+ if ASYNCCLICK_SUPPORT and isinstance (command , asyncclick .Command ):
564+ ctx = asyncclick .Context (command , info_name = name , parent = parent )
565+ else :
566+ ctx = click .Context (command , info_name = name , parent = parent )
494567
495568 if command .hidden :
496569 return []
@@ -523,7 +596,7 @@ def _generate_nodes(
523596 # Subcommands
524597
525598 if nested == NESTED_FULL :
526- if isinstance (command , click . CommandCollection ):
599+ if isinstance (command , click_command_collection_type ):
527600 for source in command .sources :
528601 section .extend (
529602 self ._generate_nodes (
0 commit comments