Coverage for tests / test_types.py: 100%

109 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-11-09 00:15 +0000

1from enum import Enum 1abcdefg

2 

3import pytest 1abcdefg

4import typer 1abcdefg

5from typer import _click 1abcdefg

6from typer.testing import CliRunner 1abcdefg

7 

8app = typer.Typer(context_settings={"token_normalize_func": str.lower}) 1abcdefg

9 

10 

11class User(str, Enum): 1abcdefg

12 rick = "Rick" 1abcdefg

13 morty = "Morty" 1abcdefg

14 

15 

16@app.command() 1abcdefg

17def hello_option(name: User = User.rick) -> None: 1abcdefg

18 print(f"Hello {name.value}!") 1abcdefg

19 

20 

21@app.command() 1abcdefg

22def hello_argument(name: User) -> None: 1abcdefg

23 print(f"Hello {name.value}!") 1abcdefg

24 

25 

26@app.command() 1abcdefg

27def hello_no_choices( 1abcdefg

28 name: User = typer.Option(..., "--name", show_choices=False), 

29): 

30 print(f"Hello {name.value}!") 1abcdefg

31 

32 

33@app.command() 1abcdefg

34def hello_all_options(name: list[str] = typer.Option(["World"])) -> None: 1abcdefg

35 for n in name: 1abcdefg

36 print(f"Hello {n}!") 1abcdefg

37 

38 

39@app.command() 1abcdefg

40def hello_all_args(names: list[str] = typer.Argument(["World"])) -> None: 1abcdefg

41 for name in names: 1abcdefg

42 print(f"Hello {name}!") 1abcdefg

43 

44 

45@app.command() 1abcdefg

46def hello_all_envvar( 1abcdefg

47 names: list[str] = typer.Argument(["World"], envvar="NAMES"), 

48) -> None: 

49 for name in names: 1abcdefg

50 print(f"Hello {name}!") 1abcdefg

51 

52 

53@app.command() 1abcdefg

54def split_variadic_and_pair(items: list[str], pair: tuple[str, str]) -> None: 1abcdefg

55 print(f"items={items}") 1abcdefg

56 print(f"pair={pair}") 1abcdefg

57 

58 

59runner = CliRunner() 1abcdefg

60 

61 

62def test_enum_choice() -> None: 1abcdefg

63 result = runner.invoke( 1abcdefg

64 app, ["hello-option", "--name", "morty"], catch_exceptions=False 

65 ) 

66 assert result.exit_code == 0 1abcdefg

67 assert "Hello Morty!" in result.output 1abcdefg

68 

69 result = runner.invoke(app, ["hello-option", "--name", "Rick"]) 1abcdefg

70 assert result.exit_code == 0 1abcdefg

71 assert "Hello Rick!" in result.output 1abcdefg

72 

73 result = runner.invoke(app, ["hello-option", "--name", "RICK"]) 1abcdefg

74 assert result.exit_code == 0 1abcdefg

75 assert "Hello Rick!" in result.output 1abcdefg

76 

77 result = runner.invoke(app, ["hello-no-choices", "--name", "RICK"]) 1abcdefg

78 assert result.exit_code == 0 1abcdefg

79 assert "Hello Rick!" in result.output 1abcdefg

80 

81 result = runner.invoke(app, ["hello-argument", "RICK"]) 1abcdefg

82 assert result.exit_code == 0 1abcdefg

83 assert "Hello Rick!" in result.output 1abcdefg

84 

85 

86def test_enum_choice_repr() -> None: 1abcdefg

87 root_command = typer.main.get_command(app) 1abcdefg

88 command = root_command.commands["hello-option"] 1abcdefg

89 name_param = next(param for param in command.params if param.name == "name") 1abcdefg

90 assert repr(name_param.type).startswith("Choice([") 1abcdefg

91 

92 

93def test_enum_choice_help() -> None: 1abcdefg

94 result = runner.invoke(app, ["hello-argument", "--help"]) 1abcdefg

95 assert result.exit_code == 0 1abcdefg

96 assert "<rick|morty>" in result.output 1abcdefg

97 

98 result = runner.invoke(app, ["hello-option", "--help"]) 1abcdefg

99 assert result.exit_code == 0 1abcdefg

100 assert "<rick|morty>" in result.output 1abcdefg

101 

102 result = runner.invoke(app, ["hello-no-choices", "--help"]) 1abcdefg

103 assert result.exit_code == 0 1abcdefg

104 assert "--name" in result.output 1abcdefg

105 assert "rick|morty" not in result.output 1abcdefg

106 

107 

108def test_enum_choice_missing_message() -> None: 1abcdefg

109 result = runner.invoke(app, ["hello-argument"]) 1abcdefg

110 assert result.exit_code != 0 1abcdefg

111 assert "Missing argument" in result.output 1abcdefg

112 assert "Choose from:" in result.output 1abcdefg

113 assert "rick" in result.output 1abcdefg

114 assert "morty" in result.output 1abcdefg

115 

116 

117def test_list() -> None: 1abcdefg

118 result = runner.invoke( 1abcdefg

119 app, ["hello-all-options", "--name", "Rick", "--name", "Morty"] 

120 ) 

121 assert result.exit_code == 0 1abcdefg

122 assert "Hello World!" not in result.output 1abcdefg

123 assert "Hello Rick!" in result.output 1abcdefg

124 assert "Hello Morty!" in result.output 1abcdefg

125 

126 result = runner.invoke(app, ["hello-all-args", "Rick", "Morty"]) 1abcdefg

127 assert result.exit_code == 0 1abcdefg

128 assert "Hello World!" not in result.output 1abcdefg

129 assert "Hello Rick!" in result.output 1abcdefg

130 assert "Hello Morty!" in result.output 1abcdefg

131 

132 

133def test_list_empty() -> None: 1abcdefg

134 result = runner.invoke(app, ["hello-all-args"]) 1abcdefg

135 assert result.exit_code == 0 1abcdefg

136 assert "Hello World!" in result.output 1abcdefg

137 

138 result = runner.invoke(app, ["hello-all-options"]) 1abcdefg

139 assert result.exit_code == 0 1abcdefg

140 assert "Hello World!" in result.output 1abcdefg

141 

142 result = runner.invoke(app, ["hello-all-envvar"]) 1abcdefg

143 assert result.exit_code == 0 1abcdefg

144 assert "Hello World!" in result.output 1abcdefg

145 

146 

147def test_split_envvar_value(monkeypatch) -> None: 1abcdefg

148 # This will use split_envvar_value to produce two strings from the envvar 

149 monkeypatch.setenv("NAMES", "Rick Morty") 1abcdefg

150 result = runner.invoke(app, ["hello-all-envvar"]) 1abcdefg

151 assert result.exit_code == 0 1abcdefg

152 assert "Hello Rick!" in result.output 1abcdefg

153 assert "Hello Morty!" in result.output 1abcdefg

154 

155 

156def test_list_pair() -> None: 1abcdefg

157 result = runner.invoke(app, ["split-variadic-and-pair", "a", "b", "c", "x", "y"]) 1abcdefg

158 assert result.exit_code == 0 1abcdefg

159 assert "items=['a', 'b', 'c']" in result.output 1abcdefg

160 assert "pair=('x', 'y')" in result.output 1abcdefg

161 

162 

163def test_float_range_open_bounds_with_clamp_not_allowed(): 1abcdefg

164 with pytest.raises(TypeError, match="Clamping is not supported for open bounds."): 1abcdefg

165 _click.types.FloatRange(min=0.0, min_open=True, clamp=True) 1abcdefg