aboutsummaryrefslogtreecommitdiffstats
path: root/python/click
diff options
context:
space:
mode:
Diffstat (limited to 'python/click')
-rw-r--r--python/click/__init__.py97
-rw-r--r--python/click/_bashcomplete.py293
-rw-r--r--python/click/_compat.py703
-rw-r--r--python/click/_termui_impl.py621
-rw-r--r--python/click/_textwrap.py38
-rw-r--r--python/click/_unicodefun.py125
-rw-r--r--python/click/_winconsole.py307
-rw-r--r--python/click/core.py1856
-rw-r--r--python/click/decorators.py311
-rw-r--r--python/click/exceptions.py235
-rw-r--r--python/click/formatting.py256
-rw-r--r--python/click/globals.py48
-rw-r--r--python/click/parser.py427
-rw-r--r--python/click/termui.py606
-rw-r--r--python/click/testing.py374
-rw-r--r--python/click/types.py668
-rw-r--r--python/click/utils.py440
17 files changed, 0 insertions, 7405 deletions
diff --git a/python/click/__init__.py b/python/click/__init__.py
deleted file mode 100644
index d3c3366..0000000
--- a/python/click/__init__.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-click
-~~~~~
-
-Click is a simple Python module inspired by the stdlib optparse to make
-writing command line scripts fun. Unlike other modules, it's based
-around a simple API that does not come with too much magic and is
-composable.
-
-:copyright: © 2014 by the Pallets team.
-:license: BSD, see LICENSE.rst for more details.
-"""
-
-# Core classes
-from .core import Context, BaseCommand, Command, MultiCommand, Group, \
- CommandCollection, Parameter, Option, Argument
-
-# Globals
-from .globals import get_current_context
-
-# Decorators
-from .decorators import pass_context, pass_obj, make_pass_decorator, \
- command, group, argument, option, confirmation_option, \
- password_option, version_option, help_option
-
-# Types
-from .types import ParamType, File, Path, Choice, IntRange, Tuple, \
- DateTime, STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED, FloatRange
-
-# Utilities
-from .utils import echo, get_binary_stream, get_text_stream, open_file, \
- format_filename, get_app_dir, get_os_args
-
-# Terminal functions
-from .termui import prompt, confirm, get_terminal_size, echo_via_pager, \
- progressbar, clear, style, unstyle, secho, edit, launch, getchar, \
- pause
-
-# Exceptions
-from .exceptions import ClickException, UsageError, BadParameter, \
- FileError, Abort, NoSuchOption, BadOptionUsage, BadArgumentUsage, \
- MissingParameter
-
-# Formatting
-from .formatting import HelpFormatter, wrap_text
-
-# Parsing
-from .parser import OptionParser
-
-
-__all__ = [
- # Core classes
- 'Context', 'BaseCommand', 'Command', 'MultiCommand', 'Group',
- 'CommandCollection', 'Parameter', 'Option', 'Argument',
-
- # Globals
- 'get_current_context',
-
- # Decorators
- 'pass_context', 'pass_obj', 'make_pass_decorator', 'command', 'group',
- 'argument', 'option', 'confirmation_option', 'password_option',
- 'version_option', 'help_option',
-
- # Types
- 'ParamType', 'File', 'Path', 'Choice', 'IntRange', 'Tuple',
- 'DateTime', 'STRING', 'INT', 'FLOAT', 'BOOL', 'UUID', 'UNPROCESSED',
- 'FloatRange',
-
- # Utilities
- 'echo', 'get_binary_stream', 'get_text_stream', 'open_file',
- 'format_filename', 'get_app_dir', 'get_os_args',
-
- # Terminal functions
- 'prompt', 'confirm', 'get_terminal_size', 'echo_via_pager',
- 'progressbar', 'clear', 'style', 'unstyle', 'secho', 'edit', 'launch',
- 'getchar', 'pause',
-
- # Exceptions
- 'ClickException', 'UsageError', 'BadParameter', 'FileError',
- 'Abort', 'NoSuchOption', 'BadOptionUsage', 'BadArgumentUsage',
- 'MissingParameter',
-
- # Formatting
- 'HelpFormatter', 'wrap_text',
-
- # Parsing
- 'OptionParser',
-]
-
-
-# Controls if click should emit the warning about the use of unicode
-# literals.
-disable_unicode_literals_warning = False
-
-
-__version__ = '7.0'
diff --git a/python/click/_bashcomplete.py b/python/click/_bashcomplete.py
deleted file mode 100644
index a5f1084..0000000
--- a/python/click/_bashcomplete.py
+++ /dev/null
@@ -1,293 +0,0 @@
-import copy
-import os
-import re
-
-from .utils import echo
-from .parser import split_arg_string
-from .core import MultiCommand, Option, Argument
-from .types import Choice
-
-try:
- from collections import abc
-except ImportError:
- import collections as abc
-
-WORDBREAK = '='
-
-# Note, only BASH version 4.4 and later have the nosort option.
-COMPLETION_SCRIPT_BASH = '''
-%(complete_func)s() {
- local IFS=$'\n'
- COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\
- COMP_CWORD=$COMP_CWORD \\
- %(autocomplete_var)s=complete $1 ) )
- return 0
-}
-
-%(complete_func)setup() {
- local COMPLETION_OPTIONS=""
- local BASH_VERSION_ARR=(${BASH_VERSION//./ })
- # Only BASH version 4.4 and later have the nosort option.
- if [ ${BASH_VERSION_ARR[0]} -gt 4 ] || ([ ${BASH_VERSION_ARR[0]} -eq 4 ] && [ ${BASH_VERSION_ARR[1]} -ge 4 ]); then
- COMPLETION_OPTIONS="-o nosort"
- fi
-
- complete $COMPLETION_OPTIONS -F %(complete_func)s %(script_names)s
-}
-
-%(complete_func)setup
-'''
-
-COMPLETION_SCRIPT_ZSH = '''
-%(complete_func)s() {
- local -a completions
- local -a completions_with_descriptions
- local -a response
- response=("${(@f)$( env COMP_WORDS=\"${words[*]}\" \\
- COMP_CWORD=$((CURRENT-1)) \\
- %(autocomplete_var)s=\"complete_zsh\" \\
- %(script_names)s )}")
-
- for key descr in ${(kv)response}; do
- if [[ "$descr" == "_" ]]; then
- completions+=("$key")
- else
- completions_with_descriptions+=("$key":"$descr")
- fi
- done
-
- if [ -n "$completions_with_descriptions" ]; then
- _describe -V unsorted completions_with_descriptions -U -Q
- fi
-
- if [ -n "$completions" ]; then
- compadd -U -V unsorted -Q -a completions
- fi
- compstate[insert]="automenu"
-}
-
-compdef %(complete_func)s %(script_names)s
-'''
-
-_invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]')
-
-
-def get_completion_script(prog_name, complete_var, shell):
- cf_name = _invalid_ident_char_re.sub('', prog_name.replace('-', '_'))
- script = COMPLETION_SCRIPT_ZSH if shell == 'zsh' else COMPLETION_SCRIPT_BASH
- return (script % {
- 'complete_func': '_%s_completion' % cf_name,
- 'script_names': prog_name,
- 'autocomplete_var': complete_var,
- }).strip() + ';'
-
-
-def resolve_ctx(cli, prog_name, args):
- """
- Parse into a hierarchy of contexts. Contexts are connected through the parent variable.
- :param cli: command definition
- :param prog_name: the program that is running
- :param args: full list of args
- :return: the final context/command parsed
- """
- ctx = cli.make_context(prog_name, args, resilient_parsing=True)
- args = ctx.protected_args + ctx.args
- while args:
- if isinstance(ctx.command, MultiCommand):
- if not ctx.command.chain:
- cmd_name, cmd, args = ctx.command.resolve_command(ctx, args)
- if cmd is None:
- return ctx
- ctx = cmd.make_context(cmd_name, args, parent=ctx,
- resilient_parsing=True)
- args = ctx.protected_args + ctx.args
- else:
- # Walk chained subcommand contexts saving the last one.
- while args:
- cmd_name, cmd, args = ctx.command.resolve_command(ctx, args)
- if cmd is None:
- return ctx
- sub_ctx = cmd.make_context(cmd_name, args, parent=ctx,
- allow_extra_args=True,
- allow_interspersed_args=False,
- resilient_parsing=True)
- args = sub_ctx.args
- ctx = sub_ctx
- args = sub_ctx.protected_args + sub_ctx.args
- else:
- break
- return ctx
-
-
-def start_of_option(param_str):
- """
- :param param_str: param_str to check
- :return: whether or not this is the start of an option declaration (i.e. starts "-" or "--")
- """
- return param_str and param_str[:1] == '-'
-
-
-def is_incomplete_option(all_args, cmd_param):
- """
- :param all_args: the full original list of args supplied
- :param cmd_param: the current command paramter
- :return: whether or not the last option declaration (i.e. starts "-" or "--") is incomplete and
- corresponds to this cmd_param. In other words whether this cmd_param option can still accept
- values
- """
- if not isinstance(cmd_param, Option):
- return False
- if cmd_param.is_flag:
- return False
- last_option = None
- for index, arg_str in enumerate(reversed([arg for arg in all_args if arg != WORDBREAK])):
- if index + 1 > cmd_param.nargs:
- break
- if start_of_option(arg_str):
- last_option = arg_str
-
- return True if last_option and last_option in cmd_param.opts else False
-
-
-def is_incomplete_argument(current_params, cmd_param):
- """
- :param current_params: the current params and values for this argument as already entered
- :param cmd_param: the current command parameter
- :return: whether or not the last argument is incomplete and corresponds to this cmd_param. In
- other words whether or not the this cmd_param argument can still accept values
- """
- if not isinstance(cmd_param, Argument):
- return False
- current_param_values = current_params[cmd_param.name]
- if current_param_values is None:
- return True
- if cmd_param.nargs == -1:
- return True
- if isinstance(current_param_values, abc.Iterable) \
- and cmd_param.nargs > 1 and len(current_param_values) < cmd_param.nargs:
- return True
- return False
-
-
-def get_user_autocompletions(ctx, args, incomplete, cmd_param):
- """
- :param ctx: context associated with the parsed command
- :param args: full list of args
- :param incomplete: the incomplete text to autocomplete
- :param cmd_param: command definition
- :return: all the possible user-specified completions for the param
- """
- results = []
- if isinstance(cmd_param.type, Choice):
- # Choices don't support descriptions.
- results = [(c, None)
- for c in cmd_param.type.choices if str(c).startswith(incomplete)]
- elif cmd_param.autocompletion is not None:
- dynamic_completions = cmd_param.autocompletion(ctx=ctx,
- args=args,
- incomplete=incomplete)
- results = [c if isinstance(c, tuple) else (c, None)
- for c in dynamic_completions]
- return results
-
-
-def get_visible_commands_starting_with(ctx, starts_with):
- """
- :param ctx: context associated with the parsed command
- :starts_with: string that visible commands must start with.
- :return: all visible (not hidden) commands that start with starts_with.
- """
- for c in ctx.command.list_commands(ctx):
- if c.startswith(starts_with):
- command = ctx.command.get_command(ctx, c)
- if not command.hidden:
- yield command
-
-
-def add_subcommand_completions(ctx, incomplete, completions_out):
- # Add subcommand completions.
- if isinstance(ctx.command, MultiCommand):
- completions_out.extend(
- [(c.name, c.get_short_help_str()) for c in get_visible_commands_starting_with(ctx, incomplete)])
-
- # Walk up the context list and add any other completion possibilities from chained commands
- while ctx.parent is not None:
- ctx = ctx.parent
- if isinstance(ctx.command, MultiCommand) and ctx.command.chain:
- remaining_commands = [c for c in get_visible_commands_starting_with(ctx, incomplete)
- if c.name not in ctx.protected_args]
- completions_out.extend([(c.name, c.get_short_help_str()) for c in remaining_commands])
-
-
-def get_choices(cli, prog_name, args, incomplete):
- """
- :param cli: command definition
- :param prog_name: the program that is running
- :param args: full list of args
- :param incomplete: the incomplete text to autocomplete
- :return: all the possible completions for the incomplete
- """
- all_args = copy.deepcopy(args)
-
- ctx = resolve_ctx(cli, prog_name, args)
- if ctx is None:
- return []
-
- # In newer versions of bash long opts with '='s are partitioned, but it's easier to parse
- # without the '='
- if start_of_option(incomplete) and WORDBREAK in incomplete:
- partition_incomplete = incomplete.partition(WORDBREAK)
- all_args.append(partition_incomplete[0])
- incomplete = partition_incomplete[2]
- elif incomplete == WORDBREAK:
- incomplete = ''
-
- completions = []
- if start_of_option(incomplete):
- # completions for partial options
- for param in ctx.command.params:
- if isinstance(param, Option) and not param.hidden:
- param_opts = [param_opt for param_opt in param.opts +
- param.secondary_opts if param_opt not in all_args or param.multiple]
- completions.extend([(o, param.help) for o in param_opts if o.startswith(incomplete)])
- return completions
- # completion for option values from user supplied values
- for param in ctx.command.params:
- if is_incomplete_option(all_args, param):
- return get_user_autocompletions(ctx, all_args, incomplete, param)
- # completion for argument values from user supplied values
- for param in ctx.command.params:
- if is_incomplete_argument(ctx.params, param):
- return get_user_autocompletions(ctx, all_args, incomplete, param)
-
- add_subcommand_completions(ctx, incomplete, completions)
- # Sort before returning so that proper ordering can be enforced in custom types.
- return sorted(completions)
-
-
-def do_complete(cli, prog_name, include_descriptions):
- cwords = split_arg_string(os.environ['COMP_WORDS'])
- cword = int(os.environ['COMP_CWORD'])
- args = cwords[1:cword]
- try:
- incomplete = cwords[cword]
- except IndexError:
- incomplete = ''
-
- for item in get_choices(cli, prog_name, args, incomplete):
- echo(item[0])
- if include_descriptions:
- # ZSH has trouble dealing with empty array parameters when returned from commands, so use a well defined character '_' to indicate no description is present.
- echo(item[1] if item[1] else '_')
-
- return True
-
-
-def bashcomplete(cli, prog_name, complete_var, complete_instr):
- if complete_instr.startswith('source'):
- shell = 'zsh' if complete_instr == 'source_zsh' else 'bash'
- echo(get_completion_script(prog_name, complete_var, shell))
- return True
- elif complete_instr == 'complete' or complete_instr == 'complete_zsh':
- return do_complete(cli, prog_name, complete_instr == 'complete_zsh')
- return False
diff --git a/python/click/_compat.py b/python/click/_compat.py
deleted file mode 100644
index 937e230..0000000
--- a/python/click/_compat.py
+++ /dev/null
@@ -1,703 +0,0 @@
-import re
-import io
-import os
-import sys
-import codecs
-from weakref import WeakKeyDictionary
-
-
-PY2 = sys.version_info[0] == 2
-CYGWIN = sys.platform.startswith('cygwin')
-# Determine local App Engine environment, per Google's own suggestion
-APP_ENGINE = ('APPENGINE_RUNTIME' in os.environ and
- 'Development/' in os.environ['SERVER_SOFTWARE'])
-WIN = sys.platform.startswith('win') and not APP_ENGINE
-DEFAULT_COLUMNS = 80
-
-
-_ansi_re = re.compile(r'\033\[((?:\d|;)*)([a-zA-Z])')
-
-
-def get_filesystem_encoding():
- return sys.getfilesystemencoding() or sys.getdefaultencoding()
-
-
-def _make_text_stream(stream, encoding, errors,
- force_readable=False, force_writable=False):
- if encoding is None:
- encoding = get_best_encoding(stream)
- if errors is None:
- errors = 'replace'
- return _NonClosingTextIOWrapper(stream, encoding, errors,
- line_buffering=True,
- force_readable=force_readable,
- force_writable=force_writable)
-
-
-def is_ascii_encoding(encoding):
- """Checks if a given encoding is ascii."""
- try:
- return codecs.lookup(encoding).name == 'ascii'
- except LookupError:
- return False
-
-
-def get_best_encoding(stream):
- """Returns the default stream encoding if not found."""
- rv = getattr(stream, 'encoding', None) or sys.getdefaultencoding()
- if is_ascii_encoding(rv):
- return 'utf-8'
- return rv
-
-
-class _NonClosingTextIOWrapper(io.TextIOWrapper):
-
- def __init__(self, stream, encoding, errors,
- force_readable=False, force_writable=False, **extra):
- self._stream = stream = _FixupStream(stream, force_readable,
- force_writable)
- io.TextIOWrapper.__init__(self, stream, encoding, errors, **extra)
-
- # The io module is a place where the Python 3 text behavior
- # was forced upon Python 2, so we need to unbreak
- # it to look like Python 2.
- if PY2:
- def write(self, x):
- if isinstance(x, str) or is_bytes(x):
- try:
- self.flush()
- except Exception:
- pass
- return self.buffer.write(str(x))
- return io.TextIOWrapper.write(self, x)
-
- def writelines(self, lines):
- for line in lines:
- self.write(line)
-
- def __del__(self):
- try:
- self.detach()
- except Exception:
- pass
-
- def isatty(self):
- # https://bitbucket.org/pypy/pypy/issue/1803
- return self._stream.isatty()
-
-
-class _FixupStream(object):
- """The new io interface needs more from streams than streams
- traditionally implement. As such, this fix-up code is necessary in
- some circumstances.
-
- The forcing of readable and writable flags are there because some tools
- put badly patched objects on sys (one such offender are certain version
- of jupyter notebook).
- """
-
- def __init__(self, stream, force_readable=False, force_writable=False):
- self._stream = stream
- self._force_readable = force_readable
- self._force_writable = force_writable
-
- def __getattr__(self, name):
- return getattr(self._stream, name)
-
- def read1(self, size):
- f = getattr(self._stream, 'read1', None)
- if f is not None:
- return f(size)
- # We only dispatch to readline instead of read in Python 2 as we
- # do not want cause problems with the different implementation
- # of line buffering.
- if PY2:
- return self._stream.readline(size)
- return self._stream.read(size)
-
- def readable(self):
- if self._force_readable:
- return True
- x = getattr(self._stream, 'readable', None)
- if x is not None:
- return x()
- try:
- self._stream.read(0)
- except Exception:
- return False
- return True
-
- def writable(self):
- if self._force_writable:
- return True
- x = getattr(self._stream, 'writable', None)
- if x is not None:
- return x()
- try:
- self._stream.write('')
- except Exception:
- try:
- self._stream.write(b'')
- except Exception:
- return False
- return True
-
- def seekable(self):
- x = getattr(self._stream, 'seekable', None)
- if x is not None:
- return x()
- try:
- self._stream.seek(self._stream.tell())
- except Exception:
- return False
- return True
-
-
-if PY2:
- text_type = unicode
- bytes = str
- raw_input = raw_input
- string_types = (str, unicode)
- int_types = (int, long)
- iteritems = lambda x: x.iteritems()
- range_type = xrange
-
- def is_bytes(x):
- return isinstance(x, (buffer, bytearray))
-
- _identifier_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$')
-
- # For Windows, we need to force stdout/stdin/stderr to binary if it's
- # fetched for that. This obviously is not the most correct way to do
- # it as it changes global state. Unfortunately, there does not seem to
- # be a clear better way to do it as just reopening the file in binary
- # mode does not change anything.
- #
- # An option would be to do what Python 3 does and to open the file as
- # binary only, patch it back to the system, and then use a wrapper
- # stream that converts newlines. It's not quite clear what's the
- # correct option here.
- #
- # This code also lives in _winconsole for the fallback to the console
- # emulation stream.
- #
- # There are also Windows environments where the `msvcrt` module is not
- # available (which is why we use try-catch instead of the WIN variable
- # here), such as the Google App Engine development server on Windows. In
- # those cases there is just nothing we can do.
- def set_binary_mode(f):
- return f
-
- try:
- import msvcrt
- except ImportError:
- pass
- else:
- def set_binary_mode(f):
- try:
- fileno = f.fileno()
- except Exception:
- pass
- else:
- msvcrt.setmode(fileno, os.O_BINARY)
- return f
-
- try:
- import fcntl
- except ImportError:
- pass
- else:
- def set_binary_mode(f):
- try:
- fileno = f.fileno()
- except Exception:
- pass
- else:
- flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
- fcntl.fcntl(fileno, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)
- return f
-
- def isidentifier(x):
- return _identifier_re.search(x) is not None
-
- def get_binary_stdin():
- return set_binary_mode(sys.stdin)
-
- def get_binary_stdout():
- _wrap_std_stream('stdout')
- return set_binary_mode(sys.stdout)
-
- def get_binary_stderr():
- _wrap_std_stream('stderr')
- return set_binary_mode(sys.stderr)
-
- def get_text_stdin(encoding=None, errors=None):
- rv = _get_windows_console_stream(sys.stdin, encoding, errors)
- if rv is not None:
- return rv
- return _make_text_stream(sys.stdin, encoding, errors,
- force_readable=True)
-
- def get_text_stdout(encoding=None, errors=None):
- _wrap_std_stream('stdout')
- rv = _get_windows_console_stream(sys.stdout, encoding, errors)
- if rv is not None:
- return rv
- return _make_text_stream(sys.stdout, encoding, errors,
- force_writable=True)
-
- def get_text_stderr(encoding=None, errors=None):
- _wrap_std_stream('stderr')
- rv = _get_windows_console_stream(sys.stderr, encoding, errors)
- if rv is not None:
- return rv
- return _make_text_stream(sys.stderr, encoding, errors,
- force_writable=True)
-
- def filename_to_ui(value):
- if isinstance(value, bytes):
- value = value.decode(get_filesystem_encoding(), 'replace')
- return value
-else:
- import io
- text_type = str
- raw_input = input
- string_types = (str,)
- int_types = (int,)
- range_type = range
- isidentifier = lambda x: x.isidentifier()
- iteritems = lambda x: iter(x.items())
-
- def is_bytes(x):
- return isinstance(x, (bytes, memoryview, bytearray))
-
- def _is_binary_reader(stream, default=False):
- try:
- return isinstance(stream.read(0), bytes)
- except Exception:
- return default
- # This happens in some cases where the stream was already
- # closed. In this case, we assume the default.
-
- def _is_binary_writer(stream, default=False):
- try:
- stream.write(b'')
- except Exception:
- try:
- stream.write('')
- return False
- except Exception:
- pass
- return default
- return True
-
- def _find_binary_reader(stream):
- # We need to figure out if the given stream is already binary.
- # This can happen because the official docs recommend detaching
- # the streams to get binary streams. Some code might do this, so
- # we need to deal with this case explicitly.
- if _is_binary_reader(stream, False):
- return stream
-
- buf = getattr(stream, 'buffer', None)
-
- # Same situation here; this time we assume that the buffer is
- # actually binary in case it's closed.
- if buf is not None and _is_binary_reader(buf, True):
- return buf
-
- def _find_binary_writer(stream):
- # We need to figure out if the given stream is already binary.
- # This can happen because the official docs recommend detatching
- # the streams to get binary streams. Some code might do this, so
- # we need to deal with this case explicitly.
- if _is_binary_writer(stream, False):
- return stream
-
- buf = getattr(stream, 'buffer', None)
-
- # Same situation here; this time we assume that the buffer is
- # actually binary in case it's closed.
- if buf is not None and _is_binary_writer(buf, True):
- return buf
-
- def _stream_is_misconfigured(stream):
- """A stream is misconfigured if its encoding is ASCII."""
- # If the stream does not have an encoding set, we assume it's set
- # to ASCII. This appears to happen in certain unittest
- # environments. It's not quite clear what the correct behavior is
- # but this at least will force Click to recover somehow.
- return is_ascii_encoding(getattr(stream, 'encoding', None) or 'ascii')
-
- def _is_compatible_text_stream(stream, encoding, errors):
- stream_encoding = getattr(stream, 'encoding', None)
- stream_errors = getattr(stream, 'errors', None)
-
- # Perfect match.
- if stream_encoding == encoding and stream_errors == errors:
- return True
-
- # Otherwise, it's only a compatible stream if we did not ask for
- # an encoding.
- if encoding is None:
- return stream_encoding is not None
-
- return False
-
- def _force_correct_text_reader(text_reader, encoding, errors,
- force_readable=False):
- if _is_binary_reader(text_reader, False):
- binary_reader = text_reader
- else:
- # If there is no target encoding set, we need to verify that the
- # reader is not actually misconfigured.
- if encoding is None and not _stream_is_misconfigured(text_reader):
- return text_reader
-
- if _is_compatible_text_stream(text_reader, encoding, errors):
- return text_reader
-
- # If the reader has no encoding, we try to find the underlying
- # binary reader for it. If that fails because the environment is
- # misconfigured, we silently go with the same reader because this
- # is too common to happen. In that case, mojibake is better than
- # exceptions.
- binary_reader = _find_binary_reader(text_reader)
- if binary_reader is None:
- return text_reader
-
- # At this point, we default the errors to replace instead of strict
- # because nobody handles those errors anyways and at this point
- # we're so fundamentally fucked that nothing can repair it.
- if errors is None:
- errors = 'replace'
- return _make_text_stream(binary_reader, encoding, errors,
- force_readable=force_readable)
-
- def _force_correct_text_writer(text_writer, encoding, errors,
- force_writable=False):
- if _is_binary_writer(text_writer, False):
- binary_writer = text_writer
- else:
- # If there is no target encoding set, we need to verify that the
- # writer is not actually misconfigured.
- if encoding is None and not _stream_is_misconfigured(text_writer):
- return text_writer
-
- if _is_compatible_text_stream(text_writer, encoding, errors):
- return text_writer
-
- # If the writer has no encoding, we try to find the underlying
- # binary writer for it. If that fails because the environment is
- # misconfigured, we silently go with the same writer because this
- # is too common to happen. In that case, mojibake is better than
- # exceptions.
- binary_writer = _find_binary_writer(text_writer)
- if binary_writer is None:
- return text_writer
-
- # At this point, we default the errors to replace instead of strict
- # because nobody handles those errors anyways and at this point
- # we're so fundamentally fucked that nothing can repair it.
- if errors is None:
- errors = 'replace'
- return _make_text_stream(binary_writer, encoding, errors,
- force_writable=force_writable)
-
- def get_binary_stdin():
- reader = _find_binary_reader(sys.stdin)
- if reader is None:
- raise RuntimeError('Was not able to determine binary '
- 'stream for sys.stdin.')
- return reader
-
- def get_binary_stdout():
- writer = _find_binary_writer(sys.stdout)
- if writer is None:
- raise RuntimeError('Was not able to determine binary '
- 'stream for sys.stdout.')
- return writer
-
- def get_binary_stderr():
- writer = _find_binary_writer(sys.stderr)
- if writer is None:
- raise RuntimeError('Was not able to determine binary '
- 'stream for sys.stderr.')
- return writer
-
- def get_text_stdin(encoding=None, errors=None):
- rv = _get_windows_console_stream(sys.stdin, encoding, errors)
- if rv is not None:
- return rv
- return _force_correct_text_reader(sys.stdin, encoding, errors,
- force_readable=True)
-
- def get_text_stdout(encoding=None, errors=None):
- rv = _get_windows_console_stream(sys.stdout, encoding, errors)
- if rv is not None:
- return rv
- return _force_correct_text_writer(sys.stdout, encoding, errors,
- force_writable=True)
-
- def get_text_stderr(encoding=None, errors=None):
- rv = _get_windows_console_stream(sys.stderr, encoding, errors)
- if rv is not None:
- return rv
- return _force_correct_text_writer(sys.stderr, encoding, errors,
- force_writable=True)
-
- def filename_to_ui(value):
- if isinstance(value, bytes):
- value = value.decode(get_filesystem_encoding(), 'replace')
- else:
- value = value.encode('utf-8', 'surrogateescape') \
- .decode('utf-8', 'replace')
- return value
-
-
-def get_streerror(e, default=None):
- if hasattr(e, 'strerror'):
- msg = e.strerror
- else:
- if default is not None:
- msg = default
- else:
- msg = str(e)
- if isinstance(msg, bytes):
- msg = msg.decode('utf-8', 'replace')
- return msg
-
-
-def open_stream(filename, mode='r', encoding=None, errors='strict',
- atomic=False):
- # Standard streams first. These are simple because they don't need
- # special handling for the atomic flag. It's entirely ignored.
- if filename == '-':
- if any(m in mode for m in ['w', 'a', 'x']):
- if 'b' in mode:
- return get_binary_stdout(), False
- return get_text_stdout(encoding=encoding, errors=errors), False
- if 'b' in mode:
- return get_binary_stdin(), False
- return get_text_stdin(encoding=encoding, errors=errors), False
-
- # Non-atomic writes directly go out through the regular open functions.
- if not atomic:
- if encoding is None:
- return open(filename, mode), True
- return io.open(filename, mode, encoding=encoding, errors=errors), True
-
- # Some usability stuff for atomic writes
- if 'a' in mode:
- raise ValueError(
- 'Appending to an existing file is not supported, because that '
- 'would involve an expensive `copy`-operation to a temporary '
- 'file. Open the file in normal `w`-mode and copy explicitly '
- 'if that\'s what you\'re after.'
- )
- if 'x' in mode:
- raise ValueError('Use the `overwrite`-parameter instead.')
- if 'w' not in mode:
- raise ValueError('Atomic writes only make sense with `w`-mode.')
-
- # Atomic writes are more complicated. They work by opening a file
- # as a proxy in the same folder and then using the fdopen
- # functionality to wrap it in a Python file. Then we wrap it in an
- # atomic file that moves the file over on close.
- import tempfile
- fd, tmp_filename = tempfile.mkstemp(dir=os.path.dirname(filename),
- prefix='.__atomic-write')
-
- if encoding is not None:
- f = io.open(fd, mode, encoding=encoding, errors=errors)
- else:
- f = os.fdopen(fd, mode)
-
- return _AtomicFile(f, tmp_filename, os.path.realpath(filename)), True
-
-
-# Used in a destructor call, needs extra protection from interpreter cleanup.
-if hasattr(os, 'replace'):
- _replace = os.replace
- _can_replace = True
-else:
- _replace = os.rename
- _can_replace = not WIN
-
-
-class _AtomicFile(object):
-
- def __init__(self, f, tmp_filename, real_filename):
- self._f = f
- self._tmp_filename = tmp_filename
- self._real_filename = real_filename
- self.closed = False
-
- @property
- def name(self):
- return self._real_filename
-
- def close(self, delete=False):
- if self.closed:
- return
- self._f.close()
- if not _can_replace:
- try:
- os.remove(self._real_filename)
- except OSError:
- pass
- _replace(self._tmp_filename, self._real_filename)
- self.closed = True
-
- def __getattr__(self, name):
- return getattr(self._f, name)
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.close(delete=exc_type is not None)
-
- def __repr__(self):
- return repr(self._f)
-
-
-auto_wrap_for_ansi = None
-colorama = None
-get_winterm_size = None
-
-
-def strip_ansi(value):
- return _ansi_re.sub('', value)
-
-
-def should_strip_ansi(stream=None, color=None):
- if color is None:
- if stream is None:
- stream = sys.stdin
- return not isatty(stream)
- return not color
-
-
-# If we're on Windows, we provide transparent integration through
-# colorama. This will make ANSI colors through the echo function
-# work automatically.
-if WIN:
- # Windows has a smaller terminal
- DEFAULT_COLUMNS = 79
-
- from ._winconsole import _get_windows_console_stream, _wrap_std_stream
-
- def _get_argv_encoding():
- import locale
- return locale.getpreferredencoding()
-
- if PY2:
- def raw_input(prompt=''):
- sys.stderr.flush()
- if prompt:
- stdout = _default_text_stdout()
- stdout.write(prompt)
- stdin = _default_text_stdin()
- return stdin.readline().rstrip('\r\n')
-
- try:
- import colorama
- except ImportError:
- pass
- else:
- _ansi_stream_wrappers = WeakKeyDictionary()
-
- def auto_wrap_for_ansi(stream, color=None):
- """This function wraps a stream so that calls through colorama
- are issued to the win32 console API to recolor on demand. It
- also ensures to reset the colors if a write call is interrupted
- to not destroy the console afterwards.
- """
- try:
- cached = _ansi_stream_wrappers.get(stream)
- except Exception:
- cached = None
- if cached is not None:
- return cached
- strip = should_strip_ansi(stream, color)
- ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip)
- rv = ansi_wrapper.stream
- _write = rv.write
-
- def _safe_write(s):
- try:
- return _write(s)
- except:
- ansi_wrapper.reset_all()
- raise
-
- rv.write = _safe_write
- try:
- _ansi_stream_wrappers[stream] = rv
- except Exception:
- pass
- return rv
-
- def get_winterm_size():
- win = colorama.win32.GetConsoleScreenBufferInfo(
- colorama.win32.STDOUT).srWindow
- return win.Right - win.Left, win.Bottom - win.Top
-else:
- def _get_argv_encoding():
- return getattr(sys.stdin, 'encoding', None) or get_filesystem_encoding()
-
- _get_windows_console_stream = lambda *x: None
- _wrap_std_stream = lambda *x: None
-
-
-def term_len(x):
- return len(strip_ansi(x))
-
-
-def isatty(stream):
- try:
- return stream.isatty()
- except Exception:
- return False
-
-
-def _make_cached_stream_func(src_func, wrapper_func):
- cache = WeakKeyDictionary()
- def func():
- stream = src_func()
- try:
- rv = cache.get(stream)
- except Exception:
- rv = None
- if rv is not None:
- return rv
- rv = wrapper_func()
- try:
- stream = src_func() # In case wrapper_func() modified the stream
- cache[stream] = rv
- except Exception:
- pass
- return rv
- return func
-
-
-_default_text_stdin = _make_cached_stream_func(
- lambda: sys.stdin, get_text_stdin)
-_default_text_stdout = _make_cached_stream_func(
- lambda: sys.stdout, get_text_stdout)
-_default_text_stderr = _make_cached_stream_func(
- lambda: sys.stderr, get_text_stderr)
-
-
-binary_streams = {
- 'stdin': get_binary_stdin,
- 'stdout': get_binary_stdout,
- 'stderr': get_binary_stderr,
-}
-
-text_streams = {
- 'stdin': get_text_stdin,
- 'stdout': get_text_stdout,
- 'stderr': get_text_stderr,
-}
diff --git a/python/click/_termui_impl.py b/python/click/_termui_impl.py
deleted file mode 100644
index 00a8e5e..0000000
--- a/python/click/_termui_impl.py
+++ /dev/null
@@ -1,621 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-click._termui_impl
-~~~~~~~~~~~~~~~~~~
-
-This module contains implementations for the termui module. To keep the
-import time of Click down, some infrequently used functionality is
-placed in this module and only imported as needed.
-
-:copyright: © 2014 by the Pallets team.
-:license: BSD, see LICENSE.rst for more details.
-"""
-
-import os
-import sys
-import time
-import math
-import contextlib
-from ._compat import _default_text_stdout, range_type, PY2, isatty, \
- open_stream, strip_ansi, term_len, get_best_encoding, WIN, int_types, \
- CYGWIN
-from .utils import echo
-from .exceptions import ClickException
-
-
-if os.name == 'nt':
- BEFORE_BAR = '\r'
- AFTER_BAR = '\n'
-else:
- BEFORE_BAR = '\r\033[?25l'
- AFTER_BAR = '\033[?25h\n'
-
-
-def _length_hint(obj):
- """Returns the length hint of an object."""
- try:
- return len(obj)
- except (AttributeError, TypeError):
- try:
- get_hint = type(obj).__length_hint__
- except AttributeError:
- return None
- try:
- hint = get_hint(obj)
- except TypeError:
- return None
- if hint is NotImplemented or \
- not isinstance(hint, int_types) or \
- hint < 0:
- return None
- return hint
-
-
-class ProgressBar(object):
-
- def __init__(self, iterable, length=None, fill_char='#', empty_char=' ',
- bar_template='%(bar)s', info_sep=' ', show_eta=True,
- show_percent=None, show_pos=False, item_show_func=None,
- label=None, file=None, color=None, width=30):
- self.fill_char = fill_char
- self.empty_char = empty_char
- self.bar_template = bar_template
- self.info_sep = info_sep
- self.show_eta = show_eta
- self.show_percent = show_percent
- self.show_pos = show_pos
- self.item_show_func = item_show_func
- self.label = label or ''
- if file is None:
- file = _default_text_stdout()
- self.file = file
- self.color = color
- self.width = width
- self.autowidth = width == 0
-
- if length is None:
- length = _length_hint(iterable)
- if iterable is None:
- if length is None:
- raise TypeError('iterable or length is required')
- iterable = range_type(length)
- self.iter = iter(iterable)
- self.length = length
- self.length_known = length is not None
- self.pos = 0
- self.avg = []
- self.start = self.last_eta = time.time()
- self.eta_known = False
- self.finished = False
- self.max_width = None
- self.entered = False
- self.current_item = None
- self.is_hidden = not isatty(self.file)
- self._last_line = None
- self.short_limit = 0.5
-
- def __enter__(self):
- self.entered = True
- self.render_progress()
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.render_finish()
-
- def __iter__(self):
- if not self.entered:
- raise RuntimeError('You need to use progress bars in a with block.')
- self.render_progress()
- return self.generator()
-
- def is_fast(self):
- return time.time() - self.start <= self.short_limit
-
- def render_finish(self):
- if self.is_hidden or self.is_fast():
- return
- self.file.write(AFTER_BAR)
- self.file.flush()
-
- @property
- def pct(self):
- if self.finished:
- return 1.0
- return min(self.pos / (float(self.length) or 1), 1.0)
-
- @property
- def time_per_iteration(self):
- if not self.avg:
- return 0.0
- return sum(self.avg) / float(len(self.avg))
-
- @property
- def eta(self):
- if self.length_known and not self.finished:
- return self.time_per_iteration * (self.length - self.pos)
- return 0.0
-
- def format_eta(self):
- if self.eta_known:
- t = int(self.eta)
- seconds = t % 60
- t //= 60
- minutes = t % 60
- t //= 60
- hours = t % 24
- t //= 24
- if t > 0:
- days = t
- return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds)
- else:
- return '%02d:%02d:%02d' % (hours, minutes, seconds)
- return ''
-
- def format_pos(self):
- pos = str(self.pos)
- if self.length_known:
- pos += '/%s' % self.length
- return pos
-
- def format_pct(self):
- return ('% 4d%%' % int(self.pct * 100))[1:]
-
- def format_bar(self):
- if self.length_known:
- bar_length = int(self.pct * self.width)
- bar = self.fill_char * bar_length
- bar += self.empty_char * (self.width - bar_length)
- elif self.finished:
- bar = self.fill_char * self.width
- else:
- bar = list(self.empty_char * (self.width or 1))
- if self.time_per_iteration != 0:
- bar[int((math.cos(self.pos * self.time_per_iteration)
- / 2.0 + 0.5) * self.width)] = self.fill_char
- bar = ''.join(bar)
- return bar
-
- def format_progress_line(self):
- show_percent = self.show_percent
-
- info_bits = []
- if self.length_known and show_percent is None:
- show_percent = not self.show_pos
-
- if self.show_pos:
- info_bits.append(self.format_pos())
- if show_percent:
- info_bits.append(self.format_pct())
- if self.show_eta and self.eta_known and not self.finished:
- info_bits.append(self.format_eta())
- if self.item_show_func is not None:
- item_info = self.item_show_func(self.current_item)
- if item_info is not None:
- info_bits.append(item_info)
-
- return (self.bar_template % {
- 'label': self.label,
- 'bar': self.format_bar(),
- 'info': self.info_sep.join(info_bits)
- }).rstrip()
-
- def render_progress(self):
- from .termui import get_terminal_size
-
- if self.is_hidden:
- return
-
- buf = []
- # Update width in case the terminal has been resized
- if self.autowidth:
- old_width = self.width
- self.width = 0
- clutter_length = term_len(self.format_progress_line())
- new_width = max(0, get_terminal_size()[0] - clutter_length)
- if new_width < old_width:
- buf.append(BEFORE_BAR)
- buf.append(' ' * self.max_width)
- self.max_width = new_width
- self.width = new_width
-
- clear_width = self.width
- if self.max_width is not None:
- clear_width = self.max_width
-
- buf.append(BEFORE_BAR)
- line = self.format_progress_line()
- line_len = term_len(line)
- if self.max_width is None or self.max_width < line_len:
- self.max_width = line_len
-
- buf.append(line)
- buf.append(' ' * (clear_width - line_len))
- line = ''.join(buf)
- # Render the line only if it changed.
-
- if line != self._last_line and not self.is_fast():
- self._last_line = line
- echo(line, file=self.file, color=self.color, nl=False)
- self.file.flush()
-
- def make_step(self, n_steps):
- self.pos += n_steps
- if self.length_known and self.pos >= self.length:
- self.finished = True
-
- if (time.time() - self.last_eta) < 1.0:
- return
-
- self.last_eta = time.time()
-
- # self.avg is a rolling list of length <= 7 of steps where steps are
- # defined as time elapsed divided by the total progress through
- # self.length.
- if self.pos:
- step = (time.time() - self.start) / self.pos
- else:
- step = time.time() - self.start
-
- self.avg = self.avg[-6:] + [step]
-
- self.eta_known = self.length_known
-
- def update(self, n_steps):
- self.make_step(n_steps)
- self.render_progress()
-
- def finish(self):
- self.eta_known = 0
- self.current_item = None
- self.finished = True
-
- def generator(self):
- """
- Returns a generator which yields the items added to the bar during
- construction, and updates the progress bar *after* the yielded block
- returns.
- """
- if not self.entered:
- raise RuntimeError('You need to use progress bars in a with block.')
-
- if self.is_hidden:
- for rv in self.iter:
- yield rv
- else:
- for rv in self.iter:
- self.current_item = rv
- yield rv
- self.update(1)
- self.finish()
- self.render_progress()
-
-
-def pager(generator, color=None):
- """Decide what method to use for paging through text."""
- stdout = _default_text_stdout()
- if not isatty(sys.stdin) or not isatty(stdout):
- return _nullpager(stdout, generator, color)
- pager_cmd = (os.environ.get('PAGER', None) or '').strip()
- if pager_cmd:
- if WIN:
- return _tempfilepager(generator, pager_cmd, color)
- return _pipepager(generator, pager_cmd, color)
- if os.environ.get('TERM') in ('dumb', 'emacs'):
- return _nullpager(stdout, generator, color)
- if WIN or sys.platform.startswith('os2'):
- return _tempfilepager(generator, 'more <', color)
- if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
- return _pipepager(generator, 'less', color)
-
- import tempfile
- fd, filename = tempfile.mkstemp()
- os.close(fd)
- try:
- if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
- return _pipepager(generator, 'more', color)
- return _nullpager(stdout, generator, color)
- finally:
- os.unlink(filename)
-
-
-def _pipepager(generator, cmd, color):
- """Page through text by feeding it to another program. Invoking a
- pager through this might support colors.
- """
- import subprocess
- env = dict(os.environ)
-
- # If we're piping to less we might support colors under the
- # condition that
- cmd_detail = cmd.rsplit('/', 1)[-1].split()
- if color is None and cmd_detail[0] == 'less':
- less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:])
- if not less_flags:
- env['LESS'] = '-R'
- color = True
- elif 'r' in less_flags or 'R' in less_flags:
- color = True
-
- c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
- env=env)
- encoding = get_best_encoding(c.stdin)
- try:
- for text in generator:
- if not color:
- text = strip_ansi(text)
-
- c.stdin.write(text.encode(encoding, 'replace'))
- except (IOError, KeyboardInterrupt):
- pass
- else:
- c.stdin.close()
-
- # Less doesn't respect ^C, but catches it for its own UI purposes (aborting
- # search or other commands inside less).
- #
- # That means when the user hits ^C, the parent process (click) terminates,
- # but less is still alive, paging the output and messing up the terminal.
- #
- # If the user wants to make the pager exit on ^C, they should set
- # `LESS='-K'`. It's not our decision to make.
- while True:
- try:
- c.wait()
- except KeyboardInterrupt:
- pass
- else:
- break
-
-
-def _tempfilepager(generator, cmd, color):
- """Page through text by invoking a program on a temporary file."""
- import tempfile
- filename = tempfile.mktemp()
- # TODO: This never terminates if the passed generator never terminates.
- text = "".join(generator)
- if not color:
- text = strip_ansi(text)
- encoding = get_best_encoding(sys.stdout)
- with open_stream(filename, 'wb')[0] as f:
- f.write(text.encode(encoding))
- try:
- os.system(cmd + ' "' + filename + '"')
- finally:
- os.unlink(filename)
-
-
-def _nullpager(stream, generator, color):
- """Simply print unformatted text. This is the ultimate fallback."""
- for text in generator:
- if not color:
- text = strip_ansi(text)
- stream.write(text)
-
-
-class Editor(object):
-
- def __init__(self, editor=None, env=None, require_save=True,
- extension='.txt'):
- self.editor = editor
- self.env = env
- self.require_save = require_save
- self.extension = extension
-
- def get_editor(self):
- if self.editor is not None:
- return self.editor
- for key in 'VISUAL', 'EDITOR':
- rv = os.environ.get(key)
- if rv:
- return rv
- if WIN:
- return 'notepad'
- for editor in 'vim', 'nano':
- if os.system('which %s >/dev/null 2>&1' % editor) == 0:
- return editor
- return 'vi'
-
- def edit_file(self, filename):
- import subprocess
- editor = self.get_editor()
- if self.env:
- environ = os.environ.copy()
- environ.update(self.env)
- else:
- environ = None
- try:
- c = subprocess.Popen('%s "%s"' % (editor, filename),
- env=environ, shell=True)
- exit_code = c.wait()
- if exit_code != 0:
- raise ClickException('%s: Editing failed!' % editor)
- except OSError as e:
- raise ClickException('%s: Editing failed: %s' % (editor, e))
-
- def edit(self, text):
- import tempfile
-
- text = text or ''
- if text and not text.endswith('\n'):
- text += '\n'
-
- fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension)
- try:
- if WIN:
- encoding = 'utf-8-sig'
- text = text.replace('\n', '\r\n')
- else:
- encoding = 'utf-8'
- text = text.encode(encoding)
-
- f = os.fdopen(fd, 'wb')
- f.write(text)
- f.close()
- timestamp = os.path.getmtime(name)
-
- self.edit_file(name)
-
- if self.require_save \
- and os.path.getmtime(name) == timestamp:
- return None
-
- f = open(name, 'rb')
- try:
- rv = f.read()
- finally:
- f.close()
- return rv.decode('utf-8-sig').replace('\r\n', '\n')
- finally:
- os.unlink(name)
-
-
-def open_url(url, wait=False, locate=False):
- import subprocess
-
- def _unquote_file(url):
- try:
- import urllib
- except ImportError:
- import urllib
- if url.startswith('file://'):
- url = urllib.unquote(url[7:])
- return url
-
- if sys.platform == 'darwin':
- args = ['open']
- if wait:
- args.append('-W')
- if locate:
- args.append('-R')
- args.append(_unquote_file(url))
- null = open('/dev/null', 'w')
- try:
- return subprocess.Popen(args, stderr=null).wait()
- finally:
- null.close()
- elif WIN:
- if locate:
- url = _unquote_file(url)
- args = 'explorer /select,"%s"' % _unquote_file(
- url.replace('"', ''))
- else:
- args = 'start %s "" "%s"' % (
- wait and '/WAIT' or '', url.replace('"', ''))
- return os.system(args)
- elif CYGWIN:
- if locate:
- url = _unquote_file(url)
- args = 'cygstart "%s"' % (os.path.dirname(url).replace('"', ''))
- else:
- args = 'cygstart %s "%s"' % (
- wait and '-w' or '', url.replace('"', ''))
- return os.system(args)
-
- try:
- if locate:
- url = os.path.dirname(_unquote_file(url)) or '.'
- else:
- url = _unquote_file(url)
- c = subprocess.Popen(['xdg-open', url])
- if wait:
- return c.wait()
- return 0
- except OSError:
- if url.startswith(('http://', 'https://')) and not locate and not wait:
- import webbrowser
- webbrowser.open(url)
- return 0
- return 1
-
-
-def _translate_ch_to_exc(ch):
- if ch == u'\x03':
- raise KeyboardInterrupt()
- if ch == u'\x04' and not WIN: # Unix-like, Ctrl+D
- raise EOFError()
- if ch == u'\x1a' and WIN: # Windows, Ctrl+Z
- raise EOFError()
-
-
-if WIN:
- import msvcrt
-
- @contextlib.contextmanager
- def raw_terminal():
- yield
-
- def getchar(echo):
- # The function `getch` will return a bytes object corresponding to
- # the pressed character. Since Windows 10 build 1803, it will also
- # return \x00 when called a second time after pressing a regular key.
- #
- # `getwch` does not share this probably-bugged behavior. Moreover, it
- # returns a Unicode object by default, which is what we want.
- #
- # Either of these functions will return \x00 or \xe0 to indicate
- # a special key, and you need to call the same function again to get
- # the "rest" of the code. The fun part is that \u00e0 is
- # "latin small letter a with grave", so if you type that on a French
- # keyboard, you _also_ get a \xe0.
- # E.g., consider the Up arrow. This returns \xe0 and then \x48. The
- # resulting Unicode string reads as "a with grave" + "capital H".
- # This is indistinguishable from when the user actually types
- # "a with grave" and then "capital H".
- #
- # When \xe0 is returned, we assume it's part of a special-key sequence
- # and call `getwch` again, but that means that when the user types
- # the \u00e0 character, `getchar` doesn't return until a second
- # character is typed.
- # The alternative is returning immediately, but that would mess up
- # cross-platform handling of arrow keys and others that start with
- # \xe0. Another option is using `getch`, but then we can't reliably
- # read non-ASCII characters, because return values of `getch` are
- # limited to the current 8-bit codepage.
- #
- # Anyway, Click doesn't claim to do this Right(tm), and using `getwch`
- # is doing the right thing in more situations than with `getch`.
- if echo:
- func = msvcrt.getwche
- else:
- func = msvcrt.getwch
-
- rv = func()
- if rv in (u'\x00', u'\xe0'):
- # \x00 and \xe0 are control characters that indicate special key,
- # see above.
- rv += func()
- _translate_ch_to_exc(rv)
- return rv
-else:
- import tty
- import termios
-
- @contextlib.contextmanager
- def raw_terminal():
- if not isatty(sys.stdin):
- f = open('/dev/tty')
- fd = f.fileno()
- else:
- fd = sys.stdin.fileno()
- f = None
- try:
- old_settings = termios.tcgetattr(fd)
- try:
- tty.setraw(fd)
- yield fd
- finally:
- termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
- sys.stdout.flush()
- if f is not None:
- f.close()
- except termios.error:
- pass
-
- def getchar(echo):
- with raw_terminal() as fd:
- ch = os.read(fd, 32)
- ch = ch.decode(get_best_encoding(sys.stdin), 'replace')
- if echo and isatty(sys.stdout):
- sys.stdout.write(ch)
- _translate_ch_to_exc(ch)
- return ch
diff --git a/python/click/_textwrap.py b/python/click/_textwrap.py
deleted file mode 100644
index 7e77603..0000000
--- a/python/click/_textwrap.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import textwrap
-from contextlib import contextmanager
-
-
-class TextWrapper(textwrap.TextWrapper):
-
- def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
- space_left = max(width - cur_len, 1)
-
- if self.break_long_words:
- last = reversed_chunks[-1]
- cut = last[:space_left]
- res = last[space_left:]
- cur_line.append(cut)
- reversed_chunks[-1] = res
- elif not cur_line:
- cur_line.append(reversed_chunks.pop())
-
- @contextmanager
- def extra_indent(self, indent):
- old_initial_indent = self.initial_indent
- old_subsequent_indent = self.subsequent_indent
- self.initial_indent += indent
- self.subsequent_indent += indent
- try:
- yield
- finally:
- self.initial_indent = old_initial_indent
- self.subsequent_indent = old_subsequent_indent
-
- def indent_only(self, text):
- rv = []
- for idx, line in enumerate(text.splitlines()):
- indent = self.initial_indent
- if idx > 0:
- indent = self.subsequent_indent
- rv.append(indent + line)
- return '\n'.join(rv)
diff --git a/python/click/_unicodefun.py b/python/click/_unicodefun.py
deleted file mode 100644
index 620edff..0000000
--- a/python/click/_unicodefun.py
+++ /dev/null
@@ -1,125 +0,0 @@
-import os
-import sys
-import codecs
-
-from ._compat import PY2
-
-
-# If someone wants to vendor click, we want to ensure the
-# correct package is discovered. Ideally we could use a
-# relative import here but unfortunately Python does not
-# support that.
-click = sys.modules[__name__.rsplit('.', 1)[0]]
-
-
-def _find_unicode_literals_frame():
- import __future__
- if not hasattr(sys, '_getframe'): # not all Python implementations have it
- return 0
- frm = sys._getframe(1)
- idx = 1
- while frm is not None:
- if frm.f_globals.get('__name__', '').startswith('click.'):
- frm = frm.f_back
- idx += 1
- elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag:
- return idx
- else:
- break
- return 0
-
-
-def _check_for_unicode_literals():
- if not __debug__:
- return
- if not PY2 or click.disable_unicode_literals_warning:
- return
- bad_frame = _find_unicode_literals_frame()
- if bad_frame <= 0:
- return
- from warnings import warn
- warn(Warning('Click detected the use of the unicode_literals '
- '__future__ import. This is heavily discouraged '
- 'because it can introduce subtle bugs in your '
- 'code. You should instead use explicit u"" literals '
- 'for your unicode strings. For more information see '
- 'https://click.palletsprojects.com/python3/'),
- stacklevel=bad_frame)
-
-
-def _verify_python3_env():
- """Ensures that the environment is good for unicode on Python 3."""
- if PY2:
- return
- try:
- import locale
- fs_enc = codecs.lookup(locale.getpreferredencoding()).name
- except Exception:
- fs_enc = 'ascii'
- if fs_enc != 'ascii':
- return
-
- extra = ''
- if os.name == 'posix':
- import subprocess
- try:
- rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()[0]
- except OSError:
- rv = b''
- good_locales = set()
- has_c_utf8 = False
-
- # Make sure we're operating on text here.
- if isinstance(rv, bytes):
- rv = rv.decode('ascii', 'replace')
-
- for line in rv.splitlines():
- locale = line.strip()
- if locale.lower().endswith(('.utf-8', '.utf8')):
- good_locales.add(locale)
- if locale.lower() in ('c.utf8', 'c.utf-8'):
- has_c_utf8 = True
-
- extra += '\n\n'
- if not good_locales:
- extra += (
- 'Additional information: on this system no suitable UTF-8\n'
- 'locales were discovered. This most likely requires resolving\n'
- 'by reconfiguring the locale system.'
- )
- elif has_c_utf8:
- extra += (
- 'This system supports the C.UTF-8 locale which is recommended.\n'
- 'You might be able to resolve your issue by exporting the\n'
- 'following environment variables:\n\n'
- ' export LC_ALL=C.UTF-8\n'
- ' export LANG=C.UTF-8'
- )
- else:
- extra += (
- 'This system lists a couple of UTF-8 supporting locales that\n'
- 'you can pick from. The following suitable locales were\n'
- 'discovered: %s'
- ) % ', '.join(sorted(good_locales))
-
- bad_locale = None
- for locale in os.environ.get('LC_ALL'), os.environ.get('LANG'):
- if locale and locale.lower().endswith(('.utf-8', '.utf8')):
- bad_locale = locale
- if locale is not None:
- break
- if bad_locale is not None:
- extra += (
- '\n\nClick discovered that you exported a UTF-8 locale\n'
- 'but the locale system could not pick up from it because\n'
- 'it does not exist. The exported locale is "%s" but it\n'
- 'is not supported'
- ) % bad_locale
-
- raise RuntimeError(
- 'Click will abort further execution because Python 3 was'
- ' configured to use ASCII as encoding for the environment.'
- ' Consult https://click.palletsprojects.com/en/7.x/python3/ for'
- ' mitigation steps.' + extra
- )
diff --git a/python/click/_winconsole.py b/python/click/_winconsole.py
deleted file mode 100644
index bbb080d..0000000
--- a/python/click/_winconsole.py
+++ /dev/null
@@ -1,307 +0,0 @@
-# -*- coding: utf-8 -*-
-# This module is based on the excellent work by Adam Bartoš who
-# provided a lot of what went into the implementation here in
-# the discussion to issue1602 in the Python bug tracker.
-#
-# There are some general differences in regards to how this works
-# compared to the original patches as we do not need to patch
-# the entire interpreter but just work in our little world of
-# echo and prmopt.
-
-import io
-import os
-import sys
-import zlib
-import time
-import ctypes
-import msvcrt
-from ._compat import _NonClosingTextIOWrapper, text_type, PY2
-from ctypes import byref, POINTER, c_int, c_char, c_char_p, \
- c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE
-try:
- from ctypes import pythonapi
- PyObject_GetBuffer = pythonapi.PyObject_GetBuffer
- PyBuffer_Release = pythonapi.PyBuffer_Release
-except ImportError:
- pythonapi = None
-from ctypes.wintypes import LPWSTR, LPCWSTR
-
-
-c_ssize_p = POINTER(c_ssize_t)
-
-kernel32 = windll.kernel32
-GetStdHandle = kernel32.GetStdHandle
-ReadConsoleW = kernel32.ReadConsoleW
-WriteConsoleW = kernel32.WriteConsoleW
-GetLastError = kernel32.GetLastError
-GetCommandLineW = WINFUNCTYPE(LPWSTR)(
- ('GetCommandLineW', windll.kernel32))
-CommandLineToArgvW = WINFUNCTYPE(
- POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(
- ('CommandLineToArgvW', windll.shell32))
-
-
-STDIN_HANDLE = GetStdHandle(-10)
-STDOUT_HANDLE = GetStdHandle(-11)
-STDERR_HANDLE = GetStdHandle(-12)
-
-
-PyBUF_SIMPLE = 0
-PyBUF_WRITABLE = 1
-
-ERROR_SUCCESS = 0
-ERROR_NOT_ENOUGH_MEMORY = 8
-ERROR_OPERATION_ABORTED = 995
-
-STDIN_FILENO = 0
-STDOUT_FILENO = 1
-STDERR_FILENO = 2
-
-EOF = b'\x1a'
-MAX_BYTES_WRITTEN = 32767
-
-
-class Py_buffer(ctypes.Structure):
- _fields_ = [
- ('buf', c_void_p),
- ('obj', py_object),
- ('len', c_ssize_t),
- ('itemsize', c_ssize_t),
- ('readonly', c_int),
- ('ndim', c_int),
- ('format', c_char_p),
- ('shape', c_ssize_p),
- ('strides', c_ssize_p),
- ('suboffsets', c_ssize_p),
- ('internal', c_void_p)
- ]
-
- if PY2:
- _fields_.insert(-1, ('smalltable', c_ssize_t * 2))
-
-
-# On PyPy we cannot get buffers so our ability to operate here is
-# serverly limited.
-if pythonapi is None:
- get_buffer = None
-else:
- def get_buffer(obj, writable=False):
- buf = Py_buffer()
- flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE
- PyObject_GetBuffer(py_object(obj), byref(buf), flags)
- try:
- buffer_type = c_char * buf.len
- return buffer_type.from_address(buf.buf)
- finally:
- PyBuffer_Release(byref(buf))
-
-
-class _WindowsConsoleRawIOBase(io.RawIOBase):
-
- def __init__(self, handle):
- self.handle = handle
-
- def isatty(self):
- io.RawIOBase.isatty(self)
- return True
-
-
-class _WindowsConsoleReader(_WindowsConsoleRawIOBase):
-
- def readable(self):
- return True
-
- def readinto(self, b):
- bytes_to_be_read = len(b)
- if not bytes_to_be_read:
- return 0
- elif bytes_to_be_read % 2:
- raise ValueError('cannot read odd number of bytes from '
- 'UTF-16-LE encoded console')
-
- buffer = get_buffer(b, writable=True)
- code_units_to_be_read = bytes_to_be_read // 2
- code_units_read = c_ulong()
-
- rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read,
- byref(code_units_read), None)
- if GetLastError() == ERROR_OPERATION_ABORTED:
- # wait for KeyboardInterrupt
- time.sleep(0.1)
- if not rv:
- raise OSError('Windows error: %s' % GetLastError())
-
- if buffer[0] == EOF:
- return 0
- return 2 * code_units_read.value
-
-
-class _WindowsConsoleWriter(_WindowsConsoleRawIOBase):
-
- def writable(self):
- return True
-
- @staticmethod
- def _get_error_message(errno):
- if errno == ERROR_SUCCESS:
- return 'ERROR_SUCCESS'
- elif errno == ERROR_NOT_ENOUGH_MEMORY:
- return 'ERROR_NOT_ENOUGH_MEMORY'
- return 'Windows error %s' % errno
-
- def write(self, b):
- bytes_to_be_written = len(b)
- buf = get_buffer(b)
- code_units_to_be_written = min(bytes_to_be_written,
- MAX_BYTES_WRITTEN) // 2
- code_units_written = c_ulong()
-
- WriteConsoleW(self.handle, buf, code_units_to_be_written,
- byref(code_units_written), None)
- bytes_written = 2 * code_units_written.value
-
- if bytes_written == 0 and bytes_to_be_written > 0:
- raise OSError(self._get_error_message(GetLastError()))
- return bytes_written
-
-
-class ConsoleStream(object):
-
- def __init__(self, text_stream, byte_stream):
- self._text_stream = text_stream
- self.buffer = byte_stream
-
- @property
- def name(self):
- return self.buffer.name
-
- def write(self, x):
- if isinstance(x, text_type):
- return self._text_stream.write(x)
- try:
- self.flush()
- except Exception:
- pass
- return self.buffer.write(x)
-
- def writelines(self, lines):
- for line in lines:
- self.write(line)
-
- def __getattr__(self, name):
- return getattr(self._text_stream, name)
-
- def isatty(self):
- return self.buffer.isatty()
-
- def __repr__(self):
- return '<ConsoleStream name=%r encoding=%r>' % (
- self.name,
- self.encoding,
- )
-
-
-class WindowsChunkedWriter(object):
- """
- Wraps a stream (such as stdout), acting as a transparent proxy for all
- attribute access apart from method 'write()' which we wrap to write in
- limited chunks due to a Windows limitation on binary console streams.
- """
- def __init__(self, wrapped):
- # double-underscore everything to prevent clashes with names of
- # attributes on the wrapped stream object.
- self.__wrapped = wrapped
-
- def __getattr__(self, name):
- return getattr(self.__wrapped, name)
-
- def write(self, text):
- total_to_write = len(text)
- written = 0
-
- while written < total_to_write:
- to_write = min(total_to_write - written, MAX_BYTES_WRITTEN)
- self.__wrapped.write(text[written:written+to_write])
- written += to_write
-
-
-_wrapped_std_streams = set()
-
-
-def _wrap_std_stream(name):
- # Python 2 & Windows 7 and below
- if PY2 and sys.getwindowsversion()[:2] <= (6, 1) and name not in _wrapped_std_streams:
- setattr(sys, name, WindowsChunkedWriter(getattr(sys, name)))
- _wrapped_std_streams.add(name)
-
-
-def _get_text_stdin(buffer_stream):
- text_stream = _NonClosingTextIOWrapper(
- io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)),
- 'utf-16-le', 'strict', line_buffering=True)
- return ConsoleStream(text_stream, buffer_stream)
-
-
-def _get_text_stdout(buffer_stream):
- text_stream = _NonClosingTextIOWrapper(
- io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)),
- 'utf-16-le', 'strict', line_buffering=True)
- return ConsoleStream(text_stream, buffer_stream)
-
-
-def _get_text_stderr(buffer_stream):
- text_stream = _NonClosingTextIOWrapper(
- io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)),
- 'utf-16-le', 'strict', line_buffering=True)
- return ConsoleStream(text_stream, buffer_stream)
-
-
-if PY2:
- def _hash_py_argv():
- return zlib.crc32('\x00'.join(sys.argv[1:]))
-
- _initial_argv_hash = _hash_py_argv()
-
- def _get_windows_argv():
- argc = c_int(0)
- argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
- argv = [argv_unicode[i] for i in range(0, argc.value)]
-
- if not hasattr(sys, 'frozen'):
- argv = argv[1:]
- while len(argv) > 0:
- arg = argv[0]
- if not arg.startswith('-') or arg == '-':
- break
- argv = argv[1:]
- if arg.startswith(('-c', '-m')):
- break
-
- return argv[1:]
-
-
-_stream_factories = {
- 0: _get_text_stdin,
- 1: _get_text_stdout,
- 2: _get_text_stderr,
-}
-
-
-def _get_windows_console_stream(f, encoding, errors):
- if get_buffer is not None and \
- encoding in ('utf-16-le', None) \
- and errors in ('strict', None) and \
- hasattr(f, 'isatty') and f.isatty():
- func = _stream_factories.get(f.fileno())
- if func is not None:
- if not PY2:
- f = getattr(f, 'buffer', None)
- if f is None:
- return None
- else:
- # If we are on Python 2 we need to set the stream that we
- # deal with to binary mode as otherwise the exercise if a
- # bit moot. The same problems apply as for
- # get_binary_stdin and friends from _compat.
- msvcrt.setmode(f.fileno(), os.O_BINARY)
- return func(f)
diff --git a/python/click/core.py b/python/click/core.py
deleted file mode 100644
index 7a1e342..0000000
--- a/python/click/core.py
+++ /dev/null
@@ -1,1856 +0,0 @@
-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
diff --git a/python/click/decorators.py b/python/click/decorators.py
deleted file mode 100644
index c57c530..0000000
--- a/python/click/decorators.py
+++ /dev/null
@@ -1,311 +0,0 @@
-import sys
-import inspect
-
-from functools import update_wrapper
-
-from ._compat import iteritems
-from ._unicodefun import _check_for_unicode_literals
-from .utils import echo
-from .globals import get_current_context
-
-
-def pass_context(f):
- """Marks a callback as wanting to receive the current context
- object as first argument.
- """
- def new_func(*args, **kwargs):
- return f(get_current_context(), *args, **kwargs)
- return update_wrapper(new_func, f)
-
-
-def pass_obj(f):
- """Similar to :func:`pass_context`, but only pass the object on the
- context onwards (:attr:`Context.obj`). This is useful if that object
- represents the state of a nested system.
- """
- def new_func(*args, **kwargs):
- return f(get_current_context().obj, *args, **kwargs)
- return update_wrapper(new_func, f)
-
-
-def make_pass_decorator(object_type, ensure=False):
- """Given an object type this creates a decorator that will work
- similar to :func:`pass_obj` but instead of passing the object of the
- current context, it will find the innermost context of type
- :func:`object_type`.
-
- This generates a decorator that works roughly like this::
-
- from functools import update_wrapper
-
- def decorator(f):
- @pass_context
- def new_func(ctx, *args, **kwargs):
- obj = ctx.find_object(object_type)
- return ctx.invoke(f, obj, *args, **kwargs)
- return update_wrapper(new_func, f)
- return decorator
-
- :param object_type: the type of the object to pass.
- :param ensure: if set to `True`, a new object will be created and
- remembered on the context if it's not there yet.
- """
- def decorator(f):
- def new_func(*args, **kwargs):
- ctx = get_current_context()
- if ensure:
- obj = ctx.ensure_object(object_type)
- else:
- obj = ctx.find_object(object_type)
- if obj is None:
- raise RuntimeError('Managed to invoke callback without a '
- 'context object of type %r existing'
- % object_type.__name__)
- return ctx.invoke(f, obj, *args, **kwargs)
- return update_wrapper(new_func, f)
- return decorator
-
-
-def _make_command(f, name, attrs, cls):
- if isinstance(f, Command):
- raise TypeError('Attempted to convert a callback into a '
- 'command twice.')
- try:
- params = f.__click_params__
- params.reverse()
- del f.__click_params__
- except AttributeError:
- params = []
- help = attrs.get('help')
- if help is None:
- help = inspect.getdoc(f)
- if isinstance(help, bytes):
- help = help.decode('utf-8')
- else:
- help = inspect.cleandoc(help)
- attrs['help'] = help
- _check_for_unicode_literals()
- return cls(name=name or f.__name__.lower().replace('_', '-'),
- callback=f, params=params, **attrs)
-
-
-def command(name=None, cls=None, **attrs):
- r"""Creates a new :class:`Command` and uses the decorated function as
- callback. This will also automatically attach all decorated
- :func:`option`\s and :func:`argument`\s as parameters to the command.
-
- The name of the command defaults to the name of the function. If you
- want to change that, you can pass the intended name as the first
- argument.
-
- All keyword arguments are forwarded to the underlying command class.
-
- Once decorated the function turns into a :class:`Command` instance
- that can be invoked as a command line utility or be attached to a
- command :class:`Group`.
-
- :param name: the name of the command. This defaults to the function
- name with underscores replaced by dashes.
- :param cls: the command class to instantiate. This defaults to
- :class:`Command`.
- """
- if cls is None:
- cls = Command
- def decorator(f):
- cmd = _make_command(f, name, attrs, cls)
- cmd.__doc__ = f.__doc__
- return cmd
- return decorator
-
-
-def group(name=None, **attrs):
- """Creates a new :class:`Group` with a function as callback. This
- works otherwise the same as :func:`command` just that the `cls`
- parameter is set to :class:`Group`.
- """
- attrs.setdefault('cls', Group)
- return command(name, **attrs)
-
-
-def _param_memo(f, param):
- if isinstance(f, Command):
- f.params.append(param)
- else:
- if not hasattr(f, '__click_params__'):
- f.__click_params__ = []
- f.__click_params__.append(param)
-
-
-def argument(*param_decls, **attrs):
- """Attaches an argument to the command. All positional arguments are
- passed as parameter declarations to :class:`Argument`; all keyword
- arguments are forwarded unchanged (except ``cls``).
- This is equivalent to creating an :class:`Argument` instance manually
- and attaching it to the :attr:`Command.params` list.
-
- :param cls: the argument class to instantiate. This defaults to
- :class:`Argument`.
- """
- def decorator(f):
- ArgumentClass = attrs.pop('cls', Argument)
- _param_memo(f, ArgumentClass(param_decls, **attrs))
- return f
- return decorator
-
-
-def option(*param_decls, **attrs):
- """Attaches an option to the command. All positional arguments are
- passed as parameter declarations to :class:`Option`; all keyword
- arguments are forwarded unchanged (except ``cls``).
- This is equivalent to creating an :class:`Option` instance manually
- and attaching it to the :attr:`Command.params` list.
-
- :param cls: the option class to instantiate. This defaults to
- :class:`Option`.
- """
- def decorator(f):
- # Issue 926, copy attrs, so pre-defined options can re-use the same cls=
- option_attrs = attrs.copy()
-
- if 'help' in option_attrs:
- option_attrs['help'] = inspect.cleandoc(option_attrs['help'])
- OptionClass = option_attrs.pop('cls', Option)
- _param_memo(f, OptionClass(param_decls, **option_attrs))
- return f
- return decorator
-
-
-def confirmation_option(*param_decls, **attrs):
- """Shortcut for confirmation prompts that can be ignored by passing
- ``--yes`` as parameter.
-
- This is equivalent to decorating a function with :func:`option` with
- the following parameters::
-
- def callback(ctx, param, value):
- if not value:
- ctx.abort()
-
- @click.command()
- @click.option('--yes', is_flag=True, callback=callback,
- expose_value=False, prompt='Do you want to continue?')
- def dropdb():
- pass
- """
- def decorator(f):
- def callback(ctx, param, value):
- if not value:
- ctx.abort()
- attrs.setdefault('is_flag', True)
- attrs.setdefault('callback', callback)
- attrs.setdefault('expose_value', False)
- attrs.setdefault('prompt', 'Do you want to continue?')
- attrs.setdefault('help', 'Confirm the action without prompting.')
- return option(*(param_decls or ('--yes',)), **attrs)(f)
- return decorator
-
-
-def password_option(*param_decls, **attrs):
- """Shortcut for password prompts.
-
- This is equivalent to decorating a function with :func:`option` with
- the following parameters::
-
- @click.command()
- @click.option('--password', prompt=True, confirmation_prompt=True,
- hide_input=True)
- def changeadmin(password):
- pass
- """
- def decorator(f):
- attrs.setdefault('prompt', True)
- attrs.setdefault('confirmation_prompt', True)
- attrs.setdefault('hide_input', True)
- return option(*(param_decls or ('--password',)), **attrs)(f)
- return decorator
-
-
-def version_option(version=None, *param_decls, **attrs):
- """Adds a ``--version`` option which immediately ends the program
- printing out the version number. This is implemented as an eager
- option that prints the version and exits the program in the callback.
-
- :param version: the version number to show. If not provided Click
- attempts an auto discovery via setuptools.
- :param prog_name: the name of the program (defaults to autodetection)
- :param message: custom message to show instead of the default
- (``'%(prog)s, version %(version)s'``)
- :param others: everything else is forwarded to :func:`option`.
- """
- if version is None:
- if hasattr(sys, '_getframe'):
- module = sys._getframe(1).f_globals.get('__name__')
- else:
- module = ''
-
- def decorator(f):
- prog_name = attrs.pop('prog_name', None)
- message = attrs.pop('message', '%(prog)s, version %(version)s')
-
- def callback(ctx, param, value):
- if not value or ctx.resilient_parsing:
- return
- prog = prog_name
- if prog is None:
- prog = ctx.find_root().info_name
- ver = version
- if ver is None:
- try:
- import pkg_resources
- except ImportError:
- pass
- else:
- for dist in pkg_resources.working_set:
- scripts = dist.get_entry_map().get('console_scripts') or {}
- for script_name, entry_point in iteritems(scripts):
- if entry_point.module_name == module:
- ver = dist.version
- break
- if ver is None:
- raise RuntimeError('Could not determine version')
- echo(message % {
- 'prog': prog,
- 'version': ver,
- }, color=ctx.color)
- ctx.exit()
-
- attrs.setdefault('is_flag', True)
- attrs.setdefault('expose_value', False)
- attrs.setdefault('is_eager', True)
- attrs.setdefault('help', 'Show the version and exit.')
- attrs['callback'] = callback
- return option(*(param_decls or ('--version',)), **attrs)(f)
- return decorator
-
-
-def help_option(*param_decls, **attrs):
- """Adds a ``--help`` option which immediately ends the program
- printing out the help page. This is usually unnecessary to add as
- this is added by default to all commands unless suppressed.
-
- Like :func:`version_option`, this is implemented as eager option that
- prints in the callback and exits.
-
- All arguments are forwarded to :func:`option`.
- """
- def decorator(f):
- def callback(ctx, param, value):
- if value and not ctx.resilient_parsing:
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
- attrs.setdefault('is_flag', True)
- attrs.setdefault('expose_value', False)
- attrs.setdefault('help', 'Show this message and exit.')
- attrs.setdefault('is_eager', True)
- attrs['callback'] = callback
- return option(*(param_decls or ('--help',)), **attrs)(f)
- return decorator
-
-
-# Circular dependencies between core and decorators
-from .core import Command, Group, Argument, Option
diff --git a/python/click/exceptions.py b/python/click/exceptions.py
deleted file mode 100644
index 6fa1765..0000000
--- a/python/click/exceptions.py
+++ /dev/null
@@ -1,235 +0,0 @@
-from ._compat import PY2, filename_to_ui, get_text_stderr
-from .utils import echo
-
-
-def _join_param_hints(param_hint):
- if isinstance(param_hint, (tuple, list)):
- return ' / '.join('"%s"' % x for x in param_hint)
- return param_hint
-
-
-class ClickException(Exception):
- """An exception that Click can handle and show to the user."""
-
- #: The exit code for this exception
- exit_code = 1
-
- def __init__(self, message):
- ctor_msg = message
- if PY2:
- if ctor_msg is not None:
- ctor_msg = ctor_msg.encode('utf-8')
- Exception.__init__(self, ctor_msg)
- self.message = message
-
- def format_message(self):
- return self.message
-
- def __str__(self):
- return self.message
-
- if PY2:
- __unicode__ = __str__
-
- def __str__(self):
- return self.message.encode('utf-8')
-
- def show(self, file=None):
- if file is None:
- file = get_text_stderr()
- echo('Error: %s' % self.format_message(), file=file)
-
-
-class UsageError(ClickException):
- """An internal exception that signals a usage error. This typically
- aborts any further handling.
-
- :param message: the error message to display.
- :param ctx: optionally the context that caused this error. Click will
- fill in the context automatically in some situations.
- """
- exit_code = 2
-
- def __init__(self, message, ctx=None):
- ClickException.__init__(self, message)
- self.ctx = ctx
- self.cmd = self.ctx and self.ctx.command or None
-
- def show(self, file=None):
- if file is None:
- file = get_text_stderr()
- color = None
- hint = ''
- if (self.cmd is not None and
- self.cmd.get_help_option(self.ctx) is not None):
- hint = ('Try "%s %s" for help.\n'
- % (self.ctx.command_path, self.ctx.help_option_names[0]))
- if self.ctx is not None:
- color = self.ctx.color
- echo(self.ctx.get_usage() + '\n%s' % hint, file=file, color=color)
- echo('Error: %s' % self.format_message(), file=file, color=color)
-
-
-class BadParameter(UsageError):
- """An exception that formats out a standardized error message for a
- bad parameter. This is useful when thrown from a callback or type as
- Click will attach contextual information to it (for instance, which
- parameter it is).
-
- .. versionadded:: 2.0
-
- :param param: the parameter object that caused this error. This can
- be left out, and Click will attach this info itself
- if possible.
- :param param_hint: a string that shows up as parameter name. This
- can be used as alternative to `param` in cases
- where custom validation should happen. If it is
- a string it's used as such, if it's a list then
- each item is quoted and separated.
- """
-
- def __init__(self, message, ctx=None, param=None,
- param_hint=None):
- UsageError.__init__(self, message, ctx)
- self.param = param
- self.param_hint = param_hint
-
- def format_message(self):
- if self.param_hint is not None:
- param_hint = self.param_hint
- elif self.param is not None:
- param_hint = self.param.get_error_hint(self.ctx)
- else:
- return 'Invalid value: %s' % self.message
- param_hint = _join_param_hints(param_hint)
-
- return 'Invalid value for %s: %s' % (param_hint, self.message)
-
-
-class MissingParameter(BadParameter):
- """Raised if click required an option or argument but it was not
- provided when invoking the script.
-
- .. versionadded:: 4.0
-
- :param param_type: a string that indicates the type of the parameter.
- The default is to inherit the parameter type from
- the given `param`. Valid values are ``'parameter'``,
- ``'option'`` or ``'argument'``.
- """
-
- def __init__(self, message=None, ctx=None, param=None,
- param_hint=None, param_type=None):
- BadParameter.__init__(self, message, ctx, param, param_hint)
- self.param_type = param_type
-
- def format_message(self):
- if self.param_hint is not None:
- param_hint = self.param_hint
- elif self.param is not None:
- param_hint = self.param.get_error_hint(self.ctx)
- else:
- param_hint = None
- param_hint = _join_param_hints(param_hint)
-
- param_type = self.param_type
- if param_type is None and self.param is not None:
- param_type = self.param.param_type_name
-
- msg = self.message
- if self.param is not None:
- msg_extra = self.param.type.get_missing_message(self.param)
- if msg_extra:
- if msg:
- msg += '. ' + msg_extra
- else:
- msg = msg_extra
-
- return 'Missing %s%s%s%s' % (
- param_type,
- param_hint and ' %s' % param_hint or '',
- msg and '. ' or '.',
- msg or '',
- )
-
-
-class NoSuchOption(UsageError):
- """Raised if click attempted to handle an option that does not
- exist.
-
- .. versionadded:: 4.0
- """
-
- def __init__(self, option_name, message=None, possibilities=None,
- ctx=None):
- if message is None:
- message = 'no such option: %s' % option_name
- UsageError.__init__(self, message, ctx)
- self.option_name = option_name
- self.possibilities = possibilities
-
- def format_message(self):
- bits = [self.message]
- if self.possibilities:
- if len(self.possibilities) == 1:
- bits.append('Did you mean %s?' % self.possibilities[0])
- else:
- possibilities = sorted(self.possibilities)
- bits.append('(Possible options: %s)' % ', '.join(possibilities))
- return ' '.join(bits)
-
-
-class BadOptionUsage(UsageError):
- """Raised if an option is generally supplied but the use of the option
- was incorrect. This is for instance raised if the number of arguments
- for an option is not correct.
-
- .. versionadded:: 4.0
-
- :param option_name: the name of the option being used incorrectly.
- """
-
- def __init__(self, option_name, message, ctx=None):
- UsageError.__init__(self, message, ctx)
- self.option_name = option_name
-
-
-class BadArgumentUsage(UsageError):
- """Raised if an argument is generally supplied but the use of the argument
- was incorrect. This is for instance raised if the number of values
- for an argument is not correct.
-
- .. versionadded:: 6.0
- """
-
- def __init__(self, message, ctx=None):
- UsageError.__init__(self, message, ctx)
-
-
-class FileError(ClickException):
- """Raised if a file cannot be opened."""
-
- def __init__(self, filename, hint=None):
- ui_filename = filename_to_ui(filename)
- if hint is None:
- hint = 'unknown error'
- ClickException.__init__(self, hint)
- self.ui_filename = ui_filename
- self.filename = filename
-
- def format_message(self):
- return 'Could not open file %s: %s' % (self.ui_filename, self.message)
-
-
-class Abort(RuntimeError):
- """An internal signalling exception that signals Click to abort."""
-
-
-class Exit(RuntimeError):
- """An exception that indicates that the application should exit with some
- status code.
-
- :param code: the status code to exit with.
- """
- def __init__(self, code=0):
- self.exit_code = code
diff --git a/python/click/formatting.py b/python/click/formatting.py
deleted file mode 100644
index a3d6a4d..0000000
--- a/python/click/formatting.py
+++ /dev/null
@@ -1,256 +0,0 @@
-from contextlib import contextmanager
-from .termui import get_terminal_size
-from .parser import split_opt
-from ._compat import term_len
-
-
-# Can force a width. This is used by the test system
-FORCED_WIDTH = None
-
-
-def measure_table(rows):
- widths = {}
- for row in rows:
- for idx, col in enumerate(row):
- widths[idx] = max(widths.get(idx, 0), term_len(col))
- return tuple(y for x, y in sorted(widths.items()))
-
-
-def iter_rows(rows, col_count):
- for row in rows:
- row = tuple(row)
- yield row + ('',) * (col_count - len(row))
-
-
-def wrap_text(text, width=78, initial_indent='', subsequent_indent='',
- preserve_paragraphs=False):
- """A helper function that intelligently wraps text. By default, it
- assumes that it operates on a single paragraph of text but if the
- `preserve_paragraphs` parameter is provided it will intelligently
- handle paragraphs (defined by two empty lines).
-
- If paragraphs are handled, a paragraph can be prefixed with an empty
- line containing the ``\\b`` character (``\\x08``) to indicate that
- no rewrapping should happen in that block.
-
- :param text: the text that should be rewrapped.
- :param width: the maximum width for the text.
- :param initial_indent: the initial indent that should be placed on the
- first line as a string.
- :param subsequent_indent: the indent string that should be placed on
- each consecutive line.
- :param preserve_paragraphs: if this flag is set then the wrapping will
- intelligently handle paragraphs.
- """
- from ._textwrap import TextWrapper
- text = text.expandtabs()
- wrapper = TextWrapper(width, initial_indent=initial_indent,
- subsequent_indent=subsequent_indent,
- replace_whitespace=False)
- if not preserve_paragraphs:
- return wrapper.fill(text)
-
- p = []
- buf = []
- indent = None
-
- def _flush_par():
- if not buf:
- return
- if buf[0].strip() == '\b':
- p.append((indent or 0, True, '\n'.join(buf[1:])))
- else:
- p.append((indent or 0, False, ' '.join(buf)))
- del buf[:]
-
- for line in text.splitlines():
- if not line:
- _flush_par()
- indent = None
- else:
- if indent is None:
- orig_len = term_len(line)
- line = line.lstrip()
- indent = orig_len - term_len(line)
- buf.append(line)
- _flush_par()
-
- rv = []
- for indent, raw, text in p:
- with wrapper.extra_indent(' ' * indent):
- if raw:
- rv.append(wrapper.indent_only(text))
- else:
- rv.append(wrapper.fill(text))
-
- return '\n\n'.join(rv)
-
-
-class HelpFormatter(object):
- """This class helps with formatting text-based help pages. It's
- usually just needed for very special internal cases, but it's also
- exposed so that developers can write their own fancy outputs.
-
- At present, it always writes into memory.
-
- :param indent_increment: the additional increment for each level.
- :param width: the width for the text. This defaults to the terminal
- width clamped to a maximum of 78.
- """
-
- def __init__(self, indent_increment=2, width=None, max_width=None):
- self.indent_increment = indent_increment
- if max_width is None:
- max_width = 80
- if width is None:
- width = FORCED_WIDTH
- if width is None:
- width = max(min(get_terminal_size()[0], max_width) - 2, 50)
- self.width = width
- self.current_indent = 0
- self.buffer = []
-
- def write(self, string):
- """Writes a unicode string into the internal buffer."""
- self.buffer.append(string)
-
- def indent(self):
- """Increases the indentation."""
- self.current_indent += self.indent_increment
-
- def dedent(self):
- """Decreases the indentation."""
- self.current_indent -= self.indent_increment
-
- def write_usage(self, prog, args='', prefix='Usage: '):
- """Writes a usage line into the buffer.
-
- :param prog: the program name.
- :param args: whitespace separated list of arguments.
- :param prefix: the prefix for the first line.
- """
- usage_prefix = '%*s%s ' % (self.current_indent, prefix, prog)
- text_width = self.width - self.current_indent
-
- if text_width >= (term_len(usage_prefix) + 20):
- # The arguments will fit to the right of the prefix.
- indent = ' ' * term_len(usage_prefix)
- self.write(wrap_text(args, text_width,
- initial_indent=usage_prefix,
- subsequent_indent=indent))
- else:
- # The prefix is too long, put the arguments on the next line.
- self.write(usage_prefix)
- self.write('\n')
- indent = ' ' * (max(self.current_indent, term_len(prefix)) + 4)
- self.write(wrap_text(args, text_width,
- initial_indent=indent,
- subsequent_indent=indent))
-
- self.write('\n')
-
- def write_heading(self, heading):
- """Writes a heading into the buffer."""
- self.write('%*s%s:\n' % (self.current_indent, '', heading))
-
- def write_paragraph(self):
- """Writes a paragraph into the buffer."""
- if self.buffer:
- self.write('\n')
-
- def write_text(self, text):
- """Writes re-indented text into the buffer. This rewraps and
- preserves paragraphs.
- """
- text_width = max(self.width - self.current_indent, 11)
- indent = ' ' * self.current_indent
- self.write(wrap_text(text, text_width,
- initial_indent=indent,
- subsequent_indent=indent,
- preserve_paragraphs=True))
- self.write('\n')
-
- def write_dl(self, rows, col_max=30, col_spacing=2):
- """Writes a definition list into the buffer. This is how options
- and commands are usually formatted.
-
- :param rows: a list of two item tuples for the terms and values.
- :param col_max: the maximum width of the first column.
- :param col_spacing: the number of spaces between the first and
- second column.
- """
- rows = list(rows)
- widths = measure_table(rows)
- if len(widths) != 2:
- raise TypeError('Expected two columns for definition list')
-
- first_col = min(widths[0], col_max) + col_spacing
-
- for first, second in iter_rows(rows, len(widths)):
- self.write('%*s%s' % (self.current_indent, '', first))
- if not second:
- self.write('\n')
- continue
- if term_len(first) <= first_col - col_spacing:
- self.write(' ' * (first_col - term_len(first)))
- else:
- self.write('\n')
- self.write(' ' * (first_col + self.current_indent))
-
- text_width = max(self.width - first_col - 2, 10)
- lines = iter(wrap_text(second, text_width).splitlines())
- if lines:
- self.write(next(lines) + '\n')
- for line in lines:
- self.write('%*s%s\n' % (
- first_col + self.current_indent, '', line))
- else:
- self.write('\n')
-
- @contextmanager
- def section(self, name):
- """Helpful context manager that writes a paragraph, a heading,
- and the indents.
-
- :param name: the section name that is written as heading.
- """
- self.write_paragraph()
- self.write_heading(name)
- self.indent()
- try:
- yield
- finally:
- self.dedent()
-
- @contextmanager
- def indentation(self):
- """A context manager that increases the indentation."""
- self.indent()
- try:
- yield
- finally:
- self.dedent()
-
- def getvalue(self):
- """Returns the buffer contents."""
- return ''.join(self.buffer)
-
-
-def join_options(options):
- """Given a list of option strings this joins them in the most appropriate
- way and returns them in the form ``(formatted_string,
- any_prefix_is_slash)`` where the second item in the tuple is a flag that
- indicates if any of the option prefixes was a slash.
- """
- rv = []
- any_prefix_is_slash = False
- for opt in options:
- prefix = split_opt(opt)[0]
- if prefix == '/':
- any_prefix_is_slash = True
- rv.append((len(prefix), opt))
-
- rv.sort(key=lambda x: x[0])
-
- rv = ', '.join(x[1] for x in rv)
- return rv, any_prefix_is_slash
diff --git a/python/click/globals.py b/python/click/globals.py
deleted file mode 100644
index 843b594..0000000
--- a/python/click/globals.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from threading import local
-
-
-_local = local()
-
-
-def get_current_context(silent=False):
- """Returns the current click context. This can be used as a way to
- access the current context object from anywhere. This is a more implicit
- alternative to the :func:`pass_context` decorator. This function is
- primarily useful for helpers such as :func:`echo` which might be
- interested in changing its behavior based on the current context.
-
- To push the current context, :meth:`Context.scope` can be used.
-
- .. versionadded:: 5.0
-
- :param silent: is set to `True` the return value is `None` if no context
- is available. The default behavior is to raise a
- :exc:`RuntimeError`.
- """
- try:
- return getattr(_local, 'stack')[-1]
- except (AttributeError, IndexError):
- if not silent:
- raise RuntimeError('There is no active click context.')
-
-
-def push_context(ctx):
- """Pushes a new context to the current stack."""
- _local.__dict__.setdefault('stack', []).append(ctx)
-
-
-def pop_context():
- """Removes the top level from the stack."""
- _local.stack.pop()
-
-
-def resolve_color_default(color=None):
- """"Internal helper to get the default value of the color flag. If a
- value is passed it's returned unchanged, otherwise it's looked up from
- the current context.
- """
- if color is not None:
- return color
- ctx = get_current_context(silent=True)
- if ctx is not None:
- return ctx.color
diff --git a/python/click/parser.py b/python/click/parser.py
deleted file mode 100644
index 1c3ae9c..0000000
--- a/python/click/parser.py
+++ /dev/null
@@ -1,427 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-click.parser
-~~~~~~~~~~~~
-
-This module started out as largely a copy paste from the stdlib's
-optparse module with the features removed that we do not need from
-optparse because we implement them in Click on a higher level (for
-instance type handling, help formatting and a lot more).
-
-The plan is to remove more and more from here over time.
-
-The reason this is a different module and not optparse from the stdlib
-is that there are differences in 2.x and 3.x about the error messages
-generated and optparse in the stdlib uses gettext for no good reason
-and might cause us issues.
-"""
-
-import re
-from collections import deque
-from .exceptions import UsageError, NoSuchOption, BadOptionUsage, \
- BadArgumentUsage
-
-
-def _unpack_args(args, nargs_spec):
- """Given an iterable of arguments and an iterable of nargs specifications,
- it returns a tuple with all the unpacked arguments at the first index
- and all remaining arguments as the second.
-
- The nargs specification is the number of arguments that should be consumed
- or `-1` to indicate that this position should eat up all the remainders.
-
- Missing items are filled with `None`.
- """
- args = deque(args)
- nargs_spec = deque(nargs_spec)
- rv = []
- spos = None
-
- def _fetch(c):
- try:
- if spos is None:
- return c.popleft()
- else:
- return c.pop()
- except IndexError:
- return None
-
- while nargs_spec:
- nargs = _fetch(nargs_spec)
- if nargs == 1:
- rv.append(_fetch(args))
- elif nargs > 1:
- x = [_fetch(args) for _ in range(nargs)]
- # If we're reversed, we're pulling in the arguments in reverse,
- # so we need to turn them around.
- if spos is not None:
- x.reverse()
- rv.append(tuple(x))
- elif nargs < 0:
- if spos is not None:
- raise TypeError('Cannot have two nargs < 0')
- spos = len(rv)
- rv.append(None)
-
- # spos is the position of the wildcard (star). If it's not `None`,
- # we fill it with the remainder.
- if spos is not None:
- rv[spos] = tuple(args)
- args = []
- rv[spos + 1:] = reversed(rv[spos + 1:])
-
- return tuple(rv), list(args)
-
-
-def _error_opt_args(nargs, opt):
- if nargs == 1:
- raise BadOptionUsage(opt, '%s option requires an argument' % opt)
- raise BadOptionUsage(opt, '%s option requires %d arguments' % (opt, nargs))
-
-
-def split_opt(opt):
- first = opt[:1]
- if first.isalnum():
- return '', opt
- if opt[1:2] == first:
- return opt[:2], opt[2:]
- return first, opt[1:]
-
-
-def normalize_opt(opt, ctx):
- if ctx is None or ctx.token_normalize_func is None:
- return opt
- prefix, opt = split_opt(opt)
- return prefix + ctx.token_normalize_func(opt)
-
-
-def split_arg_string(string):
- """Given an argument string this attempts to split it into small parts."""
- rv = []
- for match in re.finditer(r"('([^'\\]*(?:\\.[^'\\]*)*)'"
- r'|"([^"\\]*(?:\\.[^"\\]*)*)"'
- r'|\S+)\s*', string, re.S):
- arg = match.group().strip()
- if arg[:1] == arg[-1:] and arg[:1] in '"\'':
- arg = arg[1:-1].encode('ascii', 'backslashreplace') \
- .decode('unicode-escape')
- try:
- arg = type(string)(arg)
- except UnicodeError:
- pass
- rv.append(arg)
- return rv
-
-
-class Option(object):
-
- def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None):
- self._short_opts = []
- self._long_opts = []
- self.prefixes = set()
-
- for opt in opts:
- prefix, value = split_opt(opt)
- if not prefix:
- raise ValueError('Invalid start character for option (%s)'
- % opt)
- self.prefixes.add(prefix[0])
- if len(prefix) == 1 and len(value) == 1:
- self._short_opts.append(opt)
- else:
- self._long_opts.append(opt)
- self.prefixes.add(prefix)
-
- if action is None:
- action = 'store'
-
- self.dest = dest
- self.action = action
- self.nargs = nargs
- self.const = const
- self.obj = obj
-
- @property
- def takes_value(self):
- return self.action in ('store', 'append')
-
- def process(self, value, state):
- if self.action == 'store':
- state.opts[self.dest] = value
- elif self.action == 'store_const':
- state.opts[self.dest] = self.const
- elif self.action == 'append':
- state.opts.setdefault(self.dest, []).append(value)
- elif self.action == 'append_const':
- state.opts.setdefault(self.dest, []).append(self.const)
- elif self.action == 'count':
- state.opts[self.dest] = state.opts.get(self.dest, 0) + 1
- else:
- raise ValueError('unknown action %r' % self.action)
- state.order.append(self.obj)
-
-
-class Argument(object):
-
- def __init__(self, dest, nargs=1, obj=None):
- self.dest = dest
- self.nargs = nargs
- self.obj = obj
-
- def process(self, value, state):
- if self.nargs > 1:
- holes = sum(1 for x in value if x is None)
- if holes == len(value):
- value = None
- elif holes != 0:
- raise BadArgumentUsage('argument %s takes %d values'
- % (self.dest, self.nargs))
- state.opts[self.dest] = value
- state.order.append(self.obj)
-
-
-class ParsingState(object):
-
- def __init__(self, rargs):
- self.opts = {}
- self.largs = []
- self.rargs = rargs
- self.order = []
-
-
-class OptionParser(object):
- """The option parser is an internal class that is ultimately used to
- parse options and arguments. It's modelled after optparse and brings
- a similar but vastly simplified API. It should generally not be used
- directly as the high level Click classes wrap it for you.
-
- It's not nearly as extensible as optparse or argparse as it does not
- implement features that are implemented on a higher level (such as
- types or defaults).
-
- :param ctx: optionally the :class:`~click.Context` where this parser
- should go with.
- """
-
- def __init__(self, ctx=None):
- #: The :class:`~click.Context` for this parser. This might be
- #: `None` for some advanced use cases.
- self.ctx = ctx
- #: This controls how the parser deals with interspersed arguments.
- #: If this is set to `False`, the parser will stop on the first
- #: non-option. Click uses this to implement nested subcommands
- #: safely.
- self.allow_interspersed_args = True
- #: This tells the parser how to deal with unknown options. By
- #: default it will error out (which is sensible), but there is a
- #: second mode where it will ignore it and continue processing
- #: after shifting all the unknown options into the resulting args.
- self.ignore_unknown_options = False
- if ctx is not None:
- self.allow_interspersed_args = ctx.allow_interspersed_args
- self.ignore_unknown_options = ctx.ignore_unknown_options
- self._short_opt = {}
- self._long_opt = {}
- self._opt_prefixes = set(['-', '--'])
- self._args = []
-
- def add_option(self, opts, dest, action=None, nargs=1, const=None,
- obj=None):
- """Adds a new option named `dest` to the parser. The destination
- is not inferred (unlike with optparse) and needs to be explicitly
- provided. Action can be any of ``store``, ``store_const``,
- ``append``, ``appnd_const`` or ``count``.
-
- The `obj` can be used to identify the option in the order list
- that is returned from the parser.
- """
- if obj is None:
- obj = dest
- opts = [normalize_opt(opt, self.ctx) for opt in opts]
- option = Option(opts, dest, action=action, nargs=nargs,
- const=const, obj=obj)
- self._opt_prefixes.update(option.prefixes)
- for opt in option._short_opts:
- self._short_opt[opt] = option
- for opt in option._long_opts:
- self._long_opt[opt] = option
-
- def add_argument(self, dest, nargs=1, obj=None):
- """Adds a positional argument named `dest` to the parser.
-
- The `obj` can be used to identify the option in the order list
- that is returned from the parser.
- """
- if obj is None:
- obj = dest
- self._args.append(Argument(dest=dest, nargs=nargs, obj=obj))
-
- def parse_args(self, args):
- """Parses positional arguments and returns ``(values, args, order)``
- for the parsed options and arguments as well as the leftover
- arguments if there are any. The order is a list of objects as they
- appear on the command line. If arguments appear multiple times they
- will be memorized multiple times as well.
- """
- state = ParsingState(args)
- try:
- self._process_args_for_options(state)
- self._process_args_for_args(state)
- except UsageError:
- if self.ctx is None or not self.ctx.resilient_parsing:
- raise
- return state.opts, state.largs, state.order
-
- def _process_args_for_args(self, state):
- pargs, args = _unpack_args(state.largs + state.rargs,
- [x.nargs for x in self._args])
-
- for idx, arg in enumerate(self._args):
- arg.process(pargs[idx], state)
-
- state.largs = args
- state.rargs = []
-
- def _process_args_for_options(self, state):
- while state.rargs:
- arg = state.rargs.pop(0)
- arglen = len(arg)
- # Double dashes always handled explicitly regardless of what
- # prefixes are valid.
- if arg == '--':
- return
- elif arg[:1] in self._opt_prefixes and arglen > 1:
- self._process_opts(arg, state)
- elif self.allow_interspersed_args:
- state.largs.append(arg)
- else:
- state.rargs.insert(0, arg)
- return
-
- # Say this is the original argument list:
- # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
- # ^
- # (we are about to process arg(i)).
- #
- # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
- # [arg0, ..., arg(i-1)] (any options and their arguments will have
- # been removed from largs).
- #
- # The while loop will usually consume 1 or more arguments per pass.
- # If it consumes 1 (eg. arg is an option that takes no arguments),
- # then after _process_arg() is done the situation is:
- #
- # largs = subset of [arg0, ..., arg(i)]
- # rargs = [arg(i+1), ..., arg(N-1)]
- #
- # If allow_interspersed_args is false, largs will always be
- # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
- # not a very interesting subset!
-
- def _match_long_opt(self, opt, explicit_value, state):
- if opt not in self._long_opt:
- possibilities = [word for word in self._long_opt
- if word.startswith(opt)]
- raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx)
-
- option = self._long_opt[opt]
- if option.takes_value:
- # At this point it's safe to modify rargs by injecting the
- # explicit value, because no exception is raised in this
- # branch. This means that the inserted value will be fully
- # consumed.
- if explicit_value is not None:
- state.rargs.insert(0, explicit_value)
-
- nargs = option.nargs
- if len(state.rargs) < nargs:
- _error_opt_args(nargs, opt)
- elif nargs == 1:
- value = state.rargs.pop(0)
- else:
- value = tuple(state.rargs[:nargs])
- del state.rargs[:nargs]
-
- elif explicit_value is not None:
- raise BadOptionUsage(opt, '%s option does not take a value' % opt)
-
- else:
- value = None
-
- option.process(value, state)
-
- def _match_short_opt(self, arg, state):
- stop = False
- i = 1
- prefix = arg[0]
- unknown_options = []
-
- for ch in arg[1:]:
- opt = normalize_opt(prefix + ch, self.ctx)
- option = self._short_opt.get(opt)
- i += 1
-
- if not option:
- if self.ignore_unknown_options:
- unknown_options.append(ch)
- continue
- raise NoSuchOption(opt, ctx=self.ctx)
- if option.takes_value:
- # Any characters left in arg? Pretend they're the
- # next arg, and stop consuming characters of arg.
- if i < len(arg):
- state.rargs.insert(0, arg[i:])
- stop = True
-
- nargs = option.nargs
- if len(state.rargs) < nargs:
- _error_opt_args(nargs, opt)
- elif nargs == 1:
- value = state.rargs.pop(0)
- else:
- value = tuple(state.rargs[:nargs])
- del state.rargs[:nargs]
-
- else:
- value = None
-
- option.process(value, state)
-
- if stop:
- break
-
- # If we got any unknown options we re-combinate the string of the
- # remaining options and re-attach the prefix, then report that
- # to the state as new larg. This way there is basic combinatorics
- # that can be achieved while still ignoring unknown arguments.
- if self.ignore_unknown_options and unknown_options:
- state.largs.append(prefix + ''.join(unknown_options))
-
- def _process_opts(self, arg, state):
- explicit_value = None
- # Long option handling happens in two parts. The first part is
- # supporting explicitly attached values. In any case, we will try
- # to long match the option first.
- if '=' in arg:
- long_opt, explicit_value = arg.split('=', 1)
- else:
- long_opt = arg
- norm_long_opt = normalize_opt(long_opt, self.ctx)
-
- # At this point we will match the (assumed) long option through
- # the long option matching code. Note that this allows options
- # like "-foo" to be matched as long options.
- try:
- self._match_long_opt(norm_long_opt, explicit_value, state)
- except NoSuchOption:
- # At this point the long option matching failed, and we need
- # to try with short options. However there is a special rule
- # which says, that if we have a two character options prefix
- # (applies to "--foo" for instance), we do not dispatch to the
- # short option code and will instead raise the no option
- # error.
- if arg[:2] not in self._opt_prefixes:
- return self._match_short_opt(arg, state)
- if not self.ignore_unknown_options:
- raise
- state.largs.append(arg)
diff --git a/python/click/termui.py b/python/click/termui.py
deleted file mode 100644
index bf9a3aa..0000000
--- a/python/click/termui.py
+++ /dev/null
@@ -1,606 +0,0 @@
-import os
-import sys
-import struct
-import inspect
-import itertools
-
-from ._compat import raw_input, text_type, string_types, \
- isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN
-from .utils import echo
-from .exceptions import Abort, UsageError
-from .types import convert_type, Choice, Path
-from .globals import resolve_color_default
-
-
-# The prompt functions to use. The doc tools currently override these
-# functions to customize how they work.
-visible_prompt_func = raw_input
-
-_ansi_colors = {
- 'black': 30,
- 'red': 31,
- 'green': 32,
- 'yellow': 33,
- 'blue': 34,
- 'magenta': 35,
- 'cyan': 36,
- 'white': 37,
- 'reset': 39,
- 'bright_black': 90,
- 'bright_red': 91,
- 'bright_green': 92,
- 'bright_yellow': 93,
- 'bright_blue': 94,
- 'bright_magenta': 95,
- 'bright_cyan': 96,
- 'bright_white': 97,
-}
-_ansi_reset_all = '\033[0m'
-
-
-def hidden_prompt_func(prompt):
- import getpass
- return getpass.getpass(prompt)
-
-
-def _build_prompt(text, suffix, show_default=False, default=None, show_choices=True, type=None):
- prompt = text
- if type is not None and show_choices and isinstance(type, Choice):
- prompt += ' (' + ", ".join(map(str, type.choices)) + ')'
- if default is not None and show_default:
- prompt = '%s [%s]' % (prompt, default)
- return prompt + suffix
-
-
-def prompt(text, default=None, hide_input=False, confirmation_prompt=False,
- type=None, value_proc=None, prompt_suffix=': ', show_default=True,
- err=False, show_choices=True):
- """Prompts a user for input. This is a convenience function that can
- be used to prompt a user for input later.
-
- If the user aborts the input by sending a interrupt signal, this
- function will catch it and raise a :exc:`Abort` exception.
-
- .. versionadded:: 7.0
- Added the show_choices parameter.
-
- .. versionadded:: 6.0
- Added unicode support for cmd.exe on Windows.
-
- .. versionadded:: 4.0
- Added the `err` parameter.
-
- :param text: the text to show for the prompt.
- :param default: the default value to use if no input happens. If this
- is not given it will prompt until it's aborted.
- :param hide_input: if this is set to true then the input value will
- be hidden.
- :param confirmation_prompt: asks for confirmation for the value.
- :param type: the type to use to check the value against.
- :param value_proc: if this parameter is provided it's a function that
- is invoked instead of the type conversion to
- convert a value.
- :param prompt_suffix: a suffix that should be added to the prompt.
- :param show_default: shows or hides the default value in the prompt.
- :param err: if set to true the file defaults to ``stderr`` instead of
- ``stdout``, the same as with echo.
- :param show_choices: Show or hide choices if the passed type is a Choice.
- For example if type is a Choice of either day or week,
- show_choices is true and text is "Group by" then the
- prompt will be "Group by (day, week): ".
- """
- result = None
-
- def prompt_func(text):
- f = hide_input and hidden_prompt_func or visible_prompt_func
- try:
- # Write the prompt separately so that we get nice
- # coloring through colorama on Windows
- echo(text, nl=False, err=err)
- return f('')
- except (KeyboardInterrupt, EOFError):
- # getpass doesn't print a newline if the user aborts input with ^C.
- # Allegedly this behavior is inherited from getpass(3).
- # A doc bug has been filed at https://bugs.python.org/issue24711
- if hide_input:
- echo(None, err=err)
- raise Abort()
-
- if value_proc is None:
- value_proc = convert_type(type, default)
-
- prompt = _build_prompt(text, prompt_suffix, show_default, default, show_choices, type)
-
- while 1:
- while 1:
- value = prompt_func(prompt)
- if value:
- break
- elif default is not None:
- if isinstance(value_proc, Path):
- # validate Path default value(exists, dir_okay etc.)
- value = default
- break
- return default
- try:
- result = value_proc(value)
- except UsageError as e:
- echo('Error: %s' % e.message, err=err)
- continue
- if not confirmation_prompt:
- return result
- while 1:
- value2 = prompt_func('Repeat for confirmation: ')
- if value2:
- break
- if value == value2:
- return result
- echo('Error: the two entered values do not match', err=err)
-
-
-def confirm(text, default=False, abort=False, prompt_suffix=': ',
- show_default=True, err=False):
- """Prompts for confirmation (yes/no question).
-
- If the user aborts the input by sending a interrupt signal this
- function will catch it and raise a :exc:`Abort` exception.
-
- .. versionadded:: 4.0
- Added the `err` parameter.
-
- :param text: the question to ask.
- :param default: the default for the prompt.
- :param abort: if this is set to `True` a negative answer aborts the
- exception by raising :exc:`Abort`.
- :param prompt_suffix: a suffix that should be added to the prompt.
- :param show_default: shows or hides the default value in the prompt.
- :param err: if set to true the file defaults to ``stderr`` instead of
- ``stdout``, the same as with echo.
- """
- prompt = _build_prompt(text, prompt_suffix, show_default,
- default and 'Y/n' or 'y/N')
- while 1:
- try:
- # Write the prompt separately so that we get nice
- # coloring through colorama on Windows
- echo(prompt, nl=False, err=err)
- value = visible_prompt_func('').lower().strip()
- except (KeyboardInterrupt, EOFError):
- raise Abort()
- if value in ('y', 'yes'):
- rv = True
- elif value in ('n', 'no'):
- rv = False
- elif value == '':
- rv = default
- else:
- echo('Error: invalid input', err=err)
- continue
- break
- if abort and not rv:
- raise Abort()
- return rv
-
-
-def get_terminal_size():
- """Returns the current size of the terminal as tuple in the form
- ``(width, height)`` in columns and rows.
- """
- # If shutil has get_terminal_size() (Python 3.3 and later) use that
- if sys.version_info >= (3, 3):
- import shutil
- shutil_get_terminal_size = getattr(shutil, 'get_terminal_size', None)
- if shutil_get_terminal_size:
- sz = shutil_get_terminal_size()
- return sz.columns, sz.lines
-
- # We provide a sensible default for get_winterm_size() when being invoked
- # inside a subprocess. Without this, it would not provide a useful input.
- if get_winterm_size is not None:
- size = get_winterm_size()
- if size == (0, 0):
- return (79, 24)
- else:
- return size
-
- def ioctl_gwinsz(fd):
- try:
- import fcntl
- import termios
- cr = struct.unpack(
- 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
- except Exception:
- return
- return cr
-
- cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2)
- if not cr:
- try:
- fd = os.open(os.ctermid(), os.O_RDONLY)
- try:
- cr = ioctl_gwinsz(fd)
- finally:
- os.close(fd)
- except Exception:
- pass
- if not cr or not cr[0] or not cr[1]:
- cr = (os.environ.get('LINES', 25),
- os.environ.get('COLUMNS', DEFAULT_COLUMNS))
- return int(cr[1]), int(cr[0])
-
-
-def echo_via_pager(text_or_generator, color=None):
- """This function takes a text and shows it via an environment specific
- pager on stdout.
-
- .. versionchanged:: 3.0
- Added the `color` flag.
-
- :param text_or_generator: the text to page, or alternatively, a
- generator emitting the text to page.
- :param color: controls if the pager supports ANSI colors or not. The
- default is autodetection.
- """
- color = resolve_color_default(color)
-
- if inspect.isgeneratorfunction(text_or_generator):
- i = text_or_generator()
- elif isinstance(text_or_generator, string_types):
- i = [text_or_generator]
- else:
- i = iter(text_or_generator)
-
- # convert every element of i to a text type if necessary
- text_generator = (el if isinstance(el, string_types) else text_type(el)
- for el in i)
-
- from ._termui_impl import pager
- return pager(itertools.chain(text_generator, "\n"), color)
-
-
-def progressbar(iterable=None, length=None, label=None, show_eta=True,
- show_percent=None, show_pos=False,
- item_show_func=None, fill_char='#', empty_char='-',
- bar_template='%(label)s [%(bar)s] %(info)s',
- info_sep=' ', width=36, file=None, color=None):
- """This function creates an iterable context manager that can be used
- to iterate over something while showing a progress bar. It will
- either iterate over the `iterable` or `length` items (that are counted
- up). While iteration happens, this function will print a rendered
- progress bar to the given `file` (defaults to stdout) and will attempt
- to calculate remaining time and more. By default, this progress bar
- will not be rendered if the file is not a terminal.
-
- The context manager creates the progress bar. When the context
- manager is entered the progress bar is already displayed. With every
- iteration over the progress bar, the iterable passed to the bar is
- advanced and the bar is updated. When the context manager exits,
- a newline is printed and the progress bar is finalized on screen.
-
- No printing must happen or the progress bar will be unintentionally
- destroyed.
-
- Example usage::
-
- with progressbar(items) as bar:
- for item in bar:
- do_something_with(item)
-
- Alternatively, if no iterable is specified, one can manually update the
- progress bar through the `update()` method instead of directly
- iterating over the progress bar. The update method accepts the number
- of steps to increment the bar with::
-
- with progressbar(length=chunks.total_bytes) as bar:
- for chunk in chunks:
- process_chunk(chunk)
- bar.update(chunks.bytes)
-
- .. versionadded:: 2.0
-
- .. versionadded:: 4.0
- Added the `color` parameter. Added a `update` method to the
- progressbar object.
-
- :param iterable: an iterable to iterate over. If not provided the length
- is required.
- :param length: the number of items to iterate over. By default the
- progressbar will attempt to ask the iterator about its
- length, which might or might not work. If an iterable is
- also provided this parameter can be used to override the
- length. If an iterable is not provided the progress bar
- will iterate over a range of that length.
- :param label: the label to show next to the progress bar.
- :param show_eta: enables or disables the estimated time display. This is
- automatically disabled if the length cannot be
- determined.
- :param show_percent: enables or disables the percentage display. The
- default is `True` if the iterable has a length or
- `False` if not.
- :param show_pos: enables or disables the absolute position display. The
- default is `False`.
- :param item_show_func: a function called with the current item which
- can return a string to show the current item
- next to the progress bar. Note that the current
- item can be `None`!
- :param fill_char: the character to use to show the filled part of the
- progress bar.
- :param empty_char: the character to use to show the non-filled part of
- the progress bar.
- :param bar_template: the format string to use as template for the bar.
- The parameters in it are ``label`` for the label,
- ``bar`` for the progress bar and ``info`` for the
- info section.
- :param info_sep: the separator between multiple info items (eta etc.)
- :param width: the width of the progress bar in characters, 0 means full
- terminal width
- :param file: the file to write to. If this is not a terminal then
- only the label is printed.
- :param color: controls if the terminal supports ANSI colors or not. The
- default is autodetection. This is only needed if ANSI
- codes are included anywhere in the progress bar output
- which is not the case by default.
- """
- from ._termui_impl import ProgressBar
- color = resolve_color_default(color)
- return ProgressBar(iterable=iterable, length=length, show_eta=show_eta,
- show_percent=show_percent, show_pos=show_pos,
- item_show_func=item_show_func, fill_char=fill_char,
- empty_char=empty_char, bar_template=bar_template,
- info_sep=info_sep, file=file, label=label,
- width=width, color=color)
-
-
-def clear():
- """Clears the terminal screen. This will have the effect of clearing
- the whole visible space of the terminal and moving the cursor to the
- top left. This does not do anything if not connected to a terminal.
-
- .. versionadded:: 2.0
- """
- if not isatty(sys.stdout):
- return
- # If we're on Windows and we don't have colorama available, then we
- # clear the screen by shelling out. Otherwise we can use an escape
- # sequence.
- if WIN:
- os.system('cls')
- else:
- sys.stdout.write('\033[2J\033[1;1H')
-
-
-def style(text, fg=None, bg=None, bold=None, dim=None, underline=None,
- blink=None, reverse=None, reset=True):
- """Styles a text with ANSI styles and returns the new string. By
- default the styling is self contained which means that at the end
- of the string a reset code is issued. This can be prevented by
- passing ``reset=False``.
-
- Examples::
-
- click.echo(click.style('Hello World!', fg='green'))
- click.echo(click.style('ATTENTION!', blink=True))
- click.echo(click.style('Some things', reverse=True, fg='cyan'))
-
- Supported color names:
-
- * ``black`` (might be a gray)
- * ``red``
- * ``green``
- * ``yellow`` (might be an orange)
- * ``blue``
- * ``magenta``
- * ``cyan``
- * ``white`` (might be light gray)
- * ``bright_black``
- * ``bright_red``
- * ``bright_green``
- * ``bright_yellow``
- * ``bright_blue``
- * ``bright_magenta``
- * ``bright_cyan``
- * ``bright_white``
- * ``reset`` (reset the color code only)
-
- .. versionadded:: 2.0
-
- .. versionadded:: 7.0
- Added support for bright colors.
-
- :param text: the string to style with ansi codes.
- :param fg: if provided this will become the foreground color.
- :param bg: if provided this will become the background color.
- :param bold: if provided this will enable or disable bold mode.
- :param dim: if provided this will enable or disable dim mode. This is
- badly supported.
- :param underline: if provided this will enable or disable underline.
- :param blink: if provided this will enable or disable blinking.
- :param reverse: if provided this will enable or disable inverse
- rendering (foreground becomes background and the
- other way round).
- :param reset: by default a reset-all code is added at the end of the
- string which means that styles do not carry over. This
- can be disabled to compose styles.
- """
- bits = []
- if fg:
- try:
- bits.append('\033[%dm' % (_ansi_colors[fg]))
- except KeyError:
- raise TypeError('Unknown color %r' % fg)
- if bg:
- try:
- bits.append('\033[%dm' % (_ansi_colors[bg] + 10))
- except KeyError:
- raise TypeError('Unknown color %r' % bg)
- if bold is not None:
- bits.append('\033[%dm' % (1 if bold else 22))
- if dim is not None:
- bits.append('\033[%dm' % (2 if dim else 22))
- if underline is not None:
- bits.append('\033[%dm' % (4 if underline else 24))
- if blink is not None:
- bits.append('\033[%dm' % (5 if blink else 25))
- if reverse is not None:
- bits.append('\033[%dm' % (7 if reverse else 27))
- bits.append(text)
- if reset:
- bits.append(_ansi_reset_all)
- return ''.join(bits)
-
-
-def unstyle(text):
- """Removes ANSI styling information from a string. Usually it's not
- necessary to use this function as Click's echo function will
- automatically remove styling if necessary.
-
- .. versionadded:: 2.0
-
- :param text: the text to remove style information from.
- """
- return strip_ansi(text)
-
-
-def secho(message=None, file=None, nl=True, err=False, color=None, **styles):
- """This function combines :func:`echo` and :func:`style` into one
- call. As such the following two calls are the same::
-
- click.secho('Hello World!', fg='green')
- click.echo(click.style('Hello World!', fg='green'))
-
- All keyword arguments are forwarded to the underlying functions
- depending on which one they go with.
-
- .. versionadded:: 2.0
- """
- if message is not None:
- message = style(message, **styles)
- return echo(message, file=file, nl=nl, err=err, color=color)
-
-
-def edit(text=None, editor=None, env=None, require_save=True,
- extension='.txt', filename=None):
- r"""Edits the given text in the defined editor. If an editor is given
- (should be the full path to the executable but the regular operating
- system search path is used for finding the executable) it overrides
- the detected editor. Optionally, some environment variables can be
- used. If the editor is closed without changes, `None` is returned. In
- case a file is edited directly the return value is always `None` and
- `require_save` and `extension` are ignored.
-
- If the editor cannot be opened a :exc:`UsageError` is raised.
-
- Note for Windows: to simplify cross-platform usage, the newlines are
- automatically converted from POSIX to Windows and vice versa. As such,
- the message here will have ``\n`` as newline markers.
-
- :param text: the text to edit.
- :param editor: optionally the editor to use. Defaults to automatic
- detection.
- :param env: environment variables to forward to the editor.
- :param require_save: if this is true, then not saving in the editor
- will make the return value become `None`.
- :param extension: the extension to tell the editor about. This defaults
- to `.txt` but changing this might change syntax
- highlighting.
- :param filename: if provided it will edit this file instead of the
- provided text contents. It will not use a temporary
- file as an indirection in that case.
- """
- from ._termui_impl import Editor
- editor = Editor(editor=editor, env=env, require_save=require_save,
- extension=extension)
- if filename is None:
- return editor.edit(text)
- editor.edit_file(filename)
-
-
-def launch(url, wait=False, locate=False):
- """This function launches the given URL (or filename) in the default
- viewer application for this file type. If this is an executable, it
- might launch the executable in a new session. The return value is
- the exit code of the launched application. Usually, ``0`` indicates
- success.
-
- Examples::
-
- click.launch('https://click.palletsprojects.com/')
- click.launch('/my/downloaded/file', locate=True)
-
- .. versionadded:: 2.0
-
- :param url: URL or filename of the thing to launch.
- :param wait: waits for the program to stop.
- :param locate: if this is set to `True` then instead of launching the
- application associated with the URL it will attempt to
- launch a file manager with the file located. This
- might have weird effects if the URL does not point to
- the filesystem.
- """
- from ._termui_impl import open_url
- return open_url(url, wait=wait, locate=locate)
-
-
-# If this is provided, getchar() calls into this instead. This is used
-# for unittesting purposes.
-_getchar = None
-
-
-def getchar(echo=False):
- """Fetches a single character from the terminal and returns it. This
- will always return a unicode character and under certain rare
- circumstances this might return more than one character. The
- situations which more than one character is returned is when for
- whatever reason multiple characters end up in the terminal buffer or
- standard input was not actually a terminal.
-
- Note that this will always read from the terminal, even if something
- is piped into the standard input.
-
- Note for Windows: in rare cases when typing non-ASCII characters, this
- function might wait for a second character and then return both at once.
- This is because certain Unicode characters look like special-key markers.
-
- .. versionadded:: 2.0
-
- :param echo: if set to `True`, the character read will also show up on
- the terminal. The default is to not show it.
- """
- f = _getchar
- if f is None:
- from ._termui_impl import getchar as f
- return f(echo)
-
-
-def raw_terminal():
- from ._termui_impl import raw_terminal as f
- return f()
-
-
-def pause(info='Press any key to continue ...', err=False):
- """This command stops execution and waits for the user to press any
- key to continue. This is similar to the Windows batch "pause"
- command. If the program is not run through a terminal, this command
- will instead do nothing.
-
- .. versionadded:: 2.0
-
- .. versionadded:: 4.0
- Added the `err` parameter.
-
- :param info: the info string to print before pausing.
- :param err: if set to message goes to ``stderr`` instead of
- ``stdout``, the same as with echo.
- """
- if not isatty(sys.stdin) or not isatty(sys.stdout):
- return
- try:
- if info:
- echo(info, nl=False, err=err)
- try:
- getchar()
- except (KeyboardInterrupt, EOFError):
- pass
- finally:
- if info:
- echo(err=err)
diff --git a/python/click/testing.py b/python/click/testing.py
deleted file mode 100644
index 1b2924e..0000000
--- a/python/click/testing.py
+++ /dev/null
@@ -1,374 +0,0 @@
-import os
-import sys
-import shutil
-import tempfile
-import contextlib
-import shlex
-
-from ._compat import iteritems, PY2, string_types
-
-
-# If someone wants to vendor click, we want to ensure the
-# correct package is discovered. Ideally we could use a
-# relative import here but unfortunately Python does not
-# support that.
-clickpkg = sys.modules[__name__.rsplit('.', 1)[0]]
-
-
-if PY2:
- from cStringIO import StringIO
-else:
- import io
- from ._compat import _find_binary_reader
-
-
-class EchoingStdin(object):
-
- def __init__(self, input, output):
- self._input = input
- self._output = output
-
- def __getattr__(self, x):
- return getattr(self._input, x)
-
- def _echo(self, rv):
- self._output.write(rv)
- return rv
-
- def read(self, n=-1):
- return self._echo(self._input.read(n))
-
- def readline(self, n=-1):
- return self._echo(self._input.readline(n))
-
- def readlines(self):
- return [self._echo(x) for x in self._input.readlines()]
-
- def __iter__(self):
- return iter(self._echo(x) for x in self._input)
-
- def __repr__(self):
- return repr(self._input)
-
-
-def make_input_stream(input, charset):
- # Is already an input stream.
- if hasattr(input, 'read'):
- if PY2:
- return input
- rv = _find_binary_reader(input)
- if rv is not None:
- return rv
- raise TypeError('Could not find binary reader for input stream.')
-
- if input is None:
- input = b''
- elif not isinstance(input, bytes):
- input = input.encode(charset)
- if PY2:
- return StringIO(input)
- return io.BytesIO(input)
-
-
-class Result(object):
- """Holds the captured result of an invoked CLI script."""
-
- def __init__(self, runner, stdout_bytes, stderr_bytes, exit_code,
- exception, exc_info=None):
- #: The runner that created the result
- self.runner = runner
- #: The standard output as bytes.
- self.stdout_bytes = stdout_bytes
- #: The standard error as bytes, or False(y) if not available
- self.stderr_bytes = stderr_bytes
- #: The exit code as integer.
- self.exit_code = exit_code
- #: The exception that happened if one did.
- self.exception = exception
- #: The traceback
- self.exc_info = exc_info
-
- @property
- def output(self):
- """The (standard) output as unicode string."""
- return self.stdout
-
- @property
- def stdout(self):
- """The standard output as unicode string."""
- return self.stdout_bytes.decode(self.runner.charset, 'replace') \
- .replace('\r\n', '\n')
-
- @property
- def stderr(self):
- """The standard error as unicode string."""
- if not self.stderr_bytes:
- raise ValueError("stderr not separately captured")
- return self.stderr_bytes.decode(self.runner.charset, 'replace') \
- .replace('\r\n', '\n')
-
-
- def __repr__(self):
- return '<%s %s>' % (
- type(self).__name__,
- self.exception and repr(self.exception) or 'okay',
- )
-
-
-class CliRunner(object):
- """The CLI runner provides functionality to invoke a Click command line
- script for unittesting purposes in a isolated environment. This only
- works in single-threaded systems without any concurrency as it changes the
- global interpreter state.
-
- :param charset: the character set for the input and output data. This is
- UTF-8 by default and should not be changed currently as
- the reporting to Click only works in Python 2 properly.
- :param env: a dictionary with environment variables for overriding.
- :param echo_stdin: if this is set to `True`, then reading from stdin writes
- to stdout. This is useful for showing examples in
- some circumstances. Note that regular prompts
- will automatically echo the input.
- :param mix_stderr: if this is set to `False`, then stdout and stderr are
- preserved as independent streams. This is useful for
- Unix-philosophy apps that have predictable stdout and
- noisy stderr, such that each may be measured
- independently
- """
-
- def __init__(self, charset=None, env=None, echo_stdin=False,
- mix_stderr=True):
- if charset is None:
- charset = 'utf-8'
- self.charset = charset
- self.env = env or {}
- self.echo_stdin = echo_stdin
- self.mix_stderr = mix_stderr
-
- def get_default_prog_name(self, cli):
- """Given a command object it will return the default program name
- for it. The default is the `name` attribute or ``"root"`` if not
- set.
- """
- return cli.name or 'root'
-
- def make_env(self, overrides=None):
- """Returns the environment overrides for invoking a script."""
- rv = dict(self.env)
- if overrides:
- rv.update(overrides)
- return rv
-
- @contextlib.contextmanager
- def isolation(self, input=None, env=None, color=False):
- """A context manager that sets up the isolation for invoking of a
- command line tool. This sets up stdin with the given input data
- and `os.environ` with the overrides from the given dictionary.
- This also rebinds some internals in Click to be mocked (like the
- prompt functionality).
-
- This is automatically done in the :meth:`invoke` method.
-
- .. versionadded:: 4.0
- The ``color`` parameter was added.
-
- :param input: the input stream to put into sys.stdin.
- :param env: the environment overrides as dictionary.
- :param color: whether the output should contain color codes. The
- application can still override this explicitly.
- """
- input = make_input_stream(input, self.charset)
-
- old_stdin = sys.stdin
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- old_forced_width = clickpkg.formatting.FORCED_WIDTH
- clickpkg.formatting.FORCED_WIDTH = 80
-
- env = self.make_env(env)
-
- if PY2:
- bytes_output = StringIO()
- if self.echo_stdin:
- input = EchoingStdin(input, bytes_output)
- sys.stdout = bytes_output
- if not self.mix_stderr:
- bytes_error = StringIO()
- sys.stderr = bytes_error
- else:
- bytes_output = io.BytesIO()
- if self.echo_stdin:
- input = EchoingStdin(input, bytes_output)
- input = io.TextIOWrapper(input, encoding=self.charset)
- sys.stdout = io.TextIOWrapper(
- bytes_output, encoding=self.charset)
- if not self.mix_stderr:
- bytes_error = io.BytesIO()
- sys.stderr = io.TextIOWrapper(
- bytes_error, encoding=self.charset)
-
- if self.mix_stderr:
- sys.stderr = sys.stdout
-
- sys.stdin = input
-
- def visible_input(prompt=None):
- sys.stdout.write(prompt or '')
- val = input.readline().rstrip('\r\n')
- sys.stdout.write(val + '\n')
- sys.stdout.flush()
- return val
-
- def hidden_input(prompt=None):
- sys.stdout.write((prompt or '') + '\n')
- sys.stdout.flush()
- return input.readline().rstrip('\r\n')
-
- def _getchar(echo):
- char = sys.stdin.read(1)
- if echo:
- sys.stdout.write(char)
- sys.stdout.flush()
- return char
-
- default_color = color
-
- def should_strip_ansi(stream=None, color=None):
- if color is None:
- return not default_color
- return not color
-
- old_visible_prompt_func = clickpkg.termui.visible_prompt_func
- old_hidden_prompt_func = clickpkg.termui.hidden_prompt_func
- old__getchar_func = clickpkg.termui._getchar
- old_should_strip_ansi = clickpkg.utils.should_strip_ansi
- clickpkg.termui.visible_prompt_func = visible_input
- clickpkg.termui.hidden_prompt_func = hidden_input
- clickpkg.termui._getchar = _getchar
- clickpkg.utils.should_strip_ansi = should_strip_ansi
-
- old_env = {}
- try:
- for key, value in iteritems(env):
- old_env[key] = os.environ.get(key)
- if value is None:
- try:
- del os.environ[key]
- except Exception:
- pass
- else:
- os.environ[key] = value
- yield (bytes_output, not self.mix_stderr and bytes_error)
- finally:
- for key, value in iteritems(old_env):
- if value is None:
- try:
- del os.environ[key]
- except Exception:
- pass
- else:
- os.environ[key] = value
- sys.stdout = old_stdout
- sys.stderr = old_stderr
- sys.stdin = old_stdin
- clickpkg.termui.visible_prompt_func = old_visible_prompt_func
- clickpkg.termui.hidden_prompt_func = old_hidden_prompt_func
- clickpkg.termui._getchar = old__getchar_func
- clickpkg.utils.should_strip_ansi = old_should_strip_ansi
- clickpkg.formatting.FORCED_WIDTH = old_forced_width
-
- def invoke(self, cli, args=None, input=None, env=None,
- catch_exceptions=True, color=False, mix_stderr=False, **extra):
- """Invokes a command in an isolated environment. The arguments are
- forwarded directly to the command line script, the `extra` keyword
- arguments are passed to the :meth:`~clickpkg.Command.main` function of
- the command.
-
- This returns a :class:`Result` object.
-
- .. versionadded:: 3.0
- The ``catch_exceptions`` parameter was added.
-
- .. versionchanged:: 3.0
- The result object now has an `exc_info` attribute with the
- traceback if available.
-
- .. versionadded:: 4.0
- The ``color`` parameter was added.
-
- :param cli: the command to invoke
- :param args: the arguments to invoke. It may be given as an iterable
- or a string. When given as string it will be interpreted
- as a Unix shell command. More details at
- :func:`shlex.split`.
- :param input: the input data for `sys.stdin`.
- :param env: the environment overrides.
- :param catch_exceptions: Whether to catch any other exceptions than
- ``SystemExit``.
- :param extra: the keyword arguments to pass to :meth:`main`.
- :param color: whether the output should contain color codes. The
- application can still override this explicitly.
- """
- exc_info = None
- with self.isolation(input=input, env=env, color=color) as outstreams:
- exception = None
- exit_code = 0
-
- if isinstance(args, string_types):
- args = shlex.split(args)
-
- try:
- prog_name = extra.pop("prog_name")
- except KeyError:
- prog_name = self.get_default_prog_name(cli)
-
- try:
- cli.main(args=args or (), prog_name=prog_name, **extra)
- except SystemExit as e:
- exc_info = sys.exc_info()
- exit_code = e.code
- if exit_code is None:
- exit_code = 0
-
- if exit_code != 0:
- exception = e
-
- if not isinstance(exit_code, int):
- sys.stdout.write(str(exit_code))
- sys.stdout.write('\n')
- exit_code = 1
-
- except Exception as e:
- if not catch_exceptions:
- raise
- exception = e
- exit_code = 1
- exc_info = sys.exc_info()
- finally:
- sys.stdout.flush()
- stdout = outstreams[0].getvalue()
- stderr = outstreams[1] and outstreams[1].getvalue()
-
- return Result(runner=self,
- stdout_bytes=stdout,
- stderr_bytes=stderr,
- exit_code=exit_code,
- exception=exception,
- exc_info=exc_info)
-
- @contextlib.contextmanager
- def isolated_filesystem(self):
- """A context manager that creates a temporary folder and changes
- the current working directory to it for isolated filesystem tests.
- """
- cwd = os.getcwd()
- t = tempfile.mkdtemp()
- os.chdir(t)
- try:
- yield t
- finally:
- os.chdir(cwd)
- try:
- shutil.rmtree(t)
- except (OSError, IOError):
- pass
diff --git a/python/click/types.py b/python/click/types.py
deleted file mode 100644
index 1f88032..0000000
--- a/python/click/types.py
+++ /dev/null
@@ -1,668 +0,0 @@
-import os
-import stat
-from datetime import datetime
-
-from ._compat import open_stream, text_type, filename_to_ui, \
- get_filesystem_encoding, get_streerror, _get_argv_encoding, PY2
-from .exceptions import BadParameter
-from .utils import safecall, LazyFile
-
-
-class ParamType(object):
- """Helper for converting values through types. The following is
- necessary for a valid type:
-
- * it needs a name
- * it needs to pass through None unchanged
- * it needs to convert from a string
- * it needs to convert its result type through unchanged
- (eg: needs to be idempotent)
- * it needs to be able to deal with param and context being `None`.
- This can be the case when the object is used with prompt
- inputs.
- """
- is_composite = False
-
- #: the descriptive name of this type
- name = None
-
- #: if a list of this type is expected and the value is pulled from a
- #: string environment variable, this is what splits it up. `None`
- #: means any whitespace. For all parameters the general rule is that
- #: whitespace splits them up. The exception are paths and files which
- #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on
- #: Windows).
- envvar_list_splitter = None
-
- def __call__(self, value, param=None, ctx=None):
- if value is not None:
- return self.convert(value, param, ctx)
-
- def get_metavar(self, param):
- """Returns the metavar default for this param if it provides one."""
-
- def get_missing_message(self, param):
- """Optionally might return extra information about a missing
- parameter.
-
- .. versionadded:: 2.0
- """
-
- def convert(self, value, param, ctx):
- """Converts the value. This is not invoked for values that are
- `None` (the missing value).
- """
- return value
-
- def split_envvar_value(self, rv):
- """Given a value from an environment variable this splits it up
- into small chunks depending on the defined envvar list splitter.
-
- If the splitter is set to `None`, which means that whitespace splits,
- then leading and trailing whitespace is ignored. Otherwise, leading
- and trailing splitters usually lead to empty items being included.
- """
- return (rv or '').split(self.envvar_list_splitter)
-
- def fail(self, message, param=None, ctx=None):
- """Helper method to fail with an invalid value message."""
- raise BadParameter(message, ctx=ctx, param=param)
-
-
-class CompositeParamType(ParamType):
- is_composite = True
-
- @property
- def arity(self):
- raise NotImplementedError()
-
-
-class FuncParamType(ParamType):
-
- def __init__(self, func):
- self.name = func.__name__
- self.func = func
-
- def convert(self, value, param, ctx):
- try:
- return self.func(value)
- except ValueError:
- try:
- value = text_type(value)
- except UnicodeError:
- value = str(value).decode('utf-8', 'replace')
- self.fail(value, param, ctx)
-
-
-class UnprocessedParamType(ParamType):
- name = 'text'
-
- def convert(self, value, param, ctx):
- return value
-
- def __repr__(self):
- return 'UNPROCESSED'
-
-
-class StringParamType(ParamType):
- name = 'text'
-
- def convert(self, value, param, ctx):
- if isinstance(value, bytes):
- enc = _get_argv_encoding()
- try:
- value = value.decode(enc)
- except UnicodeError:
- fs_enc = get_filesystem_encoding()
- if fs_enc != enc:
- try:
- value = value.decode(fs_enc)
- except UnicodeError:
- value = value.decode('utf-8', 'replace')
- return value
- return value
-
- def __repr__(self):
- return 'STRING'
-
-
-class Choice(ParamType):
- """The choice type allows a value to be checked against a fixed set
- of supported values. All of these values have to be strings.
-
- You should only pass a list or tuple of choices. Other iterables
- (like generators) may lead to surprising results.
-
- See :ref:`choice-opts` for an example.
-
- :param case_sensitive: Set to false to make choices case
- insensitive. Defaults to true.
- """
-
- name = 'choice'
-
- def __init__(self, choices, case_sensitive=True):
- self.choices = choices
- self.case_sensitive = case_sensitive
-
- def get_metavar(self, param):
- return '[%s]' % '|'.join(self.choices)
-
- def get_missing_message(self, param):
- return 'Choose from:\n\t%s.' % ',\n\t'.join(self.choices)
-
- def convert(self, value, param, ctx):
- # Exact match
- if value in self.choices:
- return value
-
- # Match through normalization and case sensitivity
- # first do token_normalize_func, then lowercase
- # preserve original `value` to produce an accurate message in
- # `self.fail`
- normed_value = value
- normed_choices = self.choices
-
- if ctx is not None and \
- ctx.token_normalize_func is not None:
- normed_value = ctx.token_normalize_func(value)
- normed_choices = [ctx.token_normalize_func(choice) for choice in
- self.choices]
-
- if not self.case_sensitive:
- normed_value = normed_value.lower()
- normed_choices = [choice.lower() for choice in normed_choices]
-
- if normed_value in normed_choices:
- return normed_value
-
- self.fail('invalid choice: %s. (choose from %s)' %
- (value, ', '.join(self.choices)), param, ctx)
-
- def __repr__(self):
- return 'Choice(%r)' % list(self.choices)
-
-
-class DateTime(ParamType):
- """The DateTime type converts date strings into `datetime` objects.
-
- The format strings which are checked are configurable, but default to some
- common (non-timezone aware) ISO 8601 formats.
-
- When specifying *DateTime* formats, you should only pass a list or a tuple.
- Other iterables, like generators, may lead to surprising results.
-
- The format strings are processed using ``datetime.strptime``, and this
- consequently defines the format strings which are allowed.
-
- Parsing is tried using each format, in order, and the first format which
- parses successfully is used.
-
- :param formats: A list or tuple of date format strings, in the order in
- which they should be tried. Defaults to
- ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``,
- ``'%Y-%m-%d %H:%M:%S'``.
- """
- name = 'datetime'
-
- def __init__(self, formats=None):
- self.formats = formats or [
- '%Y-%m-%d',
- '%Y-%m-%dT%H:%M:%S',
- '%Y-%m-%d %H:%M:%S'
- ]
-
- def get_metavar(self, param):
- return '[{}]'.format('|'.join(self.formats))
-
- def _try_to_convert_date(self, value, format):
- try:
- return datetime.strptime(value, format)
- except ValueError:
- return None
-
- def convert(self, value, param, ctx):
- # Exact match
- for format in self.formats:
- dtime = self._try_to_convert_date(value, format)
- if dtime:
- return dtime
-
- self.fail(
- 'invalid datetime format: {}. (choose from {})'.format(
- value, ', '.join(self.formats)))
-
- def __repr__(self):
- return 'DateTime'
-
-
-class IntParamType(ParamType):
- name = 'integer'
-
- def convert(self, value, param, ctx):
- try:
- return int(value)
- except (ValueError, UnicodeError):
- self.fail('%s is not a valid integer' % value, param, ctx)
-
- def __repr__(self):
- return 'INT'
-
-
-class IntRange(IntParamType):
- """A parameter that works similar to :data:`click.INT` but restricts
- the value to fit into a range. The default behavior is to fail if the
- value falls outside the range, but it can also be silently clamped
- between the two edges.
-
- See :ref:`ranges` for an example.
- """
- name = 'integer range'
-
- def __init__(self, min=None, max=None, clamp=False):
- self.min = min
- self.max = max
- self.clamp = clamp
-
- def convert(self, value, param, ctx):
- rv = IntParamType.convert(self, value, param, ctx)
- if self.clamp:
- if self.min is not None and rv < self.min:
- return self.min
- if self.max is not None and rv > self.max:
- return self.max
- if self.min is not None and rv < self.min or \
- self.max is not None and rv > self.max:
- if self.min is None:
- self.fail('%s is bigger than the maximum valid value '
- '%s.' % (rv, self.max), param, ctx)
- elif self.max is None:
- self.fail('%s is smaller than the minimum valid value '
- '%s.' % (rv, self.min), param, ctx)
- else:
- self.fail('%s is not in the valid range of %s to %s.'
- % (rv, self.min, self.max), param, ctx)
- return rv
-
- def __repr__(self):
- return 'IntRange(%r, %r)' % (self.min, self.max)
-
-
-class FloatParamType(ParamType):
- name = 'float'
-
- def convert(self, value, param, ctx):
- try:
- return float(value)
- except (UnicodeError, ValueError):
- self.fail('%s is not a valid floating point value' %
- value, param, ctx)
-
- def __repr__(self):
- return 'FLOAT'
-
-
-class FloatRange(FloatParamType):
- """A parameter that works similar to :data:`click.FLOAT` but restricts
- the value to fit into a range. The default behavior is to fail if the
- value falls outside the range, but it can also be silently clamped
- between the two edges.
-
- See :ref:`ranges` for an example.
- """
- name = 'float range'
-
- def __init__(self, min=None, max=None, clamp=False):
- self.min = min
- self.max = max
- self.clamp = clamp
-
- def convert(self, value, param, ctx):
- rv = FloatParamType.convert(self, value, param, ctx)
- if self.clamp:
- if self.min is not None and rv < self.min:
- return self.min
- if self.max is not None and rv > self.max:
- return self.max
- if self.min is not None and rv < self.min or \
- self.max is not None and rv > self.max:
- if self.min is None:
- self.fail('%s is bigger than the maximum valid value '
- '%s.' % (rv, self.max), param, ctx)
- elif self.max is None:
- self.fail('%s is smaller than the minimum valid value '
- '%s.' % (rv, self.min), param, ctx)
- else:
- self.fail('%s is not in the valid range of %s to %s.'
- % (rv, self.min, self.max), param, ctx)
- return rv
-
- def __repr__(self):
- return 'FloatRange(%r, %r)' % (self.min, self.max)
-
-
-class BoolParamType(ParamType):
- name = 'boolean'
-
- def convert(self, value, param, ctx):
- if isinstance(value, bool):
- return bool(value)
- value = value.lower()
- if value in ('true', 't', '1', 'yes', 'y'):
- return True
- elif value in ('false', 'f', '0', 'no', 'n'):
- return False
- self.fail('%s is not a valid boolean' % value, param, ctx)
-
- def __repr__(self):
- return 'BOOL'
-
-
-class UUIDParameterType(ParamType):
- name = 'uuid'
-
- def convert(self, value, param, ctx):
- import uuid
- try:
- if PY2 and isinstance(value, text_type):
- value = value.encode('ascii')
- return uuid.UUID(value)
- except (UnicodeError, ValueError):
- self.fail('%s is not a valid UUID value' % value, param, ctx)
-
- def __repr__(self):
- return 'UUID'
-
-
-class File(ParamType):
- """Declares a parameter to be a file for reading or writing. The file
- is automatically closed once the context tears down (after the command
- finished working).
-
- Files can be opened for reading or writing. The special value ``-``
- indicates stdin or stdout depending on the mode.
-
- By default, the file is opened for reading text data, but it can also be
- opened in binary mode or for writing. The encoding parameter can be used
- to force a specific encoding.
-
- The `lazy` flag controls if the file should be opened immediately or upon
- first IO. The default is to be non-lazy for standard input and output
- streams as well as files opened for reading, `lazy` otherwise. When opening a
- file lazily for reading, it is still opened temporarily for validation, but
- will not be held open until first IO. lazy is mainly useful when opening
- for writing to avoid creating the file until it is needed.
-
- Starting with Click 2.0, files can also be opened atomically in which
- case all writes go into a separate file in the same folder and upon
- completion the file will be moved over to the original location. This
- is useful if a file regularly read by other users is modified.
-
- See :ref:`file-args` for more information.
- """
- name = 'filename'
- envvar_list_splitter = os.path.pathsep
-
- def __init__(self, mode='r', encoding=None, errors='strict', lazy=None,
- atomic=False):
- self.mode = mode
- self.encoding = encoding
- self.errors = errors
- self.lazy = lazy
- self.atomic = atomic
-
- def resolve_lazy_flag(self, value):
- if self.lazy is not None:
- return self.lazy
- if value == '-':
- return False
- elif 'w' in self.mode:
- return True
- return False
-
- def convert(self, value, param, ctx):
- try:
- if hasattr(value, 'read') or hasattr(value, 'write'):
- return value
-
- lazy = self.resolve_lazy_flag(value)
-
- if lazy:
- f = LazyFile(value, self.mode, self.encoding, self.errors,
- atomic=self.atomic)
- if ctx is not None:
- ctx.call_on_close(f.close_intelligently)
- return f
-
- f, should_close = open_stream(value, self.mode,
- self.encoding, self.errors,
- atomic=self.atomic)
- # If a context is provided, we automatically close the file
- # at the end of the context execution (or flush out). If a
- # context does not exist, it's the caller's responsibility to
- # properly close the file. This for instance happens when the
- # type is used with prompts.
- if ctx is not None:
- if should_close:
- ctx.call_on_close(safecall(f.close))
- else:
- ctx.call_on_close(safecall(f.flush))
- return f
- except (IOError, OSError) as e:
- self.fail('Could not open file: %s: %s' % (
- filename_to_ui(value),
- get_streerror(e),
- ), param, ctx)
-
-
-class Path(ParamType):
- """The path type is similar to the :class:`File` type but it performs
- different checks. First of all, instead of returning an open file
- handle it returns just the filename. Secondly, it can perform various
- basic checks about what the file or directory should be.
-
- .. versionchanged:: 6.0
- `allow_dash` was added.
-
- :param exists: if set to true, the file or directory needs to exist for
- this value to be valid. If this is not required and a
- file does indeed not exist, then all further checks are
- silently skipped.
- :param file_okay: controls if a file is a possible value.
- :param dir_okay: controls if a directory is a possible value.
- :param writable: if true, a writable check is performed.
- :param readable: if true, a readable check is performed.
- :param resolve_path: if this is true, then the path is fully resolved
- before the value is passed onwards. This means
- that it's absolute and symlinks are resolved. It
- will not expand a tilde-prefix, as this is
- supposed to be done by the shell only.
- :param allow_dash: If this is set to `True`, a single dash to indicate
- standard streams is permitted.
- :param path_type: optionally a string type that should be used to
- represent the path. The default is `None` which
- means the return value will be either bytes or
- unicode depending on what makes most sense given the
- input data Click deals with.
- """
- envvar_list_splitter = os.path.pathsep
-
- def __init__(self, exists=False, file_okay=True, dir_okay=True,
- writable=False, readable=True, resolve_path=False,
- allow_dash=False, path_type=None):
- self.exists = exists
- self.file_okay = file_okay
- self.dir_okay = dir_okay
- self.writable = writable
- self.readable = readable
- self.resolve_path = resolve_path
- self.allow_dash = allow_dash
- self.type = path_type
-
- if self.file_okay and not self.dir_okay:
- self.name = 'file'
- self.path_type = 'File'
- elif self.dir_okay and not self.file_okay:
- self.name = 'directory'
- self.path_type = 'Directory'
- else:
- self.name = 'path'
- self.path_type = 'Path'
-
- def coerce_path_result(self, rv):
- if self.type is not None and not isinstance(rv, self.type):
- if self.type is text_type:
- rv = rv.decode(get_filesystem_encoding())
- else:
- rv = rv.encode(get_filesystem_encoding())
- return rv
-
- def convert(self, value, param, ctx):
- rv = value
-
- is_dash = self.file_okay and self.allow_dash and rv in (b'-', '-')
-
- if not is_dash:
- if self.resolve_path:
- rv = os.path.realpath(rv)
-
- try:
- st = os.stat(rv)
- except OSError:
- if not self.exists:
- return self.coerce_path_result(rv)
- self.fail('%s "%s" does not exist.' % (
- self.path_type,
- filename_to_ui(value)
- ), param, ctx)
-
- if not self.file_okay and stat.S_ISREG(st.st_mode):
- self.fail('%s "%s" is a file.' % (
- self.path_type,
- filename_to_ui(value)
- ), param, ctx)
- if not self.dir_okay and stat.S_ISDIR(st.st_mode):
- self.fail('%s "%s" is a directory.' % (
- self.path_type,
- filename_to_ui(value)
- ), param, ctx)
- if self.writable and not os.access(value, os.W_OK):
- self.fail('%s "%s" is not writable.' % (
- self.path_type,
- filename_to_ui(value)
- ), param, ctx)
- if self.readable and not os.access(value, os.R_OK):
- self.fail('%s "%s" is not readable.' % (
- self.path_type,
- filename_to_ui(value)
- ), param, ctx)
-
- return self.coerce_path_result(rv)
-
-
-class Tuple(CompositeParamType):
- """The default behavior of Click is to apply a type on a value directly.
- This works well in most cases, except for when `nargs` is set to a fixed
- count and different types should be used for different items. In this
- case the :class:`Tuple` type can be used. This type can only be used
- if `nargs` is set to a fixed number.
-
- For more information see :ref:`tuple-type`.
-
- This can be selected by using a Python tuple literal as a type.
-
- :param types: a list of types that should be used for the tuple items.
- """
-
- def __init__(self, types):
- self.types = [convert_type(ty) for ty in types]
-
- @property
- def name(self):
- return "<" + " ".join(ty.name for ty in self.types) + ">"
-
- @property
- def arity(self):
- return len(self.types)
-
- def convert(self, value, param, ctx):
- if len(value) != len(self.types):
- raise TypeError('It would appear that nargs is set to conflict '
- 'with the composite type arity.')
- return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value))
-
-
-def convert_type(ty, default=None):
- """Converts a callable or python ty into the most appropriate param
- ty.
- """
- guessed_type = False
- if ty is None and default is not None:
- if isinstance(default, tuple):
- ty = tuple(map(type, default))
- else:
- ty = type(default)
- guessed_type = True
-
- if isinstance(ty, tuple):
- return Tuple(ty)
- if isinstance(ty, ParamType):
- return ty
- if ty is text_type or ty is str or ty is None:
- return STRING
- if ty is int:
- return INT
- # Booleans are only okay if not guessed. This is done because for
- # flags the default value is actually a bit of a lie in that it
- # indicates which of the flags is the one we want. See get_default()
- # for more information.
- if ty is bool and not guessed_type:
- return BOOL
- if ty is float:
- return FLOAT
- if guessed_type:
- return STRING
-
- # Catch a common mistake
- if __debug__:
- try:
- if issubclass(ty, ParamType):
- raise AssertionError('Attempted to use an uninstantiated '
- 'parameter type (%s).' % ty)
- except TypeError:
- pass
- return FuncParamType(ty)
-
-
-#: A dummy parameter type that just does nothing. From a user's
-#: perspective this appears to just be the same as `STRING` but internally
-#: no string conversion takes place. This is necessary to achieve the
-#: same bytes/unicode behavior on Python 2/3 in situations where you want
-#: to not convert argument types. This is usually useful when working
-#: with file paths as they can appear in bytes and unicode.
-#:
-#: For path related uses the :class:`Path` type is a better choice but
-#: there are situations where an unprocessed type is useful which is why
-#: it is is provided.
-#:
-#: .. versionadded:: 4.0
-UNPROCESSED = UnprocessedParamType()
-
-#: A unicode string parameter type which is the implicit default. This
-#: can also be selected by using ``str`` as type.
-STRING = StringParamType()
-
-#: An integer parameter. This can also be selected by using ``int`` as
-#: type.
-INT = IntParamType()
-
-#: A floating point value parameter. This can also be selected by using
-#: ``float`` as type.
-FLOAT = FloatParamType()
-
-#: A boolean parameter. This is the default for boolean flags. This can
-#: also be selected by using ``bool`` as a type.
-BOOL = BoolParamType()
-
-#: A UUID parameter.
-UUID = UUIDParameterType()
diff --git a/python/click/utils.py b/python/click/utils.py
deleted file mode 100644
index fc84369..0000000
--- a/python/click/utils.py
+++ /dev/null
@@ -1,440 +0,0 @@
-import os
-import sys
-
-from .globals import resolve_color_default
-
-from ._compat import text_type, open_stream, get_filesystem_encoding, \
- get_streerror, string_types, PY2, binary_streams, text_streams, \
- filename_to_ui, auto_wrap_for_ansi, strip_ansi, should_strip_ansi, \
- _default_text_stdout, _default_text_stderr, is_bytes, WIN
-
-if not PY2:
- from ._compat import _find_binary_writer
-elif WIN:
- from ._winconsole import _get_windows_argv, \
- _hash_py_argv, _initial_argv_hash
-
-
-echo_native_types = string_types + (bytes, bytearray)
-
-
-def _posixify(name):
- return '-'.join(name.split()).lower()
-
-
-def safecall(func):
- """Wraps a function so that it swallows exceptions."""
- def wrapper(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except Exception:
- pass
- return wrapper
-
-
-def make_str(value):
- """Converts a value into a valid string."""
- if isinstance(value, bytes):
- try:
- return value.decode(get_filesystem_encoding())
- except UnicodeError:
- return value.decode('utf-8', 'replace')
- return text_type(value)
-
-
-def make_default_short_help(help, max_length=45):
- """Return a condensed version of help string."""
- words = help.split()
- total_length = 0
- result = []
- done = False
-
- for word in words:
- if word[-1:] == '.':
- done = True
- new_length = result and 1 + len(word) or len(word)
- if total_length + new_length > max_length:
- result.append('...')
- done = True
- else:
- if result:
- result.append(' ')
- result.append(word)
- if done:
- break
- total_length += new_length
-
- return ''.join(result)
-
-
-class LazyFile(object):
- """A lazy file works like a regular file but it does not fully open
- the file but it does perform some basic checks early to see if the
- filename parameter does make sense. This is useful for safely opening
- files for writing.
- """
-
- def __init__(self, filename, mode='r', encoding=None, errors='strict',
- atomic=False):
- self.name = filename
- self.mode = mode
- self.encoding = encoding
- self.errors = errors
- self.atomic = atomic
-
- if filename == '-':
- self._f, self.should_close = open_stream(filename, mode,
- encoding, errors)
- else:
- if 'r' in mode:
- # Open and close the file in case we're opening it for
- # reading so that we can catch at least some errors in
- # some cases early.
- open(filename, mode).close()
- self._f = None
- self.should_close = True
-
- def __getattr__(self, name):
- return getattr(self.open(), name)
-
- def __repr__(self):
- if self._f is not None:
- return repr(self._f)
- return '<unopened file %r %s>' % (self.name, self.mode)
-
- def open(self):
- """Opens the file if it's not yet open. This call might fail with
- a :exc:`FileError`. Not handling this error will produce an error
- that Click shows.
- """
- if self._f is not None:
- return self._f
- try:
- rv, self.should_close = open_stream(self.name, self.mode,
- self.encoding,
- self.errors,
- atomic=self.atomic)
- except (IOError, OSError) as e:
- from .exceptions import FileError
- raise FileError(self.name, hint=get_streerror(e))
- self._f = rv
- return rv
-
- def close(self):
- """Closes the underlying file, no matter what."""
- if self._f is not None:
- self._f.close()
-
- def close_intelligently(self):
- """This function only closes the file if it was opened by the lazy
- file wrapper. For instance this will never close stdin.
- """
- if self.should_close:
- self.close()
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.close_intelligently()
-
- def __iter__(self):
- self.open()
- return iter(self._f)
-
-
-class KeepOpenFile(object):
-
- def __init__(self, file):
- self._file = file
-
- def __getattr__(self, name):
- return getattr(self._file, name)
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- pass
-
- def __repr__(self):
- return repr(self._file)
-
- def __iter__(self):
- return iter(self._file)
-
-
-def echo(message=None, file=None, nl=True, err=False, color=None):
- """Prints a message plus a newline to the given file or stdout. On
- first sight, this looks like the print function, but it has improved
- support for handling Unicode and binary data that does not fail no
- matter how badly configured the system is.
-
- Primarily it means that you can print binary data as well as Unicode
- data on both 2.x and 3.x to the given file in the most appropriate way
- possible. This is a very carefree function in that it will try its
- best to not fail. As of Click 6.0 this includes support for unicode
- output on the Windows console.
-
- In addition to that, if `colorama`_ is installed, the echo function will
- also support clever handling of ANSI codes. Essentially it will then
- do the following:
-
- - add transparent handling of ANSI color codes on Windows.
- - hide ANSI codes automatically if the destination file is not a
- terminal.
-
- .. _colorama: https://pypi.org/project/colorama/
-
- .. versionchanged:: 6.0
- As of Click 6.0 the echo function will properly support unicode
- output on the windows console. Not that click does not modify
- the interpreter in any way which means that `sys.stdout` or the
- print statement or function will still not provide unicode support.
-
- .. versionchanged:: 2.0
- Starting with version 2.0 of Click, the echo function will work
- with colorama if it's installed.
-
- .. versionadded:: 3.0
- The `err` parameter was added.
-
- .. versionchanged:: 4.0
- Added the `color` flag.
-
- :param message: the message to print
- :param file: the file to write to (defaults to ``stdout``)
- :param err: if set to true the file defaults to ``stderr`` instead of
- ``stdout``. This is faster and easier than calling
- :func:`get_text_stderr` yourself.
- :param nl: if set to `True` (the default) a newline is printed afterwards.
- :param color: controls if the terminal supports ANSI colors or not. The
- default is autodetection.
- """
- if file is None:
- if err:
- file = _default_text_stderr()
- else:
- file = _default_text_stdout()
-
- # Convert non bytes/text into the native string type.
- if message is not None and not isinstance(message, echo_native_types):
- message = text_type(message)
-
- if nl:
- message = message or u''
- if isinstance(message, text_type):
- message += u'\n'
- else:
- message += b'\n'
-
- # If there is a message, and we're in Python 3, and the value looks
- # like bytes, we manually need to find the binary stream and write the
- # message in there. This is done separately so that most stream
- # types will work as you would expect. Eg: you can write to StringIO
- # for other cases.
- if message and not PY2 and is_bytes(message):
- binary_file = _find_binary_writer(file)
- if binary_file is not None:
- file.flush()
- binary_file.write(message)
- binary_file.flush()
- return
-
- # ANSI-style support. If there is no message or we are dealing with
- # bytes nothing is happening. If we are connected to a file we want
- # to strip colors. If we are on windows we either wrap the stream
- # to strip the color or we use the colorama support to translate the
- # ansi codes to API calls.
- if message and not is_bytes(message):
- color = resolve_color_default(color)
- if should_strip_ansi(file, color):
- message = strip_ansi(message)
- elif WIN:
- if auto_wrap_for_ansi is not None:
- file = auto_wrap_for_ansi(file)
- elif not color:
- message = strip_ansi(message)
-
- if message:
- file.write(message)
- file.flush()
-
-
-def get_binary_stream(name):
- """Returns a system stream for byte processing. This essentially
- returns the stream from the sys module with the given name but it
- solves some compatibility issues between different Python versions.
- Primarily this function is necessary for getting binary streams on
- Python 3.
-
- :param name: the name of the stream to open. Valid names are ``'stdin'``,
- ``'stdout'`` and ``'stderr'``
- """
- opener = binary_streams.get(name)
- if opener is None:
- raise TypeError('Unknown standard stream %r' % name)
- return opener()
-
-
-def get_text_stream(name, encoding=None, errors='strict'):
- """Returns a system stream for text processing. This usually returns
- a wrapped stream around a binary stream returned from
- :func:`get_binary_stream` but it also can take shortcuts on Python 3
- for already correctly configured streams.
-
- :param name: the name of the stream to open. Valid names are ``'stdin'``,
- ``'stdout'`` and ``'stderr'``
- :param encoding: overrides the detected default encoding.
- :param errors: overrides the default error mode.
- """
- opener = text_streams.get(name)
- if opener is None:
- raise TypeError('Unknown standard stream %r' % name)
- return opener(encoding, errors)
-
-
-def open_file(filename, mode='r', encoding=None, errors='strict',
- lazy=False, atomic=False):
- """This is similar to how the :class:`File` works but for manual
- usage. Files are opened non lazy by default. This can open regular
- files as well as stdin/stdout if ``'-'`` is passed.
-
- If stdin/stdout is returned the stream is wrapped so that the context
- manager will not close the stream accidentally. This makes it possible
- to always use the function like this without having to worry to
- accidentally close a standard stream::
-
- with open_file(filename) as f:
- ...
-
- .. versionadded:: 3.0
-
- :param filename: the name of the file to open (or ``'-'`` for stdin/stdout).
- :param mode: the mode in which to open the file.
- :param encoding: the encoding to use.
- :param errors: the error handling for this file.
- :param lazy: can be flipped to true to open the file lazily.
- :param atomic: in atomic mode writes go into a temporary file and it's
- moved on close.
- """
- if lazy:
- return LazyFile(filename, mode, encoding, errors, atomic=atomic)
- f, should_close = open_stream(filename, mode, encoding, errors,
- atomic=atomic)
- if not should_close:
- f = KeepOpenFile(f)
- return f
-
-
-def get_os_args():
- """This returns the argument part of sys.argv in the most appropriate
- form for processing. What this means is that this return value is in
- a format that works for Click to process but does not necessarily
- correspond well to what's actually standard for the interpreter.
-
- On most environments the return value is ``sys.argv[:1]`` unchanged.
- However if you are on Windows and running Python 2 the return value
- will actually be a list of unicode strings instead because the
- default behavior on that platform otherwise will not be able to
- carry all possible values that sys.argv can have.
-
- .. versionadded:: 6.0
- """
- # We can only extract the unicode argv if sys.argv has not been
- # changed since the startup of the application.
- if PY2 and WIN and _initial_argv_hash == _hash_py_argv():
- return _get_windows_argv()
- return sys.argv[1:]
-
-
-def format_filename(filename, shorten=False):
- """Formats a filename for user display. The main purpose of this
- function is to ensure that the filename can be displayed at all. This
- will decode the filename to unicode if necessary in a way that it will
- not fail. Optionally, it can shorten the filename to not include the
- full path to the filename.
-
- :param filename: formats a filename for UI display. This will also convert
- the filename into unicode without failing.
- :param shorten: this optionally shortens the filename to strip of the
- path that leads up to it.
- """
- if shorten:
- filename = os.path.basename(filename)
- return filename_to_ui(filename)
-
-
-def get_app_dir(app_name, roaming=True, force_posix=False):
- r"""Returns the config folder for the application. The default behavior
- is to return whatever is most appropriate for the operating system.
-
- To give you an idea, for an app called ``"Foo Bar"``, something like
- the following folders could be returned:
-
- Mac OS X:
- ``~/Library/Application Support/Foo Bar``
- Mac OS X (POSIX):
- ``~/.foo-bar``
- Unix:
- ``~/.config/foo-bar``
- Unix (POSIX):
- ``~/.foo-bar``
- Win XP (roaming):
- ``C:\Documents and Settings\<user>\Local Settings\Application Data\Foo Bar``
- Win XP (not roaming):
- ``C:\Documents and Settings\<user>\Application Data\Foo Bar``
- Win 7 (roaming):
- ``C:\Users\<user>\AppData\Roaming\Foo Bar``
- Win 7 (not roaming):
- ``C:\Users\<user>\AppData\Local\Foo Bar``
-
- .. versionadded:: 2.0
-
- :param app_name: the application name. This should be properly capitalized
- and can contain whitespace.
- :param roaming: controls if the folder should be roaming or not on Windows.
- Has no affect otherwise.
- :param force_posix: if this is set to `True` then on any POSIX system the
- folder will be stored in the home folder with a leading
- dot instead of the XDG config home or darwin's
- application support folder.
- """
- if WIN:
- key = roaming and 'APPDATA' or 'LOCALAPPDATA'
- folder = os.environ.get(key)
- if folder is None:
- folder = os.path.expanduser('~')
- return os.path.join(folder, app_name)
- if force_posix:
- return os.path.join(os.path.expanduser('~/.' + _posixify(app_name)))
- if sys.platform == 'darwin':
- return os.path.join(os.path.expanduser(
- '~/Library/Application Support'), app_name)
- return os.path.join(
- os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
- _posixify(app_name))
-
-
-class PacifyFlushWrapper(object):
- """This wrapper is used to catch and suppress BrokenPipeErrors resulting
- from ``.flush()`` being called on broken pipe during the shutdown/final-GC
- of the Python interpreter. Notably ``.flush()`` is always called on
- ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any
- other cleanup code, and the case where the underlying file is not a broken
- pipe, all calls and attributes are proxied.
- """
-
- def __init__(self, wrapped):
- self.wrapped = wrapped
-
- def flush(self):
- try:
- self.wrapped.flush()
- except IOError as e:
- import errno
- if e.errno != errno.EPIPE:
- raise
-
- def __getattr__(self, attr):
- return getattr(self.wrapped, attr)