outerbounds 0.3.71__py3-none-any.whl → 0.3.75__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. outerbounds/_vendor/PyYAML.LICENSE +20 -0
  2. outerbounds/_vendor/__init__.py +0 -0
  3. outerbounds/_vendor/_yaml/__init__.py +34 -0
  4. outerbounds/_vendor/click/__init__.py +73 -0
  5. outerbounds/_vendor/click/_compat.py +626 -0
  6. outerbounds/_vendor/click/_termui_impl.py +717 -0
  7. outerbounds/_vendor/click/_textwrap.py +49 -0
  8. outerbounds/_vendor/click/_winconsole.py +279 -0
  9. outerbounds/_vendor/click/core.py +2998 -0
  10. outerbounds/_vendor/click/decorators.py +497 -0
  11. outerbounds/_vendor/click/exceptions.py +287 -0
  12. outerbounds/_vendor/click/formatting.py +301 -0
  13. outerbounds/_vendor/click/globals.py +68 -0
  14. outerbounds/_vendor/click/parser.py +529 -0
  15. outerbounds/_vendor/click/py.typed +0 -0
  16. outerbounds/_vendor/click/shell_completion.py +580 -0
  17. outerbounds/_vendor/click/termui.py +787 -0
  18. outerbounds/_vendor/click/testing.py +479 -0
  19. outerbounds/_vendor/click/types.py +1073 -0
  20. outerbounds/_vendor/click/utils.py +580 -0
  21. outerbounds/_vendor/click.LICENSE +28 -0
  22. outerbounds/_vendor/vendor_any.txt +2 -0
  23. outerbounds/_vendor/yaml/__init__.py +471 -0
  24. outerbounds/_vendor/yaml/composer.py +146 -0
  25. outerbounds/_vendor/yaml/constructor.py +862 -0
  26. outerbounds/_vendor/yaml/cyaml.py +177 -0
  27. outerbounds/_vendor/yaml/dumper.py +138 -0
  28. outerbounds/_vendor/yaml/emitter.py +1239 -0
  29. outerbounds/_vendor/yaml/error.py +94 -0
  30. outerbounds/_vendor/yaml/events.py +104 -0
  31. outerbounds/_vendor/yaml/loader.py +62 -0
  32. outerbounds/_vendor/yaml/nodes.py +51 -0
  33. outerbounds/_vendor/yaml/parser.py +629 -0
  34. outerbounds/_vendor/yaml/reader.py +208 -0
  35. outerbounds/_vendor/yaml/representer.py +378 -0
  36. outerbounds/_vendor/yaml/resolver.py +245 -0
  37. outerbounds/_vendor/yaml/scanner.py +1555 -0
  38. outerbounds/_vendor/yaml/serializer.py +127 -0
  39. outerbounds/_vendor/yaml/tokens.py +129 -0
  40. outerbounds/command_groups/cli.py +1 -1
  41. outerbounds/command_groups/local_setup_cli.py +1 -2
  42. outerbounds/command_groups/perimeters_cli.py +1 -2
  43. outerbounds/command_groups/workstations_cli.py +2 -2
  44. outerbounds/utils/kubeconfig.py +2 -2
  45. outerbounds/utils/metaflowconfig.py +1 -1
  46. outerbounds/vendor.py +159 -0
  47. {outerbounds-0.3.71.dist-info → outerbounds-0.3.75.dist-info}/METADATA +1 -3
  48. outerbounds-0.3.75.dist-info/RECORD +55 -0
  49. outerbounds-0.3.71.dist-info/RECORD +0 -15
  50. {outerbounds-0.3.71.dist-info → outerbounds-0.3.75.dist-info}/WHEEL +0 -0
  51. {outerbounds-0.3.71.dist-info → outerbounds-0.3.75.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