Navigation Menu

Skip to content

Commit

Permalink
Merge with upstream changes and use resilient_parsing flag to ignore …
Browse files Browse the repository at this point in the history
…default values.
  • Loading branch information
Nicholas Wiles committed Sep 11, 2018
2 parents b61ec64 + 084da90 commit b0da041
Show file tree
Hide file tree
Showing 33 changed files with 530 additions and 1,052 deletions.
428 changes: 202 additions & 226 deletions CHANGES.rst

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions README.rst
@@ -1,22 +1,20 @@
\$ click\_
==========

What's Click?
-------------

Click is a Python package for creating beautiful command line interfaces
in a composable way with as little code as necessary. It's the "Command
Line Interface Creation Kit". It's highly configurable but comes with
sensible defaults out of the box.

It aims to make the process of writing command line tools quick and fun
while also preventing any frustration caused by the inability to implement
an intended CLI API.
while also preventing any frustration caused by the inability to
implement an intended CLI API.

Click in three points:
- arbitrary nesting of commands
- automatic help page generation
- supports lazy loading of subcommands at runtime

- arbitrary nesting of commands
- automatic help page generation
- supports lazy loading of subcommands at runtime


Installing
Expand All @@ -28,7 +26,10 @@ Install and update using `pip`_:
$ pip install click
Click supports Python 3.4 and newer, Python 2.7, and PyPy
Click supports Python 3.4 and newer, Python 2.7, and PyPy.

.. _pip: https://pip.pypa.io/en/stable/quickstart/


A Simple Example
----------------
Expand Down Expand Up @@ -61,6 +62,7 @@ And what it looks like when run:
Hello John!
Hello John!
Donate
------

Expand All @@ -69,23 +71,21 @@ it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.

.. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20
.. _please donate today: https://palletsprojects.com/donate


Links
-----

* Website: https://www.palletsprojects.com/p/click/
* Documentation: http://click.pocoo.org/
* License: `BSD <https://github.com/pallets/click/blob/master/LICENSE>`_
* Releases: https://pypi.org/project/click/
* Code: https://github.com/pallets/click
* Issue tracker: https://github.com/pallets/click/issues
* Test status:
* Website: https://palletsprojects.com/p/click/
* Documentation: https://click.palletsprojects.com/
* License: `BSD <https://github.com/pallets/click/blob/master/LICENSE>`_
* Releases: https://pypi.org/project/click/
* Code: https://github.com/pallets/click
* Issue tracker: https://github.com/pallets/click/issues
* Test status:

* Linux, Mac: https://travis-ci.org/pallets/click
* Windows: https://ci.appveyor.com/project/pallets/click
* Linux, Mac: https://travis-ci.org/pallets/click
* Windows: https://ci.appveyor.com/project/pallets/click

* Test coverage: https://codecov.io/gh/pallets/click

.. _pip: https://pip.pypa.io/en/stable/quickstart/
* Test coverage: https://codecov.io/gh/pallets/click
8 changes: 3 additions & 5 deletions click/_bashcomplete.py
Expand Up @@ -72,7 +72,7 @@ def resolve_ctx(cli, prog_name, args):
:param args: full list of args
:return: the final context/command parsed
"""
ctx = cli.make_context(prog_name, args, resilient_parsing=True, ignore_default_values=True)
ctx = cli.make_context(prog_name, args, resilient_parsing=True)
args = ctx.protected_args + ctx.args
while args:
if isinstance(ctx.command, MultiCommand):
Expand All @@ -81,8 +81,7 @@ def resolve_ctx(cli, prog_name, args):
if cmd is None:
return ctx
ctx = cmd.make_context(cmd_name, args, parent=ctx,
resilient_parsing=True,
ignore_default_values=True)
resilient_parsing=True)
args = ctx.protected_args + ctx.args
else:
# Walk chained subcommand contexts saving the last one.
Expand All @@ -93,8 +92,7 @@ def resolve_ctx(cli, prog_name, args):
sub_ctx = cmd.make_context(cmd_name, args, parent=ctx,
allow_extra_args=True,
allow_interspersed_args=False,
resilient_parsing=True,
ignore_default_values=True)
resilient_parsing=True)
args = sub_ctx.args
ctx = sub_ctx
args = sub_ctx.protected_args + sub_ctx.args
Expand Down
2 changes: 1 addition & 1 deletion click/_winconsole.py
Expand Up @@ -15,7 +15,7 @@
import time
import ctypes
import msvcrt
from click._compat import _NonClosingTextIOWrapper, text_type, PY2
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:
Expand Down
44 changes: 32 additions & 12 deletions click/core.py
Expand Up @@ -9,7 +9,7 @@
from .types import convert_type, IntRange, BOOL
from .utils import make_str, make_default_short_help, echo, get_os_args
from .exceptions import ClickException, UsageError, BadParameter, Abort, \
MissingParameter
MissingParameter, Exit
from .termui import prompt, confirm, style
from .formatting import HelpFormatter, join_options
from .parser import OptionParser, split_opt
Expand Down Expand Up @@ -182,7 +182,8 @@ class Context(object):
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. This is useful for implementing
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
Expand Down Expand Up @@ -214,7 +215,7 @@ def __init__(self, command, parent=None, info_name=None, obj=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, ignore_default_values=False):
token_normalize_func=None, color=None):
#: the parent context or `None` if none exists.
self.parent = parent
#: the :class:`Command` for this context.
Expand Down Expand Up @@ -312,15 +313,10 @@ def __init__(self, command, parent=None, info_name=None, obj=None,
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.
#: will do its best to not cause any failures and default values
#: will be ignored. Useful for completion.
self.resilient_parsing = resilient_parsing

#: Indicates that default values should be ignored.
#: Useful for completion.

#: .. versionadded:: 7.0
self.ignore_default_values = ignore_default_values

# 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.
Expand Down Expand Up @@ -504,7 +500,7 @@ def abort(self):

def exit(self, code=0):
"""Exits the application with a given exit code."""
sys.exit(code)
raise Exit(code)

def get_usage(self):
"""Helper method to get formatted usage string for the current
Expand Down Expand Up @@ -720,6 +716,13 @@ def main(self, args=None, prog_name=None, complete_var=None,
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)
Expand All @@ -734,6 +737,19 @@ def main(self, args=None, prog_name=None, complete_var=None,
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
Expand Down Expand Up @@ -784,6 +800,10 @@ def __init__(self, name, context_settings=None, callback=None,
#: 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
Expand Down Expand Up @@ -1415,7 +1435,7 @@ def value_is_missing(self, value):
def full_process_value(self, ctx, value):
value = self.process_value(ctx, value)

if value is None and not ctx.ignore_default_values:
if value is None and not ctx.resilient_parsing:
value = self.get_default(ctx)

if self.required and self.value_is_missing(value):
Expand Down
2 changes: 1 addition & 1 deletion click/decorators.py
Expand Up @@ -61,7 +61,7 @@ def new_func(*args, **kwargs):
raise RuntimeError('Managed to invoke callback without a '
'context object of type %r existing'
% object_type.__name__)
return ctx.invoke(f, obj, *args[1:], **kwargs)
return ctx.invoke(f, obj, *args, **kwargs)
return update_wrapper(new_func, f)
return decorator

Expand Down
10 changes: 10 additions & 0 deletions click/exceptions.py
Expand Up @@ -223,3 +223,13 @@ def format_message(self):

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
2 changes: 1 addition & 1 deletion click/testing.py
Expand Up @@ -83,7 +83,7 @@ def __init__(self, runner, stdout_bytes, stderr_bytes, exit_code,
self.stderr_bytes = stderr_bytes
#: The exit code as integer.
self.exit_code = exit_code
#: The exception that happend if one did.
#: The exception that happened if one did.
self.exception = exception
#: The traceback
self.exc_info = exc_info
Expand Down
22 changes: 13 additions & 9 deletions click/types.py
Expand Up @@ -126,17 +126,18 @@ def __repr__(self):


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.
"""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 *choices* as list or tuple. Other iterables (like
generators) may lead to surprising results.
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.
:param case_sensitive: Set to false to make choices case
insensitive. Defaults to true.
"""

name = 'choice'

def __init__(self, choices, case_sensitive=True):
Expand Down Expand Up @@ -331,9 +332,12 @@ class File(ParamType):
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.
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
Expand Down

0 comments on commit b0da041

Please sign in to comment.