Skip to content

Commit

Permalink
#79 Improvements in std_options.py
Browse files Browse the repository at this point in the history
  • Loading branch information
ahsimb committed Oct 11, 2024
1 parent ee3cc30 commit 9c963d1
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 12 deletions.
10 changes: 10 additions & 0 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# Unreleased

## Features

* #79 Added function get_cli_arg that makes a string CLI argument from an option and its value.
Also allowed passing an option name instead of the StdParams in the following two functions:
create_std_option, check_params.

## Bug fixing

* #78 Missing default value in the definition of StdParams.path_in_bucket.
47 changes: 36 additions & 11 deletions exasol/python_extension_common/cli/std_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ def __init__(self, tags: StdTags, value):
self.tags = tags


StdParamOrName = StdParams | str


def _get_param_name(std_param: StdParamOrName) -> str:
return std_param if isinstance(std_param, str) else std_param.name


"""
Standard options defined in the form of key-value pairs, where key is the option's
StaParam key and the value is a kwargs for creating the click.Options(...).
Expand All @@ -135,7 +142,7 @@ def __init__(self, tags: StdTags, value):
StdParams.saas_database_id: {'type': str, 'hide_input': True},
StdParams.saas_database_name: {'type': str},
StdParams.saas_token: {'type': str, 'hide_input': True},
StdParams.path_in_bucket: {'type': str},
StdParams.path_in_bucket: {'type': str, 'default': ''},
StdParams.container_file: {'type': click.Path(exists=True, file_okay=True)},
StdParams.version: {'type': str, 'expose_value': False},
StdParams.dsn: {'type': str},
Expand Down Expand Up @@ -172,23 +179,26 @@ def make_option_secret(option_params: dict[str, Any], prompt: str) -> None:
option_params['callback'] = secret_callback


def create_std_option(std_param: StdParams, **kwargs) -> click.Option:
def create_std_option(std_param: StdParamOrName, **kwargs) -> click.Option:
"""
Creates a Click option.
Parameters:
std_param:
The option's StdParam key.
The option's StdParam key or its name. If the name is provided it doesn't have
to be the name of a defined StdParams. It can be an arbitrary identifier which
will be passed to the callback function of the CLI command in the kwargs.
kwargs:
The option properties.
"""
option_name = std_param.name.replace('_', '-')
std_param_name = _get_param_name(std_param)
option_name = std_param_name.replace('_', '-')
if kwargs.get('type') == bool:
param_decls = [f'--{option_name}/--no-{option_name}']
else:
param_decls = [f'--{option_name}']
if kwargs.get('hide_input', False):
make_option_secret(kwargs, prompt=std_param.name.replace('_', ' '))
make_option_secret(kwargs, prompt=std_param_name.replace('_', ' '))
return click.Option(param_decls, **kwargs)


Expand Down Expand Up @@ -238,7 +248,20 @@ def option_params(std_param: StdParams) -> dict[str, Any]:
for std_param in filtered_params]


def check_params(std_params: StdParams | list[StdParams | list[StdParams]],
def get_cli_arg(std_param: StdParamOrName, param_value: Any) -> str:
"""
Makes a CLI args string from an option and its value.
An option can be given as either an StdParams or its string name.
For boolean values the args string takes the form --option-name/--no-option-name.
"""

option_name = _get_param_name(std_param).replace("_", "-")
if isinstance(param_value, bool):
return f'--{option_name}' if param_value else f'--no-{option_name}'
return f'--{option_name} "{param_value}"'


def check_params(std_params: StdParamOrName | list[StdParamOrName | list[StdParamOrName]],
param_kwargs: dict[str, Any]) -> bool:
"""
Checks if the kwargs contain specified StdParams keys. The intention is to verify
Expand All @@ -256,16 +279,18 @@ def check_params(std_params: StdParams | list[StdParams | list[StdParams]],
Parameters:
std_params:
Required options. This can be either a single option or a list of options
representing a logical expression.
representing a logical expression. An option can be given as either an StdParams
or its string name.
param_kwargs:
A dictionary of provided values (kwargs).
"""
def check_param(std_param: StdParams | list[StdParams]) -> bool:
def check_param(std_param: StdParamOrName | list[StdParamOrName]) -> bool:
if isinstance(std_param, list):
return any(check_param(std_param_i) for std_param_i in std_param)
return ((std_param.name in param_kwargs) and
(isinstance(param_kwargs[std_param.name], bool) or
bool(param_kwargs[std_param.name])))
std_param_name = _get_param_name(std_param)
return ((std_param_name in param_kwargs) and
(isinstance(param_kwargs[std_param_name], bool) or
bool(param_kwargs[std_param_name])))

if isinstance(std_params, list):
return all(check_param(std_param) for std_param in std_params)
Expand Down
34 changes: 33 additions & 1 deletion test/unit/cli/test_std_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
StdParams,
create_std_option,
select_std_options,
get_cli_arg,
check_params
)

Expand Down Expand Up @@ -59,6 +60,12 @@ def test_create_std_option_secret():
assert opt.default == SECRET_DISPLAY


def test_create_std_option_arbitrary_name():
opt_name = 'xyz'
opt = create_std_option(opt_name, type=str)
assert opt.name == opt_name


def test_select_std_options():
for tag in StdTags:
opts = {opt.name for opt in select_std_options(tag)}
Expand Down Expand Up @@ -148,6 +155,19 @@ def func(**kwargs):
os.environ.pop(envar_name)


@pytest.mark.parametrize(
['std_param', 'param_value', 'expected_result'],
[
(StdParams.db_user, 'Me', '--db-user "Me"'),
('user_rating', 5, '--user-rating "5"'),
(StdParams.use_ssl_cert_validation, True, '--use-ssl-cert-validation'),
(StdParams.use_ssl_cert_validation, False, '--no-use-ssl-cert-validation')
]
)
def test_get_cli_arg(std_param, param_value, expected_result):
assert get_cli_arg(std_param, param_value) == expected_result


@pytest.mark.parametrize(
['std_params', 'param_kwargs', 'expected_result'],
[
Expand Down Expand Up @@ -185,7 +205,19 @@ def func(**kwargs):
StdParams.dsn,
{StdParams.dsn.name: 'my_dsn', StdParams.use_ssl_cert_validation.name: False},
True
)
),
(
[[StdParams.dsn.name, StdParams.db_user.name],
[StdParams.saas_url.name, StdParams.saas_account_id.name]],
{StdParams.dsn.name: 'my_dsn', StdParams.db_user.name: 'my_user_name'},
False,
),
(
[[StdParams.dsn.name, StdParams.saas_url.name],
[StdParams.db_user.name, StdParams.saas_account_id.name]],
{StdParams.dsn.name: 'my_dsn', StdParams.db_user.name: 'my_user_name'},
True,
),
]
)
def test_check_params(std_params, param_kwargs, expected_result):
Expand Down

0 comments on commit 9c963d1

Please sign in to comment.