outerbounds 0.3.55rc3__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.
Files changed (56) 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/_yaml.cpython-311-darwin.so +0 -0
  25. outerbounds/_vendor/yaml/composer.py +146 -0
  26. outerbounds/_vendor/yaml/constructor.py +862 -0
  27. outerbounds/_vendor/yaml/cyaml.py +177 -0
  28. outerbounds/_vendor/yaml/dumper.py +138 -0
  29. outerbounds/_vendor/yaml/emitter.py +1239 -0
  30. outerbounds/_vendor/yaml/error.py +94 -0
  31. outerbounds/_vendor/yaml/events.py +104 -0
  32. outerbounds/_vendor/yaml/loader.py +62 -0
  33. outerbounds/_vendor/yaml/nodes.py +51 -0
  34. outerbounds/_vendor/yaml/parser.py +629 -0
  35. outerbounds/_vendor/yaml/reader.py +208 -0
  36. outerbounds/_vendor/yaml/representer.py +378 -0
  37. outerbounds/_vendor/yaml/resolver.py +245 -0
  38. outerbounds/_vendor/yaml/scanner.py +1555 -0
  39. outerbounds/_vendor/yaml/serializer.py +127 -0
  40. outerbounds/_vendor/yaml/tokens.py +129 -0
  41. outerbounds/command_groups/apps_cli.py +450 -0
  42. outerbounds/command_groups/cli.py +9 -5
  43. outerbounds/command_groups/local_setup_cli.py +249 -33
  44. outerbounds/command_groups/perimeters_cli.py +231 -33
  45. outerbounds/command_groups/tutorials_cli.py +111 -0
  46. outerbounds/command_groups/workstations_cli.py +88 -15
  47. outerbounds/utils/kubeconfig.py +2 -2
  48. outerbounds/utils/metaflowconfig.py +111 -21
  49. outerbounds/utils/schema.py +8 -2
  50. outerbounds/utils/utils.py +19 -0
  51. outerbounds/vendor.py +159 -0
  52. {outerbounds-0.3.55rc3.dist-info → outerbounds-0.3.133.dist-info}/METADATA +17 -6
  53. outerbounds-0.3.133.dist-info/RECORD +59 -0
  54. {outerbounds-0.3.55rc3.dist-info → outerbounds-0.3.133.dist-info}/WHEEL +1 -1
  55. outerbounds-0.3.55rc3.dist-info/RECORD +0 -15
  56. {outerbounds-0.3.55rc3.dist-info → outerbounds-0.3.133.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,529 @@
1
+ """
2
+ This module started out as largely a copy paste from the stdlib's
3
+ optparse module with the features removed that we do not need from
4
+ optparse because we implement them in Click on a higher level (for
5
+ instance type handling, help formatting and a lot more).
6
+
7
+ The plan is to remove more and more from here over time.
8
+
9
+ The reason this is a different module and not optparse from the stdlib
10
+ is that there are differences in 2.x and 3.x about the error messages
11
+ generated and optparse in the stdlib uses gettext for no good reason
12
+ and might cause us issues.
13
+
14
+ Click uses parts of optparse written by Gregory P. Ward and maintained
15
+ by the Python Software Foundation. This is limited to code in parser.py.
16
+
17
+ Copyright 2001-2006 Gregory P. Ward. All rights reserved.
18
+ Copyright 2002-2006 Python Software Foundation. All rights reserved.
19
+ """
20
+ # This code uses parts of optparse written by Gregory P. Ward and
21
+ # maintained by the Python Software Foundation.
22
+ # Copyright 2001-2006 Gregory P. Ward
23
+ # Copyright 2002-2006 Python Software Foundation
24
+ import typing as t
25
+ from collections import deque
26
+ from gettext import gettext as _
27
+ from gettext import ngettext
28
+
29
+ from .exceptions import BadArgumentUsage
30
+ from .exceptions import BadOptionUsage
31
+ from .exceptions import NoSuchOption
32
+ from .exceptions import UsageError
33
+
34
+ if t.TYPE_CHECKING:
35
+ import typing_extensions as te
36
+ from .core import Argument as CoreArgument
37
+ from .core import Context
38
+ from .core import Option as CoreOption
39
+ from .core import Parameter as CoreParameter
40
+
41
+ V = t.TypeVar("V")
42
+
43
+ # Sentinel value that indicates an option was passed as a flag without a
44
+ # value but is not a flag option. Option.consume_value uses this to
45
+ # prompt or use the flag_value.
46
+ _flag_needs_value = object()
47
+
48
+
49
+ def _unpack_args(
50
+ args: t.Sequence[str], nargs_spec: t.Sequence[int]
51
+ ) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]:
52
+ """Given an iterable of arguments and an iterable of nargs specifications,
53
+ it returns a tuple with all the unpacked arguments at the first index
54
+ and all remaining arguments as the second.
55
+
56
+ The nargs specification is the number of arguments that should be consumed
57
+ or `-1` to indicate that this position should eat up all the remainders.
58
+
59
+ Missing items are filled with `None`.
60
+ """
61
+ args = deque(args)
62
+ nargs_spec = deque(nargs_spec)
63
+ rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = []
64
+ spos: t.Optional[int] = None
65
+
66
+ def _fetch(c: "te.Deque[V]") -> t.Optional[V]:
67
+ try:
68
+ if spos is None:
69
+ return c.popleft()
70
+ else:
71
+ return c.pop()
72
+ except IndexError:
73
+ return None
74
+
75
+ while nargs_spec:
76
+ nargs = _fetch(nargs_spec)
77
+
78
+ if nargs is None:
79
+ continue
80
+
81
+ if nargs == 1:
82
+ rv.append(_fetch(args))
83
+ elif nargs > 1:
84
+ x = [_fetch(args) for _ in range(nargs)]
85
+
86
+ # If we're reversed, we're pulling in the arguments in reverse,
87
+ # so we need to turn them around.
88
+ if spos is not None:
89
+ x.reverse()
90
+
91
+ rv.append(tuple(x))
92
+ elif nargs < 0:
93
+ if spos is not None:
94
+ raise TypeError("Cannot have two nargs < 0")
95
+
96
+ spos = len(rv)
97
+ rv.append(None)
98
+
99
+ # spos is the position of the wildcard (star). If it's not `None`,
100
+ # we fill it with the remainder.
101
+ if spos is not None:
102
+ rv[spos] = tuple(args)
103
+ args = []
104
+ rv[spos + 1 :] = reversed(rv[spos + 1 :])
105
+
106
+ return tuple(rv), list(args)
107
+
108
+
109
+ def split_opt(opt: str) -> t.Tuple[str, str]:
110
+ first = opt[:1]
111
+ if first.isalnum():
112
+ return "", opt
113
+ if opt[1:2] == first:
114
+ return opt[:2], opt[2:]
115
+ return first, opt[1:]
116
+
117
+
118
+ def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str:
119
+ if ctx is None or ctx.token_normalize_func is None:
120
+ return opt
121
+ prefix, opt = split_opt(opt)
122
+ return f"{prefix}{ctx.token_normalize_func(opt)}"
123
+
124
+
125
+ def split_arg_string(string: str) -> t.List[str]:
126
+ """Split an argument string as with :func:`shlex.split`, but don't
127
+ fail if the string is incomplete. Ignores a missing closing quote or
128
+ incomplete escape sequence and uses the partial token as-is.
129
+
130
+ .. code-block:: python
131
+
132
+ split_arg_string("example 'my file")
133
+ ["example", "my file"]
134
+
135
+ split_arg_string("example my\\")
136
+ ["example", "my"]
137
+
138
+ :param string: String to split.
139
+ """
140
+ import shlex
141
+
142
+ lex = shlex.shlex(string, posix=True)
143
+ lex.whitespace_split = True
144
+ lex.commenters = ""
145
+ out = []
146
+
147
+ try:
148
+ for token in lex:
149
+ out.append(token)
150
+ except ValueError:
151
+ # Raised when end-of-string is reached in an invalid state. Use
152
+ # the partial token as-is. The quote or escape character is in
153
+ # lex.state, not lex.token.
154
+ out.append(lex.token)
155
+
156
+ return out
157
+
158
+
159
+ class Option:
160
+ def __init__(
161
+ self,
162
+ obj: "CoreOption",
163
+ opts: t.Sequence[str],
164
+ dest: t.Optional[str],
165
+ action: t.Optional[str] = None,
166
+ nargs: int = 1,
167
+ const: t.Optional[t.Any] = None,
168
+ ):
169
+ self._short_opts = []
170
+ self._long_opts = []
171
+ self.prefixes = set()
172
+
173
+ for opt in opts:
174
+ prefix, value = split_opt(opt)
175
+ if not prefix:
176
+ raise ValueError(f"Invalid start character for option ({opt})")
177
+ self.prefixes.add(prefix[0])
178
+ if len(prefix) == 1 and len(value) == 1:
179
+ self._short_opts.append(opt)
180
+ else:
181
+ self._long_opts.append(opt)
182
+ self.prefixes.add(prefix)
183
+
184
+ if action is None:
185
+ action = "store"
186
+
187
+ self.dest = dest
188
+ self.action = action
189
+ self.nargs = nargs
190
+ self.const = const
191
+ self.obj = obj
192
+
193
+ @property
194
+ def takes_value(self) -> bool:
195
+ return self.action in ("store", "append")
196
+
197
+ def process(self, value: str, state: "ParsingState") -> None:
198
+ if self.action == "store":
199
+ state.opts[self.dest] = value # type: ignore
200
+ elif self.action == "store_const":
201
+ state.opts[self.dest] = self.const # type: ignore
202
+ elif self.action == "append":
203
+ state.opts.setdefault(self.dest, []).append(value) # type: ignore
204
+ elif self.action == "append_const":
205
+ state.opts.setdefault(self.dest, []).append(self.const) # type: ignore
206
+ elif self.action == "count":
207
+ state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore
208
+ else:
209
+ raise ValueError(f"unknown action '{self.action}'")
210
+ state.order.append(self.obj)
211
+
212
+
213
+ class Argument:
214
+ def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1):
215
+ self.dest = dest
216
+ self.nargs = nargs
217
+ self.obj = obj
218
+
219
+ def process(
220
+ self,
221
+ value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]],
222
+ state: "ParsingState",
223
+ ) -> None:
224
+ if self.nargs > 1:
225
+ assert value is not None
226
+ holes = sum(1 for x in value if x is None)
227
+ if holes == len(value):
228
+ value = None
229
+ elif holes != 0:
230
+ raise BadArgumentUsage(
231
+ _("Argument {name!r} takes {nargs} values.").format(
232
+ name=self.dest, nargs=self.nargs
233
+ )
234
+ )
235
+
236
+ if self.nargs == -1 and self.obj.envvar is not None and value == ():
237
+ # Replace empty tuple with None so that a value from the
238
+ # environment may be tried.
239
+ value = None
240
+
241
+ state.opts[self.dest] = value # type: ignore
242
+ state.order.append(self.obj)
243
+
244
+
245
+ class ParsingState:
246
+ def __init__(self, rargs: t.List[str]) -> None:
247
+ self.opts: t.Dict[str, t.Any] = {}
248
+ self.largs: t.List[str] = []
249
+ self.rargs = rargs
250
+ self.order: t.List["CoreParameter"] = []
251
+
252
+
253
+ class OptionParser:
254
+ """The option parser is an internal class that is ultimately used to
255
+ parse options and arguments. It's modelled after optparse and brings
256
+ a similar but vastly simplified API. It should generally not be used
257
+ directly as the high level Click classes wrap it for you.
258
+
259
+ It's not nearly as extensible as optparse or argparse as it does not
260
+ implement features that are implemented on a higher level (such as
261
+ types or defaults).
262
+
263
+ :param ctx: optionally the :class:`~click.Context` where this parser
264
+ should go with.
265
+ """
266
+
267
+ def __init__(self, ctx: t.Optional["Context"] = None) -> None:
268
+ #: The :class:`~click.Context` for this parser. This might be
269
+ #: `None` for some advanced use cases.
270
+ self.ctx = ctx
271
+ #: This controls how the parser deals with interspersed arguments.
272
+ #: If this is set to `False`, the parser will stop on the first
273
+ #: non-option. Click uses this to implement nested subcommands
274
+ #: safely.
275
+ self.allow_interspersed_args = True
276
+ #: This tells the parser how to deal with unknown options. By
277
+ #: default it will error out (which is sensible), but there is a
278
+ #: second mode where it will ignore it and continue processing
279
+ #: after shifting all the unknown options into the resulting args.
280
+ self.ignore_unknown_options = False
281
+
282
+ if ctx is not None:
283
+ self.allow_interspersed_args = ctx.allow_interspersed_args
284
+ self.ignore_unknown_options = ctx.ignore_unknown_options
285
+
286
+ self._short_opt: t.Dict[str, Option] = {}
287
+ self._long_opt: t.Dict[str, Option] = {}
288
+ self._opt_prefixes = {"-", "--"}
289
+ self._args: t.List[Argument] = []
290
+
291
+ def add_option(
292
+ self,
293
+ obj: "CoreOption",
294
+ opts: t.Sequence[str],
295
+ dest: t.Optional[str],
296
+ action: t.Optional[str] = None,
297
+ nargs: int = 1,
298
+ const: t.Optional[t.Any] = None,
299
+ ) -> None:
300
+ """Adds a new option named `dest` to the parser. The destination
301
+ is not inferred (unlike with optparse) and needs to be explicitly
302
+ provided. Action can be any of ``store``, ``store_const``,
303
+ ``append``, ``append_const`` or ``count``.
304
+
305
+ The `obj` can be used to identify the option in the order list
306
+ that is returned from the parser.
307
+ """
308
+ opts = [normalize_opt(opt, self.ctx) for opt in opts]
309
+ option = Option(obj, opts, dest, action=action, nargs=nargs, const=const)
310
+ self._opt_prefixes.update(option.prefixes)
311
+ for opt in option._short_opts:
312
+ self._short_opt[opt] = option
313
+ for opt in option._long_opts:
314
+ self._long_opt[opt] = option
315
+
316
+ def add_argument(
317
+ self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1
318
+ ) -> None:
319
+ """Adds a positional argument named `dest` to the parser.
320
+
321
+ The `obj` can be used to identify the option in the order list
322
+ that is returned from the parser.
323
+ """
324
+ self._args.append(Argument(obj, dest=dest, nargs=nargs))
325
+
326
+ def parse_args(
327
+ self, args: t.List[str]
328
+ ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]:
329
+ """Parses positional arguments and returns ``(values, args, order)``
330
+ for the parsed options and arguments as well as the leftover
331
+ arguments if there are any. The order is a list of objects as they
332
+ appear on the command line. If arguments appear multiple times they
333
+ will be memorized multiple times as well.
334
+ """
335
+ state = ParsingState(args)
336
+ try:
337
+ self._process_args_for_options(state)
338
+ self._process_args_for_args(state)
339
+ except UsageError:
340
+ if self.ctx is None or not self.ctx.resilient_parsing:
341
+ raise
342
+ return state.opts, state.largs, state.order
343
+
344
+ def _process_args_for_args(self, state: ParsingState) -> None:
345
+ pargs, args = _unpack_args(
346
+ state.largs + state.rargs, [x.nargs for x in self._args]
347
+ )
348
+
349
+ for idx, arg in enumerate(self._args):
350
+ arg.process(pargs[idx], state)
351
+
352
+ state.largs = args
353
+ state.rargs = []
354
+
355
+ def _process_args_for_options(self, state: ParsingState) -> None:
356
+ while state.rargs:
357
+ arg = state.rargs.pop(0)
358
+ arglen = len(arg)
359
+ # Double dashes always handled explicitly regardless of what
360
+ # prefixes are valid.
361
+ if arg == "--":
362
+ return
363
+ elif arg[:1] in self._opt_prefixes and arglen > 1:
364
+ self._process_opts(arg, state)
365
+ elif self.allow_interspersed_args:
366
+ state.largs.append(arg)
367
+ else:
368
+ state.rargs.insert(0, arg)
369
+ return
370
+
371
+ # Say this is the original argument list:
372
+ # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
373
+ # ^
374
+ # (we are about to process arg(i)).
375
+ #
376
+ # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
377
+ # [arg0, ..., arg(i-1)] (any options and their arguments will have
378
+ # been removed from largs).
379
+ #
380
+ # The while loop will usually consume 1 or more arguments per pass.
381
+ # If it consumes 1 (eg. arg is an option that takes no arguments),
382
+ # then after _process_arg() is done the situation is:
383
+ #
384
+ # largs = subset of [arg0, ..., arg(i)]
385
+ # rargs = [arg(i+1), ..., arg(N-1)]
386
+ #
387
+ # If allow_interspersed_args is false, largs will always be
388
+ # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
389
+ # not a very interesting subset!
390
+
391
+ def _match_long_opt(
392
+ self, opt: str, explicit_value: t.Optional[str], state: ParsingState
393
+ ) -> None:
394
+ if opt not in self._long_opt:
395
+ from difflib import get_close_matches
396
+
397
+ possibilities = get_close_matches(opt, self._long_opt)
398
+ raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx)
399
+
400
+ option = self._long_opt[opt]
401
+ if option.takes_value:
402
+ # At this point it's safe to modify rargs by injecting the
403
+ # explicit value, because no exception is raised in this
404
+ # branch. This means that the inserted value will be fully
405
+ # consumed.
406
+ if explicit_value is not None:
407
+ state.rargs.insert(0, explicit_value)
408
+
409
+ value = self._get_value_from_state(opt, option, state)
410
+
411
+ elif explicit_value is not None:
412
+ raise BadOptionUsage(
413
+ opt, _("Option {name!r} does not take a value.").format(name=opt)
414
+ )
415
+
416
+ else:
417
+ value = None
418
+
419
+ option.process(value, state)
420
+
421
+ def _match_short_opt(self, arg: str, state: ParsingState) -> None:
422
+ stop = False
423
+ i = 1
424
+ prefix = arg[0]
425
+ unknown_options = []
426
+
427
+ for ch in arg[1:]:
428
+ opt = normalize_opt(f"{prefix}{ch}", self.ctx)
429
+ option = self._short_opt.get(opt)
430
+ i += 1
431
+
432
+ if not option:
433
+ if self.ignore_unknown_options:
434
+ unknown_options.append(ch)
435
+ continue
436
+ raise NoSuchOption(opt, ctx=self.ctx)
437
+ if option.takes_value:
438
+ # Any characters left in arg? Pretend they're the
439
+ # next arg, and stop consuming characters of arg.
440
+ if i < len(arg):
441
+ state.rargs.insert(0, arg[i:])
442
+ stop = True
443
+
444
+ value = self._get_value_from_state(opt, option, state)
445
+
446
+ else:
447
+ value = None
448
+
449
+ option.process(value, state)
450
+
451
+ if stop:
452
+ break
453
+
454
+ # If we got any unknown options we re-combinate the string of the
455
+ # remaining options and re-attach the prefix, then report that
456
+ # to the state as new larg. This way there is basic combinatorics
457
+ # that can be achieved while still ignoring unknown arguments.
458
+ if self.ignore_unknown_options and unknown_options:
459
+ state.largs.append(f"{prefix}{''.join(unknown_options)}")
460
+
461
+ def _get_value_from_state(
462
+ self, option_name: str, option: Option, state: ParsingState
463
+ ) -> t.Any:
464
+ nargs = option.nargs
465
+
466
+ if len(state.rargs) < nargs:
467
+ if option.obj._flag_needs_value:
468
+ # Option allows omitting the value.
469
+ value = _flag_needs_value
470
+ else:
471
+ raise BadOptionUsage(
472
+ option_name,
473
+ ngettext(
474
+ "Option {name!r} requires an argument.",
475
+ "Option {name!r} requires {nargs} arguments.",
476
+ nargs,
477
+ ).format(name=option_name, nargs=nargs),
478
+ )
479
+ elif nargs == 1:
480
+ next_rarg = state.rargs[0]
481
+
482
+ if (
483
+ option.obj._flag_needs_value
484
+ and isinstance(next_rarg, str)
485
+ and next_rarg[:1] in self._opt_prefixes
486
+ and len(next_rarg) > 1
487
+ ):
488
+ # The next arg looks like the start of an option, don't
489
+ # use it as the value if omitting the value is allowed.
490
+ value = _flag_needs_value
491
+ else:
492
+ value = state.rargs.pop(0)
493
+ else:
494
+ value = tuple(state.rargs[:nargs])
495
+ del state.rargs[:nargs]
496
+
497
+ return value
498
+
499
+ def _process_opts(self, arg: str, state: ParsingState) -> None:
500
+ explicit_value = None
501
+ # Long option handling happens in two parts. The first part is
502
+ # supporting explicitly attached values. In any case, we will try
503
+ # to long match the option first.
504
+ if "=" in arg:
505
+ long_opt, explicit_value = arg.split("=", 1)
506
+ else:
507
+ long_opt = arg
508
+ norm_long_opt = normalize_opt(long_opt, self.ctx)
509
+
510
+ # At this point we will match the (assumed) long option through
511
+ # the long option matching code. Note that this allows options
512
+ # like "-foo" to be matched as long options.
513
+ try:
514
+ self._match_long_opt(norm_long_opt, explicit_value, state)
515
+ except NoSuchOption:
516
+ # At this point the long option matching failed, and we need
517
+ # to try with short options. However there is a special rule
518
+ # which says, that if we have a two character options prefix
519
+ # (applies to "--foo" for instance), we do not dispatch to the
520
+ # short option code and will instead raise the no option
521
+ # error.
522
+ if arg[:2] not in self._opt_prefixes:
523
+ self._match_short_opt(arg, state)
524
+ return
525
+
526
+ if not self.ignore_unknown_options:
527
+ raise
528
+
529
+ state.largs.append(arg)
File without changes