outerbounds 0.3.55rc8__py3-none-any.whl → 0.3.133__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- outerbounds/_vendor/PyYAML.LICENSE +20 -0
- outerbounds/_vendor/__init__.py +0 -0
- outerbounds/_vendor/_yaml/__init__.py +34 -0
- outerbounds/_vendor/click/__init__.py +73 -0
- outerbounds/_vendor/click/_compat.py +626 -0
- outerbounds/_vendor/click/_termui_impl.py +717 -0
- outerbounds/_vendor/click/_textwrap.py +49 -0
- outerbounds/_vendor/click/_winconsole.py +279 -0
- outerbounds/_vendor/click/core.py +2998 -0
- outerbounds/_vendor/click/decorators.py +497 -0
- outerbounds/_vendor/click/exceptions.py +287 -0
- outerbounds/_vendor/click/formatting.py +301 -0
- outerbounds/_vendor/click/globals.py +68 -0
- outerbounds/_vendor/click/parser.py +529 -0
- outerbounds/_vendor/click/py.typed +0 -0
- outerbounds/_vendor/click/shell_completion.py +580 -0
- outerbounds/_vendor/click/termui.py +787 -0
- outerbounds/_vendor/click/testing.py +479 -0
- outerbounds/_vendor/click/types.py +1073 -0
- outerbounds/_vendor/click/utils.py +580 -0
- outerbounds/_vendor/click.LICENSE +28 -0
- outerbounds/_vendor/vendor_any.txt +2 -0
- outerbounds/_vendor/yaml/__init__.py +471 -0
- outerbounds/_vendor/yaml/_yaml.cpython-311-darwin.so +0 -0
- outerbounds/_vendor/yaml/composer.py +146 -0
- outerbounds/_vendor/yaml/constructor.py +862 -0
- outerbounds/_vendor/yaml/cyaml.py +177 -0
- outerbounds/_vendor/yaml/dumper.py +138 -0
- outerbounds/_vendor/yaml/emitter.py +1239 -0
- outerbounds/_vendor/yaml/error.py +94 -0
- outerbounds/_vendor/yaml/events.py +104 -0
- outerbounds/_vendor/yaml/loader.py +62 -0
- outerbounds/_vendor/yaml/nodes.py +51 -0
- outerbounds/_vendor/yaml/parser.py +629 -0
- outerbounds/_vendor/yaml/reader.py +208 -0
- outerbounds/_vendor/yaml/representer.py +378 -0
- outerbounds/_vendor/yaml/resolver.py +245 -0
- outerbounds/_vendor/yaml/scanner.py +1555 -0
- outerbounds/_vendor/yaml/serializer.py +127 -0
- outerbounds/_vendor/yaml/tokens.py +129 -0
- outerbounds/command_groups/apps_cli.py +450 -0
- outerbounds/command_groups/cli.py +9 -5
- outerbounds/command_groups/local_setup_cli.py +247 -36
- outerbounds/command_groups/perimeters_cli.py +212 -32
- outerbounds/command_groups/tutorials_cli.py +111 -0
- outerbounds/command_groups/workstations_cli.py +2 -2
- outerbounds/utils/kubeconfig.py +2 -2
- outerbounds/utils/metaflowconfig.py +93 -16
- outerbounds/utils/schema.py +2 -2
- outerbounds/utils/utils.py +19 -0
- outerbounds/vendor.py +159 -0
- {outerbounds-0.3.55rc8.dist-info → outerbounds-0.3.133.dist-info}/METADATA +17 -6
- outerbounds-0.3.133.dist-info/RECORD +59 -0
- {outerbounds-0.3.55rc8.dist-info → outerbounds-0.3.133.dist-info}/WHEEL +1 -1
- outerbounds-0.3.55rc8.dist-info/RECORD +0 -15
- {outerbounds-0.3.55rc8.dist-info → outerbounds-0.3.133.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,580 @@
|
|
1
|
+
import os
|
2
|
+
import re
|
3
|
+
import typing as t
|
4
|
+
from gettext import gettext as _
|
5
|
+
|
6
|
+
from .core import Argument
|
7
|
+
from .core import BaseCommand
|
8
|
+
from .core import Context
|
9
|
+
from .core import MultiCommand
|
10
|
+
from .core import Option
|
11
|
+
from .core import Parameter
|
12
|
+
from .core import ParameterSource
|
13
|
+
from .parser import split_arg_string
|
14
|
+
from .utils import echo
|
15
|
+
|
16
|
+
|
17
|
+
def shell_complete(
|
18
|
+
cli: BaseCommand,
|
19
|
+
ctx_args: t.Dict[str, t.Any],
|
20
|
+
prog_name: str,
|
21
|
+
complete_var: str,
|
22
|
+
instruction: str,
|
23
|
+
) -> int:
|
24
|
+
"""Perform shell completion for the given CLI program.
|
25
|
+
|
26
|
+
:param cli: Command being called.
|
27
|
+
:param ctx_args: Extra arguments to pass to
|
28
|
+
``cli.make_context``.
|
29
|
+
:param prog_name: Name of the executable in the shell.
|
30
|
+
:param complete_var: Name of the environment variable that holds
|
31
|
+
the completion instruction.
|
32
|
+
:param instruction: Value of ``complete_var`` with the completion
|
33
|
+
instruction and shell, in the form ``instruction_shell``.
|
34
|
+
:return: Status code to exit with.
|
35
|
+
"""
|
36
|
+
shell, _, instruction = instruction.partition("_")
|
37
|
+
comp_cls = get_completion_class(shell)
|
38
|
+
|
39
|
+
if comp_cls is None:
|
40
|
+
return 1
|
41
|
+
|
42
|
+
comp = comp_cls(cli, ctx_args, prog_name, complete_var)
|
43
|
+
|
44
|
+
if instruction == "source":
|
45
|
+
echo(comp.source())
|
46
|
+
return 0
|
47
|
+
|
48
|
+
if instruction == "complete":
|
49
|
+
echo(comp.complete())
|
50
|
+
return 0
|
51
|
+
|
52
|
+
return 1
|
53
|
+
|
54
|
+
|
55
|
+
class CompletionItem:
|
56
|
+
"""Represents a completion value and metadata about the value. The
|
57
|
+
default metadata is ``type`` to indicate special shell handling,
|
58
|
+
and ``help`` if a shell supports showing a help string next to the
|
59
|
+
value.
|
60
|
+
|
61
|
+
Arbitrary parameters can be passed when creating the object, and
|
62
|
+
accessed using ``item.attr``. If an attribute wasn't passed,
|
63
|
+
accessing it returns ``None``.
|
64
|
+
|
65
|
+
:param value: The completion suggestion.
|
66
|
+
:param type: Tells the shell script to provide special completion
|
67
|
+
support for the type. Click uses ``"dir"`` and ``"file"``.
|
68
|
+
:param help: String shown next to the value if supported.
|
69
|
+
:param kwargs: Arbitrary metadata. The built-in implementations
|
70
|
+
don't use this, but custom type completions paired with custom
|
71
|
+
shell support could use it.
|
72
|
+
"""
|
73
|
+
|
74
|
+
__slots__ = ("value", "type", "help", "_info")
|
75
|
+
|
76
|
+
def __init__(
|
77
|
+
self,
|
78
|
+
value: t.Any,
|
79
|
+
type: str = "plain",
|
80
|
+
help: t.Optional[str] = None,
|
81
|
+
**kwargs: t.Any,
|
82
|
+
) -> None:
|
83
|
+
self.value = value
|
84
|
+
self.type = type
|
85
|
+
self.help = help
|
86
|
+
self._info = kwargs
|
87
|
+
|
88
|
+
def __getattr__(self, name: str) -> t.Any:
|
89
|
+
return self._info.get(name)
|
90
|
+
|
91
|
+
|
92
|
+
# Only Bash >= 4.4 has the nosort option.
|
93
|
+
_SOURCE_BASH = """\
|
94
|
+
%(complete_func)s() {
|
95
|
+
local IFS=$'\\n'
|
96
|
+
local response
|
97
|
+
|
98
|
+
response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \
|
99
|
+
%(complete_var)s=bash_complete $1)
|
100
|
+
|
101
|
+
for completion in $response; do
|
102
|
+
IFS=',' read type value <<< "$completion"
|
103
|
+
|
104
|
+
if [[ $type == 'dir' ]]; then
|
105
|
+
COMPREPLY=()
|
106
|
+
compopt -o dirnames
|
107
|
+
elif [[ $type == 'file' ]]; then
|
108
|
+
COMPREPLY=()
|
109
|
+
compopt -o default
|
110
|
+
elif [[ $type == 'plain' ]]; then
|
111
|
+
COMPREPLY+=($value)
|
112
|
+
fi
|
113
|
+
done
|
114
|
+
|
115
|
+
return 0
|
116
|
+
}
|
117
|
+
|
118
|
+
%(complete_func)s_setup() {
|
119
|
+
complete -o nosort -F %(complete_func)s %(prog_name)s
|
120
|
+
}
|
121
|
+
|
122
|
+
%(complete_func)s_setup;
|
123
|
+
"""
|
124
|
+
|
125
|
+
_SOURCE_ZSH = """\
|
126
|
+
#compdef %(prog_name)s
|
127
|
+
|
128
|
+
%(complete_func)s() {
|
129
|
+
local -a completions
|
130
|
+
local -a completions_with_descriptions
|
131
|
+
local -a response
|
132
|
+
(( ! $+commands[%(prog_name)s] )) && return 1
|
133
|
+
|
134
|
+
response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \
|
135
|
+
%(complete_var)s=zsh_complete %(prog_name)s)}")
|
136
|
+
|
137
|
+
for type key descr in ${response}; do
|
138
|
+
if [[ "$type" == "plain" ]]; then
|
139
|
+
if [[ "$descr" == "_" ]]; then
|
140
|
+
completions+=("$key")
|
141
|
+
else
|
142
|
+
completions_with_descriptions+=("$key":"$descr")
|
143
|
+
fi
|
144
|
+
elif [[ "$type" == "dir" ]]; then
|
145
|
+
_path_files -/
|
146
|
+
elif [[ "$type" == "file" ]]; then
|
147
|
+
_path_files -f
|
148
|
+
fi
|
149
|
+
done
|
150
|
+
|
151
|
+
if [ -n "$completions_with_descriptions" ]; then
|
152
|
+
_describe -V unsorted completions_with_descriptions -U
|
153
|
+
fi
|
154
|
+
|
155
|
+
if [ -n "$completions" ]; then
|
156
|
+
compadd -U -V unsorted -a completions
|
157
|
+
fi
|
158
|
+
}
|
159
|
+
|
160
|
+
compdef %(complete_func)s %(prog_name)s;
|
161
|
+
"""
|
162
|
+
|
163
|
+
_SOURCE_FISH = """\
|
164
|
+
function %(complete_func)s;
|
165
|
+
set -l response;
|
166
|
+
|
167
|
+
for value in (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \
|
168
|
+
COMP_CWORD=(commandline -t) %(prog_name)s);
|
169
|
+
set response $response $value;
|
170
|
+
end;
|
171
|
+
|
172
|
+
for completion in $response;
|
173
|
+
set -l metadata (string split "," $completion);
|
174
|
+
|
175
|
+
if test $metadata[1] = "dir";
|
176
|
+
__fish_complete_directories $metadata[2];
|
177
|
+
else if test $metadata[1] = "file";
|
178
|
+
__fish_complete_path $metadata[2];
|
179
|
+
else if test $metadata[1] = "plain";
|
180
|
+
echo $metadata[2];
|
181
|
+
end;
|
182
|
+
end;
|
183
|
+
end;
|
184
|
+
|
185
|
+
complete --no-files --command %(prog_name)s --arguments \
|
186
|
+
"(%(complete_func)s)";
|
187
|
+
"""
|
188
|
+
|
189
|
+
|
190
|
+
class ShellComplete:
|
191
|
+
"""Base class for providing shell completion support. A subclass for
|
192
|
+
a given shell will override attributes and methods to implement the
|
193
|
+
completion instructions (``source`` and ``complete``).
|
194
|
+
|
195
|
+
:param cli: Command being called.
|
196
|
+
:param prog_name: Name of the executable in the shell.
|
197
|
+
:param complete_var: Name of the environment variable that holds
|
198
|
+
the completion instruction.
|
199
|
+
|
200
|
+
.. versionadded:: 8.0
|
201
|
+
"""
|
202
|
+
|
203
|
+
name: t.ClassVar[str]
|
204
|
+
"""Name to register the shell as with :func:`add_completion_class`.
|
205
|
+
This is used in completion instructions (``{name}_source`` and
|
206
|
+
``{name}_complete``).
|
207
|
+
"""
|
208
|
+
|
209
|
+
source_template: t.ClassVar[str]
|
210
|
+
"""Completion script template formatted by :meth:`source`. This must
|
211
|
+
be provided by subclasses.
|
212
|
+
"""
|
213
|
+
|
214
|
+
def __init__(
|
215
|
+
self,
|
216
|
+
cli: BaseCommand,
|
217
|
+
ctx_args: t.Dict[str, t.Any],
|
218
|
+
prog_name: str,
|
219
|
+
complete_var: str,
|
220
|
+
) -> None:
|
221
|
+
self.cli = cli
|
222
|
+
self.ctx_args = ctx_args
|
223
|
+
self.prog_name = prog_name
|
224
|
+
self.complete_var = complete_var
|
225
|
+
|
226
|
+
@property
|
227
|
+
def func_name(self) -> str:
|
228
|
+
"""The name of the shell function defined by the completion
|
229
|
+
script.
|
230
|
+
"""
|
231
|
+
safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), re.ASCII)
|
232
|
+
return f"_{safe_name}_completion"
|
233
|
+
|
234
|
+
def source_vars(self) -> t.Dict[str, t.Any]:
|
235
|
+
"""Vars for formatting :attr:`source_template`.
|
236
|
+
|
237
|
+
By default this provides ``complete_func``, ``complete_var``,
|
238
|
+
and ``prog_name``.
|
239
|
+
"""
|
240
|
+
return {
|
241
|
+
"complete_func": self.func_name,
|
242
|
+
"complete_var": self.complete_var,
|
243
|
+
"prog_name": self.prog_name,
|
244
|
+
}
|
245
|
+
|
246
|
+
def source(self) -> str:
|
247
|
+
"""Produce the shell script that defines the completion
|
248
|
+
function. By default this ``%``-style formats
|
249
|
+
:attr:`source_template` with the dict returned by
|
250
|
+
:meth:`source_vars`.
|
251
|
+
"""
|
252
|
+
return self.source_template % self.source_vars()
|
253
|
+
|
254
|
+
def get_completion_args(self) -> t.Tuple[t.List[str], str]:
|
255
|
+
"""Use the env vars defined by the shell script to return a
|
256
|
+
tuple of ``args, incomplete``. This must be implemented by
|
257
|
+
subclasses.
|
258
|
+
"""
|
259
|
+
raise NotImplementedError
|
260
|
+
|
261
|
+
def get_completions(
|
262
|
+
self, args: t.List[str], incomplete: str
|
263
|
+
) -> t.List[CompletionItem]:
|
264
|
+
"""Determine the context and last complete command or parameter
|
265
|
+
from the complete args. Call that object's ``shell_complete``
|
266
|
+
method to get the completions for the incomplete value.
|
267
|
+
|
268
|
+
:param args: List of complete args before the incomplete value.
|
269
|
+
:param incomplete: Value being completed. May be empty.
|
270
|
+
"""
|
271
|
+
ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args)
|
272
|
+
obj, incomplete = _resolve_incomplete(ctx, args, incomplete)
|
273
|
+
return obj.shell_complete(ctx, incomplete)
|
274
|
+
|
275
|
+
def format_completion(self, item: CompletionItem) -> str:
|
276
|
+
"""Format a completion item into the form recognized by the
|
277
|
+
shell script. This must be implemented by subclasses.
|
278
|
+
|
279
|
+
:param item: Completion item to format.
|
280
|
+
"""
|
281
|
+
raise NotImplementedError
|
282
|
+
|
283
|
+
def complete(self) -> str:
|
284
|
+
"""Produce the completion data to send back to the shell.
|
285
|
+
|
286
|
+
By default this calls :meth:`get_completion_args`, gets the
|
287
|
+
completions, then calls :meth:`format_completion` for each
|
288
|
+
completion.
|
289
|
+
"""
|
290
|
+
args, incomplete = self.get_completion_args()
|
291
|
+
completions = self.get_completions(args, incomplete)
|
292
|
+
out = [self.format_completion(item) for item in completions]
|
293
|
+
return "\n".join(out)
|
294
|
+
|
295
|
+
|
296
|
+
class BashComplete(ShellComplete):
|
297
|
+
"""Shell completion for Bash."""
|
298
|
+
|
299
|
+
name = "bash"
|
300
|
+
source_template = _SOURCE_BASH
|
301
|
+
|
302
|
+
def _check_version(self) -> None:
|
303
|
+
import subprocess
|
304
|
+
|
305
|
+
output = subprocess.run(
|
306
|
+
["bash", "-c", "echo ${BASH_VERSION}"], stdout=subprocess.PIPE
|
307
|
+
)
|
308
|
+
match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode())
|
309
|
+
|
310
|
+
if match is not None:
|
311
|
+
major, minor = match.groups()
|
312
|
+
|
313
|
+
if major < "4" or major == "4" and minor < "4":
|
314
|
+
raise RuntimeError(
|
315
|
+
_(
|
316
|
+
"Shell completion is not supported for Bash"
|
317
|
+
" versions older than 4.4."
|
318
|
+
)
|
319
|
+
)
|
320
|
+
else:
|
321
|
+
raise RuntimeError(
|
322
|
+
_("Couldn't detect Bash version, shell completion is not supported.")
|
323
|
+
)
|
324
|
+
|
325
|
+
def source(self) -> str:
|
326
|
+
self._check_version()
|
327
|
+
return super().source()
|
328
|
+
|
329
|
+
def get_completion_args(self) -> t.Tuple[t.List[str], str]:
|
330
|
+
cwords = split_arg_string(os.environ["COMP_WORDS"])
|
331
|
+
cword = int(os.environ["COMP_CWORD"])
|
332
|
+
args = cwords[1:cword]
|
333
|
+
|
334
|
+
try:
|
335
|
+
incomplete = cwords[cword]
|
336
|
+
except IndexError:
|
337
|
+
incomplete = ""
|
338
|
+
|
339
|
+
return args, incomplete
|
340
|
+
|
341
|
+
def format_completion(self, item: CompletionItem) -> str:
|
342
|
+
return f"{item.type},{item.value}"
|
343
|
+
|
344
|
+
|
345
|
+
class ZshComplete(ShellComplete):
|
346
|
+
"""Shell completion for Zsh."""
|
347
|
+
|
348
|
+
name = "zsh"
|
349
|
+
source_template = _SOURCE_ZSH
|
350
|
+
|
351
|
+
def get_completion_args(self) -> t.Tuple[t.List[str], str]:
|
352
|
+
cwords = split_arg_string(os.environ["COMP_WORDS"])
|
353
|
+
cword = int(os.environ["COMP_CWORD"])
|
354
|
+
args = cwords[1:cword]
|
355
|
+
|
356
|
+
try:
|
357
|
+
incomplete = cwords[cword]
|
358
|
+
except IndexError:
|
359
|
+
incomplete = ""
|
360
|
+
|
361
|
+
return args, incomplete
|
362
|
+
|
363
|
+
def format_completion(self, item: CompletionItem) -> str:
|
364
|
+
return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}"
|
365
|
+
|
366
|
+
|
367
|
+
class FishComplete(ShellComplete):
|
368
|
+
"""Shell completion for Fish."""
|
369
|
+
|
370
|
+
name = "fish"
|
371
|
+
source_template = _SOURCE_FISH
|
372
|
+
|
373
|
+
def get_completion_args(self) -> t.Tuple[t.List[str], str]:
|
374
|
+
cwords = split_arg_string(os.environ["COMP_WORDS"])
|
375
|
+
incomplete = os.environ["COMP_CWORD"]
|
376
|
+
args = cwords[1:]
|
377
|
+
|
378
|
+
# Fish stores the partial word in both COMP_WORDS and
|
379
|
+
# COMP_CWORD, remove it from complete args.
|
380
|
+
if incomplete and args and args[-1] == incomplete:
|
381
|
+
args.pop()
|
382
|
+
|
383
|
+
return args, incomplete
|
384
|
+
|
385
|
+
def format_completion(self, item: CompletionItem) -> str:
|
386
|
+
if item.help:
|
387
|
+
return f"{item.type},{item.value}\t{item.help}"
|
388
|
+
|
389
|
+
return f"{item.type},{item.value}"
|
390
|
+
|
391
|
+
|
392
|
+
_available_shells: t.Dict[str, t.Type[ShellComplete]] = {
|
393
|
+
"bash": BashComplete,
|
394
|
+
"fish": FishComplete,
|
395
|
+
"zsh": ZshComplete,
|
396
|
+
}
|
397
|
+
|
398
|
+
|
399
|
+
def add_completion_class(
|
400
|
+
cls: t.Type[ShellComplete], name: t.Optional[str] = None
|
401
|
+
) -> None:
|
402
|
+
"""Register a :class:`ShellComplete` subclass under the given name.
|
403
|
+
The name will be provided by the completion instruction environment
|
404
|
+
variable during completion.
|
405
|
+
|
406
|
+
:param cls: The completion class that will handle completion for the
|
407
|
+
shell.
|
408
|
+
:param name: Name to register the class under. Defaults to the
|
409
|
+
class's ``name`` attribute.
|
410
|
+
"""
|
411
|
+
if name is None:
|
412
|
+
name = cls.name
|
413
|
+
|
414
|
+
_available_shells[name] = cls
|
415
|
+
|
416
|
+
|
417
|
+
def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]:
|
418
|
+
"""Look up a registered :class:`ShellComplete` subclass by the name
|
419
|
+
provided by the completion instruction environment variable. If the
|
420
|
+
name isn't registered, returns ``None``.
|
421
|
+
|
422
|
+
:param shell: Name the class is registered under.
|
423
|
+
"""
|
424
|
+
return _available_shells.get(shell)
|
425
|
+
|
426
|
+
|
427
|
+
def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool:
|
428
|
+
"""Determine if the given parameter is an argument that can still
|
429
|
+
accept values.
|
430
|
+
|
431
|
+
:param ctx: Invocation context for the command represented by the
|
432
|
+
parsed complete args.
|
433
|
+
:param param: Argument object being checked.
|
434
|
+
"""
|
435
|
+
if not isinstance(param, Argument):
|
436
|
+
return False
|
437
|
+
|
438
|
+
assert param.name is not None
|
439
|
+
value = ctx.params[param.name]
|
440
|
+
return (
|
441
|
+
param.nargs == -1
|
442
|
+
or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE
|
443
|
+
or (
|
444
|
+
param.nargs > 1
|
445
|
+
and isinstance(value, (tuple, list))
|
446
|
+
and len(value) < param.nargs
|
447
|
+
)
|
448
|
+
)
|
449
|
+
|
450
|
+
|
451
|
+
def _start_of_option(ctx: Context, value: str) -> bool:
|
452
|
+
"""Check if the value looks like the start of an option."""
|
453
|
+
if not value:
|
454
|
+
return False
|
455
|
+
|
456
|
+
c = value[0]
|
457
|
+
return c in ctx._opt_prefixes
|
458
|
+
|
459
|
+
|
460
|
+
def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool:
|
461
|
+
"""Determine if the given parameter is an option that needs a value.
|
462
|
+
|
463
|
+
:param args: List of complete args before the incomplete value.
|
464
|
+
:param param: Option object being checked.
|
465
|
+
"""
|
466
|
+
if not isinstance(param, Option):
|
467
|
+
return False
|
468
|
+
|
469
|
+
if param.is_flag or param.count:
|
470
|
+
return False
|
471
|
+
|
472
|
+
last_option = None
|
473
|
+
|
474
|
+
for index, arg in enumerate(reversed(args)):
|
475
|
+
if index + 1 > param.nargs:
|
476
|
+
break
|
477
|
+
|
478
|
+
if _start_of_option(ctx, arg):
|
479
|
+
last_option = arg
|
480
|
+
|
481
|
+
return last_option is not None and last_option in param.opts
|
482
|
+
|
483
|
+
|
484
|
+
def _resolve_context(
|
485
|
+
cli: BaseCommand, ctx_args: t.Dict[str, t.Any], prog_name: str, args: t.List[str]
|
486
|
+
) -> Context:
|
487
|
+
"""Produce the context hierarchy starting with the command and
|
488
|
+
traversing the complete arguments. This only follows the commands,
|
489
|
+
it doesn't trigger input prompts or callbacks.
|
490
|
+
|
491
|
+
:param cli: Command being called.
|
492
|
+
:param prog_name: Name of the executable in the shell.
|
493
|
+
:param args: List of complete args before the incomplete value.
|
494
|
+
"""
|
495
|
+
ctx_args["resilient_parsing"] = True
|
496
|
+
ctx = cli.make_context(prog_name, args.copy(), **ctx_args)
|
497
|
+
args = ctx.protected_args + ctx.args
|
498
|
+
|
499
|
+
while args:
|
500
|
+
command = ctx.command
|
501
|
+
|
502
|
+
if isinstance(command, MultiCommand):
|
503
|
+
if not command.chain:
|
504
|
+
name, cmd, args = command.resolve_command(ctx, args)
|
505
|
+
|
506
|
+
if cmd is None:
|
507
|
+
return ctx
|
508
|
+
|
509
|
+
ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True)
|
510
|
+
args = ctx.protected_args + ctx.args
|
511
|
+
else:
|
512
|
+
while args:
|
513
|
+
name, cmd, args = command.resolve_command(ctx, args)
|
514
|
+
|
515
|
+
if cmd is None:
|
516
|
+
return ctx
|
517
|
+
|
518
|
+
sub_ctx = cmd.make_context(
|
519
|
+
name,
|
520
|
+
args,
|
521
|
+
parent=ctx,
|
522
|
+
allow_extra_args=True,
|
523
|
+
allow_interspersed_args=False,
|
524
|
+
resilient_parsing=True,
|
525
|
+
)
|
526
|
+
args = sub_ctx.args
|
527
|
+
|
528
|
+
ctx = sub_ctx
|
529
|
+
args = [*sub_ctx.protected_args, *sub_ctx.args]
|
530
|
+
else:
|
531
|
+
break
|
532
|
+
|
533
|
+
return ctx
|
534
|
+
|
535
|
+
|
536
|
+
def _resolve_incomplete(
|
537
|
+
ctx: Context, args: t.List[str], incomplete: str
|
538
|
+
) -> t.Tuple[t.Union[BaseCommand, Parameter], str]:
|
539
|
+
"""Find the Click object that will handle the completion of the
|
540
|
+
incomplete value. Return the object and the incomplete value.
|
541
|
+
|
542
|
+
:param ctx: Invocation context for the command represented by
|
543
|
+
the parsed complete args.
|
544
|
+
:param args: List of complete args before the incomplete value.
|
545
|
+
:param incomplete: Value being completed. May be empty.
|
546
|
+
"""
|
547
|
+
# Different shells treat an "=" between a long option name and
|
548
|
+
# value differently. Might keep the value joined, return the "="
|
549
|
+
# as a separate item, or return the split name and value. Always
|
550
|
+
# split and discard the "=" to make completion easier.
|
551
|
+
if incomplete == "=":
|
552
|
+
incomplete = ""
|
553
|
+
elif "=" in incomplete and _start_of_option(ctx, incomplete):
|
554
|
+
name, _, incomplete = incomplete.partition("=")
|
555
|
+
args.append(name)
|
556
|
+
|
557
|
+
# The "--" marker tells Click to stop treating values as options
|
558
|
+
# even if they start with the option character. If it hasn't been
|
559
|
+
# given and the incomplete arg looks like an option, the current
|
560
|
+
# command will provide option name completions.
|
561
|
+
if "--" not in args and _start_of_option(ctx, incomplete):
|
562
|
+
return ctx.command, incomplete
|
563
|
+
|
564
|
+
params = ctx.command.get_params(ctx)
|
565
|
+
|
566
|
+
# If the last complete arg is an option name with an incomplete
|
567
|
+
# value, the option will provide value completions.
|
568
|
+
for param in params:
|
569
|
+
if _is_incomplete_option(ctx, args, param):
|
570
|
+
return param, incomplete
|
571
|
+
|
572
|
+
# It's not an option name or value. The first argument without a
|
573
|
+
# parsed value will provide value completions.
|
574
|
+
for param in params:
|
575
|
+
if _is_incomplete_argument(ctx, param):
|
576
|
+
return param, incomplete
|
577
|
+
|
578
|
+
# There were no unparsed arguments, the command may be a group that
|
579
|
+
# will provide command name completions.
|
580
|
+
return ctx.command, incomplete
|