12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856 |
- import errno
- import inspect
- import os
- import sys
- from contextlib import contextmanager
- from itertools import repeat
- from functools import update_wrapper
- from .types import convert_type, IntRange, BOOL
- from .utils import PacifyFlushWrapper, make_str, make_default_short_help, \
- echo, get_os_args
- from .exceptions import ClickException, UsageError, BadParameter, Abort, \
- MissingParameter, Exit
- from .termui import prompt, confirm, style
- from .formatting import HelpFormatter, join_options
- from .parser import OptionParser, split_opt
- from .globals import push_context, pop_context
- from ._compat import PY2, isidentifier, iteritems, string_types
- from ._unicodefun import _check_for_unicode_literals, _verify_python3_env
- _missing = object()
- SUBCOMMAND_METAVAR = 'COMMAND [ARGS]...'
- SUBCOMMANDS_METAVAR = 'COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...'
- DEPRECATED_HELP_NOTICE = ' (DEPRECATED)'
- DEPRECATED_INVOKE_NOTICE = 'DeprecationWarning: ' + \
- 'The command %(name)s is deprecated.'
- def _maybe_show_deprecated_notice(cmd):
- if cmd.deprecated:
- echo(style(DEPRECATED_INVOKE_NOTICE % {'name': cmd.name}, fg='red'), err=True)
- def fast_exit(code):
- """Exit without garbage collection, this speeds up exit by about 10ms for
- things like bash completion.
- """
- sys.stdout.flush()
- sys.stderr.flush()
- os._exit(code)
- def _bashcomplete(cmd, prog_name, complete_var=None):
- """Internal handler for the bash completion support."""
- if complete_var is None:
- complete_var = '_%s_COMPLETE' % (prog_name.replace('-', '_')).upper()
- complete_instr = os.environ.get(complete_var)
- if not complete_instr:
- return
- from ._bashcomplete import bashcomplete
- if bashcomplete(cmd, prog_name, complete_var, complete_instr):
- fast_exit(1)
- def _check_multicommand(base_command, cmd_name, cmd, register=False):
- if not base_command.chain or not isinstance(cmd, MultiCommand):
- return
- if register:
- hint = 'It is not possible to add multi commands as children to ' \
- 'another multi command that is in chain mode'
- else:
- hint = 'Found a multi command as subcommand to a multi command ' \
- 'that is in chain mode. This is not supported'
- raise RuntimeError('%s. Command "%s" is set to chain and "%s" was '
- 'added as subcommand but it in itself is a '
- 'multi command. ("%s" is a %s within a chained '
- '%s named "%s").' % (
- hint, base_command.name, cmd_name,
- cmd_name, cmd.__class__.__name__,
- base_command.__class__.__name__,
- base_command.name))
- def batch(iterable, batch_size):
- return list(zip(*repeat(iter(iterable), batch_size)))
- def invoke_param_callback(callback, ctx, param, value):
- code = getattr(callback, '__code__', None)
- args = getattr(code, 'co_argcount', 3)
- if args < 3:
- # This will become a warning in Click 3.0:
- from warnings import warn
- warn(Warning('Invoked legacy parameter callback "%s". The new '
- 'signature for such callbacks starting with '
- 'click 2.0 is (ctx, param, value).'
- % callback), stacklevel=3)
- return callback(ctx, value)
- return callback(ctx, param, value)
- @contextmanager
- def augment_usage_errors(ctx, param=None):
- """Context manager that attaches extra information to exceptions that
- fly.
- """
- try:
- yield
- except BadParameter as e:
- if e.ctx is None:
- e.ctx = ctx
- if param is not None and e.param is None:
- e.param = param
- raise
- except UsageError as e:
- if e.ctx is None:
- e.ctx = ctx
- raise
- def iter_params_for_processing(invocation_order, declaration_order):
- """Given a sequence of parameters in the order as should be considered
- for processing and an iterable of parameters that exist, this returns
- a list in the correct order as they should be processed.
- """
- def sort_key(item):
- try:
- idx = invocation_order.index(item)
- except ValueError:
- idx = float('inf')
- return (not item.is_eager, idx)
- return sorted(declaration_order, key=sort_key)
- class Context(object):
- """The context is a special internal object that holds state relevant
- for the script execution at every single level. It's normally invisible
- to commands unless they opt-in to getting access to it.
- The context is useful as it can pass internal objects around and can
- control special execution features such as reading data from
- environment variables.
- A context can be used as context manager in which case it will call
- :meth:`close` on teardown.
- .. versionadded:: 2.0
- Added the `resilient_parsing`, `help_option_names`,
- `token_normalize_func` parameters.
- .. versionadded:: 3.0
- Added the `allow_extra_args` and `allow_interspersed_args`
- parameters.
- .. versionadded:: 4.0
- Added the `color`, `ignore_unknown_options`, and
- `max_content_width` parameters.
- :param command: the command class for this context.
- :param parent: the parent context.
- :param info_name: the info name for this invocation. Generally this
- is the most descriptive name for the script or
- command. For the toplevel script it is usually
- the name of the script, for commands below it it's
- the name of the script.
- :param obj: an arbitrary object of user data.
- :param auto_envvar_prefix: the prefix to use for automatic environment
- variables. If this is `None` then reading
- from environment variables is disabled. This
- does not affect manually set environment
- variables which are always read.
- :param default_map: a dictionary (like object) with default values
- for parameters.
- :param terminal_width: the width of the terminal. The default is
- inherit from parent context. If no context
- defines the terminal width then auto
- detection will be applied.
- :param max_content_width: the maximum width for content rendered by
- Click (this currently only affects help
- pages). This defaults to 80 characters if
- not overridden. In other words: even if the
- terminal is larger than that, Click will not
- format things wider than 80 characters by
- default. In addition to that, formatters might
- add some safety mapping on the right.
- :param resilient_parsing: if this flag is enabled then Click will
- parse without any interactivity or callback
- invocation. Default values will also be
- ignored. This is useful for implementing
- things such as completion support.
- :param allow_extra_args: if this is set to `True` then extra arguments
- at the end will not raise an error and will be
- kept on the context. The default is to inherit
- from the command.
- :param allow_interspersed_args: if this is set to `False` then options
- and arguments cannot be mixed. The
- default is to inherit from the command.
- :param ignore_unknown_options: instructs click to ignore options it does
- not know and keeps them for later
- processing.
- :param help_option_names: optionally a list of strings that define how
- the default help parameter is named. The
- default is ``['--help']``.
- :param token_normalize_func: an optional function that is used to
- normalize tokens (options, choices,
- etc.). This for instance can be used to
- implement case insensitive behavior.
- :param color: controls if the terminal supports ANSI colors or not. The
- default is autodetection. This is only needed if ANSI
- codes are used in texts that Click prints which is by
- default not the case. This for instance would affect
- help output.
- """
- def __init__(self, command, parent=None, info_name=None, obj=None,
- auto_envvar_prefix=None, default_map=None,
- terminal_width=None, max_content_width=None,
- resilient_parsing=False, allow_extra_args=None,
- allow_interspersed_args=None,
- ignore_unknown_options=None, help_option_names=None,
- token_normalize_func=None, color=None):
- #: the parent context or `None` if none exists.
- self.parent = parent
- #: the :class:`Command` for this context.
- self.command = command
- #: the descriptive information name
- self.info_name = info_name
- #: the parsed parameters except if the value is hidden in which
- #: case it's not remembered.
- self.params = {}
- #: the leftover arguments.
- self.args = []
- #: protected arguments. These are arguments that are prepended
- #: to `args` when certain parsing scenarios are encountered but
- #: must be never propagated to another arguments. This is used
- #: to implement nested parsing.
- self.protected_args = []
- if obj is None and parent is not None:
- obj = parent.obj
- #: the user object stored.
- self.obj = obj
- self._meta = getattr(parent, 'meta', {})
- #: A dictionary (-like object) with defaults for parameters.
- if default_map is None \
- and parent is not None \
- and parent.default_map is not None:
- default_map = parent.default_map.get(info_name)
- self.default_map = default_map
- #: This flag indicates if a subcommand is going to be executed. A
- #: group callback can use this information to figure out if it's
- #: being executed directly or because the execution flow passes
- #: onwards to a subcommand. By default it's None, but it can be
- #: the name of the subcommand to execute.
- #:
- #: If chaining is enabled this will be set to ``'*'`` in case
- #: any commands are executed. It is however not possible to
- #: figure out which ones. If you require this knowledge you
- #: should use a :func:`resultcallback`.
- self.invoked_subcommand = None
- if terminal_width is None and parent is not None:
- terminal_width = parent.terminal_width
- #: The width of the terminal (None is autodetection).
- self.terminal_width = terminal_width
- if max_content_width is None and parent is not None:
- max_content_width = parent.max_content_width
- #: The maximum width of formatted content (None implies a sensible
- #: default which is 80 for most things).
- self.max_content_width = max_content_width
- if allow_extra_args is None:
- allow_extra_args = command.allow_extra_args
- #: Indicates if the context allows extra args or if it should
- #: fail on parsing.
- #:
- #: .. versionadded:: 3.0
- self.allow_extra_args = allow_extra_args
- if allow_interspersed_args is None:
- allow_interspersed_args = command.allow_interspersed_args
- #: Indicates if the context allows mixing of arguments and
- #: options or not.
- #:
- #: .. versionadded:: 3.0
- self.allow_interspersed_args = allow_interspersed_args
- if ignore_unknown_options is None:
- ignore_unknown_options = command.ignore_unknown_options
- #: Instructs click to ignore options that a command does not
- #: understand and will store it on the context for later
- #: processing. This is primarily useful for situations where you
- #: want to call into external programs. Generally this pattern is
- #: strongly discouraged because it's not possibly to losslessly
- #: forward all arguments.
- #:
- #: .. versionadded:: 4.0
- self.ignore_unknown_options = ignore_unknown_options
- if help_option_names is None:
- if parent is not None:
- help_option_names = parent.help_option_names
- else:
- help_option_names = ['--help']
- #: The names for the help options.
- self.help_option_names = help_option_names
- if token_normalize_func is None and parent is not None:
- token_normalize_func = parent.token_normalize_func
- #: An optional normalization function for tokens. This is
- #: options, choices, commands etc.
- self.token_normalize_func = token_normalize_func
- #: Indicates if resilient parsing is enabled. In that case Click
- #: will do its best to not cause any failures and default values
- #: will be ignored. Useful for completion.
- self.resilient_parsing = resilient_parsing
- # If there is no envvar prefix yet, but the parent has one and
- # the command on this level has a name, we can expand the envvar
- # prefix automatically.
- if auto_envvar_prefix is None:
- if parent is not None \
- and parent.auto_envvar_prefix is not None and \
- self.info_name is not None:
- auto_envvar_prefix = '%s_%s' % (parent.auto_envvar_prefix,
- self.info_name.upper())
- else:
- auto_envvar_prefix = auto_envvar_prefix.upper()
- self.auto_envvar_prefix = auto_envvar_prefix
- if color is None and parent is not None:
- color = parent.color
- #: Controls if styling output is wanted or not.
- self.color = color
- self._close_callbacks = []
- self._depth = 0
- def __enter__(self):
- self._depth += 1
- push_context(self)
- return self
- def __exit__(self, exc_type, exc_value, tb):
- self._depth -= 1
- if self._depth == 0:
- self.close()
- pop_context()
- @contextmanager
- def scope(self, cleanup=True):
- """This helper method can be used with the context object to promote
- it to the current thread local (see :func:`get_current_context`).
- The default behavior of this is to invoke the cleanup functions which
- can be disabled by setting `cleanup` to `False`. The cleanup
- functions are typically used for things such as closing file handles.
- If the cleanup is intended the context object can also be directly
- used as a context manager.
- Example usage::
- with ctx.scope():
- assert get_current_context() is ctx
- This is equivalent::
- with ctx:
- assert get_current_context() is ctx
- .. versionadded:: 5.0
- :param cleanup: controls if the cleanup functions should be run or
- not. The default is to run these functions. In
- some situations the context only wants to be
- temporarily pushed in which case this can be disabled.
- Nested pushes automatically defer the cleanup.
- """
- if not cleanup:
- self._depth += 1
- try:
- with self as rv:
- yield rv
- finally:
- if not cleanup:
- self._depth -= 1
- @property
- def meta(self):
- """This is a dictionary which is shared with all the contexts
- that are nested. It exists so that click utilities can store some
- state here if they need to. It is however the responsibility of
- that code to manage this dictionary well.
- The keys are supposed to be unique dotted strings. For instance
- module paths are a good choice for it. What is stored in there is
- irrelevant for the operation of click. However what is important is
- that code that places data here adheres to the general semantics of
- the system.
- Example usage::
- LANG_KEY = __name__ + '.lang'
- def set_language(value):
- ctx = get_current_context()
- ctx.meta[LANG_KEY] = value
- def get_language():
- return get_current_context().meta.get(LANG_KEY, 'en_US')
- .. versionadded:: 5.0
- """
- return self._meta
- def make_formatter(self):
- """Creates the formatter for the help and usage output."""
- return HelpFormatter(width=self.terminal_width,
- max_width=self.max_content_width)
- def call_on_close(self, f):
- """This decorator remembers a function as callback that should be
- executed when the context tears down. This is most useful to bind
- resource handling to the script execution. For instance, file objects
- opened by the :class:`File` type will register their close callbacks
- here.
- :param f: the function to execute on teardown.
- """
- self._close_callbacks.append(f)
- return f
- def close(self):
- """Invokes all close callbacks."""
- for cb in self._close_callbacks:
- cb()
- self._close_callbacks = []
- @property
- def command_path(self):
- """The computed command path. This is used for the ``usage``
- information on the help page. It's automatically created by
- combining the info names of the chain of contexts to the root.
- """
- rv = ''
- if self.info_name is not None:
- rv = self.info_name
- if self.parent is not None:
- rv = self.parent.command_path + ' ' + rv
- return rv.lstrip()
- def find_root(self):
- """Finds the outermost context."""
- node = self
- while node.parent is not None:
- node = node.parent
- return node
- def find_object(self, object_type):
- """Finds the closest object of a given type."""
- node = self
- while node is not None:
- if isinstance(node.obj, object_type):
- return node.obj
- node = node.parent
- def ensure_object(self, object_type):
- """Like :meth:`find_object` but sets the innermost object to a
- new instance of `object_type` if it does not exist.
- """
- rv = self.find_object(object_type)
- if rv is None:
- self.obj = rv = object_type()
- return rv
- def lookup_default(self, name):
- """Looks up the default for a parameter name. This by default
- looks into the :attr:`default_map` if available.
- """
- if self.default_map is not None:
- rv = self.default_map.get(name)
- if callable(rv):
- rv = rv()
- return rv
- def fail(self, message):
- """Aborts the execution of the program with a specific error
- message.
- :param message: the error message to fail with.
- """
- raise UsageError(message, self)
- def abort(self):
- """Aborts the script."""
- raise Abort()
- def exit(self, code=0):
- """Exits the application with a given exit code."""
- raise Exit(code)
- def get_usage(self):
- """Helper method to get formatted usage string for the current
- context and command.
- """
- return self.command.get_usage(self)
- def get_help(self):
- """Helper method to get formatted help page for the current
- context and command.
- """
- return self.command.get_help(self)
- def invoke(*args, **kwargs):
- """Invokes a command callback in exactly the way it expects. There
- are two ways to invoke this method:
- 1. the first argument can be a callback and all other arguments and
- keyword arguments are forwarded directly to the function.
- 2. the first argument is a click command object. In that case all
- arguments are forwarded as well but proper click parameters
- (options and click arguments) must be keyword arguments and Click
- will fill in defaults.
- Note that before Click 3.2 keyword arguments were not properly filled
- in against the intention of this code and no context was created. For
- more information about this change and why it was done in a bugfix
- release see :ref:`upgrade-to-3.2`.
- """
- self, callback = args[:2]
- ctx = self
- # It's also possible to invoke another command which might or
- # might not have a callback. In that case we also fill
- # in defaults and make a new context for this command.
- if isinstance(callback, Command):
- other_cmd = callback
- callback = other_cmd.callback
- ctx = Context(other_cmd, info_name=other_cmd.name, parent=self)
- if callback is None:
- raise TypeError('The given command does not have a '
- 'callback that can be invoked.')
- for param in other_cmd.params:
- if param.name not in kwargs and param.expose_value:
- kwargs[param.name] = param.get_default(ctx)
- args = args[2:]
- with augment_usage_errors(self):
- with ctx:
- return callback(*args, **kwargs)
- def forward(*args, **kwargs):
- """Similar to :meth:`invoke` but fills in default keyword
- arguments from the current context if the other command expects
- it. This cannot invoke callbacks directly, only other commands.
- """
- self, cmd = args[:2]
- # It's also possible to invoke another command which might or
- # might not have a callback.
- if not isinstance(cmd, Command):
- raise TypeError('Callback is not a command.')
- for param in self.params:
- if param not in kwargs:
- kwargs[param] = self.params[param]
- return self.invoke(cmd, **kwargs)
- class BaseCommand(object):
- """The base command implements the minimal API contract of commands.
- Most code will never use this as it does not implement a lot of useful
- functionality but it can act as the direct subclass of alternative
- parsing methods that do not depend on the Click parser.
- For instance, this can be used to bridge Click and other systems like
- argparse or docopt.
- Because base commands do not implement a lot of the API that other
- parts of Click take for granted, they are not supported for all
- operations. For instance, they cannot be used with the decorators
- usually and they have no built-in callback system.
- .. versionchanged:: 2.0
- Added the `context_settings` parameter.
- :param name: the name of the command to use unless a group overrides it.
- :param context_settings: an optional dictionary with defaults that are
- passed to the context object.
- """
- #: the default for the :attr:`Context.allow_extra_args` flag.
- allow_extra_args = False
- #: the default for the :attr:`Context.allow_interspersed_args` flag.
- allow_interspersed_args = True
- #: the default for the :attr:`Context.ignore_unknown_options` flag.
- ignore_unknown_options = False
- def __init__(self, name, context_settings=None):
- #: the name the command thinks it has. Upon registering a command
- #: on a :class:`Group` the group will default the command name
- #: with this information. You should instead use the
- #: :class:`Context`\'s :attr:`~Context.info_name` attribute.
- self.name = name
- if context_settings is None:
- context_settings = {}
- #: an optional dictionary with defaults passed to the context.
- self.context_settings = context_settings
- def get_usage(self, ctx):
- raise NotImplementedError('Base commands cannot get usage')
- def get_help(self, ctx):
- raise NotImplementedError('Base commands cannot get help')
- def make_context(self, info_name, args, parent=None, **extra):
- """This function when given an info name and arguments will kick
- off the parsing and create a new :class:`Context`. It does not
- invoke the actual command callback though.
- :param info_name: the info name for this invokation. Generally this
- is the most descriptive name for the script or
- command. For the toplevel script it's usually
- the name of the script, for commands below it it's
- the name of the script.
- :param args: the arguments to parse as list of strings.
- :param parent: the parent context if available.
- :param extra: extra keyword arguments forwarded to the context
- constructor.
- """
- for key, value in iteritems(self.context_settings):
- if key not in extra:
- extra[key] = value
- ctx = Context(self, info_name=info_name, parent=parent, **extra)
- with ctx.scope(cleanup=False):
- self.parse_args(ctx, args)
- return ctx
- def parse_args(self, ctx, args):
- """Given a context and a list of arguments this creates the parser
- and parses the arguments, then modifies the context as necessary.
- This is automatically invoked by :meth:`make_context`.
- """
- raise NotImplementedError('Base commands do not know how to parse '
- 'arguments.')
- def invoke(self, ctx):
- """Given a context, this invokes the command. The default
- implementation is raising a not implemented error.
- """
- raise NotImplementedError('Base commands are not invokable by default')
- def main(self, args=None, prog_name=None, complete_var=None,
- standalone_mode=True, **extra):
- """This is the way to invoke a script with all the bells and
- whistles as a command line application. This will always terminate
- the application after a call. If this is not wanted, ``SystemExit``
- needs to be caught.
- This method is also available by directly calling the instance of
- a :class:`Command`.
- .. versionadded:: 3.0
- Added the `standalone_mode` flag to control the standalone mode.
- :param args: the arguments that should be used for parsing. If not
- provided, ``sys.argv[1:]`` is used.
- :param prog_name: the program name that should be used. By default
- the program name is constructed by taking the file
- name from ``sys.argv[0]``.
- :param complete_var: the environment variable that controls the
- bash completion support. The default is
- ``"_<prog_name>_COMPLETE"`` with prog_name in
- uppercase.
- :param standalone_mode: the default behavior is to invoke the script
- in standalone mode. Click will then
- handle exceptions and convert them into
- error messages and the function will never
- return but shut down the interpreter. If
- this is set to `False` they will be
- propagated to the caller and the return
- value of this function is the return value
- of :meth:`invoke`.
- :param extra: extra keyword arguments are forwarded to the context
- constructor. See :class:`Context` for more information.
- """
- # If we are in Python 3, we will verify that the environment is
- # sane at this point or reject further execution to avoid a
- # broken script.
- if not PY2:
- _verify_python3_env()
- else:
- _check_for_unicode_literals()
- if args is None:
- args = get_os_args()
- else:
- args = list(args)
- if prog_name is None:
- prog_name = make_str(os.path.basename(
- sys.argv and sys.argv[0] or __file__))
- # Hook for the Bash completion. This only activates if the Bash
- # completion is actually enabled, otherwise this is quite a fast
- # noop.
- _bashcomplete(self, prog_name, complete_var)
- try:
- try:
- with self.make_context(prog_name, args, **extra) as ctx:
- rv = self.invoke(ctx)
- if not standalone_mode:
- return rv
- # it's not safe to `ctx.exit(rv)` here!
- # note that `rv` may actually contain data like "1" which
- # has obvious effects
- # more subtle case: `rv=[None, None]` can come out of
- # chained commands which all returned `None` -- so it's not
- # even always obvious that `rv` indicates success/failure
- # by its truthiness/falsiness
- ctx.exit()
- except (EOFError, KeyboardInterrupt):
- echo(file=sys.stderr)
- raise Abort()
- except ClickException as e:
- if not standalone_mode:
- raise
- e.show()
- sys.exit(e.exit_code)
- except IOError as e:
- if e.errno == errno.EPIPE:
- sys.stdout = PacifyFlushWrapper(sys.stdout)
- sys.stderr = PacifyFlushWrapper(sys.stderr)
- sys.exit(1)
- else:
- raise
- except Exit as e:
- if standalone_mode:
- sys.exit(e.exit_code)
- else:
- # in non-standalone mode, return the exit code
- # note that this is only reached if `self.invoke` above raises
- # an Exit explicitly -- thus bypassing the check there which
- # would return its result
- # the results of non-standalone execution may therefore be
- # somewhat ambiguous: if there are codepaths which lead to
- # `ctx.exit(1)` and to `return 1`, the caller won't be able to
- # tell the difference between the two
- return e.exit_code
- except Abort:
- if not standalone_mode:
- raise
- echo('Aborted!', file=sys.stderr)
- sys.exit(1)
- def __call__(self, *args, **kwargs):
- """Alias for :meth:`main`."""
- return self.main(*args, **kwargs)
- class Command(BaseCommand):
- """Commands are the basic building block of command line interfaces in
- Click. A basic command handles command line parsing and might dispatch
- more parsing to commands nested below it.
- .. versionchanged:: 2.0
- Added the `context_settings` parameter.
- :param name: the name of the command to use unless a group overrides it.
- :param context_settings: an optional dictionary with defaults that are
- passed to the context object.
- :param callback: the callback to invoke. This is optional.
- :param params: the parameters to register with this command. This can
- be either :class:`Option` or :class:`Argument` objects.
- :param help: the help string to use for this command.
- :param epilog: like the help string but it's printed at the end of the
- help page after everything else.
- :param short_help: the short help to use for this command. This is
- shown on the command listing of the parent command.
- :param add_help_option: by default each command registers a ``--help``
- option. This can be disabled by this parameter.
- :param hidden: hide this command from help outputs.
- :param deprecated: issues a message indicating that
- the command is deprecated.
- """
- def __init__(self, name, context_settings=None, callback=None,
- params=None, help=None, epilog=None, short_help=None,
- options_metavar='[OPTIONS]', add_help_option=True,
- hidden=False, deprecated=False):
- BaseCommand.__init__(self, name, context_settings)
- #: the callback to execute when the command fires. This might be
- #: `None` in which case nothing happens.
- self.callback = callback
- #: the list of parameters for this command in the order they
- #: should show up in the help page and execute. Eager parameters
- #: will automatically be handled before non eager ones.
- self.params = params or []
- # if a form feed (page break) is found in the help text, truncate help
- # text to the content preceding the first form feed
- if help and '\f' in help:
- help = help.split('\f', 1)[0]
- self.help = help
- self.epilog = epilog
- self.options_metavar = options_metavar
- self.short_help = short_help
- self.add_help_option = add_help_option
- self.hidden = hidden
- self.deprecated = deprecated
- def get_usage(self, ctx):
- formatter = ctx.make_formatter()
- self.format_usage(ctx, formatter)
- return formatter.getvalue().rstrip('\n')
- def get_params(self, ctx):
- rv = self.params
- help_option = self.get_help_option(ctx)
- if help_option is not None:
- rv = rv + [help_option]
- return rv
- def format_usage(self, ctx, formatter):
- """Writes the usage line into the formatter."""
- pieces = self.collect_usage_pieces(ctx)
- formatter.write_usage(ctx.command_path, ' '.join(pieces))
- def collect_usage_pieces(self, ctx):
- """Returns all the pieces that go into the usage line and returns
- it as a list of strings.
- """
- rv = [self.options_metavar]
- for param in self.get_params(ctx):
- rv.extend(param.get_usage_pieces(ctx))
- return rv
- def get_help_option_names(self, ctx):
- """Returns the names for the help option."""
- all_names = set(ctx.help_option_names)
- for param in self.params:
- all_names.difference_update(param.opts)
- all_names.difference_update(param.secondary_opts)
- return all_names
- def get_help_option(self, ctx):
- """Returns the help option object."""
- help_options = self.get_help_option_names(ctx)
- if not help_options or not self.add_help_option:
- return
- def show_help(ctx, param, value):
- if value and not ctx.resilient_parsing:
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
- return Option(help_options, is_flag=True,
- is_eager=True, expose_value=False,
- callback=show_help,
- help='Show this message and exit.')
- def make_parser(self, ctx):
- """Creates the underlying option parser for this command."""
- parser = OptionParser(ctx)
- for param in self.get_params(ctx):
- param.add_to_parser(parser, ctx)
- return parser
- def get_help(self, ctx):
- """Formats the help into a string and returns it. This creates a
- formatter and will call into the following formatting methods:
- """
- formatter = ctx.make_formatter()
- self.format_help(ctx, formatter)
- return formatter.getvalue().rstrip('\n')
- def get_short_help_str(self, limit=45):
- """Gets short help for the command or makes it by shortening the long help string."""
- return self.short_help or self.help and make_default_short_help(self.help, limit) or ''
- def format_help(self, ctx, formatter):
- """Writes the help into the formatter if it exists.
- This calls into the following methods:
- - :meth:`format_usage`
- - :meth:`format_help_text`
- - :meth:`format_options`
- - :meth:`format_epilog`
- """
- self.format_usage(ctx, formatter)
- self.format_help_text(ctx, formatter)
- self.format_options(ctx, formatter)
- self.format_epilog(ctx, formatter)
- def format_help_text(self, ctx, formatter):
- """Writes the help text to the formatter if it exists."""
- if self.help:
- formatter.write_paragraph()
- with formatter.indentation():
- help_text = self.help
- if self.deprecated:
- help_text += DEPRECATED_HELP_NOTICE
- formatter.write_text(help_text)
- elif self.deprecated:
- formatter.write_paragraph()
- with formatter.indentation():
- formatter.write_text(DEPRECATED_HELP_NOTICE)
- def format_options(self, ctx, formatter):
- """Writes all the options into the formatter if they exist."""
- opts = []
- for param in self.get_params(ctx):
- rv = param.get_help_record(ctx)
- if rv is not None:
- opts.append(rv)
- if opts:
- with formatter.section('Options'):
- formatter.write_dl(opts)
- def format_epilog(self, ctx, formatter):
- """Writes the epilog into the formatter if it exists."""
- if self.epilog:
- formatter.write_paragraph()
- with formatter.indentation():
- formatter.write_text(self.epilog)
- def parse_args(self, ctx, args):
- parser = self.make_parser(ctx)
- opts, args, param_order = parser.parse_args(args=args)
- for param in iter_params_for_processing(
- param_order, self.get_params(ctx)):
- value, args = param.handle_parse_result(ctx, opts, args)
- if args and not ctx.allow_extra_args and not ctx.resilient_parsing:
- ctx.fail('Got unexpected extra argument%s (%s)'
- % (len(args) != 1 and 's' or '',
- ' '.join(map(make_str, args))))
- ctx.args = args
- return args
- def invoke(self, ctx):
- """Given a context, this invokes the attached callback (if it exists)
- in the right way.
- """
- _maybe_show_deprecated_notice(self)
- if self.callback is not None:
- return ctx.invoke(self.callback, **ctx.params)
- class MultiCommand(Command):
- """A multi command is the basic implementation of a command that
- dispatches to subcommands. The most common version is the
- :class:`Group`.
- :param invoke_without_command: this controls how the multi command itself
- is invoked. By default it's only invoked
- if a subcommand is provided.
- :param no_args_is_help: this controls what happens if no arguments are
- provided. This option is enabled by default if
- `invoke_without_command` is disabled or disabled
- if it's enabled. If enabled this will add
- ``--help`` as argument if no arguments are
- passed.
- :param subcommand_metavar: the string that is used in the documentation
- to indicate the subcommand place.
- :param chain: if this is set to `True` chaining of multiple subcommands
- is enabled. This restricts the form of commands in that
- they cannot have optional arguments but it allows
- multiple commands to be chained together.
- :param result_callback: the result callback to attach to this multi
- command.
- """
- allow_extra_args = True
- allow_interspersed_args = False
- def __init__(self, name=None, invoke_without_command=False,
- no_args_is_help=None, subcommand_metavar=None,
- chain=False, result_callback=None, **attrs):
- Command.__init__(self, name, **attrs)
- if no_args_is_help is None:
- no_args_is_help = not invoke_without_command
- self.no_args_is_help = no_args_is_help
- self.invoke_without_command = invoke_without_command
- if subcommand_metavar is None:
- if chain:
- subcommand_metavar = SUBCOMMANDS_METAVAR
- else:
- subcommand_metavar = SUBCOMMAND_METAVAR
- self.subcommand_metavar = subcommand_metavar
- self.chain = chain
- #: The result callback that is stored. This can be set or
- #: overridden with the :func:`resultcallback` decorator.
- self.result_callback = result_callback
- if self.chain:
- for param in self.params:
- if isinstance(param, Argument) and not param.required:
- raise RuntimeError('Multi commands in chain mode cannot '
- 'have optional arguments.')
- def collect_usage_pieces(self, ctx):
- rv = Command.collect_usage_pieces(self, ctx)
- rv.append(self.subcommand_metavar)
- return rv
- def format_options(self, ctx, formatter):
- Command.format_options(self, ctx, formatter)
- self.format_commands(ctx, formatter)
- def resultcallback(self, replace=False):
- """Adds a result callback to the chain command. By default if a
- result callback is already registered this will chain them but
- this can be disabled with the `replace` parameter. The result
- callback is invoked with the return value of the subcommand
- (or the list of return values from all subcommands if chaining
- is enabled) as well as the parameters as they would be passed
- to the main callback.
- Example::
- @click.group()
- @click.option('-i', '--input', default=23)
- def cli(input):
- return 42
- @cli.resultcallback()
- def process_result(result, input):
- return result + input
- .. versionadded:: 3.0
- :param replace: if set to `True` an already existing result
- callback will be removed.
- """
- def decorator(f):
- old_callback = self.result_callback
- if old_callback is None or replace:
- self.result_callback = f
- return f
- def function(__value, *args, **kwargs):
- return f(old_callback(__value, *args, **kwargs),
- *args, **kwargs)
- self.result_callback = rv = update_wrapper(function, f)
- return rv
- return decorator
- def format_commands(self, ctx, formatter):
- """Extra format methods for multi methods that adds all the commands
- after the options.
- """
- commands = []
- for subcommand in self.list_commands(ctx):
- cmd = self.get_command(ctx, subcommand)
- # What is this, the tool lied about a command. Ignore it
- if cmd is None:
- continue
- if cmd.hidden:
- continue
- commands.append((subcommand, cmd))
- # allow for 3 times the default spacing
- if len(commands):
- limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands)
- rows = []
- for subcommand, cmd in commands:
- help = cmd.get_short_help_str(limit)
- rows.append((subcommand, help))
- if rows:
- with formatter.section('Commands'):
- formatter.write_dl(rows)
- def parse_args(self, ctx, args):
- if not args and self.no_args_is_help and not ctx.resilient_parsing:
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
- rest = Command.parse_args(self, ctx, args)
- if self.chain:
- ctx.protected_args = rest
- ctx.args = []
- elif rest:
- ctx.protected_args, ctx.args = rest[:1], rest[1:]
- return ctx.args
- def invoke(self, ctx):
- def _process_result(value):
- if self.result_callback is not None:
- value = ctx.invoke(self.result_callback, value,
- **ctx.params)
- return value
- if not ctx.protected_args:
- # If we are invoked without command the chain flag controls
- # how this happens. If we are not in chain mode, the return
- # value here is the return value of the command.
- # If however we are in chain mode, the return value is the
- # return value of the result processor invoked with an empty
- # list (which means that no subcommand actually was executed).
- if self.invoke_without_command:
- if not self.chain:
- return Command.invoke(self, ctx)
- with ctx:
- Command.invoke(self, ctx)
- return _process_result([])
- ctx.fail('Missing command.')
- # Fetch args back out
- args = ctx.protected_args + ctx.args
- ctx.args = []
- ctx.protected_args = []
- # If we're not in chain mode, we only allow the invocation of a
- # single command but we also inform the current context about the
- # name of the command to invoke.
- if not self.chain:
- # Make sure the context is entered so we do not clean up
- # resources until the result processor has worked.
- with ctx:
- cmd_name, cmd, args = self.resolve_command(ctx, args)
- ctx.invoked_subcommand = cmd_name
- Command.invoke(self, ctx)
- sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)
- with sub_ctx:
- return _process_result(sub_ctx.command.invoke(sub_ctx))
- # In chain mode we create the contexts step by step, but after the
- # base command has been invoked. Because at that point we do not
- # know the subcommands yet, the invoked subcommand attribute is
- # set to ``*`` to inform the command that subcommands are executed
- # but nothing else.
- with ctx:
- ctx.invoked_subcommand = args and '*' or None
- Command.invoke(self, ctx)
- # Otherwise we make every single context and invoke them in a
- # chain. In that case the return value to the result processor
- # is the list of all invoked subcommand's results.
- contexts = []
- while args:
- cmd_name, cmd, args = self.resolve_command(ctx, args)
- sub_ctx = cmd.make_context(cmd_name, args, parent=ctx,
- allow_extra_args=True,
- allow_interspersed_args=False)
- contexts.append(sub_ctx)
- args, sub_ctx.args = sub_ctx.args, []
- rv = []
- for sub_ctx in contexts:
- with sub_ctx:
- rv.append(sub_ctx.command.invoke(sub_ctx))
- return _process_result(rv)
- def resolve_command(self, ctx, args):
- cmd_name = make_str(args[0])
- original_cmd_name = cmd_name
- # Get the command
- cmd = self.get_command(ctx, cmd_name)
- # If we can't find the command but there is a normalization
- # function available, we try with that one.
- if cmd is None and ctx.token_normalize_func is not None:
- cmd_name = ctx.token_normalize_func(cmd_name)
- cmd = self.get_command(ctx, cmd_name)
- # If we don't find the command we want to show an error message
- # to the user that it was not provided. However, there is
- # something else we should do: if the first argument looks like
- # an option we want to kick off parsing again for arguments to
- # resolve things like --help which now should go to the main
- # place.
- if cmd is None and not ctx.resilient_parsing:
- if split_opt(cmd_name)[0]:
- self.parse_args(ctx, ctx.args)
- ctx.fail('No such command "%s".' % original_cmd_name)
- return cmd_name, cmd, args[1:]
- def get_command(self, ctx, cmd_name):
- """Given a context and a command name, this returns a
- :class:`Command` object if it exists or returns `None`.
- """
- raise NotImplementedError()
- def list_commands(self, ctx):
- """Returns a list of subcommand names in the order they should
- appear.
- """
- return []
- class Group(MultiCommand):
- """A group allows a command to have subcommands attached. This is the
- most common way to implement nesting in Click.
- :param commands: a dictionary of commands.
- """
- def __init__(self, name=None, commands=None, **attrs):
- MultiCommand.__init__(self, name, **attrs)
- #: the registered subcommands by their exported names.
- self.commands = commands or {}
- def add_command(self, cmd, name=None):
- """Registers another :class:`Command` with this group. If the name
- is not provided, the name of the command is used.
- """
- name = name or cmd.name
- if name is None:
- raise TypeError('Command has no name.')
- _check_multicommand(self, name, cmd, register=True)
- self.commands[name] = cmd
- def command(self, *args, **kwargs):
- """A shortcut decorator for declaring and attaching a command to
- the group. This takes the same arguments as :func:`command` but
- immediately registers the created command with this instance by
- calling into :meth:`add_command`.
- """
- def decorator(f):
- cmd = command(*args, **kwargs)(f)
- self.add_command(cmd)
- return cmd
- return decorator
- def group(self, *args, **kwargs):
- """A shortcut decorator for declaring and attaching a group to
- the group. This takes the same arguments as :func:`group` but
- immediately registers the created command with this instance by
- calling into :meth:`add_command`.
- """
- def decorator(f):
- cmd = group(*args, **kwargs)(f)
- self.add_command(cmd)
- return cmd
- return decorator
- def get_command(self, ctx, cmd_name):
- return self.commands.get(cmd_name)
- def list_commands(self, ctx):
- return sorted(self.commands)
- class CommandCollection(MultiCommand):
- """A command collection is a multi command that merges multiple multi
- commands together into one. This is a straightforward implementation
- that accepts a list of different multi commands as sources and
- provides all the commands for each of them.
- """
- def __init__(self, name=None, sources=None, **attrs):
- MultiCommand.__init__(self, name, **attrs)
- #: The list of registered multi commands.
- self.sources = sources or []
- def add_source(self, multi_cmd):
- """Adds a new multi command to the chain dispatcher."""
- self.sources.append(multi_cmd)
- def get_command(self, ctx, cmd_name):
- for source in self.sources:
- rv = source.get_command(ctx, cmd_name)
- if rv is not None:
- if self.chain:
- _check_multicommand(self, cmd_name, rv)
- return rv
- def list_commands(self, ctx):
- rv = set()
- for source in self.sources:
- rv.update(source.list_commands(ctx))
- return sorted(rv)
- class Parameter(object):
- r"""A parameter to a command comes in two versions: they are either
- :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently
- not supported by design as some of the internals for parsing are
- intentionally not finalized.
- Some settings are supported by both options and arguments.
- .. versionchanged:: 2.0
- Changed signature for parameter callback to also be passed the
- parameter. In Click 2.0, the old callback format will still work,
- but it will raise a warning to give you change to migrate the
- code easier.
- :param param_decls: the parameter declarations for this option or
- argument. This is a list of flags or argument
- names.
- :param type: the type that should be used. Either a :class:`ParamType`
- or a Python type. The later is converted into the former
- automatically if supported.
- :param required: controls if this is optional or not.
- :param default: the default value if omitted. This can also be a callable,
- in which case it's invoked when the default is needed
- without any arguments.
- :param callback: a callback that should be executed after the parameter
- was matched. This is called as ``fn(ctx, param,
- value)`` and needs to return the value. Before Click
- 2.0, the signature was ``(ctx, value)``.
- :param nargs: the number of arguments to match. If not ``1`` the return
- value is a tuple instead of single value. The default for
- nargs is ``1`` (except if the type is a tuple, then it's
- the arity of the tuple).
- :param metavar: how the value is represented in the help page.
- :param expose_value: if this is `True` then the value is passed onwards
- to the command callback and stored on the context,
- otherwise it's skipped.
- :param is_eager: eager values are processed before non eager ones. This
- should not be set for arguments or it will inverse the
- order of processing.
- :param envvar: a string or list of strings that are environment variables
- that should be checked.
- """
- param_type_name = 'parameter'
- def __init__(self, param_decls=None, type=None, required=False,
- default=None, callback=None, nargs=None, metavar=None,
- expose_value=True, is_eager=False, envvar=None,
- autocompletion=None):
- self.name, self.opts, self.secondary_opts = \
- self._parse_decls(param_decls or (), expose_value)
- self.type = convert_type(type, default)
- # Default nargs to what the type tells us if we have that
- # information available.
- if nargs is None:
- if self.type.is_composite:
- nargs = self.type.arity
- else:
- nargs = 1
- self.required = required
- self.callback = callback
- self.nargs = nargs
- self.multiple = False
- self.expose_value = expose_value
- self.default = default
- self.is_eager = is_eager
- self.metavar = metavar
- self.envvar = envvar
- self.autocompletion = autocompletion
- @property
- def human_readable_name(self):
- """Returns the human readable name of this parameter. This is the
- same as the name for options, but the metavar for arguments.
- """
- return self.name
- def make_metavar(self):
- if self.metavar is not None:
- return self.metavar
- metavar = self.type.get_metavar(self)
- if metavar is None:
- metavar = self.type.name.upper()
- if self.nargs != 1:
- metavar += '...'
- return metavar
- def get_default(self, ctx):
- """Given a context variable this calculates the default value."""
- # Otherwise go with the regular default.
- if callable(self.default):
- rv = self.default()
- else:
- rv = self.default
- return self.type_cast_value(ctx, rv)
- def add_to_parser(self, parser, ctx):
- pass
- def consume_value(self, ctx, opts):
- value = opts.get(self.name)
- if value is None:
- value = self.value_from_envvar(ctx)
- if value is None:
- value = ctx.lookup_default(self.name)
- return value
- def type_cast_value(self, ctx, value):
- """Given a value this runs it properly through the type system.
- This automatically handles things like `nargs` and `multiple` as
- well as composite types.
- """
- if self.type.is_composite:
- if self.nargs <= 1:
- raise TypeError('Attempted to invoke composite type '
- 'but nargs has been set to %s. This is '
- 'not supported; nargs needs to be set to '
- 'a fixed value > 1.' % self.nargs)
- if self.multiple:
- return tuple(self.type(x or (), self, ctx) for x in value or ())
- return self.type(value or (), self, ctx)
- def _convert(value, level):
- if level == 0:
- return self.type(value, self, ctx)
- return tuple(_convert(x, level - 1) for x in value or ())
- return _convert(value, (self.nargs != 1) + bool(self.multiple))
- def process_value(self, ctx, value):
- """Given a value and context this runs the logic to convert the
- value as necessary.
- """
- # If the value we were given is None we do nothing. This way
- # code that calls this can easily figure out if something was
- # not provided. Otherwise it would be converted into an empty
- # tuple for multiple invocations which is inconvenient.
- if value is not None:
- return self.type_cast_value(ctx, value)
- def value_is_missing(self, value):
- if value is None:
- return True
- if (self.nargs != 1 or self.multiple) and value == ():
- return True
- return False
- def full_process_value(self, ctx, value):
- value = self.process_value(ctx, value)
- if value is None and not ctx.resilient_parsing:
- value = self.get_default(ctx)
- if self.required and self.value_is_missing(value):
- raise MissingParameter(ctx=ctx, param=self)
- return value
- def resolve_envvar_value(self, ctx):
- if self.envvar is None:
- return
- if isinstance(self.envvar, (tuple, list)):
- for envvar in self.envvar:
- rv = os.environ.get(envvar)
- if rv is not None:
- return rv
- else:
- return os.environ.get(self.envvar)
- def value_from_envvar(self, ctx):
- rv = self.resolve_envvar_value(ctx)
- if rv is not None and self.nargs != 1:
- rv = self.type.split_envvar_value(rv)
- return rv
- def handle_parse_result(self, ctx, opts, args):
- with augment_usage_errors(ctx, param=self):
- value = self.consume_value(ctx, opts)
- try:
- value = self.full_process_value(ctx, value)
- except Exception:
- if not ctx.resilient_parsing:
- raise
- value = None
- if self.callback is not None:
- try:
- value = invoke_param_callback(
- self.callback, ctx, self, value)
- except Exception:
- if not ctx.resilient_parsing:
- raise
- if self.expose_value:
- ctx.params[self.name] = value
- return value, args
- def get_help_record(self, ctx):
- pass
- def get_usage_pieces(self, ctx):
- return []
- def get_error_hint(self, ctx):
- """Get a stringified version of the param for use in error messages to
- indicate which param caused the error.
- """
- hint_list = self.opts or [self.human_readable_name]
- return ' / '.join('"%s"' % x for x in hint_list)
- class Option(Parameter):
- """Options are usually optional values on the command line and
- have some extra features that arguments don't have.
- All other parameters are passed onwards to the parameter constructor.
- :param show_default: controls if the default value should be shown on the
- help page. Normally, defaults are not shown. If this
- value is a string, it shows the string instead of the
- value. This is particularly useful for dynamic options.
- :param show_envvar: controls if an environment variable should be shown on
- the help page. Normally, environment variables
- are not shown.
- :param prompt: if set to `True` or a non empty string then the user will be
- prompted for input. If set to `True` the prompt will be the
- option name capitalized.
- :param confirmation_prompt: if set then the value will need to be confirmed
- if it was prompted for.
- :param hide_input: if this is `True` then the input on the prompt will be
- hidden from the user. This is useful for password
- input.
- :param is_flag: forces this option to act as a flag. The default is
- auto detection.
- :param flag_value: which value should be used for this flag if it's
- enabled. This is set to a boolean automatically if
- the option string contains a slash to mark two options.
- :param multiple: if this is set to `True` then the argument is accepted
- multiple times and recorded. This is similar to ``nargs``
- in how it works but supports arbitrary number of
- arguments.
- :param count: this flag makes an option increment an integer.
- :param allow_from_autoenv: if this is enabled then the value of this
- parameter will be pulled from an environment
- variable in case a prefix is defined on the
- context.
- :param help: the help string.
- :param hidden: hide this option from help outputs.
- """
- param_type_name = 'option'
- def __init__(self, param_decls=None, show_default=False,
- prompt=False, confirmation_prompt=False,
- hide_input=False, is_flag=None, flag_value=None,
- multiple=False, count=False, allow_from_autoenv=True,
- type=None, help=None, hidden=False, show_choices=True,
- show_envvar=False, **attrs):
- default_is_missing = attrs.get('default', _missing) is _missing
- Parameter.__init__(self, param_decls, type=type, **attrs)
- if prompt is True:
- prompt_text = self.name.replace('_', ' ').capitalize()
- elif prompt is False:
- prompt_text = None
- else:
- prompt_text = prompt
- self.prompt = prompt_text
- self.confirmation_prompt = confirmation_prompt
- self.hide_input = hide_input
- self.hidden = hidden
- # Flags
- if is_flag is None:
- if flag_value is not None:
- is_flag = True
- else:
- is_flag = bool(self.secondary_opts)
- if is_flag and default_is_missing:
- self.default = False
- if flag_value is None:
- flag_value = not self.default
- self.is_flag = is_flag
- self.flag_value = flag_value
- if self.is_flag and isinstance(self.flag_value, bool) \
- and type is None:
- self.type = BOOL
- self.is_bool_flag = True
- else:
- self.is_bool_flag = False
- # Counting
- self.count = count
- if count:
- if type is None:
- self.type = IntRange(min=0)
- if default_is_missing:
- self.default = 0
- self.multiple = multiple
- self.allow_from_autoenv = allow_from_autoenv
- self.help = help
- self.show_default = show_default
- self.show_choices = show_choices
- self.show_envvar = show_envvar
- # Sanity check for stuff we don't support
- if __debug__:
- if self.nargs < 0:
- raise TypeError('Options cannot have nargs < 0')
- if self.prompt and self.is_flag and not self.is_bool_flag:
- raise TypeError('Cannot prompt for flags that are not bools.')
- if not self.is_bool_flag and self.secondary_opts:
- raise TypeError('Got secondary option for non boolean flag.')
- if self.is_bool_flag and self.hide_input \
- and self.prompt is not None:
- raise TypeError('Hidden input does not work with boolean '
- 'flag prompts.')
- if self.count:
- if self.multiple:
- raise TypeError('Options cannot be multiple and count '
- 'at the same time.')
- elif self.is_flag:
- raise TypeError('Options cannot be count and flags at '
- 'the same time.')
- def _parse_decls(self, decls, expose_value):
- opts = []
- secondary_opts = []
- name = None
- possible_names = []
- for decl in decls:
- if isidentifier(decl):
- if name is not None:
- raise TypeError('Name defined twice')
- name = decl
- else:
- split_char = decl[:1] == '/' and ';' or '/'
- if split_char in decl:
- first, second = decl.split(split_char, 1)
- first = first.rstrip()
- if first:
- possible_names.append(split_opt(first))
- opts.append(first)
- second = second.lstrip()
- if second:
- secondary_opts.append(second.lstrip())
- else:
- possible_names.append(split_opt(decl))
- opts.append(decl)
- if name is None and possible_names:
- possible_names.sort(key=lambda x: -len(x[0])) # group long options first
- name = possible_names[0][1].replace('-', '_').lower()
- if not isidentifier(name):
- name = None
- if name is None:
- if not expose_value:
- return None, opts, secondary_opts
- raise TypeError('Could not determine name for option')
- if not opts and not secondary_opts:
- raise TypeError('No options defined but a name was passed (%s). '
- 'Did you mean to declare an argument instead '
- 'of an option?' % name)
- return name, opts, secondary_opts
- def add_to_parser(self, parser, ctx):
- kwargs = {
- 'dest': self.name,
- 'nargs': self.nargs,
- 'obj': self,
- }
- if self.multiple:
- action = 'append'
- elif self.count:
- action = 'count'
- else:
- action = 'store'
- if self.is_flag:
- kwargs.pop('nargs', None)
- if self.is_bool_flag and self.secondary_opts:
- parser.add_option(self.opts, action=action + '_const',
- const=True, **kwargs)
- parser.add_option(self.secondary_opts, action=action +
- '_const', const=False, **kwargs)
- else:
- parser.add_option(self.opts, action=action + '_const',
- const=self.flag_value,
- **kwargs)
- else:
- kwargs['action'] = action
- parser.add_option(self.opts, **kwargs)
- def get_help_record(self, ctx):
- if self.hidden:
- return
- any_prefix_is_slash = []
- def _write_opts(opts):
- rv, any_slashes = join_options(opts)
- if any_slashes:
- any_prefix_is_slash[:] = [True]
- if not self.is_flag and not self.count:
- rv += ' ' + self.make_metavar()
- return rv
- rv = [_write_opts(self.opts)]
- if self.secondary_opts:
- rv.append(_write_opts(self.secondary_opts))
- help = self.help or ''
- extra = []
- if self.show_envvar:
- envvar = self.envvar
- if envvar is None:
- if self.allow_from_autoenv and \
- ctx.auto_envvar_prefix is not None:
- envvar = '%s_%s' % (ctx.auto_envvar_prefix, self.name.upper())
- if envvar is not None:
- extra.append('env var: %s' % (
- ', '.join('%s' % d for d in envvar)
- if isinstance(envvar, (list, tuple))
- else envvar, ))
- if self.default is not None and self.show_default:
- if isinstance(self.show_default, string_types):
- default_string = '({})'.format(self.show_default)
- elif isinstance(self.default, (list, tuple)):
- default_string = ', '.join('%s' % d for d in self.default)
- elif inspect.isfunction(self.default):
- default_string = "(dynamic)"
- else:
- default_string = self.default
- extra.append('default: {}'.format(default_string))
- if self.required:
- extra.append('required')
- if extra:
- help = '%s[%s]' % (help and help + ' ' or '', '; '.join(extra))
- return ((any_prefix_is_slash and '; ' or ' / ').join(rv), help)
- def get_default(self, ctx):
- # If we're a non boolean flag out default is more complex because
- # we need to look at all flags in the same group to figure out
- # if we're the the default one in which case we return the flag
- # value as default.
- if self.is_flag and not self.is_bool_flag:
- for param in ctx.command.params:
- if param.name == self.name and param.default:
- return param.flag_value
- return None
- return Parameter.get_default(self, ctx)
- def prompt_for_value(self, ctx):
- """This is an alternative flow that can be activated in the full
- value processing if a value does not exist. It will prompt the
- user until a valid value exists and then returns the processed
- value as result.
- """
- # Calculate the default before prompting anything to be stable.
- default = self.get_default(ctx)
- # If this is a prompt for a flag we need to handle this
- # differently.
- if self.is_bool_flag:
- return confirm(self.prompt, default)
- return prompt(self.prompt, default=default, type=self.type,
- hide_input=self.hide_input, show_choices=self.show_choices,
- confirmation_prompt=self.confirmation_prompt,
- value_proc=lambda x: self.process_value(ctx, x))
- def resolve_envvar_value(self, ctx):
- rv = Parameter.resolve_envvar_value(self, ctx)
- if rv is not None:
- return rv
- if self.allow_from_autoenv and \
- ctx.auto_envvar_prefix is not None:
- envvar = '%s_%s' % (ctx.auto_envvar_prefix, self.name.upper())
- return os.environ.get(envvar)
- def value_from_envvar(self, ctx):
- rv = self.resolve_envvar_value(ctx)
- if rv is None:
- return None
- value_depth = (self.nargs != 1) + bool(self.multiple)
- if value_depth > 0 and rv is not None:
- rv = self.type.split_envvar_value(rv)
- if self.multiple and self.nargs != 1:
- rv = batch(rv, self.nargs)
- return rv
- def full_process_value(self, ctx, value):
- if value is None and self.prompt is not None \
- and not ctx.resilient_parsing:
- return self.prompt_for_value(ctx)
- return Parameter.full_process_value(self, ctx, value)
- class Argument(Parameter):
- """Arguments are positional parameters to a command. They generally
- provide fewer features than options but can have infinite ``nargs``
- and are required by default.
- All parameters are passed onwards to the parameter constructor.
- """
- param_type_name = 'argument'
- def __init__(self, param_decls, required=None, **attrs):
- if required is None:
- if attrs.get('default') is not None:
- required = False
- else:
- required = attrs.get('nargs', 1) > 0
- Parameter.__init__(self, param_decls, required=required, **attrs)
- if self.default is not None and self.nargs < 0:
- raise TypeError('nargs=-1 in combination with a default value '
- 'is not supported.')
- @property
- def human_readable_name(self):
- if self.metavar is not None:
- return self.metavar
- return self.name.upper()
- def make_metavar(self):
- if self.metavar is not None:
- return self.metavar
- var = self.type.get_metavar(self)
- if not var:
- var = self.name.upper()
- if not self.required:
- var = '[%s]' % var
- if self.nargs != 1:
- var += '...'
- return var
- def _parse_decls(self, decls, expose_value):
- if not decls:
- if not expose_value:
- return None, [], []
- raise TypeError('Could not determine name for argument')
- if len(decls) == 1:
- name = arg = decls[0]
- name = name.replace('-', '_').lower()
- else:
- raise TypeError('Arguments take exactly one '
- 'parameter declaration, got %d' % len(decls))
- return name, [arg], []
- def get_usage_pieces(self, ctx):
- return [self.make_metavar()]
- def get_error_hint(self, ctx):
- return '"%s"' % self.make_metavar()
- def add_to_parser(self, parser, ctx):
- parser.add_argument(dest=self.name, nargs=self.nargs,
- obj=self)
- # Circular dependency between decorators and core
- from .decorators import command, group
|