Coverage for tests/test_type_conversion.py: 100%
86 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-06-24 00:17 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-06-24 00:17 +0000
1from enum import Enum 1habcdefg
2from pathlib import Path 1habcdefg
3from typing import Any, List, Optional, Tuple 1habcdefg
5import click 1habcdefg
6import pytest 1habcdefg
7import typer 1habcdefg
8from typer.testing import CliRunner 1habcdefg
10runner = CliRunner() 1habcdefg
13def test_optional(): 1habcdefg
14 app = typer.Typer() 1habcdefg
16 @app.command() 1habcdefg
17 def opt(user: Optional[str] = None): 1habcdefg
18 if user: 1habcdefg
19 print(f"User: {user}") 1habcdefg
20 else:
21 print("No user") 1habcdefg
23 result = runner.invoke(app) 1habcdefg
24 assert result.exit_code == 0 1habcdefg
25 assert "No user" in result.output 1habcdefg
27 result = runner.invoke(app, ["--user", "Camila"]) 1habcdefg
28 assert result.exit_code == 0 1habcdefg
29 assert "User: Camila" in result.output 1habcdefg
32def test_optional_tuple(): 1habcdefg
33 app = typer.Typer() 1habcdefg
35 @app.command() 1habcdefg
36 def opt(number: Optional[Tuple[int, int]] = None): 1habcdefg
37 if number: 1habcdefg
38 print(f"Number: {number}") 1habcdefg
39 else:
40 print("No number") 1habcdefg
42 result = runner.invoke(app) 1habcdefg
43 assert result.exit_code == 0 1habcdefg
44 assert "No number" in result.output 1habcdefg
46 result = runner.invoke(app, ["--number", "4", "2"]) 1habcdefg
47 assert result.exit_code == 0 1habcdefg
48 assert "Number: (4, 2)" in result.output 1habcdefg
51def test_no_type(): 1habcdefg
52 app = typer.Typer() 1habcdefg
54 @app.command() 1habcdefg
55 def no_type(user): 1abcdefg
56 print(f"User: {user}") 1habcdefg
58 result = runner.invoke(app, ["Camila"]) 1habcdefg
59 assert result.exit_code == 0 1habcdefg
60 assert "User: Camila" in result.output 1habcdefg
63class SomeEnum(Enum): 1habcdefg
64 ONE = "one" 1habcdefg
65 TWO = "two" 1habcdefg
66 THREE = "three" 1habcdefg
69@pytest.mark.parametrize( 1habcdefg
70 "type_annotation",
71 [List[Path], List[SomeEnum], List[str]],
72)
73def test_list_parameters_convert_to_lists(type_annotation): 1abcdefg
74 # Lists containing objects that are converted by Click (i.e. not Path or Enum)
75 # should not be inadvertently converted to tuples
76 expected_element_type = type_annotation.__args__[0] 1habcdefg
77 app = typer.Typer() 1habcdefg
79 @app.command() 1habcdefg
80 def list_conversion(container: type_annotation): 1habcdefg
81 assert isinstance(container, list) 1habcdefg
82 for element in container: 1habcdefg
83 assert isinstance(element, expected_element_type) 1habcdefg
85 result = runner.invoke(app, ["one", "two", "three"]) 1habcdefg
86 assert result.exit_code == 0 1habcdefg
89@pytest.mark.parametrize( 1habcdefg
90 "type_annotation",
91 [
92 Tuple[str, str],
93 Tuple[str, Path],
94 Tuple[Path, Path],
95 Tuple[str, SomeEnum],
96 Tuple[SomeEnum, SomeEnum],
97 ],
98)
99def test_tuple_parameter_elements_are_converted_recursively(type_annotation): 1abcdefg
100 # Tuple elements that aren't converted by Click (i.e. Path or Enum)
101 # should be recursively converted by Typer
102 expected_element_types = type_annotation.__args__ 1habcdefg
103 app = typer.Typer() 1habcdefg
105 @app.command() 1habcdefg
106 def tuple_recursive_conversion(container: type_annotation): 1habcdefg
107 assert isinstance(container, tuple) 1habcdefg
108 for element, expected_type in zip(container, expected_element_types): 1habcdefg
109 assert isinstance(element, expected_type) 1habcdefg
111 result = runner.invoke(app, ["one", "two"]) 1habcdefg
112 assert result.exit_code == 0 1habcdefg
115def test_custom_parse(): 1habcdefg
116 app = typer.Typer() 1habcdefg
118 @app.command() 1habcdefg
119 def custom_parser( 1abcdefg
120 hex_value: int = typer.Argument(None, parser=lambda x: int(x, 0)),
121 ):
122 assert hex_value == 0x56 1habcdefg
124 result = runner.invoke(app, ["0x56"]) 1habcdefg
125 assert result.exit_code == 0 1habcdefg
128def test_custom_click_type(): 1habcdefg
129 class BaseNumberParamType(click.ParamType): 1habcdefg
130 name = "base_integer" 1habcdefg
132 def convert( 1abcdefg
133 self,
134 value: Any,
135 param: Optional[click.Parameter],
136 ctx: Optional[click.Context],
137 ) -> Any:
138 return int(value, 0) 1habcdefg
140 app = typer.Typer() 1habcdefg
142 @app.command() 1habcdefg
143 def custom_click_type( 1abcdefg
144 hex_value: int = typer.Argument(None, click_type=BaseNumberParamType()),
145 ):
146 assert hex_value == 0x56 1habcdefg
148 result = runner.invoke(app, ["0x56"]) 1habcdefg
149 assert result.exit_code == 0 1habcdefg