Source code for message_ix_models.tests.util.test_click

"""Basic tests of the command line."""

import click
import pytest

from message_ix_models.cli import cli_test_group
from message_ix_models.util.click import (
    common_params,
    scenario_param,
    temporary_command,
)


[docs]def test_default_path_cb(session_context, mix_models_cli): """Test :func:`.default_path_cb`.""" # Create a hidden command and attach it to the CLI @click.command("default_path_cb") @common_params("rep_out_path") @click.pass_obj def func(ctx, rep_out_path): print(ctx["rep_out_path"]) # Print the value stored on the Context object # Command parameters: --local-data gives the local data path, but the --rep-out-path # option is *not* given cmd = [f"--local-data={session_context.local_data}", "_test", func.name] # …so default_path_cb() should supply "{local_data}/reporting_output". expected = session_context.local_data / "reporting_output" # Run the command with temporary_command(cli_test_group, func): result = mix_models_cli.assert_exit_0(cmd) # The value was stored on, and retrieved from, `ctx` assert result.output.startswith(f"{expected}\n")
[docs]def test_regions(mix_models_cli): """--regions=… used on both group and a command within the group. If the option is not provided to the inner command, the value given to the outer group should persist. """ @click.group() @common_params("regions") def outer(regions): pass @outer.command() @common_params("regions") @click.pass_obj def inner(context, regions): print(context.model.regions) # Give the option for the outer group, but not for the inner command with temporary_command(cli_test_group, outer): result = mix_models_cli.assert_exit_0( ["_test", "outer", "--regions=ZMB", "inner"] ) # Value given to the outer group is stored and available to the inner command assert "ZMB" == result.output.strip()
[docs]@pytest.mark.parametrize( "args, command, expected", [ # As a (required, positional) argument (dict(param_decls="ssp"), ["LED"], "LED"), (dict(param_decls="ssp"), ["FOO"], "'FOO' is not one of 'LED', 'SSP1', "), # As an option # With no default (dict(param_decls="--ssp"), [], "None"), # With a limited of values ( dict(param_decls="--ssp", values=["LED", "SSP2"]), ["--ssp=SSP1"], "'SSP1' is not one of 'LED', 'SSP2'", ), # With a default (dict(param_decls="--ssp", default="SSP2"), [], "SSP2"), # With a different name (dict(param_decls=["--scenario", "ssp"]), ["--scenario=SSP5"], "SSP5"), ], ) def test_scenario_param(capsys, mix_models_cli, args, command, expected): """Tests of :func:`scenario_param`.""" # scenario_param() can be used as a decorator with `args` @click.command @scenario_param(**args) @click.pass_obj def cmd(context): """Temporary click Command: print the direct value and Context attribute.""" print(f"{context.ssp}") with temporary_command(cli_test_group, cmd): try: result = mix_models_cli.assert_exit_0(["_test", "cmd"] + command) except RuntimeError as e: # `command` raises the expected value or error message assert expected in capsys.readouterr().out, e else: # `command` can be invoked without error, and the function/Context get the # expected value assert expected == result.output.strip()
[docs]def test_store_context(mix_models_cli): """Test :func:`.store_context`.""" # Create a hidden command and attach it to the CLI @click.command("store_context") @common_params("ssp") @click.pass_obj def func(ctx, ssp): print(ctx["ssp"]) # Print the value stored on the Context object # Run the command with a valid value with temporary_command(cli_test_group, func): result = mix_models_cli.assert_exit_0(["_test", func.name, "SSP2"]) # The value was stored on, and retrieved from, `ctx` assert "SSP2\n" == result.output
[docs]def test_urls_from_file(mix_models_cli, tmp_path): """Test :func:`.urls_from_file` callback.""" # Create a hidden command and attach it to the CLI @click.command("urls_from_file") @common_params("urls_from_file") @click.pass_obj def func(ctx, **kwargs): # Print the value stored on the Context object print("\n".join([s.url for s in ctx.core.scenarios])) # Create a temporary file with some scenario URLs text = """m/s#3 foo/bar#5 baz/qux#123 """ p = tmp_path.joinpath("scenarios.txt") p.write_text(text) # Run the command, referring to the temporary file with temporary_command(cli_test_group, func): result = mix_models_cli.assert_exit_0( ["_test", func.name, f"--urls-from-file={p}"] ) # Scenario URLs are parsed to ScenarioInfo objects, and then can be reconstructed → # data is round-tripped assert text == result.output