test_chain.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import sys
  2. import pytest
  3. import click
  4. def debug():
  5. click.echo(
  6. f"{sys._getframe(1).f_code.co_name}"
  7. f"={'|'.join(click.get_current_context().args)}"
  8. )
  9. def test_basic_chaining(runner):
  10. @click.group(chain=True)
  11. def cli():
  12. pass
  13. @cli.command("sdist")
  14. def sdist():
  15. click.echo("sdist called")
  16. @cli.command("bdist")
  17. def bdist():
  18. click.echo("bdist called")
  19. result = runner.invoke(cli, ["bdist", "sdist", "bdist"])
  20. assert not result.exception
  21. assert result.output.splitlines() == [
  22. "bdist called",
  23. "sdist called",
  24. "bdist called",
  25. ]
  26. @pytest.mark.parametrize(
  27. ("args", "expect"),
  28. [
  29. (["--help"], "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..."),
  30. (["--help"], "ROOT HELP"),
  31. (["sdist", "--help"], "SDIST HELP"),
  32. (["bdist", "--help"], "BDIST HELP"),
  33. (["bdist", "sdist", "--help"], "SDIST HELP"),
  34. ],
  35. )
  36. def test_chaining_help(runner, args, expect):
  37. @click.group(chain=True)
  38. def cli():
  39. """ROOT HELP"""
  40. pass
  41. @cli.command("sdist")
  42. def sdist():
  43. """SDIST HELP"""
  44. click.echo("sdist called")
  45. @cli.command("bdist")
  46. def bdist():
  47. """BDIST HELP"""
  48. click.echo("bdist called")
  49. result = runner.invoke(cli, args)
  50. assert not result.exception
  51. assert expect in result.output
  52. def test_chaining_with_options(runner):
  53. @click.group(chain=True)
  54. def cli():
  55. pass
  56. @cli.command("sdist")
  57. @click.option("--format")
  58. def sdist(format):
  59. click.echo(f"sdist called {format}")
  60. @cli.command("bdist")
  61. @click.option("--format")
  62. def bdist(format):
  63. click.echo(f"bdist called {format}")
  64. result = runner.invoke(cli, ["bdist", "--format=1", "sdist", "--format=2"])
  65. assert not result.exception
  66. assert result.output.splitlines() == ["bdist called 1", "sdist called 2"]
  67. @pytest.mark.parametrize(("chain", "expect"), [(False, "1"), (True, "[]")])
  68. def test_no_command_result_callback(runner, chain, expect):
  69. """When a group has ``invoke_without_command=True``, the result
  70. callback is always invoked. A regular group invokes it with
  71. its return value, a chained group with ``[]``.
  72. """
  73. @click.group(invoke_without_command=True, chain=chain)
  74. def cli():
  75. return 1
  76. @cli.result_callback()
  77. def process_result(result):
  78. click.echo(result, nl=False)
  79. result = runner.invoke(cli, [])
  80. assert result.output == expect
  81. def test_chaining_with_arguments(runner):
  82. @click.group(chain=True)
  83. def cli():
  84. pass
  85. @cli.command("sdist")
  86. @click.argument("format")
  87. def sdist(format):
  88. click.echo(f"sdist called {format}")
  89. @cli.command("bdist")
  90. @click.argument("format")
  91. def bdist(format):
  92. click.echo(f"bdist called {format}")
  93. result = runner.invoke(cli, ["bdist", "1", "sdist", "2"])
  94. assert not result.exception
  95. assert result.output.splitlines() == ["bdist called 1", "sdist called 2"]
  96. @pytest.mark.parametrize(
  97. ("args", "input", "expect"),
  98. [
  99. (["-f", "-"], "foo\nbar", ["foo", "bar"]),
  100. (["-f", "-", "strip"], "foo \n bar", ["foo", "bar"]),
  101. (["-f", "-", "strip", "uppercase"], "foo \n bar", ["FOO", "BAR"]),
  102. ],
  103. )
  104. def test_pipeline(runner, args, input, expect):
  105. @click.group(chain=True, invoke_without_command=True)
  106. @click.option("-f", type=click.File("r"))
  107. def cli(f):
  108. pass
  109. @cli.result_callback()
  110. def process_pipeline(processors, f):
  111. iterator = (x.rstrip("\r\n") for x in f)
  112. for processor in processors:
  113. iterator = processor(iterator)
  114. for item in iterator:
  115. click.echo(item)
  116. @cli.command("uppercase")
  117. def make_uppercase():
  118. def processor(iterator):
  119. for line in iterator:
  120. yield line.upper()
  121. return processor
  122. @cli.command("strip")
  123. def make_strip():
  124. def processor(iterator):
  125. for line in iterator:
  126. yield line.strip()
  127. return processor
  128. result = runner.invoke(cli, args, input=input)
  129. assert not result.exception
  130. assert result.output.splitlines() == expect
  131. def test_args_and_chain(runner):
  132. @click.group(chain=True)
  133. def cli():
  134. debug()
  135. @cli.command()
  136. def a():
  137. debug()
  138. @cli.command()
  139. def b():
  140. debug()
  141. @cli.command()
  142. def c():
  143. debug()
  144. result = runner.invoke(cli, ["a", "b", "c"])
  145. assert not result.exception
  146. assert result.output.splitlines() == ["cli=", "a=", "b=", "c="]
  147. def test_multicommand_arg_behavior(runner):
  148. with pytest.raises(RuntimeError):
  149. @click.group(chain=True)
  150. @click.argument("forbidden", required=False)
  151. def bad_cli():
  152. pass
  153. with pytest.raises(RuntimeError):
  154. @click.group(chain=True)
  155. @click.argument("forbidden", nargs=-1)
  156. def bad_cli2():
  157. pass
  158. @click.group(chain=True)
  159. @click.argument("arg")
  160. def cli(arg):
  161. click.echo(f"cli:{arg}")
  162. @cli.command()
  163. def a():
  164. click.echo("a")
  165. result = runner.invoke(cli, ["foo", "a"])
  166. assert not result.exception
  167. assert result.output.splitlines() == ["cli:foo", "a"]
  168. @pytest.mark.xfail
  169. def test_multicommand_chaining(runner):
  170. @click.group(chain=True)
  171. def cli():
  172. debug()
  173. @cli.group()
  174. def l1a():
  175. debug()
  176. @l1a.command()
  177. def l2a():
  178. debug()
  179. @l1a.command()
  180. def l2b():
  181. debug()
  182. @cli.command()
  183. def l1b():
  184. debug()
  185. result = runner.invoke(cli, ["l1a", "l2a", "l1b"])
  186. assert not result.exception
  187. assert result.output.splitlines() == ["cli=", "l1a=", "l2a=", "l1b="]