Coverage for tests/test_utils_package.py: 100%
119 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-11-11 09:18 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-11-11 09:18 +0000
1from pathlib import Path 1abcdefghijklmn
3import pytest 1abcdefghijklmn
4from pytest import CaptureFixture 1abcdefghijklmn
6from fastapi_cli.discover import get_import_data 1abcdefghijklmn
7from fastapi_cli.exceptions import FastAPICLIException 1abcdefghijklmn
8from tests.utils import changing_dir 1abcdefghijklmn
10assets_path = Path(__file__).parent / "assets" 1abcdefghijklmn
13def test_package_app_root() -> None: 1abcdefghijklmn
14 with changing_dir(assets_path): 1CDEFGHIJKLMNOP
15 import_data = get_import_data(path=Path("package/mod/app.py")) 1CDEFGHIJKLMNOP
17 assert import_data.import_string == "package.mod.app:app" 1CDEFGHIJKLMNOP
19 assert import_data.module_data.extra_sys_path == assets_path 1CDEFGHIJKLMNOP
20 assert import_data.module_data.module_import_str == "package.mod.app" 1CDEFGHIJKLMNOP
23def test_package_api_root() -> None: 1abcdefghijklmn
24 with changing_dir(assets_path): 1QRSTUVWXYZ0123
25 import_data = get_import_data(path=Path("package/mod/api.py")) 1QRSTUVWXYZ0123
27 assert import_data.import_string == "package.mod.api:api" 1QRSTUVWXYZ0123
29 assert import_data.module_data.extra_sys_path == assets_path 1QRSTUVWXYZ0123
30 assert import_data.module_data.module_import_str == "package.mod.api" 1QRSTUVWXYZ0123
33def test_package_other_root() -> None: 1abcdefghijklmn
34 with changing_dir(assets_path): 1456789!#$%'()*
35 import_data = get_import_data(path=Path("package/mod/other.py")) 1456789!#$%'()*
37 assert import_data.import_string == "package.mod.other:first_other" 1456789!#$%'()*
39 assert import_data.module_data.extra_sys_path == assets_path 1456789!#$%'()*
40 assert import_data.module_data.module_import_str == "package.mod.other" 1456789!#$%'()*
43def test_package_app_mod() -> None: 1abcdefghijklmn
44 with changing_dir(assets_path / "package/mod"): 1+,-./:;=?@[]^_
45 import_data = get_import_data(path=Path("app.py")) 1+,-./:;=?@[]^_
47 assert import_data.import_string == "package.mod.app:app" 1+,-./:;=?@[]^_
49 assert import_data.module_data.extra_sys_path == assets_path 1+,-./:;=?@[]^_
50 assert import_data.module_data.module_import_str == "package.mod.app" 1+,-./:;=?@[]^_
53def test_package_api_mod() -> None: 1abcdefghijklmn
54 with changing_dir(assets_path / "package/mod"): 2` { | } ~ abbbcbdbebfbgbhbib
55 import_data = get_import_data(path=Path("api.py")) 2` { | } ~ abbbcbdbebfbgbhbib
57 assert import_data.import_string == "package.mod.api:api" 2` { | } ~ abbbcbdbebfbgbhbib
59 assert import_data.module_data.extra_sys_path == assets_path 2` { | } ~ abbbcbdbebfbgbhbib
60 assert import_data.module_data.module_import_str == "package.mod.api" 2` { | } ~ abbbcbdbebfbgbhbib
63def test_package_other_mod() -> None: 1abcdefghijklmn
64 with changing_dir(assets_path / "package/mod"): 2jbkblbmbnbobpbqbrbsbtbubvbwb
65 import_data = get_import_data(path=Path("other.py")) 2jbkblbmbnbobpbqbrbsbtbubvbwb
67 assert import_data.import_string == "package.mod.other:first_other" 2jbkblbmbnbobpbqbrbsbtbubvbwb
69 assert import_data.module_data.extra_sys_path == assets_path 2jbkblbmbnbobpbqbrbsbtbubvbwb
70 assert import_data.module_data.module_import_str == "package.mod.other" 2jbkblbmbnbobpbqbrbsbtbubvbwb
73def test_package_app_above() -> None: 1abcdefghijklmn
74 with changing_dir(assets_path.parent): 2xbybzbAbBbCbDbEbFbGbHbIbJbKb
75 import_data = get_import_data(path=Path("assets/package/mod/app.py")) 2xbybzbAbBbCbDbEbFbGbHbIbJbKb
77 assert import_data.import_string == "package.mod.app:app" 2xbybzbAbBbCbDbEbFbGbHbIbJbKb
79 assert import_data.module_data.extra_sys_path == assets_path 2xbybzbAbBbCbDbEbFbGbHbIbJbKb
80 assert import_data.module_data.module_import_str == "package.mod.app" 2xbybzbAbBbCbDbEbFbGbHbIbJbKb
83def test_package_api_parent() -> None: 1abcdefghijklmn
84 with changing_dir(assets_path.parent): 2LbMbNbObPbQbRbSbTbUbVbWbXbYb
85 import_data = get_import_data(path=Path("assets/package/mod/api.py")) 2LbMbNbObPbQbRbSbTbUbVbWbXbYb
87 assert import_data.import_string == "package.mod.api:api" 2LbMbNbObPbQbRbSbTbUbVbWbXbYb
89 assert import_data.module_data.extra_sys_path == assets_path 2LbMbNbObPbQbRbSbTbUbVbWbXbYb
90 assert import_data.module_data.module_import_str == "package.mod.api" 2LbMbNbObPbQbRbSbTbUbVbWbXbYb
93def test_package_other_parent() -> None: 1abcdefghijklmn
94 with changing_dir(assets_path.parent): 2Zb0b1b2b3b4b5b6b7b8b9b!b#b$b
95 import_data = get_import_data(path=Path("assets/package/mod/other.py")) 2Zb0b1b2b3b4b5b6b7b8b9b!b#b$b
97 assert import_data.import_string == "package.mod.other:first_other" 2Zb0b1b2b3b4b5b6b7b8b9b!b#b$b
99 assert import_data.module_data.extra_sys_path == assets_path 2Zb0b1b2b3b4b5b6b7b8b9b!b#b$b
100 assert import_data.module_data.module_import_str == "package.mod.other" 2Zb0b1b2b3b4b5b6b7b8b9b!b#b$b
103def test_package_mod_init_inside() -> None: 1abcdefghijklmn
104 with changing_dir(assets_path / "package/mod"): 2%b'b(b)b*b+b,b-b.b/b:b;b=b?b
105 import_data = get_import_data(path=Path("__init__.py")) 2%b'b(b)b*b+b,b-b.b/b:b;b=b?b
106 assert import_data.import_string == "package.mod:app" 2%b'b(b)b*b+b,b-b.b/b:b;b=b?b
108 assert import_data.module_data.extra_sys_path == assets_path 2%b'b(b)b*b+b,b-b.b/b:b;b=b?b
109 assert import_data.module_data.module_import_str == "package.mod" 2%b'b(b)b*b+b,b-b.b/b:b;b=b?b
112def test_package_mod_dir() -> None: 1abcdefghijklmn
113 with changing_dir(assets_path): 2@b[b]b^b_b`b{b|b}b~bacbcccdc
114 import_data = get_import_data(path=Path("package/mod")) 2@b[b]b^b_b`b{b|b}b~bacbcccdc
116 assert import_data.import_string == "package.mod:app" 2@b[b]b^b_b`b{b|b}b~bacbcccdc
118 assert import_data.module_data.extra_sys_path == assets_path 2@b[b]b^b_b`b{b|b}b~bacbcccdc
119 assert import_data.module_data.module_import_str == "package.mod" 2@b[b]b^b_b`b{b|b}b~bacbcccdc
122def test_package_init_inside() -> None: 1abcdefghijklmn
123 with changing_dir(assets_path / "package"): 2ecfcgchcicjckclcmcncocpcqcrc
124 import_data = get_import_data(path=Path("__init__.py")) 2ecfcgchcicjckclcmcncocpcqcrc
126 assert import_data.import_string == "package:app" 2ecfcgchcicjckclcmcncocpcqcrc
128 assert import_data.module_data.extra_sys_path == assets_path 2ecfcgchcicjckclcmcncocpcqcrc
129 assert import_data.module_data.module_import_str == "package" 2ecfcgchcicjckclcmcncocpcqcrc
132def test_package_dir_inside_package() -> None: 1abcdefghijklmn
133 with changing_dir(assets_path / "package/mod"): 2sctcucvcwcxcyczcAcBcCcDcEcFc
134 import_data = get_import_data(path=Path("../")) 2sctcucvcwcxcyczcAcBcCcDcEcFc
136 assert import_data.import_string == "package:app" 2sctcucvcwcxcyczcAcBcCcDcEcFc
137 assert import_data.module_data.extra_sys_path == assets_path 2sctcucvcwcxcyczcAcBcCcDcEcFc
138 assert import_data.module_data.module_import_str == "package" 2sctcucvcwcxcyczcAcBcCcDcEcFc
141def test_package_dir_above_package() -> None: 1abcdefghijklmn
142 with changing_dir(assets_path.parent): 2GcHcIcJcKcLcMcNcOcPcQcRcScTc
143 import_data = get_import_data(path=Path("assets/package")) 2GcHcIcJcKcLcMcNcOcPcQcRcScTc
145 assert import_data.import_string == "package:app" 2GcHcIcJcKcLcMcNcOcPcQcRcScTc
147 assert import_data.module_data.extra_sys_path == assets_path 2GcHcIcJcKcLcMcNcOcPcQcRcScTc
148 assert import_data.module_data.module_import_str == "package" 2GcHcIcJcKcLcMcNcOcPcQcRcScTc
151def test_package_dir_explicit_app() -> None: 1abcdefghijklmn
152 with changing_dir(assets_path): 2UcVcWcXcYcZc0c1c2c3c4c5c6c7c
153 import_data = get_import_data(path=Path("package"), app_name="api") 2UcVcWcXcYcZc0c1c2c3c4c5c6c7c
155 assert import_data.import_string == "package:api" 2UcVcWcXcYcZc0c1c2c3c4c5c6c7c
157 assert import_data.module_data.extra_sys_path == assets_path 2UcVcWcXcYcZc0c1c2c3c4c5c6c7c
158 assert import_data.module_data.module_import_str == "package" 2UcVcWcXcYcZc0c1c2c3c4c5c6c7c
161def test_broken_package_dir(capsys: CaptureFixture[str]) -> None: 1abcdefghijklmn
162 with changing_dir(assets_path): 1opqrstuvwxyzAB
163 # TODO (when deprecating Python 3.8): remove ValueError
164 with pytest.raises((ImportError, ValueError)): 1opqrstuvwxyzAB
165 get_import_data(path=Path("broken_package/mod/app.py")) 1opqrstuvwxyzAB
167 captured = capsys.readouterr() 1opqrstuvwxyzAB
168 assert "Import error:" in captured.out 1opqrstuvwxyzAB
169 assert "Ensure all the package directories have an __init__.py file" in captured.out 1opqrstuvwxyzAB
172def test_package_dir_no_app() -> None: 1abcdefghijklmn
173 with changing_dir(assets_path): 28c9c!c#c$c%c'c(c)c*c+c,c-c.c
174 with pytest.raises(FastAPICLIException) as e: 28c9c!c#c$c%c'c(c)c*c+c,c-c.c
175 get_import_data(path=Path("package/core/utils.py")) 28c9c!c#c$c%c'c(c)c*c+c,c-c.c
176 assert ( 28c9c!c#c$c%c'c(c)c*c+c,c-c.c
177 "Could not find FastAPI app in module, try using --app" in e.value.args[0]
178 )
181def test_package_dir_object_not_an_app() -> None: 1abcdefghijklmn
182 with changing_dir(assets_path): 2/c:c;c=c?c@c[c]c^c_c`c{c|c}c
183 with pytest.raises(FastAPICLIException) as e: 2/c:c;c=c?c@c[c]c^c_c`c{c|c}c
184 get_import_data( 2/c:c;c=c?c@c[c]c^c_c`c{c|c}c
185 path=Path("package/core/utils.py"), app_name="get_hello_world"
186 )
187 assert ( 2/c:c;c=c?c@c[c]c^c_c`c{c|c}c
188 "The app name get_hello_world in package.core.utils doesn't seem to be a FastAPI app"
189 in e.value.args[0]
190 )
193def test_package_dir_object_app_name_not_found() -> None: 1abcdefghijklmn
194 with changing_dir(assets_path): 2~cadbdcdddedfdgdhdidjdkdldmd
195 with pytest.raises(FastAPICLIException) as e: 2~cadbdcdddedfdgdhdidjdkdldmd
196 get_import_data(path=Path("package"), app_name="non_existent_app") 2~cadbdcdddedfdgdhdidjdkdldmd
197 assert "Could not find app name non_existent_app in package" in e.value.args[0] 2~cadbdcdddedfdgdhdidjdkdldmd