1import inspect 2import sys 3from functools import update_wrapper 4 5from ._compat import iteritems 6from ._unicodefun import _check_for_unicode_literals 7from .core import Argument 8from .core import Command 9from .core import Group 10from .core import Option 11from .globals import get_current_context 12from .utils import echo 13 14 15def 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 26def 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 38def 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 80def _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 106def 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 137def 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 146def _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 155def 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 174def 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 198def 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 231def 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 253def 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 309def 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 334