comparison env/lib/python3.9/site-packages/click/decorators.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import inspect
2 import sys
3 from functools import update_wrapper
4
5 from ._compat import iteritems
6 from ._unicodefun import _check_for_unicode_literals
7 from .core import Argument
8 from .core import Command
9 from .core import Group
10 from .core import Option
11 from .globals import get_current_context
12 from .utils import echo
13
14
15 def pass_context(f):
16 """Marks a callback as wanting to receive the current context
17 object as first argument.
18 """
19
20 def new_func(*args, **kwargs):
21 return f(get_current_context(), *args, **kwargs)
22
23 return update_wrapper(new_func, f)
24
25
26 def pass_obj(f):
27 """Similar to :func:`pass_context`, but only pass the object on the
28 context onwards (:attr:`Context.obj`). This is useful if that object
29 represents the state of a nested system.
30 """
31
32 def new_func(*args, **kwargs):
33 return f(get_current_context().obj, *args, **kwargs)
34
35 return update_wrapper(new_func, f)
36
37
38 def make_pass_decorator(object_type, ensure=False):
39 """Given an object type this creates a decorator that will work
40 similar to :func:`pass_obj` but instead of passing the object of the
41 current context, it will find the innermost context of type
42 :func:`object_type`.
43
44 This generates a decorator that works roughly like this::
45
46 from functools import update_wrapper
47
48 def decorator(f):
49 @pass_context
50 def new_func(ctx, *args, **kwargs):
51 obj = ctx.find_object(object_type)
52 return ctx.invoke(f, obj, *args, **kwargs)
53 return update_wrapper(new_func, f)
54 return decorator
55
56 :param object_type: the type of the object to pass.
57 :param ensure: if set to `True`, a new object will be created and
58 remembered on the context if it's not there yet.
59 """
60
61 def decorator(f):
62 def new_func(*args, **kwargs):
63 ctx = get_current_context()
64 if ensure:
65 obj = ctx.ensure_object(object_type)
66 else:
67 obj = ctx.find_object(object_type)
68 if obj is None:
69 raise RuntimeError(
70 "Managed to invoke callback without a context"
71 " object of type '{}' existing".format(object_type.__name__)
72 )
73 return ctx.invoke(f, obj, *args, **kwargs)
74
75 return update_wrapper(new_func, f)
76
77 return decorator
78
79
80 def _make_command(f, name, attrs, cls):
81 if isinstance(f, Command):
82 raise TypeError("Attempted to convert a callback into a command twice.")
83 try:
84 params = f.__click_params__
85 params.reverse()
86 del f.__click_params__
87 except AttributeError:
88 params = []
89 help = attrs.get("help")
90 if help is None:
91 help = inspect.getdoc(f)
92 if isinstance(help, bytes):
93 help = help.decode("utf-8")
94 else:
95 help = inspect.cleandoc(help)
96 attrs["help"] = help
97 _check_for_unicode_literals()
98 return cls(
99 name=name or f.__name__.lower().replace("_", "-"),
100 callback=f,
101 params=params,
102 **attrs
103 )
104
105
106 def command(name=None, cls=None, **attrs):
107 r"""Creates a new :class:`Command` and uses the decorated function as
108 callback. This will also automatically attach all decorated
109 :func:`option`\s and :func:`argument`\s as parameters to the command.
110
111 The name of the command defaults to the name of the function with
112 underscores replaced by dashes. If you want to change that, you can
113 pass the intended name as the first argument.
114
115 All keyword arguments are forwarded to the underlying command class.
116
117 Once decorated the function turns into a :class:`Command` instance
118 that can be invoked as a command line utility or be attached to a
119 command :class:`Group`.
120
121 :param name: the name of the command. This defaults to the function
122 name with underscores replaced by dashes.
123 :param cls: the command class to instantiate. This defaults to
124 :class:`Command`.
125 """
126 if cls is None:
127 cls = Command
128
129 def decorator(f):
130 cmd = _make_command(f, name, attrs, cls)
131 cmd.__doc__ = f.__doc__
132 return cmd
133
134 return decorator
135
136
137 def group(name=None, **attrs):
138 """Creates a new :class:`Group` with a function as callback. This
139 works otherwise the same as :func:`command` just that the `cls`
140 parameter is set to :class:`Group`.
141 """
142 attrs.setdefault("cls", Group)
143 return command(name, **attrs)
144
145
146 def _param_memo(f, param):
147 if isinstance(f, Command):
148 f.params.append(param)
149 else:
150 if not hasattr(f, "__click_params__"):
151 f.__click_params__ = []
152 f.__click_params__.append(param)
153
154
155 def argument(*param_decls, **attrs):
156 """Attaches an argument to the command. All positional arguments are
157 passed as parameter declarations to :class:`Argument`; all keyword
158 arguments are forwarded unchanged (except ``cls``).
159 This is equivalent to creating an :class:`Argument` instance manually
160 and attaching it to the :attr:`Command.params` list.
161
162 :param cls: the argument class to instantiate. This defaults to
163 :class:`Argument`.
164 """
165
166 def decorator(f):
167 ArgumentClass = attrs.pop("cls", Argument)
168 _param_memo(f, ArgumentClass(param_decls, **attrs))
169 return f
170
171 return decorator
172
173
174 def option(*param_decls, **attrs):
175 """Attaches an option to the command. All positional arguments are
176 passed as parameter declarations to :class:`Option`; all keyword
177 arguments are forwarded unchanged (except ``cls``).
178 This is equivalent to creating an :class:`Option` instance manually
179 and attaching it to the :attr:`Command.params` list.
180
181 :param cls: the option class to instantiate. This defaults to
182 :class:`Option`.
183 """
184
185 def decorator(f):
186 # Issue 926, copy attrs, so pre-defined options can re-use the same cls=
187 option_attrs = attrs.copy()
188
189 if "help" in option_attrs:
190 option_attrs["help"] = inspect.cleandoc(option_attrs["help"])
191 OptionClass = option_attrs.pop("cls", Option)
192 _param_memo(f, OptionClass(param_decls, **option_attrs))
193 return f
194
195 return decorator
196
197
198 def confirmation_option(*param_decls, **attrs):
199 """Shortcut for confirmation prompts that can be ignored by passing
200 ``--yes`` as parameter.
201
202 This is equivalent to decorating a function with :func:`option` with
203 the following parameters::
204
205 def callback(ctx, param, value):
206 if not value:
207 ctx.abort()
208
209 @click.command()
210 @click.option('--yes', is_flag=True, callback=callback,
211 expose_value=False, prompt='Do you want to continue?')
212 def dropdb():
213 pass
214 """
215
216 def decorator(f):
217 def callback(ctx, param, value):
218 if not value:
219 ctx.abort()
220
221 attrs.setdefault("is_flag", True)
222 attrs.setdefault("callback", callback)
223 attrs.setdefault("expose_value", False)
224 attrs.setdefault("prompt", "Do you want to continue?")
225 attrs.setdefault("help", "Confirm the action without prompting.")
226 return option(*(param_decls or ("--yes",)), **attrs)(f)
227
228 return decorator
229
230
231 def password_option(*param_decls, **attrs):
232 """Shortcut for password prompts.
233
234 This is equivalent to decorating a function with :func:`option` with
235 the following parameters::
236
237 @click.command()
238 @click.option('--password', prompt=True, confirmation_prompt=True,
239 hide_input=True)
240 def changeadmin(password):
241 pass
242 """
243
244 def decorator(f):
245 attrs.setdefault("prompt", True)
246 attrs.setdefault("confirmation_prompt", True)
247 attrs.setdefault("hide_input", True)
248 return option(*(param_decls or ("--password",)), **attrs)(f)
249
250 return decorator
251
252
253 def version_option(version=None, *param_decls, **attrs):
254 """Adds a ``--version`` option which immediately ends the program
255 printing out the version number. This is implemented as an eager
256 option that prints the version and exits the program in the callback.
257
258 :param version: the version number to show. If not provided Click
259 attempts an auto discovery via setuptools.
260 :param prog_name: the name of the program (defaults to autodetection)
261 :param message: custom message to show instead of the default
262 (``'%(prog)s, version %(version)s'``)
263 :param others: everything else is forwarded to :func:`option`.
264 """
265 if version is None:
266 if hasattr(sys, "_getframe"):
267 module = sys._getframe(1).f_globals.get("__name__")
268 else:
269 module = ""
270
271 def decorator(f):
272 prog_name = attrs.pop("prog_name", None)
273 message = attrs.pop("message", "%(prog)s, version %(version)s")
274
275 def callback(ctx, param, value):
276 if not value or ctx.resilient_parsing:
277 return
278 prog = prog_name
279 if prog is None:
280 prog = ctx.find_root().info_name
281 ver = version
282 if ver is None:
283 try:
284 import pkg_resources
285 except ImportError:
286 pass
287 else:
288 for dist in pkg_resources.working_set:
289 scripts = dist.get_entry_map().get("console_scripts") or {}
290 for _, entry_point in iteritems(scripts):
291 if entry_point.module_name == module:
292 ver = dist.version
293 break
294 if ver is None:
295 raise RuntimeError("Could not determine version")
296 echo(message % {"prog": prog, "version": ver}, color=ctx.color)
297 ctx.exit()
298
299 attrs.setdefault("is_flag", True)
300 attrs.setdefault("expose_value", False)
301 attrs.setdefault("is_eager", True)
302 attrs.setdefault("help", "Show the version and exit.")
303 attrs["callback"] = callback
304 return option(*(param_decls or ("--version",)), **attrs)(f)
305
306 return decorator
307
308
309 def help_option(*param_decls, **attrs):
310 """Adds a ``--help`` option which immediately ends the program
311 printing out the help page. This is usually unnecessary to add as
312 this is added by default to all commands unless suppressed.
313
314 Like :func:`version_option`, this is implemented as eager option that
315 prints in the callback and exits.
316
317 All arguments are forwarded to :func:`option`.
318 """
319
320 def decorator(f):
321 def callback(ctx, param, value):
322 if value and not ctx.resilient_parsing:
323 echo(ctx.get_help(), color=ctx.color)
324 ctx.exit()
325
326 attrs.setdefault("is_flag", True)
327 attrs.setdefault("expose_value", False)
328 attrs.setdefault("help", "Show this message and exit.")
329 attrs.setdefault("is_eager", True)
330 attrs["callback"] = callback
331 return option(*(param_decls or ("--help",)), **attrs)(f)
332
333 return decorator