Commit df27e233 authored by Amir MOHAMMADI's avatar Amir MOHAMMADI

[click] ResourceOption can be used without ConfigCommand

parent f3ead456
Pipeline #36163 passed with stage
in 7 minutes and 7 seconds
......@@ -299,9 +299,21 @@ file.""".format(
class ResourceOption(click.Option):
"""A click.Option that is aware if the user actually provided this option
through command-line or it holds a default value. The option can also be a
resource that will be automatically loaded.
"""A click.Option that automatically loads resources.
It uses :any:`load` to convert provided strings in the command line into Python
It also integrates with the ConfigCommand class.
You may use this class in three ways:
1. Using this class without using :any:`ConfigCommand` AND providing
2. Using this class with :any:`ConfigCommand` AND providing `entry_point_group`.
3. Using this class with :any:`ConfigCommand` AND without providing
Using this class without :any:`ConfigCommand` and without providing
`entry_point_group` does nothing and is not allowed.
......@@ -355,11 +367,25 @@ class ResourceOption(click.Option):
def consume_value(self, ctx, opts):
logger.debug("consuming resource option for option %s",
if (not hasattr(ctx, "config_context")) and self.entry_point_group is None:
raise TypeError(
"The ResourceOption class is not meant to be used this way. "
"Please see the docs of the class."
logger.debug("consuming resource option for %s",
value = opts.get(
# if value is not given from command line, lookup the config files
# if value is not given from command line, lookup the config files given as
# arguments (not options).
if value is None:
value = ctx.config_context.get(
# if this class is used with the ConfigCommand class. This is not always
# true.
if hasattr(ctx, "config_context"):
value = ctx.config_context.get(
"config_context attribute not found in context. Did you mean to "
"use the ConfigCommand class with this ResourceOption class?"
# if not from config files, lookup the environment variables
if value is None:
value = self.value_from_envvar(ctx)
......@@ -426,7 +452,7 @@ def log_parameters(logger_handle, ignore=tuple()):
logger_handle.debug("%s: %s", k, v)
def assert_click_runner_result(result, exit_code=0):
def assert_click_runner_result(result, exit_code=0, exception_type=None):
"""Helper for asserting click runner results"""
m = "Click command exited with code `{}' and exception:\n{}" "\nThe output was:\n{}"
exception = (
......@@ -438,3 +464,5 @@ def assert_click_runner_result(result, exit_code=0):
assert result.exit_code == exit_code, m
if exit_code == 0:
assert not result.exception, m
if exception_type is not None:
assert isinstance(result.exception, exception_type), m
......@@ -274,3 +274,27 @@ def test_config_command_with_callback_options():
runner = CliRunner(env=dict(VERBOSE='2'))
result = runner.invoke(cli, catch_exceptions=False)
def test_resource_option():
# tests of ResourceOption used with ConfigCommand are done in other tests.
# test usage without ConfigCommand and with entry_point_group
@click.option('-a', '--a', cls=ResourceOption, entry_point_group='bob.extension.test_config_load')
def cli(a):
assert a == 1, a
runner = CliRunner()
result = runner.invoke(cli, ['-a', ''], catch_exceptions=False)
# test usage without ConfigCommand and without entry_point_group
# should raise a TypeError
@click.option('-a', '--a', cls=ResourceOption)
def cli(a):
raise ValueError("Should not have reached here!")
runner = CliRunner()
result = runner.invoke(cli, ['-a', '1'], catch_exceptions=True)
assert_click_runner_result(result, exit_code=1, exception_type=TypeError)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment