python-click/tests/test_arguments.py

380 lines
10 KiB
Python
Raw Normal View History

2020-07-21 08:23:42 +02:00
import sys
2019-01-07 17:51:19 +01:00
import pytest
2020-07-21 08:23:42 +02:00
2014-10-16 20:40:34 +02:00
import click
def test_nargs_star(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("src", nargs=-1)
@click.argument("dst")
2014-10-16 20:40:34 +02:00
def copy(src, dst):
2021-10-10 03:31:57 +02:00
click.echo(f"src={'|'.join(src)}")
click.echo(f"dst={dst}")
2014-10-16 20:40:34 +02:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(copy, ["foo.txt", "bar.txt", "dir"])
2014-10-16 20:40:34 +02:00
assert not result.exception
2020-07-21 08:23:42 +02:00
assert result.output.splitlines() == ["src=foo.txt|bar.txt", "dst=dir"]
2014-10-16 20:40:34 +02:00
2021-10-10 03:31:57 +02:00
def test_argument_unbounded_nargs_cant_have_default(runner):
2020-07-21 08:23:42 +02:00
with pytest.raises(TypeError, match="nargs=-1"):
2015-12-04 16:51:02 +01:00
@click.command()
2021-10-10 03:31:57 +02:00
@click.argument("src", nargs=-1, default=["42"])
2015-12-04 16:51:02 +01:00
def copy(src):
pass
2014-10-16 20:40:34 +02:00
def test_nargs_tup(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("name", nargs=1)
@click.argument("point", nargs=2, type=click.INT)
2014-10-16 20:40:34 +02:00
def copy(name, point):
2021-10-10 03:31:57 +02:00
click.echo(f"name={name}")
x, y = point
click.echo(f"point={x}/{y}")
2014-10-16 20:40:34 +02:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(copy, ["peter", "1", "2"])
2014-10-16 20:40:34 +02:00
assert not result.exception
2020-07-21 08:23:42 +02:00
assert result.output.splitlines() == ["name=peter", "point=1/2"]
2014-10-16 20:40:34 +02:00
2022-11-30 09:52:01 +01:00
@pytest.mark.parametrize(
"opts",
[
2015-07-16 14:26:14 +02:00
dict(type=(str, int)),
dict(type=click.Tuple([str, int])),
dict(nargs=2, type=click.Tuple([str, int])),
dict(nargs=2, type=(str, int)),
2022-11-30 09:52:01 +01:00
],
)
def test_nargs_tup_composite(runner, opts):
@click.command()
@click.argument("item", **opts)
def copy(item):
name, id = item
click.echo(f"name={name} id={id:d}")
2015-07-16 14:26:14 +02:00
2022-11-30 09:52:01 +01:00
result = runner.invoke(copy, ["peter", "1"])
assert result.exception is None
assert result.output.splitlines() == ["name=peter id=1"]
2015-07-16 14:26:14 +02:00
2014-10-16 20:40:34 +02:00
def test_nargs_err(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("x")
2014-10-16 20:40:34 +02:00
def copy(x):
click.echo(x)
2020-07-21 08:23:42 +02:00
result = runner.invoke(copy, ["foo"])
2014-10-16 20:40:34 +02:00
assert not result.exception
2020-07-21 08:23:42 +02:00
assert result.output == "foo\n"
2014-10-16 20:40:34 +02:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(copy, ["foo", "bar"])
2014-10-16 20:40:34 +02:00
assert result.exit_code == 2
2020-07-21 08:23:42 +02:00
assert "Got unexpected extra argument (bar)" in result.output
def test_bytes_args(runner, monkeypatch):
@click.command()
@click.argument("arg")
def from_bytes(arg):
assert isinstance(
2021-10-10 03:31:57 +02:00
arg, str
2020-07-21 08:23:42 +02:00
), "UTF-8 encoded argument should be implicitly converted to Unicode"
# Simulate empty locale environment variables
2021-10-10 03:31:57 +02:00
monkeypatch.setattr(sys.stdin, "encoding", "utf-8")
monkeypatch.setattr(sys, "getfilesystemencoding", lambda: "utf-8")
monkeypatch.setattr(sys, "getdefaultencoding", lambda: "utf-8")
2020-07-21 08:23:42 +02:00
runner.invoke(
from_bytes,
2021-10-10 03:31:57 +02:00
["Something outside of ASCII range: 林".encode()],
2020-07-21 08:23:42 +02:00
catch_exceptions=False,
)
2014-10-16 20:40:34 +02:00
def test_file_args(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("input", type=click.File("rb"))
@click.argument("output", type=click.File("wb"))
2014-10-16 20:40:34 +02:00
def inout(input, output):
while True:
chunk = input.read(1024)
if not chunk:
break
output.write(chunk)
with runner.isolated_filesystem():
2020-07-21 08:23:42 +02:00
result = runner.invoke(inout, ["-", "hello.txt"], input="Hey!")
assert result.output == ""
2014-10-16 20:40:34 +02:00
assert result.exit_code == 0
2020-07-21 08:23:42 +02:00
with open("hello.txt", "rb") as f:
assert f.read() == b"Hey!"
2014-10-16 20:40:34 +02:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(inout, ["hello.txt", "-"])
assert result.output == "Hey!"
2014-10-16 20:40:34 +02:00
assert result.exit_code == 0
2022-11-30 09:52:01 +01:00
def test_path_allow_dash(runner):
2016-04-06 18:13:57 +02:00
@click.command()
2022-11-30 09:52:01 +01:00
@click.argument("input", type=click.Path(allow_dash=True))
2016-04-06 18:13:57 +02:00
def foo(input):
click.echo(input)
2020-07-21 08:23:42 +02:00
result = runner.invoke(foo, ["-"])
assert result.output == "-\n"
2016-04-06 18:13:57 +02:00
assert result.exit_code == 0
2014-10-16 20:40:34 +02:00
def test_file_atomics(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("output", type=click.File("wb", atomic=True))
2014-10-16 20:40:34 +02:00
def inout(output):
2020-07-21 08:23:42 +02:00
output.write(b"Foo bar baz\n")
2014-10-16 20:40:34 +02:00
output.flush()
2020-07-21 08:23:42 +02:00
with open(output.name, "rb") as f:
2014-10-16 20:40:34 +02:00
old_content = f.read()
2020-07-21 08:23:42 +02:00
assert old_content == b"OLD\n"
2014-10-16 20:40:34 +02:00
with runner.isolated_filesystem():
2020-07-21 08:23:42 +02:00
with open("foo.txt", "wb") as f:
f.write(b"OLD\n")
result = runner.invoke(inout, ["foo.txt"], input="Hey!", catch_exceptions=False)
assert result.output == ""
2014-10-16 20:40:34 +02:00
assert result.exit_code == 0
2020-07-21 08:23:42 +02:00
with open("foo.txt", "rb") as f:
assert f.read() == b"Foo bar baz\n"
2014-10-16 20:40:34 +02:00
def test_stdout_default(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("output", type=click.File("w"), default="-")
2014-10-16 20:40:34 +02:00
def inout(output):
2020-07-21 08:23:42 +02:00
output.write("Foo bar baz\n")
2014-10-16 20:40:34 +02:00
output.flush()
result = runner.invoke(inout, [])
assert not result.exception
2020-07-21 08:23:42 +02:00
assert result.output == "Foo bar baz\n"
2014-10-16 20:40:34 +02:00
2021-10-10 03:31:57 +02:00
@pytest.mark.parametrize(
("nargs", "value", "expect"),
[
(2, "", None),
(2, "a", "Takes 2 values but 1 was given."),
(2, "a b", ("a", "b")),
(2, "a b c", "Takes 2 values but 3 were given."),
(-1, "a b c", ("a", "b", "c")),
(-1, "", ()),
],
)
def test_nargs_envvar(runner, nargs, value, expect):
if nargs == -1:
param = click.argument("arg", envvar="X", nargs=nargs)
else:
param = click.option("--arg", envvar="X", nargs=nargs)
2014-10-16 20:40:34 +02:00
@click.command()
2021-10-10 03:31:57 +02:00
@param
2014-10-16 20:40:34 +02:00
def cmd(arg):
2021-10-10 03:31:57 +02:00
return arg
2014-10-16 20:40:34 +02:00
2021-10-10 03:31:57 +02:00
result = runner.invoke(cmd, env={"X": value}, standalone_mode=False)
if isinstance(expect, str):
assert isinstance(result.exception, click.BadParameter)
assert expect in result.exception.format_message()
else:
assert result.return_value == expect
2014-10-16 20:40:34 +02:00
2021-10-10 03:31:57 +02:00
def test_nargs_envvar_only_if_values_empty(runner):
2014-10-16 20:40:34 +02:00
@click.command()
2021-10-10 03:31:57 +02:00
@click.argument("arg", envvar="X", nargs=-1)
def cli(arg):
return arg
2014-10-16 20:40:34 +02:00
2021-10-10 03:31:57 +02:00
result = runner.invoke(cli, ["a", "b"], standalone_mode=False)
assert result.return_value == ("a", "b")
result = runner.invoke(cli, env={"X": "a"}, standalone_mode=False)
assert result.return_value == ("a",)
2014-10-16 20:40:34 +02:00
def test_empty_nargs(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("arg", nargs=-1)
2014-10-16 20:40:34 +02:00
def cmd(arg):
2021-10-10 03:31:57 +02:00
click.echo(f"arg:{'|'.join(arg)}")
2014-10-16 20:40:34 +02:00
result = runner.invoke(cmd, [])
assert result.exit_code == 0
2020-07-21 08:23:42 +02:00
assert result.output == "arg:\n"
2014-10-16 20:40:34 +02:00
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("arg", nargs=-1, required=True)
2014-10-16 20:40:34 +02:00
def cmd2(arg):
2021-10-10 03:31:57 +02:00
click.echo(f"arg:{'|'.join(arg)}")
2014-10-16 20:40:34 +02:00
result = runner.invoke(cmd2, [])
assert result.exit_code == 2
2020-07-21 08:23:42 +02:00
assert "Missing argument 'ARG...'" in result.output
2014-10-16 20:40:34 +02:00
def test_missing_arg(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("arg")
2014-10-16 20:40:34 +02:00
def cmd(arg):
2021-10-10 03:31:57 +02:00
click.echo(f"arg:{arg}")
2014-10-16 20:40:34 +02:00
result = runner.invoke(cmd, [])
assert result.exit_code == 2
2020-07-21 08:23:42 +02:00
assert "Missing argument 'ARG'." in result.output
def test_missing_argument_string_cast():
ctx = click.Context(click.Command(""))
with pytest.raises(click.MissingParameter) as excinfo:
2021-10-10 03:31:57 +02:00
click.Argument(["a"], required=True).process_value(ctx, None)
2020-07-21 08:23:42 +02:00
2021-10-10 03:31:57 +02:00
assert str(excinfo.value) == "Missing parameter: a"
2014-10-16 20:40:34 +02:00
def test_implicit_non_required(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("f", default="test")
2014-10-16 20:40:34 +02:00
def cli(f):
click.echo(f)
result = runner.invoke(cli, [])
assert result.exit_code == 0
2020-07-21 08:23:42 +02:00
assert result.output == "test\n"
2014-10-16 20:40:34 +02:00
def test_eat_options(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.option("-f")
@click.argument("files", nargs=-1)
2014-10-16 20:40:34 +02:00
def cmd(f, files):
for filename in files:
click.echo(filename)
click.echo(f)
2020-07-21 08:23:42 +02:00
result = runner.invoke(cmd, ["--", "-foo", "bar"])
assert result.output.splitlines() == ["-foo", "bar", ""]
2014-10-16 20:40:34 +02:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(cmd, ["-f", "-x", "--", "-foo", "bar"])
assert result.output.splitlines() == ["-foo", "bar", "-x"]
2015-07-16 14:26:14 +02:00
def test_nargs_star_ordering(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("a", nargs=-1)
@click.argument("b")
@click.argument("c")
2015-07-16 14:26:14 +02:00
def cmd(a, b, c):
for arg in (a, b, c):
click.echo(arg)
2020-07-21 08:23:42 +02:00
result = runner.invoke(cmd, ["a", "b", "c"])
2021-10-10 03:31:57 +02:00
assert result.output.splitlines() == ["('a',)", "b", "c"]
2015-07-16 14:26:14 +02:00
def test_nargs_specified_plus_star_ordering(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("a", nargs=-1)
@click.argument("b")
@click.argument("c", nargs=2)
2015-07-16 14:26:14 +02:00
def cmd(a, b, c):
for arg in (a, b, c):
click.echo(arg)
2020-07-21 08:23:42 +02:00
result = runner.invoke(cmd, ["a", "b", "c", "d", "e", "f"])
2021-10-10 03:31:57 +02:00
assert result.output.splitlines() == ["('a', 'b', 'c')", "d", "('e', 'f')"]
2015-12-04 16:51:02 +01:00
def test_defaults_for_nargs(runner):
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("a", nargs=2, type=int, default=(1, 2))
2015-12-04 16:51:02 +01:00
def cmd(a):
x, y = a
click.echo(x + y)
result = runner.invoke(cmd, [])
2020-07-21 08:23:42 +02:00
assert result.output.strip() == "3"
2015-12-04 16:51:02 +01:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(cmd, ["3", "4"])
assert result.output.strip() == "7"
2015-12-04 16:51:02 +01:00
2020-07-21 08:23:42 +02:00
result = runner.invoke(cmd, ["3"])
2015-12-04 16:51:02 +01:00
assert result.exception is not None
2021-10-10 03:31:57 +02:00
assert "Argument 'a' takes 2 values." in result.output
2019-01-07 17:51:19 +01:00
def test_multiple_param_decls_not_allowed(runner):
with pytest.raises(TypeError):
2020-07-21 08:23:42 +02:00
2019-01-07 17:51:19 +01:00
@click.command()
2020-07-21 08:23:42 +02:00
@click.argument("x", click.Choice(["a", "b"]))
2019-01-07 17:51:19 +01:00
def copy(x):
click.echo(x)
2021-10-10 03:31:57 +02:00
def test_multiple_not_allowed():
with pytest.raises(TypeError, match="multiple"):
click.Argument(["a"], multiple=True)
@pytest.mark.parametrize("value", [(), ("a",), ("a", "b", "c")])
def test_nargs_bad_default(runner, value):
with pytest.raises(ValueError, match="nargs=2"):
click.Argument(["a"], nargs=2, default=value)
def test_subcommand_help(runner):
@click.group()
@click.argument("name")
@click.argument("val")
@click.option("--opt")
@click.pass_context
def cli(ctx, name, val, opt):
ctx.obj = dict(name=name, val=val)
@cli.command()
@click.pass_obj
def cmd(obj):
click.echo(f"CMD for {obj['name']} with value {obj['val']}")
result = runner.invoke(cli, ["foo", "bar", "cmd", "--help"])
assert not result.exception
assert "Usage: cli NAME VAL cmd [OPTIONS]" in result.output
def test_nested_subcommand_help(runner):
@click.group()
@click.argument("arg1")
@click.option("--opt1")
def cli(arg1, opt1):
pass
@cli.group()
@click.argument("arg2")
@click.option("--opt2")
def cmd(arg2, opt2):
pass
@cmd.command()
def subcmd():
click.echo("subcommand")
result = runner.invoke(cli, ["arg1", "cmd", "arg2", "subcmd", "--help"])
assert not result.exception
assert "Usage: cli ARG1 cmd ARG2 subcmd [OPTIONS]" in result.output