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,287 @@
1
+ import os
2
+ import typing as t
3
+ from gettext import gettext as _
4
+ from gettext import ngettext
5
+
6
+ from ._compat import get_text_stderr
7
+ from .utils import echo
8
+
9
+ if t.TYPE_CHECKING:
10
+ from .core import Context
11
+ from .core import Parameter
12
+
13
+
14
+ def _join_param_hints(
15
+ param_hint: t.Optional[t.Union[t.Sequence[str], str]]
16
+ ) -> t.Optional[str]:
17
+ if param_hint is not None and not isinstance(param_hint, str):
18
+ return " / ".join(repr(x) for x in param_hint)
19
+
20
+ return param_hint
21
+
22
+
23
+ class ClickException(Exception):
24
+ """An exception that Click can handle and show to the user."""
25
+
26
+ #: The exit code for this exception.
27
+ exit_code = 1
28
+
29
+ def __init__(self, message: str) -> None:
30
+ super().__init__(message)
31
+ self.message = message
32
+
33
+ def format_message(self) -> str:
34
+ return self.message
35
+
36
+ def __str__(self) -> str:
37
+ return self.message
38
+
39
+ def show(self, file: t.Optional[t.IO] = None) -> None:
40
+ if file is None:
41
+ file = get_text_stderr()
42
+
43
+ echo(_("Error: {message}").format(message=self.format_message()), file=file)
44
+
45
+
46
+ class UsageError(ClickException):
47
+ """An internal exception that signals a usage error. This typically
48
+ aborts any further handling.
49
+
50
+ :param message: the error message to display.
51
+ :param ctx: optionally the context that caused this error. Click will
52
+ fill in the context automatically in some situations.
53
+ """
54
+
55
+ exit_code = 2
56
+
57
+ def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None:
58
+ super().__init__(message)
59
+ self.ctx = ctx
60
+ self.cmd = self.ctx.command if self.ctx else None
61
+
62
+ def show(self, file: t.Optional[t.IO] = None) -> None:
63
+ if file is None:
64
+ file = get_text_stderr()
65
+ color = None
66
+ hint = ""
67
+ if (
68
+ self.ctx is not None
69
+ and self.ctx.command.get_help_option(self.ctx) is not None
70
+ ):
71
+ hint = _("Try '{command} {option}' for help.").format(
72
+ command=self.ctx.command_path, option=self.ctx.help_option_names[0]
73
+ )
74
+ hint = f"{hint}\n"
75
+ if self.ctx is not None:
76
+ color = self.ctx.color
77
+ echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color)
78
+ echo(
79
+ _("Error: {message}").format(message=self.format_message()),
80
+ file=file,
81
+ color=color,
82
+ )
83
+
84
+
85
+ class BadParameter(UsageError):
86
+ """An exception that formats out a standardized error message for a
87
+ bad parameter. This is useful when thrown from a callback or type as
88
+ Click will attach contextual information to it (for instance, which
89
+ parameter it is).
90
+
91
+ .. versionadded:: 2.0
92
+
93
+ :param param: the parameter object that caused this error. This can
94
+ be left out, and Click will attach this info itself
95
+ if possible.
96
+ :param param_hint: a string that shows up as parameter name. This
97
+ can be used as alternative to `param` in cases
98
+ where custom validation should happen. If it is
99
+ a string it's used as such, if it's a list then
100
+ each item is quoted and separated.
101
+ """
102
+
103
+ def __init__(
104
+ self,
105
+ message: str,
106
+ ctx: t.Optional["Context"] = None,
107
+ param: t.Optional["Parameter"] = None,
108
+ param_hint: t.Optional[str] = None,
109
+ ) -> None:
110
+ super().__init__(message, ctx)
111
+ self.param = param
112
+ self.param_hint = param_hint
113
+
114
+ def format_message(self) -> str:
115
+ if self.param_hint is not None:
116
+ param_hint = self.param_hint
117
+ elif self.param is not None:
118
+ param_hint = self.param.get_error_hint(self.ctx) # type: ignore
119
+ else:
120
+ return _("Invalid value: {message}").format(message=self.message)
121
+
122
+ return _("Invalid value for {param_hint}: {message}").format(
123
+ param_hint=_join_param_hints(param_hint), message=self.message
124
+ )
125
+
126
+
127
+ class MissingParameter(BadParameter):
128
+ """Raised if click required an option or argument but it was not
129
+ provided when invoking the script.
130
+
131
+ .. versionadded:: 4.0
132
+
133
+ :param param_type: a string that indicates the type of the parameter.
134
+ The default is to inherit the parameter type from
135
+ the given `param`. Valid values are ``'parameter'``,
136
+ ``'option'`` or ``'argument'``.
137
+ """
138
+
139
+ def __init__(
140
+ self,
141
+ message: t.Optional[str] = None,
142
+ ctx: t.Optional["Context"] = None,
143
+ param: t.Optional["Parameter"] = None,
144
+ param_hint: t.Optional[str] = None,
145
+ param_type: t.Optional[str] = None,
146
+ ) -> None:
147
+ super().__init__(message or "", ctx, param, param_hint)
148
+ self.param_type = param_type
149
+
150
+ def format_message(self) -> str:
151
+ if self.param_hint is not None:
152
+ param_hint: t.Optional[str] = self.param_hint
153
+ elif self.param is not None:
154
+ param_hint = self.param.get_error_hint(self.ctx) # type: ignore
155
+ else:
156
+ param_hint = None
157
+
158
+ param_hint = _join_param_hints(param_hint)
159
+ param_hint = f" {param_hint}" if param_hint else ""
160
+
161
+ param_type = self.param_type
162
+ if param_type is None and self.param is not None:
163
+ param_type = self.param.param_type_name
164
+
165
+ msg = self.message
166
+ if self.param is not None:
167
+ msg_extra = self.param.type.get_missing_message(self.param)
168
+ if msg_extra:
169
+ if msg:
170
+ msg += f". {msg_extra}"
171
+ else:
172
+ msg = msg_extra
173
+
174
+ msg = f" {msg}" if msg else ""
175
+
176
+ # Translate param_type for known types.
177
+ if param_type == "argument":
178
+ missing = _("Missing argument")
179
+ elif param_type == "option":
180
+ missing = _("Missing option")
181
+ elif param_type == "parameter":
182
+ missing = _("Missing parameter")
183
+ else:
184
+ missing = _("Missing {param_type}").format(param_type=param_type)
185
+
186
+ return f"{missing}{param_hint}.{msg}"
187
+
188
+ def __str__(self) -> str:
189
+ if not self.message:
190
+ param_name = self.param.name if self.param else None
191
+ return _("Missing parameter: {param_name}").format(param_name=param_name)
192
+ else:
193
+ return self.message
194
+
195
+
196
+ class NoSuchOption(UsageError):
197
+ """Raised if click attempted to handle an option that does not
198
+ exist.
199
+
200
+ .. versionadded:: 4.0
201
+ """
202
+
203
+ def __init__(
204
+ self,
205
+ option_name: str,
206
+ message: t.Optional[str] = None,
207
+ possibilities: t.Optional[t.Sequence[str]] = None,
208
+ ctx: t.Optional["Context"] = None,
209
+ ) -> None:
210
+ if message is None:
211
+ message = _("No such option: {name}").format(name=option_name)
212
+
213
+ super().__init__(message, ctx)
214
+ self.option_name = option_name
215
+ self.possibilities = possibilities
216
+
217
+ def format_message(self) -> str:
218
+ if not self.possibilities:
219
+ return self.message
220
+
221
+ possibility_str = ", ".join(sorted(self.possibilities))
222
+ suggest = ngettext(
223
+ "Did you mean {possibility}?",
224
+ "(Possible options: {possibilities})",
225
+ len(self.possibilities),
226
+ ).format(possibility=possibility_str, possibilities=possibility_str)
227
+ return f"{self.message} {suggest}"
228
+
229
+
230
+ class BadOptionUsage(UsageError):
231
+ """Raised if an option is generally supplied but the use of the option
232
+ was incorrect. This is for instance raised if the number of arguments
233
+ for an option is not correct.
234
+
235
+ .. versionadded:: 4.0
236
+
237
+ :param option_name: the name of the option being used incorrectly.
238
+ """
239
+
240
+ def __init__(
241
+ self, option_name: str, message: str, ctx: t.Optional["Context"] = None
242
+ ) -> None:
243
+ super().__init__(message, ctx)
244
+ self.option_name = option_name
245
+
246
+
247
+ class BadArgumentUsage(UsageError):
248
+ """Raised if an argument is generally supplied but the use of the argument
249
+ was incorrect. This is for instance raised if the number of values
250
+ for an argument is not correct.
251
+
252
+ .. versionadded:: 6.0
253
+ """
254
+
255
+
256
+ class FileError(ClickException):
257
+ """Raised if a file cannot be opened."""
258
+
259
+ def __init__(self, filename: str, hint: t.Optional[str] = None) -> None:
260
+ if hint is None:
261
+ hint = _("unknown error")
262
+
263
+ super().__init__(hint)
264
+ self.ui_filename = os.fsdecode(filename)
265
+ self.filename = filename
266
+
267
+ def format_message(self) -> str:
268
+ return _("Could not open file {filename!r}: {message}").format(
269
+ filename=self.ui_filename, message=self.message
270
+ )
271
+
272
+
273
+ class Abort(RuntimeError):
274
+ """An internal signalling exception that signals Click to abort."""
275
+
276
+
277
+ class Exit(RuntimeError):
278
+ """An exception that indicates that the application should exit with some
279
+ status code.
280
+
281
+ :param code: the status code to exit with.
282
+ """
283
+
284
+ __slots__ = ("exit_code",)
285
+
286
+ def __init__(self, code: int = 0) -> None:
287
+ self.exit_code = code
@@ -0,0 +1,301 @@
1
+ import typing as t
2
+ from contextlib import contextmanager
3
+ from gettext import gettext as _
4
+
5
+ from ._compat import term_len
6
+ from .parser import split_opt
7
+
8
+ # Can force a width. This is used by the test system
9
+ FORCED_WIDTH: t.Optional[int] = None
10
+
11
+
12
+ def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]:
13
+ widths: t.Dict[int, int] = {}
14
+
15
+ for row in rows:
16
+ for idx, col in enumerate(row):
17
+ widths[idx] = max(widths.get(idx, 0), term_len(col))
18
+
19
+ return tuple(y for x, y in sorted(widths.items()))
20
+
21
+
22
+ def iter_rows(
23
+ rows: t.Iterable[t.Tuple[str, str]], col_count: int
24
+ ) -> t.Iterator[t.Tuple[str, ...]]:
25
+ for row in rows:
26
+ yield row + ("",) * (col_count - len(row))
27
+
28
+
29
+ def wrap_text(
30
+ text: str,
31
+ width: int = 78,
32
+ initial_indent: str = "",
33
+ subsequent_indent: str = "",
34
+ preserve_paragraphs: bool = False,
35
+ ) -> str:
36
+ """A helper function that intelligently wraps text. By default, it
37
+ assumes that it operates on a single paragraph of text but if the
38
+ `preserve_paragraphs` parameter is provided it will intelligently
39
+ handle paragraphs (defined by two empty lines).
40
+
41
+ If paragraphs are handled, a paragraph can be prefixed with an empty
42
+ line containing the ``\\b`` character (``\\x08``) to indicate that
43
+ no rewrapping should happen in that block.
44
+
45
+ :param text: the text that should be rewrapped.
46
+ :param width: the maximum width for the text.
47
+ :param initial_indent: the initial indent that should be placed on the
48
+ first line as a string.
49
+ :param subsequent_indent: the indent string that should be placed on
50
+ each consecutive line.
51
+ :param preserve_paragraphs: if this flag is set then the wrapping will
52
+ intelligently handle paragraphs.
53
+ """
54
+ from ._textwrap import TextWrapper
55
+
56
+ text = text.expandtabs()
57
+ wrapper = TextWrapper(
58
+ width,
59
+ initial_indent=initial_indent,
60
+ subsequent_indent=subsequent_indent,
61
+ replace_whitespace=False,
62
+ )
63
+ if not preserve_paragraphs:
64
+ return wrapper.fill(text)
65
+
66
+ p: t.List[t.Tuple[int, bool, str]] = []
67
+ buf: t.List[str] = []
68
+ indent = None
69
+
70
+ def _flush_par() -> None:
71
+ if not buf:
72
+ return
73
+ if buf[0].strip() == "\b":
74
+ p.append((indent or 0, True, "\n".join(buf[1:])))
75
+ else:
76
+ p.append((indent or 0, False, " ".join(buf)))
77
+ del buf[:]
78
+
79
+ for line in text.splitlines():
80
+ if not line:
81
+ _flush_par()
82
+ indent = None
83
+ else:
84
+ if indent is None:
85
+ orig_len = term_len(line)
86
+ line = line.lstrip()
87
+ indent = orig_len - term_len(line)
88
+ buf.append(line)
89
+ _flush_par()
90
+
91
+ rv = []
92
+ for indent, raw, text in p:
93
+ with wrapper.extra_indent(" " * indent):
94
+ if raw:
95
+ rv.append(wrapper.indent_only(text))
96
+ else:
97
+ rv.append(wrapper.fill(text))
98
+
99
+ return "\n\n".join(rv)
100
+
101
+
102
+ class HelpFormatter:
103
+ """This class helps with formatting text-based help pages. It's
104
+ usually just needed for very special internal cases, but it's also
105
+ exposed so that developers can write their own fancy outputs.
106
+
107
+ At present, it always writes into memory.
108
+
109
+ :param indent_increment: the additional increment for each level.
110
+ :param width: the width for the text. This defaults to the terminal
111
+ width clamped to a maximum of 78.
112
+ """
113
+
114
+ def __init__(
115
+ self,
116
+ indent_increment: int = 2,
117
+ width: t.Optional[int] = None,
118
+ max_width: t.Optional[int] = None,
119
+ ) -> None:
120
+ import shutil
121
+
122
+ self.indent_increment = indent_increment
123
+ if max_width is None:
124
+ max_width = 80
125
+ if width is None:
126
+ width = FORCED_WIDTH
127
+ if width is None:
128
+ width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50)
129
+ self.width = width
130
+ self.current_indent = 0
131
+ self.buffer: t.List[str] = []
132
+
133
+ def write(self, string: str) -> None:
134
+ """Writes a unicode string into the internal buffer."""
135
+ self.buffer.append(string)
136
+
137
+ def indent(self) -> None:
138
+ """Increases the indentation."""
139
+ self.current_indent += self.indent_increment
140
+
141
+ def dedent(self) -> None:
142
+ """Decreases the indentation."""
143
+ self.current_indent -= self.indent_increment
144
+
145
+ def write_usage(
146
+ self, prog: str, args: str = "", prefix: t.Optional[str] = None
147
+ ) -> None:
148
+ """Writes a usage line into the buffer.
149
+
150
+ :param prog: the program name.
151
+ :param args: whitespace separated list of arguments.
152
+ :param prefix: The prefix for the first line. Defaults to
153
+ ``"Usage: "``.
154
+ """
155
+ if prefix is None:
156
+ prefix = f"{_('Usage:')} "
157
+
158
+ usage_prefix = f"{prefix:>{self.current_indent}}{prog} "
159
+ text_width = self.width - self.current_indent
160
+
161
+ if text_width >= (term_len(usage_prefix) + 20):
162
+ # The arguments will fit to the right of the prefix.
163
+ indent = " " * term_len(usage_prefix)
164
+ self.write(
165
+ wrap_text(
166
+ args,
167
+ text_width,
168
+ initial_indent=usage_prefix,
169
+ subsequent_indent=indent,
170
+ )
171
+ )
172
+ else:
173
+ # The prefix is too long, put the arguments on the next line.
174
+ self.write(usage_prefix)
175
+ self.write("\n")
176
+ indent = " " * (max(self.current_indent, term_len(prefix)) + 4)
177
+ self.write(
178
+ wrap_text(
179
+ args, text_width, initial_indent=indent, subsequent_indent=indent
180
+ )
181
+ )
182
+
183
+ self.write("\n")
184
+
185
+ def write_heading(self, heading: str) -> None:
186
+ """Writes a heading into the buffer."""
187
+ self.write(f"{'':>{self.current_indent}}{heading}:\n")
188
+
189
+ def write_paragraph(self) -> None:
190
+ """Writes a paragraph into the buffer."""
191
+ if self.buffer:
192
+ self.write("\n")
193
+
194
+ def write_text(self, text: str) -> None:
195
+ """Writes re-indented text into the buffer. This rewraps and
196
+ preserves paragraphs.
197
+ """
198
+ indent = " " * self.current_indent
199
+ self.write(
200
+ wrap_text(
201
+ text,
202
+ self.width,
203
+ initial_indent=indent,
204
+ subsequent_indent=indent,
205
+ preserve_paragraphs=True,
206
+ )
207
+ )
208
+ self.write("\n")
209
+
210
+ def write_dl(
211
+ self,
212
+ rows: t.Sequence[t.Tuple[str, str]],
213
+ col_max: int = 30,
214
+ col_spacing: int = 2,
215
+ ) -> None:
216
+ """Writes a definition list into the buffer. This is how options
217
+ and commands are usually formatted.
218
+
219
+ :param rows: a list of two item tuples for the terms and values.
220
+ :param col_max: the maximum width of the first column.
221
+ :param col_spacing: the number of spaces between the first and
222
+ second column.
223
+ """
224
+ rows = list(rows)
225
+ widths = measure_table(rows)
226
+ if len(widths) != 2:
227
+ raise TypeError("Expected two columns for definition list")
228
+
229
+ first_col = min(widths[0], col_max) + col_spacing
230
+
231
+ for first, second in iter_rows(rows, len(widths)):
232
+ self.write(f"{'':>{self.current_indent}}{first}")
233
+ if not second:
234
+ self.write("\n")
235
+ continue
236
+ if term_len(first) <= first_col - col_spacing:
237
+ self.write(" " * (first_col - term_len(first)))
238
+ else:
239
+ self.write("\n")
240
+ self.write(" " * (first_col + self.current_indent))
241
+
242
+ text_width = max(self.width - first_col - 2, 10)
243
+ wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True)
244
+ lines = wrapped_text.splitlines()
245
+
246
+ if lines:
247
+ self.write(f"{lines[0]}\n")
248
+
249
+ for line in lines[1:]:
250
+ self.write(f"{'':>{first_col + self.current_indent}}{line}\n")
251
+ else:
252
+ self.write("\n")
253
+
254
+ @contextmanager
255
+ def section(self, name: str) -> t.Iterator[None]:
256
+ """Helpful context manager that writes a paragraph, a heading,
257
+ and the indents.
258
+
259
+ :param name: the section name that is written as heading.
260
+ """
261
+ self.write_paragraph()
262
+ self.write_heading(name)
263
+ self.indent()
264
+ try:
265
+ yield
266
+ finally:
267
+ self.dedent()
268
+
269
+ @contextmanager
270
+ def indentation(self) -> t.Iterator[None]:
271
+ """A context manager that increases the indentation."""
272
+ self.indent()
273
+ try:
274
+ yield
275
+ finally:
276
+ self.dedent()
277
+
278
+ def getvalue(self) -> str:
279
+ """Returns the buffer contents."""
280
+ return "".join(self.buffer)
281
+
282
+
283
+ def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]:
284
+ """Given a list of option strings this joins them in the most appropriate
285
+ way and returns them in the form ``(formatted_string,
286
+ any_prefix_is_slash)`` where the second item in the tuple is a flag that
287
+ indicates if any of the option prefixes was a slash.
288
+ """
289
+ rv = []
290
+ any_prefix_is_slash = False
291
+
292
+ for opt in options:
293
+ prefix = split_opt(opt)[0]
294
+
295
+ if prefix == "/":
296
+ any_prefix_is_slash = True
297
+
298
+ rv.append((len(prefix), opt))
299
+
300
+ rv.sort(key=lambda x: x[0])
301
+ return ", ".join(x[1] for x in rv), any_prefix_is_slash
@@ -0,0 +1,68 @@
1
+ import typing as t
2
+ from threading import local
3
+
4
+ if t.TYPE_CHECKING:
5
+ import typing_extensions as te
6
+ from .core import Context
7
+
8
+ _local = local()
9
+
10
+
11
+ @t.overload
12
+ def get_current_context(silent: "te.Literal[False]" = False) -> "Context":
13
+ ...
14
+
15
+
16
+ @t.overload
17
+ def get_current_context(silent: bool = ...) -> t.Optional["Context"]:
18
+ ...
19
+
20
+
21
+ def get_current_context(silent: bool = False) -> t.Optional["Context"]:
22
+ """Returns the current click context. This can be used as a way to
23
+ access the current context object from anywhere. This is a more implicit
24
+ alternative to the :func:`pass_context` decorator. This function is
25
+ primarily useful for helpers such as :func:`echo` which might be
26
+ interested in changing its behavior based on the current context.
27
+
28
+ To push the current context, :meth:`Context.scope` can be used.
29
+
30
+ .. versionadded:: 5.0
31
+
32
+ :param silent: if set to `True` the return value is `None` if no context
33
+ is available. The default behavior is to raise a
34
+ :exc:`RuntimeError`.
35
+ """
36
+ try:
37
+ return t.cast("Context", _local.stack[-1])
38
+ except (AttributeError, IndexError) as e:
39
+ if not silent:
40
+ raise RuntimeError("There is no active click context.") from e
41
+
42
+ return None
43
+
44
+
45
+ def push_context(ctx: "Context") -> None:
46
+ """Pushes a new context to the current stack."""
47
+ _local.__dict__.setdefault("stack", []).append(ctx)
48
+
49
+
50
+ def pop_context() -> None:
51
+ """Removes the top level from the stack."""
52
+ _local.stack.pop()
53
+
54
+
55
+ def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]:
56
+ """Internal helper to get the default value of the color flag. If a
57
+ value is passed it's returned unchanged, otherwise it's looked up from
58
+ the current context.
59
+ """
60
+ if color is not None:
61
+ return color
62
+
63
+ ctx = get_current_context(silent=True)
64
+
65
+ if ctx is not None:
66
+ return ctx.color
67
+
68
+ return None