fastapi-spawn 0.4.38__tar.gz → 0.4.39__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 (77) hide show
  1. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/PKG-INFO +1 -1
  2. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/cli.py +52 -1
  3. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/generator.py +16 -0
  4. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/pyproject.toml +1 -1
  5. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/.gitignore +0 -0
  6. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/LICENSE +0 -0
  7. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/README.md +0 -0
  8. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/__init__.py +0 -0
  9. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/config.py +0 -0
  10. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/constants.py +0 -0
  11. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/interactive.py +0 -0
  12. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/alembic/alembic.ini.j2 +0 -0
  13. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/alembic/env.py.j2 +0 -0
  14. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/__init__.py.j2 +0 -0
  15. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/admin/setup.py.j2 +0 -0
  16. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/deps.py.j2 +0 -0
  17. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/graphql.py.j2 +0 -0
  18. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/auth/router.py.j2 +0 -0
  19. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/auth/sso.py.j2 +0 -0
  20. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/health/router.py.j2 +0 -0
  21. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/pagination/router.py.j2 +0 -0
  22. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/payments/router.py.j2 +0 -0
  23. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/permissions/router.py.j2 +0 -0
  24. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/router.py.j2 +0 -0
  25. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/streaming/router.py.j2 +0 -0
  26. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/uploads/router.py.j2 +0 -0
  27. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/api/v1/ws/router.py.j2 +0 -0
  28. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/ai.py.j2 +0 -0
  29. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/cache.py.j2 +0 -0
  30. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/config.py.j2 +0 -0
  31. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/email.py.j2 +0 -0
  32. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/exceptions.py.j2 +0 -0
  33. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/logger.py.j2 +0 -0
  34. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/logging.py.j2 +0 -0
  35. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/monitoring.py.j2 +0 -0
  36. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/notifications.py.j2 +0 -0
  37. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/ocr.py.j2 +0 -0
  38. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/permissions.py.j2 +0 -0
  39. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/search.py.j2 +0 -0
  40. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/security.py.j2 +0 -0
  41. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/storage.py.j2 +0 -0
  42. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/vector_db.py.j2 +0 -0
  43. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/core/ws_manager.py.j2 +0 -0
  44. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/db/session.py.j2 +0 -0
  45. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/frontend/index.html.j2 +0 -0
  46. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/main.py.j2 +0 -0
  47. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/middleware/__init__.py.j2 +0 -0
  48. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/middleware/rate_limit.py.j2 +0 -0
  49. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/middleware/request_logger.py.j2 +0 -0
  50. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/app/middleware/response_format.py.j2 +0 -0
  51. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/Makefile.j2 +0 -0
  52. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/README.md.j2 +0 -0
  53. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/env.j2 +0 -0
  54. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/env_example.j2 +0 -0
  55. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/gitignore.j2 +0 -0
  56. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/pre_commit.j2 +0 -0
  57. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/base/pyproject.toml.j2 +0 -0
  58. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/ci/github/publish.yml.j2 +0 -0
  59. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/ci/github/tests.yml.j2 +0 -0
  60. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/ci/gitlab/gitlab-ci.yml.j2 +0 -0
  61. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/db/seed.py.j2 +0 -0
  62. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/docker/Dockerfile.j2 +0 -0
  63. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/docker/docker-compose.yml.j2 +0 -0
  64. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/docker/dockerignore.j2 +0 -0
  65. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/infra/docker/docker-compose.prod.yml.j2 +0 -0
  66. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/infra/helm/Chart.yaml.j2 +0 -0
  67. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/infra/helm/values.yaml.j2 +0 -0
  68. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/infra/terraform/main.tf.j2 +0 -0
  69. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/infra/terraform/variables.tf.j2 +0 -0
  70. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/root/main.py.j2 +0 -0
  71. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/tasks/arq_worker.py.j2 +0 -0
  72. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/tasks/celery_app.py.j2 +0 -0
  73. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/tasks/sample_tasks.py.j2 +0 -0
  74. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/tests/conftest.py.j2 +0 -0
  75. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/templates/tests/test_health.py.j2 +0 -0
  76. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/utils.py +0 -0
  77. {fastapi_spawn-0.4.38 → fastapi_spawn-0.4.39}/fastapi_spawn/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-spawn
3
- Version: 0.4.38
3
+ Version: 0.4.39
4
4
  Summary: A powerful CLI tool to scaffold production-ready FastAPI projects with flexible database, auth, broker, and deployment options.
5
5
  Project-URL: Homepage, https://github.com/Bishwajitgarai/fastapi-spawn
6
6
  Project-URL: Documentation, https://github.com/Bishwajitgarai/fastapi-spawn#readme
@@ -523,7 +523,6 @@ def add_feature(
523
523
  project_dir: Path = typer.Option(Path("."), "--dir", "-d", help="Path to the existing project"),
524
524
  ) -> None:
525
525
  _print_banner()
526
-
527
526
  if not feature:
528
527
  console.print("\n[bold cyan]Available features to add:[/bold cyan]\n")
529
528
  table = Table(box=None)
@@ -548,6 +547,58 @@ def add_feature(
548
547
  console.print(f"[bold red]✗ Directory not found:[/bold red] {project_dir.resolve()}")
549
548
  raise typer.Exit(1)
550
549
 
550
+ if feature == "alembic":
551
+ console.print("[bold cyan]→ Automatically adding Alembic...[/bold cyan]")
552
+
553
+ # 1. Prompt for DB type
554
+ from fastapi_spawn.constants import Database
555
+ import questionary
556
+
557
+ db_type = questionary.select(
558
+ "Which database are you using?",
559
+ choices=[Database.postgresql.value, Database.mysql.value, Database.sqlite.value],
560
+ default=Database.postgresql.value
561
+ ).ask()
562
+
563
+ if not db_type:
564
+ console.print("[bold red]✗ Database selection cancelled[/bold red]")
565
+ raise typer.Exit(1)
566
+
567
+ # 2. Run uv add alembic
568
+ import subprocess
569
+ try:
570
+ console.print("[dim]Running: uv add alembic[/dim]")
571
+ subprocess.run(["uv", "add", "alembic"], cwd=project_dir, check=True)
572
+ except subprocess.CalledProcessError:
573
+ console.print("[bold red]✗ Failed to add alembic dependency[/bold red]")
574
+ raise typer.Exit(1)
575
+
576
+ # 3. Run alembic init
577
+ try:
578
+ console.print("[dim]Running: uv run alembic init migrations[/dim]")
579
+ subprocess.run(["uv", "run", "alembic", "init", "migrations"], cwd=project_dir, check=True)
580
+ except subprocess.CalledProcessError:
581
+ console.print("[bold red]✗ Failed to initialize alembic[/bold red]")
582
+ raise typer.Exit(1)
583
+
584
+ # 4. Render env.py
585
+ console.print("[dim]Rendering async env.py...[/dim]")
586
+ from fastapi_spawn.generator import ProjectGenerator
587
+ from fastapi_spawn.config import ProjectConfig
588
+
589
+ cfg = ProjectConfig(project_name=project_dir.name, db=Database(db_type), orm=ORM.sqlalchemy)
590
+ cfg.has_alembic = True
591
+ generator = ProjectGenerator(cfg, project_dir)
592
+
593
+ generator._render_to(project_dir / "migrations" / "env.py", "alembic/env.py.j2")
594
+
595
+ console.print("[bold green]✓ Alembic added successfully![/bold green]")
596
+ console.print("\n[bold yellow]Next Steps:[/bold yellow]")
597
+ console.print(" 1. Update [bold]alembic.ini[/bold] with your database URL.")
598
+ console.print(" 2. Run [bold]uv run alembic revision --autogenerate -m 'initial'[/bold]")
599
+ console.print(" 3. Run [bold]uv run alembic upgrade head[/bold]\n")
600
+ raise typer.Exit(0)
601
+
551
602
  console.print(f"[bold cyan]→ Adding feature:[/bold cyan] [bold]{feature}[/bold] — {_ADDABLE_FEATURES[feature]}")
552
603
  console.print(f"[dim]Target project:[/dim] {project_dir.resolve()}\n")
553
604
  _feature_guidance(feature, project_dir)
@@ -5,6 +5,8 @@ from __future__ import annotations
5
5
  import shutil
6
6
  import tempfile
7
7
  from pathlib import Path
8
+ from dataclasses import asdict
9
+ import json
8
10
 
9
11
  from jinja2 import Environment, PackageLoader, StrictUndefined, TemplateNotFound
10
12
  from rich.console import Console
@@ -132,6 +134,20 @@ class ProjectGenerator:
132
134
  self._render_to(root / ".gitignore", "base/gitignore.j2")
133
135
  self._render_to(root / ".pre-commit-config.yaml", "base/pre_commit.j2")
134
136
  self._render_to(root / "README.md", "base/README.md.j2")
137
+
138
+ # Save tracking log for future add commands
139
+ def _enum_to_str(obj):
140
+ if isinstance(obj, dict):
141
+ return {k: _enum_to_str(v) for k, v in obj.items()}
142
+ elif isinstance(obj, list):
143
+ return [_enum_to_str(v) for v in obj]
144
+ elif hasattr(obj, "value") and not isinstance(obj, str): # Enum
145
+ return obj.value
146
+ return obj
147
+
148
+ config_dict = _enum_to_str(asdict(self.config))
149
+ config_path = root / ".fastapi-spawn.json"
150
+ config_path.write_text(json.dumps(config_dict, indent=2), encoding="utf-8")
135
151
 
136
152
  def _generate_app(self, root: Path) -> None:
137
153
  pkg = root / "app"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fastapi-spawn"
7
- version = "0.4.38"
7
+ version = "0.4.39"
8
8
  description = "A powerful CLI tool to scaffold production-ready FastAPI projects with flexible database, auth, broker, and deployment options."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes