fastapi-cli 0.0.10__tar.gz → 0.0.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/PKG-INFO +1 -1
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/pyproject.toml +1 -1
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/requirements-tests.txt +2 -2
- fastapi_cli-0.0.12/src/fastapi_cli/__init__.py +1 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/cli.py +32 -7
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/discover.py +23 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_cli.py +168 -0
- fastapi_cli-0.0.12/tests/test_discover.py +58 -0
- fastapi_cli-0.0.10/src/fastapi_cli/__init__.py +0 -1
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/LICENSE +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/README.md +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/pdm_build.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/requirements-github-actions.txt +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/requirements.txt +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/scripts/format.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/scripts/lint.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/scripts/test-cov-html.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/scripts/test.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/__main__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/exceptions.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/logging.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/py.typed +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/utils/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/src/fastapi_cli/utils/cli.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/broken_package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/broken_package/mod/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/broken_package/utils.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_api/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_api/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_api/app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_app/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_app/app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_app/app/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_main/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_main/app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_main/app/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_main/app/main.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_non_default/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_non_default/app/nondefault.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_main/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_main/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_main/main.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/non_default/nonstandard.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/core/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/core/utils.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/mod/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/mod/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/mod/other.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/core/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/core/utils.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/mod/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/mod/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/package/mod/other.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/single_file_api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/single_file_app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/single_file_other.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/conftest.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_requirements.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_utils_cli.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_utils_default_dir.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_utils_default_file.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_utils_package.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/test_utils_single_file.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.12"
|
|
@@ -7,7 +7,7 @@ from rich import print
|
|
|
7
7
|
from rich.tree import Tree
|
|
8
8
|
from typing_extensions import Annotated
|
|
9
9
|
|
|
10
|
-
from fastapi_cli.discover import get_import_data
|
|
10
|
+
from fastapi_cli.discover import get_import_data, get_import_data_from_import_string
|
|
11
11
|
from fastapi_cli.exceptions import FastAPICLIException
|
|
12
12
|
|
|
13
13
|
from . import __version__
|
|
@@ -95,6 +95,7 @@ def _run(
|
|
|
95
95
|
root_path: str = "",
|
|
96
96
|
command: str,
|
|
97
97
|
app: Union[str, None] = None,
|
|
98
|
+
entrypoint: Union[str, None] = None,
|
|
98
99
|
proxy_headers: bool = False,
|
|
99
100
|
forwarded_allow_ips: Union[str, None] = None,
|
|
100
101
|
) -> None:
|
|
@@ -109,7 +110,10 @@ def _run(
|
|
|
109
110
|
)
|
|
110
111
|
|
|
111
112
|
try:
|
|
112
|
-
|
|
113
|
+
if entrypoint:
|
|
114
|
+
import_data = get_import_data_from_import_string(entrypoint)
|
|
115
|
+
else:
|
|
116
|
+
import_data = get_import_data(path=path, app_name=app)
|
|
113
117
|
except FastAPICLIException as e:
|
|
114
118
|
toolkit.print_line()
|
|
115
119
|
toolkit.print(f"[error]{e}")
|
|
@@ -124,10 +128,11 @@ def _run(
|
|
|
124
128
|
toolkit.print(f"Importing from {module_data.extra_sys_path}")
|
|
125
129
|
toolkit.print_line()
|
|
126
130
|
|
|
127
|
-
|
|
131
|
+
if module_data.module_paths:
|
|
132
|
+
root_tree = _get_module_tree(module_data.module_paths)
|
|
128
133
|
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
toolkit.print(root_tree, tag="module")
|
|
135
|
+
toolkit.print_line()
|
|
131
136
|
|
|
132
137
|
toolkit.print(
|
|
133
138
|
"Importing the FastAPI app object from the module with the following code:",
|
|
@@ -201,7 +206,8 @@ def dev(
|
|
|
201
206
|
port: Annotated[
|
|
202
207
|
int,
|
|
203
208
|
typer.Option(
|
|
204
|
-
help="The port to serve on. You would normally have a termination proxy on top (another program) handling HTTPS on port [blue]443[/blue] and HTTP on port [blue]80[/blue], transferring the communication to your app."
|
|
209
|
+
help="The port to serve on. You would normally have a termination proxy on top (another program) handling HTTPS on port [blue]443[/blue] and HTTP on port [blue]80[/blue], transferring the communication to your app.",
|
|
210
|
+
envvar="PORT",
|
|
205
211
|
),
|
|
206
212
|
] = 8000,
|
|
207
213
|
reload: Annotated[
|
|
@@ -222,6 +228,14 @@ def dev(
|
|
|
222
228
|
help="The name of the variable that contains the [bold]FastAPI[/bold] app in the imported module or package. If not provided, it is detected automatically."
|
|
223
229
|
),
|
|
224
230
|
] = None,
|
|
231
|
+
entrypoint: Annotated[
|
|
232
|
+
Union[str, None],
|
|
233
|
+
typer.Option(
|
|
234
|
+
"--entrypoint",
|
|
235
|
+
"-e",
|
|
236
|
+
help="The FastAPI app import string in the format 'some.importable_module:app_name'.",
|
|
237
|
+
),
|
|
238
|
+
] = None,
|
|
225
239
|
proxy_headers: Annotated[
|
|
226
240
|
bool,
|
|
227
241
|
typer.Option(
|
|
@@ -267,6 +281,7 @@ def dev(
|
|
|
267
281
|
reload=reload,
|
|
268
282
|
root_path=root_path,
|
|
269
283
|
app=app,
|
|
284
|
+
entrypoint=entrypoint,
|
|
270
285
|
command="dev",
|
|
271
286
|
proxy_headers=proxy_headers,
|
|
272
287
|
forwarded_allow_ips=forwarded_allow_ips,
|
|
@@ -291,7 +306,8 @@ def run(
|
|
|
291
306
|
port: Annotated[
|
|
292
307
|
int,
|
|
293
308
|
typer.Option(
|
|
294
|
-
help="The port to serve on. You would normally have a termination proxy on top (another program) handling HTTPS on port [blue]443[/blue] and HTTP on port [blue]80[/blue], transferring the communication to your app."
|
|
309
|
+
help="The port to serve on. You would normally have a termination proxy on top (another program) handling HTTPS on port [blue]443[/blue] and HTTP on port [blue]80[/blue], transferring the communication to your app.",
|
|
310
|
+
envvar="PORT",
|
|
295
311
|
),
|
|
296
312
|
] = 8000,
|
|
297
313
|
reload: Annotated[
|
|
@@ -318,6 +334,14 @@ def run(
|
|
|
318
334
|
help="The name of the variable that contains the [bold]FastAPI[/bold] app in the imported module or package. If not provided, it is detected automatically."
|
|
319
335
|
),
|
|
320
336
|
] = None,
|
|
337
|
+
entrypoint: Annotated[
|
|
338
|
+
Union[str, None],
|
|
339
|
+
typer.Option(
|
|
340
|
+
"--entrypoint",
|
|
341
|
+
"-e",
|
|
342
|
+
help="The FastAPI app import string in the format 'some.importable_module:app_name'.",
|
|
343
|
+
),
|
|
344
|
+
] = None,
|
|
321
345
|
proxy_headers: Annotated[
|
|
322
346
|
bool,
|
|
323
347
|
typer.Option(
|
|
@@ -364,6 +388,7 @@ def run(
|
|
|
364
388
|
workers=workers,
|
|
365
389
|
root_path=root_path,
|
|
366
390
|
app=app,
|
|
391
|
+
entrypoint=entrypoint,
|
|
367
392
|
command="run",
|
|
368
393
|
proxy_headers=proxy_headers,
|
|
369
394
|
forwarded_allow_ips=forwarded_allow_ips,
|
|
@@ -130,3 +130,26 @@ def get_import_data(
|
|
|
130
130
|
return ImportData(
|
|
131
131
|
app_name=use_app_name, module_data=mod_data, import_string=import_string
|
|
132
132
|
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_import_data_from_import_string(import_string: str) -> ImportData:
|
|
136
|
+
module_str, _, app_name = import_string.partition(":")
|
|
137
|
+
|
|
138
|
+
if not module_str or not app_name:
|
|
139
|
+
raise FastAPICLIException(
|
|
140
|
+
"Import string must be in the format module.submodule:app_name"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
here = Path(".").resolve()
|
|
144
|
+
|
|
145
|
+
sys.path.insert(0, str(here))
|
|
146
|
+
|
|
147
|
+
return ImportData(
|
|
148
|
+
app_name=app_name,
|
|
149
|
+
module_data=ModuleData(
|
|
150
|
+
module_import_str=module_str,
|
|
151
|
+
extra_sys_path=here,
|
|
152
|
+
module_paths=[],
|
|
153
|
+
),
|
|
154
|
+
import_string=import_string,
|
|
155
|
+
)
|
|
@@ -122,6 +122,73 @@ def test_dev_args() -> None:
|
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
def test_dev_env_vars() -> None:
|
|
126
|
+
with changing_dir(assets_path):
|
|
127
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
128
|
+
result = runner.invoke(
|
|
129
|
+
app, ["dev", "single_file_app.py"], env={"PORT": "8111"}
|
|
130
|
+
)
|
|
131
|
+
assert result.exit_code == 0, result.output
|
|
132
|
+
assert mock_run.called
|
|
133
|
+
assert mock_run.call_args
|
|
134
|
+
assert mock_run.call_args.kwargs == {
|
|
135
|
+
"app": "single_file_app:app",
|
|
136
|
+
"host": "127.0.0.1",
|
|
137
|
+
"port": 8111,
|
|
138
|
+
"reload": True,
|
|
139
|
+
"workers": None,
|
|
140
|
+
"root_path": "",
|
|
141
|
+
"proxy_headers": True,
|
|
142
|
+
"forwarded_allow_ips": None,
|
|
143
|
+
"log_config": get_uvicorn_log_config(),
|
|
144
|
+
}
|
|
145
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
146
|
+
assert "Starting development server 🚀" in result.output
|
|
147
|
+
assert "Server started at http://127.0.0.1:8111" in result.output
|
|
148
|
+
assert "Documentation at http://127.0.0.1:8111/docs" in result.output
|
|
149
|
+
assert (
|
|
150
|
+
"Running in development mode, for production use: fastapi run"
|
|
151
|
+
in result.output
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_dev_env_vars_and_args() -> None:
|
|
156
|
+
with changing_dir(assets_path):
|
|
157
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
158
|
+
result = runner.invoke(
|
|
159
|
+
app,
|
|
160
|
+
[
|
|
161
|
+
"dev",
|
|
162
|
+
"single_file_app.py",
|
|
163
|
+
"--port",
|
|
164
|
+
"8080",
|
|
165
|
+
],
|
|
166
|
+
env={"PORT": "8111"},
|
|
167
|
+
)
|
|
168
|
+
assert result.exit_code == 0, result.output
|
|
169
|
+
assert mock_run.called
|
|
170
|
+
assert mock_run.call_args
|
|
171
|
+
assert mock_run.call_args.kwargs == {
|
|
172
|
+
"app": "single_file_app:app",
|
|
173
|
+
"host": "127.0.0.1",
|
|
174
|
+
"port": 8080,
|
|
175
|
+
"reload": True,
|
|
176
|
+
"workers": None,
|
|
177
|
+
"root_path": "",
|
|
178
|
+
"proxy_headers": True,
|
|
179
|
+
"forwarded_allow_ips": None,
|
|
180
|
+
"log_config": get_uvicorn_log_config(),
|
|
181
|
+
}
|
|
182
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
183
|
+
assert "Starting development server 🚀" in result.output
|
|
184
|
+
assert "Server started at http://127.0.0.1:8080" in result.output
|
|
185
|
+
assert "Documentation at http://127.0.0.1:8080/docs" in result.output
|
|
186
|
+
assert (
|
|
187
|
+
"Running in development mode, for production use: fastapi run"
|
|
188
|
+
in result.output
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
|
|
125
192
|
def test_run() -> None:
|
|
126
193
|
with changing_dir(assets_path):
|
|
127
194
|
with patch.object(uvicorn, "run") as mock_run:
|
|
@@ -223,6 +290,65 @@ def test_run_args() -> None:
|
|
|
223
290
|
)
|
|
224
291
|
|
|
225
292
|
|
|
293
|
+
def test_run_env_vars() -> None:
|
|
294
|
+
with changing_dir(assets_path):
|
|
295
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
296
|
+
result = runner.invoke(
|
|
297
|
+
app, ["run", "single_file_app.py"], env={"PORT": "8111"}
|
|
298
|
+
)
|
|
299
|
+
assert result.exit_code == 0, result.output
|
|
300
|
+
assert mock_run.called
|
|
301
|
+
assert mock_run.call_args
|
|
302
|
+
assert mock_run.call_args.kwargs == {
|
|
303
|
+
"app": "single_file_app:app",
|
|
304
|
+
"host": "0.0.0.0",
|
|
305
|
+
"port": 8111,
|
|
306
|
+
"reload": False,
|
|
307
|
+
"workers": None,
|
|
308
|
+
"root_path": "",
|
|
309
|
+
"proxy_headers": True,
|
|
310
|
+
"forwarded_allow_ips": None,
|
|
311
|
+
"log_config": get_uvicorn_log_config(),
|
|
312
|
+
}
|
|
313
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
314
|
+
assert "Starting production server 🚀" in result.output
|
|
315
|
+
assert "Server started at http://0.0.0.0:8111" in result.output
|
|
316
|
+
assert "Documentation at http://0.0.0.0:8111/docs" in result.output
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def test_run_env_vars_and_args() -> None:
|
|
320
|
+
with changing_dir(assets_path):
|
|
321
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
322
|
+
result = runner.invoke(
|
|
323
|
+
app,
|
|
324
|
+
[
|
|
325
|
+
"run",
|
|
326
|
+
"single_file_app.py",
|
|
327
|
+
"--port",
|
|
328
|
+
"8080",
|
|
329
|
+
],
|
|
330
|
+
env={"PORT": "8111"},
|
|
331
|
+
)
|
|
332
|
+
assert result.exit_code == 0, result.output
|
|
333
|
+
assert mock_run.called
|
|
334
|
+
assert mock_run.call_args
|
|
335
|
+
assert mock_run.call_args.kwargs == {
|
|
336
|
+
"app": "single_file_app:app",
|
|
337
|
+
"host": "0.0.0.0",
|
|
338
|
+
"port": 8080,
|
|
339
|
+
"reload": False,
|
|
340
|
+
"workers": None,
|
|
341
|
+
"root_path": "",
|
|
342
|
+
"proxy_headers": True,
|
|
343
|
+
"forwarded_allow_ips": None,
|
|
344
|
+
"log_config": get_uvicorn_log_config(),
|
|
345
|
+
}
|
|
346
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
347
|
+
assert "Starting production server 🚀" in result.output
|
|
348
|
+
assert "Server started at http://0.0.0.0:8080" in result.output
|
|
349
|
+
assert "Documentation at http://0.0.0.0:8080/docs" in result.output
|
|
350
|
+
|
|
351
|
+
|
|
226
352
|
def test_run_error() -> None:
|
|
227
353
|
with changing_dir(assets_path):
|
|
228
354
|
result = runner.invoke(app, ["run", "non_existing_file.py"])
|
|
@@ -285,6 +411,48 @@ def test_version() -> None:
|
|
|
285
411
|
assert "FastAPI CLI version:" in result.output
|
|
286
412
|
|
|
287
413
|
|
|
414
|
+
def test_dev_with_import_string() -> None:
|
|
415
|
+
with changing_dir(assets_path):
|
|
416
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
417
|
+
result = runner.invoke(app, ["dev", "--entrypoint", "single_file_app:api"])
|
|
418
|
+
assert result.exit_code == 0, result.output
|
|
419
|
+
assert mock_run.called
|
|
420
|
+
assert mock_run.call_args
|
|
421
|
+
assert mock_run.call_args.kwargs == {
|
|
422
|
+
"app": "single_file_app:api",
|
|
423
|
+
"forwarded_allow_ips": None,
|
|
424
|
+
"host": "127.0.0.1",
|
|
425
|
+
"port": 8000,
|
|
426
|
+
"reload": True,
|
|
427
|
+
"workers": None,
|
|
428
|
+
"root_path": "",
|
|
429
|
+
"proxy_headers": True,
|
|
430
|
+
"log_config": get_uvicorn_log_config(),
|
|
431
|
+
}
|
|
432
|
+
assert "Using import string: single_file_app:api" in result.output
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def test_run_with_import_string() -> None:
|
|
436
|
+
with changing_dir(assets_path):
|
|
437
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
438
|
+
result = runner.invoke(app, ["run", "--entrypoint", "single_file_app:app"])
|
|
439
|
+
assert result.exit_code == 0, result.output
|
|
440
|
+
assert mock_run.called
|
|
441
|
+
assert mock_run.call_args
|
|
442
|
+
assert mock_run.call_args.kwargs == {
|
|
443
|
+
"app": "single_file_app:app",
|
|
444
|
+
"forwarded_allow_ips": None,
|
|
445
|
+
"host": "0.0.0.0",
|
|
446
|
+
"port": 8000,
|
|
447
|
+
"reload": False,
|
|
448
|
+
"workers": None,
|
|
449
|
+
"root_path": "",
|
|
450
|
+
"proxy_headers": True,
|
|
451
|
+
"log_config": get_uvicorn_log_config(),
|
|
452
|
+
}
|
|
453
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
454
|
+
|
|
455
|
+
|
|
288
456
|
def test_script() -> None:
|
|
289
457
|
result = subprocess.run(
|
|
290
458
|
[sys.executable, "-m", "coverage", "run", "-m", "fastapi_cli", "--help"],
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from fastapi_cli.discover import (
|
|
6
|
+
ImportData,
|
|
7
|
+
get_import_data_from_import_string,
|
|
8
|
+
)
|
|
9
|
+
from fastapi_cli.exceptions import FastAPICLIException
|
|
10
|
+
|
|
11
|
+
assets_path = Path(__file__).parent / "assets"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_get_import_data_from_import_string_valid() -> None:
|
|
15
|
+
result = get_import_data_from_import_string("module.submodule:app")
|
|
16
|
+
|
|
17
|
+
assert isinstance(result, ImportData)
|
|
18
|
+
assert result.app_name == "app"
|
|
19
|
+
assert result.import_string == "module.submodule:app"
|
|
20
|
+
assert result.module_data.module_import_str == "module.submodule"
|
|
21
|
+
assert result.module_data.extra_sys_path == Path(".").resolve()
|
|
22
|
+
assert result.module_data.module_paths == []
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_get_import_data_from_import_string_missing_colon() -> None:
|
|
26
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
27
|
+
get_import_data_from_import_string("module.submodule")
|
|
28
|
+
|
|
29
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
30
|
+
exc_info.value
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_import_data_from_import_string_missing_app() -> None:
|
|
35
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
36
|
+
get_import_data_from_import_string("module.submodule:")
|
|
37
|
+
|
|
38
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
39
|
+
exc_info.value
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_get_import_data_from_import_string_missing_module() -> None:
|
|
44
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
45
|
+
get_import_data_from_import_string(":app")
|
|
46
|
+
|
|
47
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
48
|
+
exc_info.value
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_get_import_data_from_import_string_empty() -> None:
|
|
53
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
54
|
+
get_import_data_from_import_string("")
|
|
55
|
+
|
|
56
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
57
|
+
exc_info.value
|
|
58
|
+
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_api/app/api.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_app/app/api.py
RENAMED
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_app/app/app.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_main/app/api.py
RENAMED
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/default_app_dir_main/app/app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/default_files/non_default/nonstandard.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.12}/tests/assets/nested_package/package/mod/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|