# -*- coding: utf-8 -*- import sys import pytest import click from click._compat import PY2 from click._compat import text_type def test_nargs_star(runner): @click.command() @click.argument("src", nargs=-1) @click.argument("dst") def copy(src, dst): click.echo("src={}".format("|".join(src))) click.echo("dst={}".format(dst)) result = runner.invoke(copy, ["foo.txt", "bar.txt", "dir"]) assert not result.exception assert result.output.splitlines() == ["src=foo.txt|bar.txt", "dst=dir"] def test_nargs_default(runner): with pytest.raises(TypeError, match="nargs=-1"): @click.command() @click.argument("src", nargs=-1, default=42) def copy(src): pass def test_nargs_tup(runner): @click.command() @click.argument("name", nargs=1) @click.argument("point", nargs=2, type=click.INT) def copy(name, point): click.echo("name={}".format(name)) click.echo("point={0[0]}/{0[1]}".format(point)) result = runner.invoke(copy, ["peter", "1", "2"]) assert not result.exception assert result.output.splitlines() == ["name=peter", "point=1/2"] def test_nargs_tup_composite(runner): variations = [ dict(type=(str, int)), dict(type=click.Tuple([str, int])), dict(nargs=2, type=click.Tuple([str, int])), dict(nargs=2, type=(str, int)), ] for opts in variations: @click.command() @click.argument("item", **opts) def copy(item): click.echo("name={0[0]} id={0[1]:d}".format(item)) result = runner.invoke(copy, ["peter", "1"]) assert not result.exception assert result.output.splitlines() == ["name=peter id=1"] def test_nargs_err(runner): @click.command() @click.argument("x") def copy(x): click.echo(x) result = runner.invoke(copy, ["foo"]) assert not result.exception assert result.output == "foo\n" result = runner.invoke(copy, ["foo", "bar"]) assert result.exit_code == 2 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( arg, text_type ), "UTF-8 encoded argument should be implicitly converted to Unicode" # Simulate empty locale environment variables if PY2: monkeypatch.setattr(sys.stdin, "encoding", "ANSI_X3.4-1968") monkeypatch.setattr(sys, "getfilesystemencoding", lambda: "ANSI_X3.4-1968") monkeypatch.setattr(sys, "getdefaultencoding", lambda: "ascii") else: monkeypatch.setattr(sys.stdin, "encoding", "utf-8") monkeypatch.setattr(sys, "getfilesystemencoding", lambda: "utf-8") monkeypatch.setattr(sys, "getdefaultencoding", lambda: "utf-8") runner.invoke( from_bytes, [u"Something outside of ASCII range: 林".encode("UTF-8")], catch_exceptions=False, ) def test_file_args(runner): @click.command() @click.argument("input", type=click.File("rb")) @click.argument("output", type=click.File("wb")) def inout(input, output): while True: chunk = input.read(1024) if not chunk: break output.write(chunk) with runner.isolated_filesystem(): result = runner.invoke(inout, ["-", "hello.txt"], input="Hey!") assert result.output == "" assert result.exit_code == 0 with open("hello.txt", "rb") as f: assert f.read() == b"Hey!" result = runner.invoke(inout, ["hello.txt", "-"]) assert result.output == "Hey!" assert result.exit_code == 0 def test_path_args(runner): @click.command() @click.argument("input", type=click.Path(dir_okay=False, allow_dash=True)) def foo(input): click.echo(input) result = runner.invoke(foo, ["-"]) assert result.output == "-\n" assert result.exit_code == 0 def test_file_atomics(runner): @click.command() @click.argument("output", type=click.File("wb", atomic=True)) def inout(output): output.write(b"Foo bar baz\n") output.flush() with open(output.name, "rb") as f: old_content = f.read() assert old_content == b"OLD\n" with runner.isolated_filesystem(): 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 == "" assert result.exit_code == 0 with open("foo.txt", "rb") as f: assert f.read() == b"Foo bar baz\n" def test_stdout_default(runner): @click.command() @click.argument("output", type=click.File("w"), default="-") def inout(output): output.write("Foo bar baz\n") output.flush() result = runner.invoke(inout, []) assert not result.exception assert result.output == "Foo bar baz\n" def test_nargs_envvar(runner): @click.command() @click.option("--arg", nargs=2) def cmd(arg): click.echo("|".join(arg)) result = runner.invoke( cmd, [], auto_envvar_prefix="TEST", env={"TEST_ARG": "foo bar"} ) assert not result.exception assert result.output == "foo|bar\n" @click.command() @click.option("--arg", envvar="X", nargs=2) def cmd(arg): click.echo("|".join(arg)) result = runner.invoke(cmd, [], env={"X": "foo bar"}) assert not result.exception assert result.output == "foo|bar\n" def test_empty_nargs(runner): @click.command() @click.argument("arg", nargs=-1) def cmd(arg): click.echo("arg:{}".format("|".join(arg))) result = runner.invoke(cmd, []) assert result.exit_code == 0 assert result.output == "arg:\n" @click.command() @click.argument("arg", nargs=-1, required=True) def cmd2(arg): click.echo("arg:{}".format("|".join(arg))) result = runner.invoke(cmd2, []) assert result.exit_code == 2 assert "Missing argument 'ARG...'" in result.output def test_missing_arg(runner): @click.command() @click.argument("arg") def cmd(arg): click.echo("arg:{}".format(arg)) result = runner.invoke(cmd, []) assert result.exit_code == 2 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: click.Argument(["a"], required=True).full_process_value(ctx, None) assert str(excinfo.value) == "missing parameter: a" def test_implicit_non_required(runner): @click.command() @click.argument("f", default="test") def cli(f): click.echo(f) result = runner.invoke(cli, []) assert result.exit_code == 0 assert result.output == "test\n" def test_eat_options(runner): @click.command() @click.option("-f") @click.argument("files", nargs=-1) def cmd(f, files): for filename in files: click.echo(filename) click.echo(f) result = runner.invoke(cmd, ["--", "-foo", "bar"]) assert result.output.splitlines() == ["-foo", "bar", ""] result = runner.invoke(cmd, ["-f", "-x", "--", "-foo", "bar"]) assert result.output.splitlines() == ["-foo", "bar", "-x"] def test_nargs_star_ordering(runner): @click.command() @click.argument("a", nargs=-1) @click.argument("b") @click.argument("c") def cmd(a, b, c): for arg in (a, b, c): click.echo(arg) result = runner.invoke(cmd, ["a", "b", "c"]) assert result.output.splitlines() == ["(u'a',)" if PY2 else "('a',)", "b", "c"] def test_nargs_specified_plus_star_ordering(runner): @click.command() @click.argument("a", nargs=-1) @click.argument("b") @click.argument("c", nargs=2) def cmd(a, b, c): for arg in (a, b, c): click.echo(arg) result = runner.invoke(cmd, ["a", "b", "c", "d", "e", "f"]) assert result.output.splitlines() == [ "(u'a', u'b', u'c')" if PY2 else "('a', 'b', 'c')", "d", "(u'e', u'f')" if PY2 else "('e', 'f')", ] def test_defaults_for_nargs(runner): @click.command() @click.argument("a", nargs=2, type=int, default=(1, 2)) def cmd(a): x, y = a click.echo(x + y) result = runner.invoke(cmd, []) assert result.output.strip() == "3" result = runner.invoke(cmd, ["3", "4"]) assert result.output.strip() == "7" result = runner.invoke(cmd, ["3"]) assert result.exception is not None assert "argument a takes 2 values" in result.output def test_multiple_param_decls_not_allowed(runner): with pytest.raises(TypeError): @click.command() @click.argument("x", click.Choice(["a", "b"])) def copy(x): click.echo(x)