fastapi-cli 0.0.25__tar.gz → 0.0.27__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.
Files changed (76) hide show
  1. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/PKG-INFO +1 -1
  2. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/pyproject.toml +1 -1
  3. fastapi_cli-0.0.27/src/fastapi_cli/__init__.py +1 -0
  4. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/cli.py +24 -1
  5. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_cli.py +63 -0
  6. fastapi_cli-0.0.25/src/fastapi_cli/__init__.py +0 -1
  7. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/LICENSE +0 -0
  8. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/README.md +0 -0
  9. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/scripts/add_latest_release_date.py +0 -0
  10. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/scripts/format.sh +0 -0
  11. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/scripts/lint.sh +0 -0
  12. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/scripts/prepare_release.py +0 -0
  13. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/scripts/test-cov-html.sh +0 -0
  14. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/scripts/test.sh +0 -0
  15. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/__main__.py +0 -0
  16. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/config.py +0 -0
  17. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/discover.py +0 -0
  18. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/exceptions.py +0 -0
  19. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/logging.py +0 -0
  20. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/py.typed +0 -0
  21. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/utils/__init__.py +0 -0
  22. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/src/fastapi_cli/utils/cli.py +0 -0
  23. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/__init__.py +0 -0
  24. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/broken_package/mod/__init__.py +0 -0
  25. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/broken_package/mod/app.py +0 -0
  26. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/broken_package/utils.py +0 -0
  27. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_api/api.py +0 -0
  28. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app/api.py +0 -0
  29. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app/app.py +0 -0
  30. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_api/app/__init__.py +0 -0
  31. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_api/app/api.py +0 -0
  32. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_app/app/__init__.py +0 -0
  33. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_app/app/api.py +0 -0
  34. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_app/app/app.py +0 -0
  35. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_main/app/__init__.py +0 -0
  36. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_main/app/api.py +0 -0
  37. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_main/app/app.py +0 -0
  38. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_main/app/main.py +0 -0
  39. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_non_default/app/__init__.py +0 -0
  40. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_app_dir_non_default/app/nondefault.py +0 -0
  41. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_main/api.py +0 -0
  42. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_main/app.py +0 -0
  43. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/default_main/main.py +0 -0
  44. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/default_files/non_default/nonstandard.py +0 -0
  45. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/__init__.py +0 -0
  46. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/__init__.py +0 -0
  47. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/core/__init__.py +0 -0
  48. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/core/utils.py +0 -0
  49. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/mod/__init__.py +0 -0
  50. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/mod/api.py +0 -0
  51. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/mod/app.py +0 -0
  52. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/nested_package/package/mod/other.py +0 -0
  53. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/__init__.py +0 -0
  54. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/core/__init__.py +0 -0
  55. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/core/utils.py +0 -0
  56. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/mod/__init__.py +0 -0
  57. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/mod/api.py +0 -0
  58. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/mod/app.py +0 -0
  59. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/package/mod/other.py +0 -0
  60. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/pyproject_config/another_module.py +0 -0
  61. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/pyproject_config/my_module.py +0 -0
  62. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/pyproject_config/pyproject.toml +0 -0
  63. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/single_file_api.py +0 -0
  64. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/single_file_app.py +0 -0
  65. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/assets/single_file_other.py +0 -0
  66. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/conftest.py +0 -0
  67. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_cli_pyproject.py +0 -0
  68. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_discover.py +0 -0
  69. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_prepare_release.py +0 -0
  70. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_requirements.py +0 -0
  71. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_utils_cli.py +0 -0
  72. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_utils_default_dir.py +0 -0
  73. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_utils_default_file.py +0 -0
  74. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_utils_package.py +0 -0
  75. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/test_utils_single_file.py +0 -0
  76. {fastapi_cli-0.0.25 → fastapi_cli-0.0.27}/tests/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-cli
3
- Version: 0.0.25
3
+ Version: 0.0.27
4
4
  Summary: Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀
5
5
  Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
6
6
  License-Expression: MIT
@@ -38,7 +38,7 @@ dependencies = [
38
38
  "rich-toolkit >= 0.14.8",
39
39
  "tomli >= 2.0.0; python_version < '3.11'",
40
40
  ]
41
- version = "0.0.25"
41
+ version = "0.0.27"
42
42
 
43
43
  [project.optional-dependencies]
44
44
  standard = [
@@ -0,0 +1 @@
1
+ __version__ = "0.0.27"
@@ -1,10 +1,12 @@
1
1
  import logging
2
+ import os
2
3
  from pathlib import Path
3
4
  from typing import Annotated, Any
4
5
 
5
6
  import typer
6
7
  from pydantic import ValidationError
7
8
  from rich import print
9
+ from rich.syntax import Syntax
8
10
  from rich.tree import Tree
9
11
 
10
12
  from fastapi_cli.config import FastAPIConfig
@@ -135,6 +137,7 @@ def _run(
135
137
  entrypoint: str | None = None,
136
138
  proxy_headers: bool = False,
137
139
  forwarded_allow_ips: str | None = None,
140
+ public_url: str | None = None,
138
141
  ) -> None:
139
142
  with get_rich_toolkit() as toolkit:
140
143
  server_type = "development" if command == "dev" else "production"
@@ -224,7 +227,25 @@ def _run(
224
227
  toolkit.print(f" • Module: {mod_source_desc}")
225
228
  toolkit.print(f" • App name: {app_source_desc}")
226
229
 
227
- url = f"http://{host}:{port}"
230
+ if import_data.module_config_source == "auto-discovery":
231
+ toolkit.print_line()
232
+ toolkit.print(
233
+ "You can configure an entrypoint in [blue]pyproject.toml[/] for this app with:",
234
+ tag="tip",
235
+ )
236
+ toolkit.print_line()
237
+ toolkit.print(
238
+ Syntax(
239
+ (
240
+ "[tool.fastapi]\n"
241
+ f'entrypoint = "{import_data.module_data.module_import_str}:{import_data.app_name}"'
242
+ ),
243
+ "toml",
244
+ theme="ansi_light",
245
+ )
246
+ )
247
+
248
+ url = public_url.rstrip("/") if public_url else f"http://{host}:{port}"
228
249
  url_docs = f"{url}/docs"
229
250
 
230
251
  toolkit.print_line()
@@ -372,6 +393,7 @@ def dev(
372
393
  command="dev",
373
394
  proxy_headers=proxy_headers,
374
395
  forwarded_allow_ips=forwarded_allow_ips,
396
+ public_url=os.getenv("FASTAPI_PUBLIC_URL"),
375
397
  )
376
398
 
377
399
 
@@ -479,6 +501,7 @@ def run(
479
501
  command="run",
480
502
  proxy_headers=proxy_headers,
481
503
  forwarded_allow_ips=forwarded_allow_ips,
504
+ public_url=os.getenv("FASTAPI_PUBLIC_URL"),
482
505
  )
483
506
 
484
507
 
@@ -3,6 +3,7 @@ import sys
3
3
  from pathlib import Path
4
4
  from unittest.mock import patch
5
5
 
6
+ import pytest
6
7
  import uvicorn
7
8
  from typer.testing import CliRunner
8
9
 
@@ -38,6 +39,7 @@ def test_dev() -> None:
38
39
  assert "Configuration sources:" in result.output
39
40
  assert "Module: path CLI argument" in result.output
40
41
  assert "App name: auto-discovery" in result.output
42
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
41
43
  assert "Starting development server 🚀" in result.output
42
44
  assert "Server started at http://127.0.0.1:8000" in result.output
43
45
  assert "Documentation at http://127.0.0.1:8000/docs" in result.output
@@ -64,6 +66,9 @@ def test_dev_no_args_auto_discovery() -> None:
64
66
  assert "Using import string: main:app" in result.output
65
67
  assert "Configuration sources:" in result.output
66
68
  assert "Import string: auto-discovery" in result.output
69
+ assert "You can configure an entrypoint in pyproject.toml" in result.output
70
+ assert "[tool.fastapi]" in result.output
71
+ assert 'entrypoint = "main:app"' in result.output
67
72
 
68
73
 
69
74
  def test_dev_package() -> None:
@@ -88,6 +93,7 @@ def test_dev_package() -> None:
88
93
  assert "Using import string: nested_package.package:app" in result.output
89
94
  assert "Module: path CLI argument" in result.output
90
95
  assert "App name: auto-discovery" in result.output
96
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
91
97
  assert "Starting development server 🚀" in result.output
92
98
  assert "Server started at http://127.0.0.1:8000" in result.output
93
99
  assert "Documentation at http://127.0.0.1:8000/docs" in result.output
@@ -140,6 +146,7 @@ def test_dev_args() -> None:
140
146
  assert "Using import string: single_file_app:api" in result.output
141
147
  assert "Module: path CLI argument" in result.output
142
148
  assert "App name: --app CLI option" in result.output
149
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
143
150
  assert "Starting development server 🚀" in result.output
144
151
  assert "Server started at http://192.168.0.2:8080" in result.output
145
152
  assert "Documentation at http://192.168.0.2:8080/docs" in result.output
@@ -173,6 +180,7 @@ def test_dev_env_vars() -> None:
173
180
  assert "Using import string: single_file_app:app" in result.output
174
181
  assert "Module: path CLI argument" in result.output
175
182
  assert "App name: auto-discovery" in result.output
183
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
176
184
  assert "Starting development server 🚀" in result.output
177
185
  assert "Server started at http://127.0.0.1:8111" in result.output
178
186
  assert "Documentation at http://127.0.0.1:8111/docs" in result.output
@@ -213,6 +221,7 @@ def test_dev_env_vars_and_args() -> None:
213
221
  assert "Using import string: single_file_app:app" in result.output
214
222
  assert "Module: path CLI argument" in result.output
215
223
  assert "App name: auto-discovery" in result.output
224
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
216
225
  assert "Starting development server 🚀" in result.output
217
226
  assert "Server started at http://127.0.0.1:8080" in result.output
218
227
  assert "Documentation at http://127.0.0.1:8080/docs" in result.output
@@ -261,6 +270,7 @@ def test_run() -> None:
261
270
  assert "Using import string: single_file_app:app" in result.output
262
271
  assert "Module: path CLI argument" in result.output
263
272
  assert "App name: auto-discovery" in result.output
273
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
264
274
  assert "Starting production server 🚀" in result.output
265
275
  assert "Server started at http://0.0.0.0:8000" in result.output
266
276
  assert "Documentation at http://0.0.0.0:8000/docs" in result.output
@@ -338,6 +348,7 @@ def test_run_args() -> None:
338
348
  assert "Using import string: single_file_app:api" in result.output
339
349
  assert "Module: path CLI argument" in result.output
340
350
  assert "App name: --app CLI option" in result.output
351
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
341
352
  assert "Starting production server 🚀" in result.output
342
353
  assert "Server started at http://192.168.0.2:8080" in result.output
343
354
  assert "Documentation at http://192.168.0.2:8080/docs" in result.output
@@ -371,6 +382,7 @@ def test_run_env_vars() -> None:
371
382
  assert "Using import string: single_file_app:app" in result.output
372
383
  assert "Module: path CLI argument" in result.output
373
384
  assert "App name: auto-discovery" in result.output
385
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
374
386
  assert "Starting production server 🚀" in result.output
375
387
  assert "Server started at http://0.0.0.0:8111" in result.output
376
388
  assert "Documentation at http://0.0.0.0:8111/docs" in result.output
@@ -407,11 +419,60 @@ def test_run_env_vars_and_args() -> None:
407
419
  assert "Using import string: single_file_app:app" in result.output
408
420
  assert "Module: path CLI argument" in result.output
409
421
  assert "App name: auto-discovery" in result.output
422
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
410
423
  assert "Starting production server 🚀" in result.output
411
424
  assert "Server started at http://0.0.0.0:8080" in result.output
412
425
  assert "Documentation at http://0.0.0.0:8080/docs" in result.output
413
426
 
414
427
 
428
+ @pytest.mark.parametrize("command", ["dev", "run"])
429
+ @pytest.mark.parametrize(
430
+ "public_url",
431
+ [
432
+ "https://myapp.example.com",
433
+ "https://myapp.example.com/",
434
+ "https://myapp.example.com/subpath/",
435
+ ],
436
+ )
437
+ def test_public_url_env_var(command: str, public_url: str) -> None:
438
+ with changing_dir(assets_path):
439
+ with patch.object(uvicorn, "run") as mock_run:
440
+ result = runner.invoke(
441
+ app,
442
+ [
443
+ command,
444
+ "single_file_app.py",
445
+ "--host",
446
+ "0.0.0.0",
447
+ ],
448
+ env={"FASTAPI_PUBLIC_URL": public_url},
449
+ )
450
+ assert result.exit_code == 0, result.output
451
+ assert mock_run.called
452
+ assert mock_run.call_args
453
+ assert mock_run.call_args.kwargs == {
454
+ "app": "single_file_app:app",
455
+ "host": "0.0.0.0",
456
+ "port": 8000,
457
+ "reload": True if command == "dev" else False,
458
+ "reload_dirs": None,
459
+ "workers": None,
460
+ "root_path": "",
461
+ "proxy_headers": True,
462
+ "forwarded_allow_ips": None,
463
+ "log_config": get_uvicorn_log_config(),
464
+ }
465
+
466
+ assert "Using import string: single_file_app:app" in result.output
467
+ assert (
468
+ f"Starting {'development' if command == 'dev' else 'production'} server 🚀"
469
+ in result.output
470
+ )
471
+ expected_url_base = public_url.rstrip("/")
472
+ assert f"Server started at {expected_url_base}" in result.output
473
+ assert f"Documentation at {expected_url_base}/docs" in result.output
474
+
475
+
415
476
  def test_run_error() -> None:
416
477
  with changing_dir(assets_path):
417
478
  result = runner.invoke(app, ["run", "non_existing_file.py"])
@@ -521,6 +582,7 @@ def test_dev_with_import_string() -> None:
521
582
  }
522
583
  assert "Using import string: single_file_app:api" in result.output
523
584
  assert "Import string: --entrypoint CLI option" in result.output
585
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
524
586
 
525
587
 
526
588
  def test_run_with_import_string() -> None:
@@ -544,6 +606,7 @@ def test_run_with_import_string() -> None:
544
606
  }
545
607
  assert "Using import string: single_file_app:app" in result.output
546
608
  assert "Import string: --entrypoint CLI option" in result.output
609
+ assert "You can configure an entrypoint in pyproject.toml" not in result.output
547
610
 
548
611
 
549
612
  def test_script() -> None:
@@ -1 +0,0 @@
1
- __version__ = "0.0.25"
File without changes
File without changes