Source code for tests.test_envvar

# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

from __future__ import annotations

import os

import click
import cloup
import pytest
from extra_platforms import is_windows

from click_extra import command, echo, option
from click_extra.envvar import clean_envvar_id, env_copy, merge_envvar_ids


[docs] @pytest.mark.parametrize( ("envvars", "result"), ( (("MY_VAR", "MY_VAR"), ("MY_VAR",)), ((None, "MY_VAR"), ("MY_VAR",)), (("MY_VAR", None), ("MY_VAR",)), ((["MY_VAR"], "MY_VAR"), ("MY_VAR",)), ((["MY_VAR"], None), ("MY_VAR",)), (("MY_VAR", ["MY_VAR"]), ("MY_VAR",)), ((None, ["MY_VAR"]), ("MY_VAR",)), ((["MY_VAR"], ["MY_VAR"]), ("MY_VAR",)), ((["MY_VAR1"], ["MY_VAR2"]), ("MY_VAR1", "MY_VAR2")), ((["MY_VAR1", "MY_VAR2"], ["MY_VAR2"]), ("MY_VAR1", "MY_VAR2")), ((["MY_VAR1"], ["MY_VAR1", "MY_VAR2"]), ("MY_VAR1", "MY_VAR2")), ((["MY_VAR1"], ["MY_VAR2", "MY_VAR2"]), ("MY_VAR1", "MY_VAR2")), ((["MY_VAR1", "MY_VAR1"], ["MY_VAR2"]), ("MY_VAR1", "MY_VAR2")), ( (["MY_VAR1", ["MY_VAR1", None, "MY_VAR1"]], ["MY_VAR2"]), ("MY_VAR1", "MY_VAR2"), ), ), ) def test_merge_envvar_ids(envvars, result): assert merge_envvar_ids(*envvars) == result
[docs] @pytest.mark.parametrize( ("env_name", "clean_name"), ( ("show-params-cli_VERSION", "SHOW_PARAMS_CLI_VERSION"), ("show---params-cli___VERSION", "SHOW_PARAMS_CLI_VERSION"), ("__show-__params-_-_-", "SHOW_PARAMS"), ), ) def test_clean_envvar_id(env_name, clean_name): assert clean_envvar_id(env_name) == clean_name
[docs] @pytest.mark.parametrize( ("cmd_decorator", "option_help"), ( # Click and Cloup do not show the auto-generated envvar in the help screen. ( click.command, " --flag / --no-flag [env var: custom]\n", ), ( cloup.command, " --flag / --no-flag [env var: custom]\n", ), # Click Extra always adds the auto-generated envvar to the help screen # (and show the defaults). ( command, " --flag / --no-flag [env var: " + ("CUSTOM, YO_FLAG" if os.name == "nt" else "custom, yo_FLAG") + "; default: no-flag]\n", ), ), ) def test_show_auto_envvar_help(invoke, cmd_decorator, option_help): """Check that the auto-generated envvar appears in the help screen with the extra variants. Checks that https://github.com/pallets/click/issues/2483 is addressed. """ @cmd_decorator(context_settings={"auto_envvar_prefix": "yo"}) @option("--flag/--no-flag", envvar=["custom"], show_envvar=True) def envvar_help(): pass # Remove colors to simplify output comparison. result = invoke(envvar_help, "--help", color=False) assert option_help in result.stdout assert not result.stderr assert result.exit_code == 0
[docs] def envvars_test_cases(): params = [] matrix = { (click.command, "click.command"): { "working_envvar": ( # User-defined envvars are recognized as-is. "Magic", "sUper", # XXX Uppercased auto-generated envvar is recognized but should not be. "YO_FLAG", ), "unknown_envvar": ( # Uppercased user-defined envvar is not recognized. "MAGIC", # XXX Literal auto-generated is not recognized but should be. "yo_FLAG", # Mixed-cased auto-generated envvat is not recognized. "yo_FlAg", ), }, (cloup.command, "cloup.command"): { "working_envvar": ( # User-defined envvars are recognized as-is. "Magic", "sUper", # XXX Uppercased auto-generated envvar is recognized but should not be. "YO_FLAG", ), "unknown_envvar": ( # Uppercased user-defined envvar is not recognized. "MAGIC", # XXX Literal auto-generated is not recognized but should be. "yo_FLAG", # Mixed-cased auto-generated envvat is not recognized. "yo_FlAg", ), }, (command, "click_extra.command"): { "working_envvar": ( # User-defined envvars are recognized as-is. "Magic", "sUper", # Literal auto-generated is properly recognized but is not in vanilla # Click (see above). "yo_FLAG", # XXX Uppercased auto-generated envvar is recognized but should not be. "YO_FLAG", ), "unknown_envvar": ( # Uppercased user-defined envvar is not recognized. "MAGIC", # Mixed-cased auto-generated envvat is not recognized. "yo_FlAg", ), }, } # Windows is automaticcaly normalizing any env var to upper-case, see: # https://github.com/python/cpython/blob/e715da6/Lib/os.py#L748-L749 # https://docs.python.org/3/library/os.html?highlight=environ#os.environ # So Windows needs its own test case. if is_windows(): all_envvars = ( "Magic", "MAGIC", "sUper", "yo_FLAG", "YO_FLAG", "yo_FlAg", ) matrix = { (click.command, "click.command"): { "working_envvar": all_envvars, "unknown_envvar": (), }, (cloup.command, "cloup.command"): { "working_envvar": all_envvars, "unknown_envvar": (), }, (command, "click_extra.command"): { "working_envvar": all_envvars, "unknown_envvar": (), }, } # If properly recognized, these envvar values should be passed to the flag. working_value_map = { "True": True, "true": True, "tRuE": True, "1": True, "": False, # XXX: Should be True? "False": False, "false": False, "fAlsE": False, "0": False, } # No envvar value will have an effect on the flag if the envvar is not recognized. broken_value_map = {k: False for k in working_value_map} for (cmd_decorator, decorator_name), envvar_cases in matrix.items(): for case_name, envvar_names in envvar_cases.items(): value_map = ( working_value_map if case_name == "working_envvar" else broken_value_map ) for envvar_name in envvar_names: for envar_value, expected_flag in value_map.items(): envvar = {envvar_name: envar_value} test_id = ( f"{decorator_name}|{case_name}={envvar}" f"|expected_flag={expected_flag}" ) params.append( pytest.param(cmd_decorator, envvar, expected_flag, id=test_id) ) return params
[docs] @pytest.mark.parametrize( ("cmd_decorator", "envvars", "expected_flag"), envvars_test_cases() ) def test_auto_envvar_parsing(invoke, cmd_decorator, envvars, expected_flag): """This test highlights the way Click recognize and parse envvars. It shows that the default behavior is not ideal, and covers how ``command`` improves the situation by normalizing the envvar name. """ @cmd_decorator(context_settings={"auto_envvar_prefix": "yo"}) @option("--flag/--no-flag", envvar=["Magic", "sUper"]) def my_cli(flag): echo(f"Flag value: {flag}") registered_envvars = ["Magic", "sUper"] # Specific behavior of @click_extra.command that is not present in vanilla Click. if cmd_decorator == command: # @command forces registration of auto-generated envvar. registered_envvars = [*registered_envvars, "yo_FLAG"] # On Windows, envvars are normalizes to uppercase. if os.name == "nt": registered_envvars = [envvar.upper() for envvar in registered_envvars] # @command parameters returns envvar property as tuple, while vanilla Click # returns a list. registered_envvars = tuple(registered_envvars) assert my_cli.params[0].envvar == registered_envvars result = invoke(my_cli, env=envvars) assert result.stdout == f"Flag value: {expected_flag}\n" assert not result.stderr assert result.exit_code == 0
[docs] def test_env_copy(): envvar = "MPM_DUMMY_ENVVAR_93725" assert envvar not in os.environ no_env = env_copy() assert no_env is None extended_env = env_copy({envvar: "yo"}) assert envvar in extended_env assert extended_env[envvar] == "yo" assert envvar not in os.environ