diff --git a/dvc/utils/__init__.py b/dvc/utils/__init__.py index ee0575212c..051f819ef3 100644 --- a/dvc/utils/__init__.py +++ b/dvc/utils/__init__.py @@ -237,14 +237,19 @@ def as_posix(path: str) -> str: return path.replace(ntpath.sep, posixpath.sep) +TRUTHY_VALUES = frozenset({"1", "y", "yes", "true"}) + + def env2bool(var, undefined=False): """ undefined: return value if env var is unset """ - var = os.getenv(var, None) - if var is None: + value = os.getenv(var, None) + if value is None: return undefined - return bool(re.search("1|y|yes|true", var, flags=re.IGNORECASE)) + # Compare the whole value: a substring search treats any value that merely + # contains "1" or "y" (e.g. "deny", "only", "10") as true. + return value.strip().lower() in TRUTHY_VALUES def resolve_output(inp: str, out: Optional[str], force=False) -> str: diff --git a/tests/unit/utils/test_env2bool.py b/tests/unit/utils/test_env2bool.py new file mode 100644 index 0000000000..3309edbe89 --- /dev/null +++ b/tests/unit/utils/test_env2bool.py @@ -0,0 +1,31 @@ +import pytest + +from dvc.utils import env2bool + +VAR = "DVC_TEST_ENV2BOOL" + + +def test_unset_returns_undefined(monkeypatch): + monkeypatch.delenv(VAR, raising=False) + assert env2bool(VAR) is False + assert env2bool(VAR, undefined=True) is True + + +@pytest.mark.parametrize("value", ["1", "y", "yes", "true", "TRUE", "Yes", " true "]) +def test_truthy_values(monkeypatch, value): + monkeypatch.setenv(VAR, value) + assert env2bool(VAR) is True + + +@pytest.mark.parametrize("value", ["0", "n", "no", "false", "off", ""]) +def test_falsy_values(monkeypatch, value): + monkeypatch.setenv(VAR, value) + assert env2bool(VAR) is False + + +@pytest.mark.parametrize("value", ["deny", "only", "anything", "my-value", "10", "1a"]) +def test_values_merely_containing_a_truthy_token_are_false(monkeypatch, value): + # The value is compared as a whole: a substring search would treat anything + # containing "1" or "y" as true, so "deny" and "10" would enable a flag. + monkeypatch.setenv(VAR, value) + assert env2bool(VAR) is False