diff --git a/src/click/core.py b/src/click/core.py
index 524c255..788e3f2 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -48,19 +48,39 @@ def _complete_visible_commands(ctx: 'Context', incomplete: str) -> t.Iterator[t.
:param ctx: Invocation context for the group.
:param incomplete: Value being completed. May be empty.
"""
- pass
+ for name, command in ctx.command.commands.items():
+ if not command.hidden and name.startswith(incomplete):
+ yield name, command
@contextmanager
def augment_usage_errors(ctx: 'Context', param: t.Optional['Parameter']=None) -> t.Iterator[None]:
"""Context manager that attaches extra information to exceptions."""
- pass
+ try:
+ yield
+ except UsageError as e:
+ if e.ctx is None:
+ e.ctx = ctx
+ if param is not None and e.param is None:
+ e.param = param
+ raise
def iter_params_for_processing(invocation_order: t.Sequence['Parameter'], declaration_order: t.Sequence['Parameter']) -> t.List['Parameter']:
"""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.
"""
- pass
+ def sort_key(param: 'Parameter') -> t.Tuple[int, int]:
+ try:
+ inv_idx = invocation_order.index(param)
+ except ValueError:
+ inv_idx = float('inf')
+ try:
+ decl_idx = declaration_order.index(param)
+ except ValueError:
+ decl_idx = float('inf')
+ return (inv_idx, decl_idx)
+
+ return sorted(set(invocation_order) | set(declaration_order), key=sort_key)
class ParameterSource(enum.Enum):
"""This is an :class:`~enum.Enum` that indicates the source of a
@@ -248,13 +268,19 @@ class Context:
structure.
.. code-block:: python
-
with Context(cli) as ctx:
info = ctx.to_info_dict()
.. versionadded:: 8.0
"""
- pass
+ return {
+ "command": self.command.to_info_dict() if self.command else None,
+ "info_name": self.info_name,
+ "allow_extra_args": self.allow_extra_args,
+ "allow_interspersed_args": self.allow_interspersed_args,
+ "ignore_unknown_options": self.ignore_unknown_options,
+ "auto_envvar_prefix": self.auto_envvar_prefix,
+ }
def __enter__(self) -> 'Context':
self._depth += 1
@@ -324,7 +350,9 @@ class Context:
.. versionadded:: 5.0
"""
- pass
+ if self._meta is None:
+ self._meta = {}
+ return self._meta
def make_formatter(self) -> HelpFormatter:
"""Creates the :class:`~click.HelpFormatter` for the help and
@@ -336,7 +364,7 @@ class Context:
.. versionchanged:: 8.0
Added the :attr:`formatter_class` attribute.
"""
- pass
+ return self.formatter_class(width=self.terminal_width, max_width=self.max_content_width)
def with_resource(self, context_manager: t.ContextManager[V]) -> V:
"""Register a resource as if it were used in a ``with``
@@ -365,7 +393,7 @@ class Context:
.. versionadded:: 8.0
"""
- pass
+ return self._exit_stack.enter_context(context_manager)
def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
"""Register a function to be called when the context tears down.
@@ -377,14 +405,17 @@ class Context:
:param f: The function to execute on teardown.
"""
- pass
+ self._close_callbacks.append(f)
+ return f
def close(self) -> None:
"""Invoke all close callbacks registered with
:meth:`call_on_close`, and exit all context managers entered
with :meth:`with_resource`.
"""
- pass
+ for cb in reversed(self._close_callbacks):
+ cb()
+ self._exit_stack.close()
@property
def command_path(self) -> str:
@@ -392,21 +423,38 @@ class Context:
information on the help page. It's automatically created by
combining the info names of the chain of contexts to the root.
"""
- pass
+ rv = ''
+ if self.parent is not None:
+ rv = self.parent.command_path
+ if rv:
+ rv += ' '
+ rv += self.info_name or ''
+ return rv
def find_root(self) -> 'Context':
"""Finds the outermost context."""
- pass
+ node = self
+ while node.parent is not None:
+ node = node.parent
+ return node
def find_object(self, object_type: t.Type[V]) -> t.Optional[V]:
"""Finds the closest object of a given type."""
- pass
+ node = self
+ while node is not None:
+ if isinstance(node.obj, object_type):
+ return node.obj
+ node = node.parent
+ return None
def ensure_object(self, object_type: t.Type[V]) -> V:
"""Like :meth:`find_object` but sets the innermost object to a
new instance of `object_type` if it does not exist.
"""
- pass
+ rv = self.find_object(object_type)
+ if rv is None:
+ self.obj = rv = object_type()
+ return rv
def lookup_default(self, name: str, call: bool=True) -> t.Optional[t.Any]:
"""Get the default for a parameter from :attr:`default_map`.
@@ -418,7 +466,12 @@ class Context:
.. versionchanged:: 8.0
Added the ``call`` parameter.
"""
- pass
+ if self.default_map is None:
+ return None
+ value = self.default_map.get(name)
+ if call and callable(value):
+ return value()
+ return value
def fail(self, message: str) -> 'te.NoReturn':
"""Aborts the execution of the program with a specific error
@@ -426,27 +479,27 @@ class Context:
:param message: the error message to fail with.
"""
- pass
+ raise UsageError(message, self)
def abort(self) -> 'te.NoReturn':
"""Aborts the script."""
- pass
+ raise Abort()
def exit(self, code: int=0) -> 'te.NoReturn':
"""Exits the application with a given exit code."""
- pass
+ raise Exit(code)
def get_usage(self) -> str:
"""Helper method to get formatted usage string for the current
context and command.
"""
- pass
+ return self.command.get_usage(self)
def get_help(self) -> str:
"""Helper method to get formatted help page for the current
context and command.
"""
- pass
+ return self.command.get_help(self)
def _make_sub_context(self, command: 'Command') -> 'Context':
"""Create a new context of the same type as this context, but
@@ -454,7 +507,7 @@ class Context:
:meta private:
"""
- pass
+ return type(self)(command, parent=self, info_name=command.name, auto_envvar_prefix=self.auto_envvar_prefix)
def invoke(__self, __callback: t.Union['Command', 't.Callable[..., V]'], *args: t.Any, **kwargs: t.Any) -> t.Union[t.Any, V]:
"""Invokes a command callback in exactly the way it expects. There
@@ -476,7 +529,10 @@ class Context:
All ``kwargs`` are tracked in :attr:`params` so they will be
passed if :meth:`forward` is called at multiple levels.
"""
- pass
+ if isinstance(__callback, Command):
+ return __callback.invoke(__self)
+ __self.params.update(kwargs)
+ return __callback(*args, **kwargs)
def forward(__self, __cmd: 'Command', *args: t.Any, **kwargs: t.Any) -> t.Any:
"""Similar to :meth:`invoke` but fills in default keyword
@@ -487,7 +543,8 @@ class Context:
All ``kwargs`` are tracked in :attr:`params` so they will be
passed if ``forward`` is called at multiple levels.
"""
- pass
+ __self.params.update(kwargs)
+ return __cmd.invoke(__self)
def set_parameter_source(self, name: str, source: ParameterSource) -> None:
"""Set the source of a parameter. This indicates the location
@@ -496,7 +553,7 @@ class Context:
:param name: The name of the parameter.
:param source: A member of :class:`~click.core.ParameterSource`.
"""
- pass
+ self._parameter_source[name] = source
def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]:
"""Get the source of a parameter. This indicates the location
@@ -514,7 +571,7 @@ class Context:
Returns ``None`` if the parameter was not provided from any
source.
"""
- pass
+ return self._parameter_source.get(name)
class BaseCommand:
"""The base command implements the minimal API contract of commands.
@@ -740,7 +797,7 @@ class Command(BaseCommand):
Calls :meth:`format_usage` internally.
"""
- pass
+ return None
def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None:
"""Writes the usage line into the formatter.
@@ -761,7 +818,20 @@ class Command(BaseCommand):
def get_help_option(self, ctx: Context) -> t.Optional['Option']:
"""Returns the help option object."""
- pass
+ help_options = self.get_help_option_names(ctx)
+ if not help_options or not self.add_help_option:
+ return None
+
+ import click
+
+ return click.Option(
+ help_options,
+ is_flag=True,
+ is_eager=True,
+ expose_value=False,
+ callback=click.core._help_option,
+ help='Show this message and exit.',
+ )
def make_parser(self, ctx: Context) -> OptionParser:
"""Creates the underlying option parser for this command."""
@@ -778,7 +848,10 @@ class Command(BaseCommand):
"""Gets short help for the command or makes it by shortening the
long help string.
"""
- pass
+ help_text = self.short_help or self.help or ''
+ if len(help_text) <= limit:
+ return help_text
+ return help_text[:limit - 3] + "..."
def format_help(self, ctx: Context, formatter: HelpFormatter) -> None:
"""Writes the help into the formatter if it exists.
@@ -792,25 +865,43 @@ class Command(BaseCommand):
- :meth:`format_options`
- :meth:`format_epilog`
"""
- pass
+ 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: Context, formatter: HelpFormatter) -> None:
"""Writes the help text to the formatter if it exists."""
- pass
+ if self.help:
+ formatter.write_paragraph()
+ with formatter.indentation():
+ formatter.write_text(self.help)
def format_options(self, ctx: Context, formatter: HelpFormatter) -> None:
"""Writes all the options into the formatter if they exist."""
- pass
+ 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: Context, formatter: HelpFormatter) -> None:
"""Writes the epilog into the formatter if it exists."""
- pass
+ if self.epilog:
+ formatter.write_paragraph()
+ with formatter.indentation():
+ formatter.write_text(self.epilog)
def invoke(self, ctx: Context) -> t.Any:
"""Given a context, this invokes the attached callback (if it exists)
in the right way.
"""
- pass
+ if self.callback is not None:
+ return ctx.invoke(self.callback, **ctx.params)
def shell_complete(self, ctx: Context, incomplete: str) -> t.List['CompletionItem']:
"""Return a list of completions for the incomplete value. Looks
@@ -821,7 +912,12 @@ class Command(BaseCommand):
.. versionadded:: 8.0
"""
- pass
+ from click.shell_completion import CompletionItem
+
+ results = []
+ for param in self.get_params(ctx):
+ results.extend(param.shell_complete(ctx, incomplete))
+ return results
class MultiCommand(Command):
"""A multi command is the basic implementation of a command that
@@ -1366,4 +1462,4 @@ class Argument(Parameter):
super().__init__(param_decls, required=required, **attrs)
if __debug__:
if self.default is not None and self.nargs == -1:
- raise TypeError("'default' is not supported for nargs=-1.")
\ No newline at end of file
+ raise TypeError("'default' is not supported for nargs=-1.")