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,497 @@
|
|
1
|
+
import inspect
|
2
|
+
import types
|
3
|
+
import typing as t
|
4
|
+
from functools import update_wrapper
|
5
|
+
from gettext import gettext as _
|
6
|
+
|
7
|
+
from .core import Argument
|
8
|
+
from .core import Command
|
9
|
+
from .core import Context
|
10
|
+
from .core import Group
|
11
|
+
from .core import Option
|
12
|
+
from .core import Parameter
|
13
|
+
from .globals import get_current_context
|
14
|
+
from .utils import echo
|
15
|
+
|
16
|
+
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
|
17
|
+
FC = t.TypeVar("FC", bound=t.Union[t.Callable[..., t.Any], Command])
|
18
|
+
|
19
|
+
|
20
|
+
def pass_context(f: F) -> F:
|
21
|
+
"""Marks a callback as wanting to receive the current context
|
22
|
+
object as first argument.
|
23
|
+
"""
|
24
|
+
|
25
|
+
def new_func(*args, **kwargs): # type: ignore
|
26
|
+
return f(get_current_context(), *args, **kwargs)
|
27
|
+
|
28
|
+
return update_wrapper(t.cast(F, new_func), f)
|
29
|
+
|
30
|
+
|
31
|
+
def pass_obj(f: F) -> F:
|
32
|
+
"""Similar to :func:`pass_context`, but only pass the object on the
|
33
|
+
context onwards (:attr:`Context.obj`). This is useful if that object
|
34
|
+
represents the state of a nested system.
|
35
|
+
"""
|
36
|
+
|
37
|
+
def new_func(*args, **kwargs): # type: ignore
|
38
|
+
return f(get_current_context().obj, *args, **kwargs)
|
39
|
+
|
40
|
+
return update_wrapper(t.cast(F, new_func), f)
|
41
|
+
|
42
|
+
|
43
|
+
def make_pass_decorator(
|
44
|
+
object_type: t.Type, ensure: bool = False
|
45
|
+
) -> "t.Callable[[F], F]":
|
46
|
+
"""Given an object type this creates a decorator that will work
|
47
|
+
similar to :func:`pass_obj` but instead of passing the object of the
|
48
|
+
current context, it will find the innermost context of type
|
49
|
+
:func:`object_type`.
|
50
|
+
|
51
|
+
This generates a decorator that works roughly like this::
|
52
|
+
|
53
|
+
from functools import update_wrapper
|
54
|
+
|
55
|
+
def decorator(f):
|
56
|
+
@pass_context
|
57
|
+
def new_func(ctx, *args, **kwargs):
|
58
|
+
obj = ctx.find_object(object_type)
|
59
|
+
return ctx.invoke(f, obj, *args, **kwargs)
|
60
|
+
return update_wrapper(new_func, f)
|
61
|
+
return decorator
|
62
|
+
|
63
|
+
:param object_type: the type of the object to pass.
|
64
|
+
:param ensure: if set to `True`, a new object will be created and
|
65
|
+
remembered on the context if it's not there yet.
|
66
|
+
"""
|
67
|
+
|
68
|
+
def decorator(f: F) -> F:
|
69
|
+
def new_func(*args, **kwargs): # type: ignore
|
70
|
+
ctx = get_current_context()
|
71
|
+
|
72
|
+
if ensure:
|
73
|
+
obj = ctx.ensure_object(object_type)
|
74
|
+
else:
|
75
|
+
obj = ctx.find_object(object_type)
|
76
|
+
|
77
|
+
if obj is None:
|
78
|
+
raise RuntimeError(
|
79
|
+
"Managed to invoke callback without a context"
|
80
|
+
f" object of type {object_type.__name__!r}"
|
81
|
+
" existing."
|
82
|
+
)
|
83
|
+
|
84
|
+
return ctx.invoke(f, obj, *args, **kwargs)
|
85
|
+
|
86
|
+
return update_wrapper(t.cast(F, new_func), f)
|
87
|
+
|
88
|
+
return decorator
|
89
|
+
|
90
|
+
|
91
|
+
def pass_meta_key(
|
92
|
+
key: str, *, doc_description: t.Optional[str] = None
|
93
|
+
) -> "t.Callable[[F], F]":
|
94
|
+
"""Create a decorator that passes a key from
|
95
|
+
:attr:`click.Context.meta` as the first argument to the decorated
|
96
|
+
function.
|
97
|
+
|
98
|
+
:param key: Key in ``Context.meta`` to pass.
|
99
|
+
:param doc_description: Description of the object being passed,
|
100
|
+
inserted into the decorator's docstring. Defaults to "the 'key'
|
101
|
+
key from Context.meta".
|
102
|
+
|
103
|
+
.. versionadded:: 8.0
|
104
|
+
"""
|
105
|
+
|
106
|
+
def decorator(f: F) -> F:
|
107
|
+
def new_func(*args, **kwargs): # type: ignore
|
108
|
+
ctx = get_current_context()
|
109
|
+
obj = ctx.meta[key]
|
110
|
+
return ctx.invoke(f, obj, *args, **kwargs)
|
111
|
+
|
112
|
+
return update_wrapper(t.cast(F, new_func), f)
|
113
|
+
|
114
|
+
if doc_description is None:
|
115
|
+
doc_description = f"the {key!r} key from :attr:`click.Context.meta`"
|
116
|
+
|
117
|
+
decorator.__doc__ = (
|
118
|
+
f"Decorator that passes {doc_description} as the first argument"
|
119
|
+
" to the decorated function."
|
120
|
+
)
|
121
|
+
return decorator
|
122
|
+
|
123
|
+
|
124
|
+
CmdType = t.TypeVar("CmdType", bound=Command)
|
125
|
+
|
126
|
+
|
127
|
+
@t.overload
|
128
|
+
def command(
|
129
|
+
__func: t.Callable[..., t.Any],
|
130
|
+
) -> Command:
|
131
|
+
...
|
132
|
+
|
133
|
+
|
134
|
+
@t.overload
|
135
|
+
def command(
|
136
|
+
name: t.Optional[str] = None,
|
137
|
+
**attrs: t.Any,
|
138
|
+
) -> t.Callable[..., Command]:
|
139
|
+
...
|
140
|
+
|
141
|
+
|
142
|
+
@t.overload
|
143
|
+
def command(
|
144
|
+
name: t.Optional[str] = None,
|
145
|
+
cls: t.Type[CmdType] = ...,
|
146
|
+
**attrs: t.Any,
|
147
|
+
) -> t.Callable[..., CmdType]:
|
148
|
+
...
|
149
|
+
|
150
|
+
|
151
|
+
def command(
|
152
|
+
name: t.Union[str, t.Callable[..., t.Any], None] = None,
|
153
|
+
cls: t.Optional[t.Type[Command]] = None,
|
154
|
+
**attrs: t.Any,
|
155
|
+
) -> t.Union[Command, t.Callable[..., Command]]:
|
156
|
+
r"""Creates a new :class:`Command` and uses the decorated function as
|
157
|
+
callback. This will also automatically attach all decorated
|
158
|
+
:func:`option`\s and :func:`argument`\s as parameters to the command.
|
159
|
+
|
160
|
+
The name of the command defaults to the name of the function with
|
161
|
+
underscores replaced by dashes. If you want to change that, you can
|
162
|
+
pass the intended name as the first argument.
|
163
|
+
|
164
|
+
All keyword arguments are forwarded to the underlying command class.
|
165
|
+
For the ``params`` argument, any decorated params are appended to
|
166
|
+
the end of the list.
|
167
|
+
|
168
|
+
Once decorated the function turns into a :class:`Command` instance
|
169
|
+
that can be invoked as a command line utility or be attached to a
|
170
|
+
command :class:`Group`.
|
171
|
+
|
172
|
+
:param name: the name of the command. This defaults to the function
|
173
|
+
name with underscores replaced by dashes.
|
174
|
+
:param cls: the command class to instantiate. This defaults to
|
175
|
+
:class:`Command`.
|
176
|
+
|
177
|
+
.. versionchanged:: 8.1
|
178
|
+
This decorator can be applied without parentheses.
|
179
|
+
|
180
|
+
.. versionchanged:: 8.1
|
181
|
+
The ``params`` argument can be used. Decorated params are
|
182
|
+
appended to the end of the list.
|
183
|
+
"""
|
184
|
+
|
185
|
+
func: t.Optional[t.Callable[..., t.Any]] = None
|
186
|
+
|
187
|
+
if callable(name):
|
188
|
+
func = name
|
189
|
+
name = None
|
190
|
+
assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class."
|
191
|
+
assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments."
|
192
|
+
|
193
|
+
if cls is None:
|
194
|
+
cls = Command
|
195
|
+
|
196
|
+
def decorator(f: t.Callable[..., t.Any]) -> Command:
|
197
|
+
if isinstance(f, Command):
|
198
|
+
raise TypeError("Attempted to convert a callback into a command twice.")
|
199
|
+
|
200
|
+
attr_params = attrs.pop("params", None)
|
201
|
+
params = attr_params if attr_params is not None else []
|
202
|
+
|
203
|
+
try:
|
204
|
+
decorator_params = f.__click_params__ # type: ignore
|
205
|
+
except AttributeError:
|
206
|
+
pass
|
207
|
+
else:
|
208
|
+
del f.__click_params__ # type: ignore
|
209
|
+
params.extend(reversed(decorator_params))
|
210
|
+
|
211
|
+
if attrs.get("help") is None:
|
212
|
+
attrs["help"] = f.__doc__
|
213
|
+
|
214
|
+
cmd = cls( # type: ignore[misc]
|
215
|
+
name=name or f.__name__.lower().replace("_", "-"), # type: ignore[arg-type]
|
216
|
+
callback=f,
|
217
|
+
params=params,
|
218
|
+
**attrs,
|
219
|
+
)
|
220
|
+
cmd.__doc__ = f.__doc__
|
221
|
+
return cmd
|
222
|
+
|
223
|
+
if func is not None:
|
224
|
+
return decorator(func)
|
225
|
+
|
226
|
+
return decorator
|
227
|
+
|
228
|
+
|
229
|
+
@t.overload
|
230
|
+
def group(
|
231
|
+
__func: t.Callable[..., t.Any],
|
232
|
+
) -> Group:
|
233
|
+
...
|
234
|
+
|
235
|
+
|
236
|
+
@t.overload
|
237
|
+
def group(
|
238
|
+
name: t.Optional[str] = None,
|
239
|
+
**attrs: t.Any,
|
240
|
+
) -> t.Callable[[F], Group]:
|
241
|
+
...
|
242
|
+
|
243
|
+
|
244
|
+
def group(
|
245
|
+
name: t.Union[str, t.Callable[..., t.Any], None] = None, **attrs: t.Any
|
246
|
+
) -> t.Union[Group, t.Callable[[F], Group]]:
|
247
|
+
"""Creates a new :class:`Group` with a function as callback. This
|
248
|
+
works otherwise the same as :func:`command` just that the `cls`
|
249
|
+
parameter is set to :class:`Group`.
|
250
|
+
|
251
|
+
.. versionchanged:: 8.1
|
252
|
+
This decorator can be applied without parentheses.
|
253
|
+
"""
|
254
|
+
if attrs.get("cls") is None:
|
255
|
+
attrs["cls"] = Group
|
256
|
+
|
257
|
+
if callable(name):
|
258
|
+
grp: t.Callable[[F], Group] = t.cast(Group, command(**attrs))
|
259
|
+
return grp(name)
|
260
|
+
|
261
|
+
return t.cast(Group, command(name, **attrs))
|
262
|
+
|
263
|
+
|
264
|
+
def _param_memo(f: FC, param: Parameter) -> None:
|
265
|
+
if isinstance(f, Command):
|
266
|
+
f.params.append(param)
|
267
|
+
else:
|
268
|
+
if not hasattr(f, "__click_params__"):
|
269
|
+
f.__click_params__ = [] # type: ignore
|
270
|
+
|
271
|
+
f.__click_params__.append(param) # type: ignore
|
272
|
+
|
273
|
+
|
274
|
+
def argument(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]:
|
275
|
+
"""Attaches an argument to the command. All positional arguments are
|
276
|
+
passed as parameter declarations to :class:`Argument`; all keyword
|
277
|
+
arguments are forwarded unchanged (except ``cls``).
|
278
|
+
This is equivalent to creating an :class:`Argument` instance manually
|
279
|
+
and attaching it to the :attr:`Command.params` list.
|
280
|
+
|
281
|
+
:param cls: the argument class to instantiate. This defaults to
|
282
|
+
:class:`Argument`.
|
283
|
+
"""
|
284
|
+
|
285
|
+
def decorator(f: FC) -> FC:
|
286
|
+
ArgumentClass = attrs.pop("cls", None) or Argument
|
287
|
+
_param_memo(f, ArgumentClass(param_decls, **attrs))
|
288
|
+
return f
|
289
|
+
|
290
|
+
return decorator
|
291
|
+
|
292
|
+
|
293
|
+
def option(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]:
|
294
|
+
"""Attaches an option to the command. All positional arguments are
|
295
|
+
passed as parameter declarations to :class:`Option`; all keyword
|
296
|
+
arguments are forwarded unchanged (except ``cls``).
|
297
|
+
This is equivalent to creating an :class:`Option` instance manually
|
298
|
+
and attaching it to the :attr:`Command.params` list.
|
299
|
+
|
300
|
+
:param cls: the option class to instantiate. This defaults to
|
301
|
+
:class:`Option`.
|
302
|
+
"""
|
303
|
+
|
304
|
+
def decorator(f: FC) -> FC:
|
305
|
+
# Issue 926, copy attrs, so pre-defined options can re-use the same cls=
|
306
|
+
option_attrs = attrs.copy()
|
307
|
+
OptionClass = option_attrs.pop("cls", None) or Option
|
308
|
+
_param_memo(f, OptionClass(param_decls, **option_attrs))
|
309
|
+
return f
|
310
|
+
|
311
|
+
return decorator
|
312
|
+
|
313
|
+
|
314
|
+
def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]:
|
315
|
+
"""Add a ``--yes`` option which shows a prompt before continuing if
|
316
|
+
not passed. If the prompt is declined, the program will exit.
|
317
|
+
|
318
|
+
:param param_decls: One or more option names. Defaults to the single
|
319
|
+
value ``"--yes"``.
|
320
|
+
:param kwargs: Extra arguments are passed to :func:`option`.
|
321
|
+
"""
|
322
|
+
|
323
|
+
def callback(ctx: Context, param: Parameter, value: bool) -> None:
|
324
|
+
if not value:
|
325
|
+
ctx.abort()
|
326
|
+
|
327
|
+
if not param_decls:
|
328
|
+
param_decls = ("--yes",)
|
329
|
+
|
330
|
+
kwargs.setdefault("is_flag", True)
|
331
|
+
kwargs.setdefault("callback", callback)
|
332
|
+
kwargs.setdefault("expose_value", False)
|
333
|
+
kwargs.setdefault("prompt", "Do you want to continue?")
|
334
|
+
kwargs.setdefault("help", "Confirm the action without prompting.")
|
335
|
+
return option(*param_decls, **kwargs)
|
336
|
+
|
337
|
+
|
338
|
+
def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]:
|
339
|
+
"""Add a ``--password`` option which prompts for a password, hiding
|
340
|
+
input and asking to enter the value again for confirmation.
|
341
|
+
|
342
|
+
:param param_decls: One or more option names. Defaults to the single
|
343
|
+
value ``"--password"``.
|
344
|
+
:param kwargs: Extra arguments are passed to :func:`option`.
|
345
|
+
"""
|
346
|
+
if not param_decls:
|
347
|
+
param_decls = ("--password",)
|
348
|
+
|
349
|
+
kwargs.setdefault("prompt", True)
|
350
|
+
kwargs.setdefault("confirmation_prompt", True)
|
351
|
+
kwargs.setdefault("hide_input", True)
|
352
|
+
return option(*param_decls, **kwargs)
|
353
|
+
|
354
|
+
|
355
|
+
def version_option(
|
356
|
+
version: t.Optional[str] = None,
|
357
|
+
*param_decls: str,
|
358
|
+
package_name: t.Optional[str] = None,
|
359
|
+
prog_name: t.Optional[str] = None,
|
360
|
+
message: t.Optional[str] = None,
|
361
|
+
**kwargs: t.Any,
|
362
|
+
) -> t.Callable[[FC], FC]:
|
363
|
+
"""Add a ``--version`` option which immediately prints the version
|
364
|
+
number and exits the program.
|
365
|
+
|
366
|
+
If ``version`` is not provided, Click will try to detect it using
|
367
|
+
:func:`importlib.metadata.version` to get the version for the
|
368
|
+
``package_name``. On Python < 3.8, the ``importlib_metadata``
|
369
|
+
backport must be installed.
|
370
|
+
|
371
|
+
If ``package_name`` is not provided, Click will try to detect it by
|
372
|
+
inspecting the stack frames. This will be used to detect the
|
373
|
+
version, so it must match the name of the installed package.
|
374
|
+
|
375
|
+
:param version: The version number to show. If not provided, Click
|
376
|
+
will try to detect it.
|
377
|
+
:param param_decls: One or more option names. Defaults to the single
|
378
|
+
value ``"--version"``.
|
379
|
+
:param package_name: The package name to detect the version from. If
|
380
|
+
not provided, Click will try to detect it.
|
381
|
+
:param prog_name: The name of the CLI to show in the message. If not
|
382
|
+
provided, it will be detected from the command.
|
383
|
+
:param message: The message to show. The values ``%(prog)s``,
|
384
|
+
``%(package)s``, and ``%(version)s`` are available. Defaults to
|
385
|
+
``"%(prog)s, version %(version)s"``.
|
386
|
+
:param kwargs: Extra arguments are passed to :func:`option`.
|
387
|
+
:raise RuntimeError: ``version`` could not be detected.
|
388
|
+
|
389
|
+
.. versionchanged:: 8.0
|
390
|
+
Add the ``package_name`` parameter, and the ``%(package)s``
|
391
|
+
value for messages.
|
392
|
+
|
393
|
+
.. versionchanged:: 8.0
|
394
|
+
Use :mod:`importlib.metadata` instead of ``pkg_resources``. The
|
395
|
+
version is detected based on the package name, not the entry
|
396
|
+
point name. The Python package name must match the installed
|
397
|
+
package name, or be passed with ``package_name=``.
|
398
|
+
"""
|
399
|
+
if message is None:
|
400
|
+
message = _("%(prog)s, version %(version)s")
|
401
|
+
|
402
|
+
if version is None and package_name is None:
|
403
|
+
frame = inspect.currentframe()
|
404
|
+
f_back = frame.f_back if frame is not None else None
|
405
|
+
f_globals = f_back.f_globals if f_back is not None else None
|
406
|
+
# break reference cycle
|
407
|
+
# https://docs.python.org/3/library/inspect.html#the-interpreter-stack
|
408
|
+
del frame
|
409
|
+
|
410
|
+
if f_globals is not None:
|
411
|
+
package_name = f_globals.get("__name__")
|
412
|
+
|
413
|
+
if package_name == "__main__":
|
414
|
+
package_name = f_globals.get("__package__")
|
415
|
+
|
416
|
+
if package_name:
|
417
|
+
package_name = package_name.partition(".")[0]
|
418
|
+
|
419
|
+
def callback(ctx: Context, param: Parameter, value: bool) -> None:
|
420
|
+
if not value or ctx.resilient_parsing:
|
421
|
+
return
|
422
|
+
|
423
|
+
nonlocal prog_name
|
424
|
+
nonlocal version
|
425
|
+
|
426
|
+
if prog_name is None:
|
427
|
+
prog_name = ctx.find_root().info_name
|
428
|
+
|
429
|
+
if version is None and package_name is not None:
|
430
|
+
metadata: t.Optional[types.ModuleType]
|
431
|
+
|
432
|
+
try:
|
433
|
+
from importlib import metadata # type: ignore
|
434
|
+
except ImportError:
|
435
|
+
# Python < 3.8
|
436
|
+
import importlib_metadata as metadata # type: ignore
|
437
|
+
|
438
|
+
try:
|
439
|
+
version = metadata.version(package_name) # type: ignore
|
440
|
+
except metadata.PackageNotFoundError: # type: ignore
|
441
|
+
raise RuntimeError(
|
442
|
+
f"{package_name!r} is not installed. Try passing"
|
443
|
+
" 'package_name' instead."
|
444
|
+
) from None
|
445
|
+
|
446
|
+
if version is None:
|
447
|
+
raise RuntimeError(
|
448
|
+
f"Could not determine the version for {package_name!r} automatically."
|
449
|
+
)
|
450
|
+
|
451
|
+
echo(
|
452
|
+
t.cast(str, message)
|
453
|
+
% {"prog": prog_name, "package": package_name, "version": version},
|
454
|
+
color=ctx.color,
|
455
|
+
)
|
456
|
+
ctx.exit()
|
457
|
+
|
458
|
+
if not param_decls:
|
459
|
+
param_decls = ("--version",)
|
460
|
+
|
461
|
+
kwargs.setdefault("is_flag", True)
|
462
|
+
kwargs.setdefault("expose_value", False)
|
463
|
+
kwargs.setdefault("is_eager", True)
|
464
|
+
kwargs.setdefault("help", _("Show the version and exit."))
|
465
|
+
kwargs["callback"] = callback
|
466
|
+
return option(*param_decls, **kwargs)
|
467
|
+
|
468
|
+
|
469
|
+
def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]:
|
470
|
+
"""Add a ``--help`` option which immediately prints the help page
|
471
|
+
and exits the program.
|
472
|
+
|
473
|
+
This is usually unnecessary, as the ``--help`` option is added to
|
474
|
+
each command automatically unless ``add_help_option=False`` is
|
475
|
+
passed.
|
476
|
+
|
477
|
+
:param param_decls: One or more option names. Defaults to the single
|
478
|
+
value ``"--help"``.
|
479
|
+
:param kwargs: Extra arguments are passed to :func:`option`.
|
480
|
+
"""
|
481
|
+
|
482
|
+
def callback(ctx: Context, param: Parameter, value: bool) -> None:
|
483
|
+
if not value or ctx.resilient_parsing:
|
484
|
+
return
|
485
|
+
|
486
|
+
echo(ctx.get_help(), color=ctx.color)
|
487
|
+
ctx.exit()
|
488
|
+
|
489
|
+
if not param_decls:
|
490
|
+
param_decls = ("--help",)
|
491
|
+
|
492
|
+
kwargs.setdefault("is_flag", True)
|
493
|
+
kwargs.setdefault("expose_value", False)
|
494
|
+
kwargs.setdefault("is_eager", True)
|
495
|
+
kwargs.setdefault("help", _("Show this message and exit."))
|
496
|
+
kwargs["callback"] = callback
|
497
|
+
return option(*param_decls, **kwargs)
|