spawnio 1.0.5__py3-none-any.whl

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 (56) hide show
  1. spawn/__init__.py +6 -0
  2. spawn/cli/__init__.py +0 -0
  3. spawn/cli/app.py +218 -0
  4. spawn/cli/noninteractive.py +204 -0
  5. spawn/cli/prompts.py +267 -0
  6. spawn/core/__init__.py +0 -0
  7. spawn/core/exceptions.py +7 -0
  8. spawn/core/models.py +21 -0
  9. spawn/core/registry.py +152 -0
  10. spawn/generators/__init__.py +0 -0
  11. spawn/generators/custom_structure.py +508 -0
  12. spawn/generators/project_generator.py +115 -0
  13. spawn/github/__init__.py +0 -0
  14. spawn/github/exceptions.py +5 -0
  15. spawn/github/publisher.py +69 -0
  16. spawn/github/validators.py +23 -0
  17. spawn/templates/__init__.py +0 -0
  18. spawn/templates/agent/__init__.py +182 -0
  19. spawn/templates/agent/content.py +374 -0
  20. spawn/templates/automation/__init__.py +100 -0
  21. spawn/templates/automation/content.py +181 -0
  22. spawn/templates/backend_api/__init__.py +243 -0
  23. spawn/templates/backend_api/content.py +509 -0
  24. spawn/templates/base.py +58 -0
  25. spawn/templates/chatbot/__init__.py +243 -0
  26. spawn/templates/chatbot/content.py +668 -0
  27. spawn/templates/cli_application/__init__.py +211 -0
  28. spawn/templates/cli_application/content.py +512 -0
  29. spawn/templates/data_project/__init__.py +125 -0
  30. spawn/templates/data_project/analysis/__init__.py +74 -0
  31. spawn/templates/data_project/analysis/content.py +190 -0
  32. spawn/templates/data_project/dashboard/__init__.py +61 -0
  33. spawn/templates/data_project/dashboard/content.py +135 -0
  34. spawn/templates/data_project/etl/__init__.py +66 -0
  35. spawn/templates/data_project/etl/content.py +239 -0
  36. spawn/templates/data_project/ml/__init__.py +62 -0
  37. spawn/templates/data_project/ml/content.py +239 -0
  38. spawn/templates/mcp_server/__init__.py +83 -0
  39. spawn/templates/mcp_server/content.py +161 -0
  40. spawn/templates/rag/__init__.py +124 -0
  41. spawn/templates/rag/content.py +463 -0
  42. spawn/templates/shared_content.py +89 -0
  43. spawn/utils/__init__.py +0 -0
  44. spawn/utils/banner.py +41 -0
  45. spawn/utils/console.py +3 -0
  46. spawn/utils/doctor.py +594 -0
  47. spawn/utils/git.py +132 -0
  48. spawn/utils/success.py +47 -0
  49. spawn/utils/theme.py +25 -0
  50. spawn/utils/uv.py +61 -0
  51. spawn/utils/validators.py +15 -0
  52. spawnio-1.0.5.dist-info/METADATA +798 -0
  53. spawnio-1.0.5.dist-info/RECORD +56 -0
  54. spawnio-1.0.5.dist-info/WHEEL +4 -0
  55. spawnio-1.0.5.dist-info/entry_points.txt +2 -0
  56. spawnio-1.0.5.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,509 @@
1
+ MAIN_CONTENT = """\
2
+ from fastapi import FastAPI
3
+
4
+ from app.core.config import settings
5
+ from app.api.routes.health import router as health_router
6
+
7
+ app = FastAPI(title=settings.APP_NAME)
8
+
9
+ app.include_router(health_router)
10
+ """
11
+
12
+ HEALTH_ROUTER_CONTENT = """\
13
+ from fastapi import APIRouter
14
+
15
+ router = APIRouter()
16
+
17
+
18
+ @router.get("/")
19
+ def health_check():
20
+ return {{"status": "running"}}
21
+ """
22
+
23
+ CONFIG_CONTENT = """\
24
+ from pydantic_settings import BaseSettings, SettingsConfigDict
25
+
26
+
27
+ class Settings(BaseSettings):
28
+ model_config = SettingsConfigDict(env_file=".env")
29
+
30
+ APP_NAME: str = "{project_name}"
31
+ DEBUG: bool = False
32
+
33
+
34
+ settings = Settings()
35
+ """
36
+
37
+ TEST_HEALTH_CONTENT = """\
38
+ from fastapi.testclient import TestClient
39
+
40
+ from app.main import app
41
+
42
+ client = TestClient(app)
43
+
44
+
45
+ def test_health_check():
46
+ response = client.get("/")
47
+ assert response.status_code == 200
48
+ assert response.json() == {{"status": "running"}}
49
+ """
50
+
51
+ ENV_EXAMPLE_CONTENT = """\
52
+ APP_NAME={project_name}
53
+ DEBUG=True
54
+ """
55
+
56
+ BACKEND_API_README_CONTENT = """\
57
+ # {project_name}
58
+
59
+ Generated with [Spawn](https://github.com/your-org/spawn).
60
+
61
+ ## Getting Started
62
+
63
+ Install dependencies and start the development server:
64
+
65
+ ```bash
66
+ uv run uvicorn app.main:app --reload
67
+ ```
68
+
69
+ ## Running Tests
70
+
71
+ ```bash
72
+ uv run pytest
73
+ ```
74
+
75
+ ## Endpoints
76
+
77
+ | Method | Path | Description |
78
+ |--------|------|--------------|
79
+ | GET | / | Health check |
80
+
81
+ ## Project Structure
82
+
83
+ ```
84
+ {project_name}/
85
+ ├── app/
86
+ │ ├── api/
87
+ │ │ └── routes/
88
+ │ │ └── health.py # Health check route
89
+ │ ├── core/
90
+ │ │ └── config.py # App settings (pydantic-settings)
91
+ │ ├── models/ # SQLAlchemy / domain models
92
+ │ ├── schemas/ # Pydantic request/response schemas
93
+ │ ├── services/ # Business logic
94
+ │ └── main.py # FastAPI app entry point
95
+ ├── tests/
96
+ │ └── test_health.py
97
+ ├── .env.example
98
+ └── README.md
99
+ ```
100
+ """
101
+
102
+ BACKEND_API_AGENTS_MD_CONTENT = """\
103
+ # {project_name}
104
+
105
+ Backend API built with FastAPI.
106
+
107
+ ## Run Command
108
+
109
+ ```bash
110
+ uv run uvicorn app.main:app --reload
111
+ ```
112
+ """
113
+
114
+ INIT_CONTENT = ""
115
+
116
+
117
+ # ---------------------------------------------------------------------------
118
+ # Flask
119
+ # ---------------------------------------------------------------------------
120
+
121
+ FLASK_APP_INIT_CONTENT = """\
122
+ from flask import Flask
123
+ from app.config import Config
124
+
125
+
126
+ def create_app() -> Flask:
127
+ app = Flask(__name__)
128
+ app.config.from_object(Config)
129
+
130
+ from app.routes.health import health_bp
131
+ app.register_blueprint(health_bp)
132
+
133
+ return app
134
+ """
135
+
136
+ FLASK_CONFIG_CONTENT = """\
137
+ import os
138
+
139
+
140
+ class Config:
141
+ APP_NAME: str = os.getenv("APP_NAME", "{project_name}")
142
+ DEBUG: bool = os.getenv("DEBUG", "True").lower() == "true"
143
+ """
144
+
145
+ FLASK_HEALTH_CONTENT = """\
146
+ from flask import Blueprint, jsonify
147
+
148
+ health_bp = Blueprint("health", __name__)
149
+
150
+
151
+ @health_bp.route("/")
152
+ def health_check():
153
+ return jsonify({{"status": "running"}})
154
+ """
155
+
156
+ FLASK_RUN_CONTENT = """\
157
+ from app import create_app
158
+
159
+ app = create_app()
160
+
161
+ if __name__ == "__main__":
162
+ app.run(debug=app.config.get("DEBUG", True))
163
+ """
164
+
165
+ FLASK_TEST_HEALTH_CONTENT = """\
166
+ import pytest
167
+ from app import create_app
168
+
169
+
170
+ @pytest.fixture
171
+ def client():
172
+ app = create_app()
173
+ app.config["TESTING"] = True
174
+ with app.test_client() as client:
175
+ yield client
176
+
177
+
178
+ def test_health_check(client):
179
+ response = client.get("/")
180
+ assert response.status_code == 200
181
+ assert response.get_json() == {{"status": "running"}}
182
+ """
183
+
184
+ FLASK_ENV_EXAMPLE_CONTENT = """\
185
+ APP_NAME={project_name}
186
+ DEBUG=True
187
+ """
188
+
189
+ FLASK_README_CONTENT = """\
190
+ # {project_name}
191
+
192
+ Generated with [Spawn](https://github.com/Abhiix0/spawn).
193
+
194
+ ## Getting Started
195
+
196
+ Install dependencies and start the development server:
197
+
198
+ ```bash
199
+ uv run python run.py
200
+ ```
201
+
202
+ ## Running Tests
203
+
204
+ ```bash
205
+ uv run pytest
206
+ ```
207
+
208
+ ## Endpoints
209
+
210
+ | Method | Path | Description |
211
+ |--------|------|--------------|
212
+ | GET | / | Health check |
213
+
214
+ ## Project Structure
215
+
216
+ ```
217
+ {project_name}/
218
+ ├── app/
219
+ │ ├── routes/
220
+ │ │ └── health.py # Health check blueprint
221
+ │ ├── models/ # Domain models
222
+ │ ├── services/ # Business logic
223
+ │ ├── config.py # App configuration
224
+ │ └── __init__.py # App factory
225
+ ├── run.py # Entry point
226
+ ├── tests/
227
+ │ └── test_health.py
228
+ ├── .env.example
229
+ └── README.md
230
+ ```
231
+ """
232
+
233
+ FLASK_AGENTS_MD_CONTENT = """\
234
+ # {project_name}
235
+
236
+ Backend API built with Flask.
237
+
238
+ ## Run Command
239
+
240
+ ```bash
241
+ uv run python run.py
242
+ ```
243
+ """
244
+
245
+ # ---------------------------------------------------------------------------
246
+ # Django
247
+ # ---------------------------------------------------------------------------
248
+
249
+ DJANGO_MANAGE_CONTENT = """\
250
+ #!/usr/bin/env python
251
+ import os
252
+ import sys
253
+
254
+
255
+ def main():
256
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
257
+ try:
258
+ from django.core.management import execute_from_command_line
259
+ except ImportError as exc:
260
+ raise ImportError(
261
+ "Couldn't import Django. Are you sure it's installed?"
262
+ ) from exc
263
+ execute_from_command_line(sys.argv)
264
+
265
+
266
+ if __name__ == "__main__":
267
+ main()
268
+ """
269
+
270
+ DJANGO_SETTINGS_CONTENT = """\
271
+ from pathlib import Path
272
+
273
+ BASE_DIR = Path(__file__).resolve().parent.parent
274
+
275
+ SECRET_KEY = "django-insecure-change-me-in-production"
276
+
277
+ DEBUG = True
278
+
279
+ ALLOWED_HOSTS = ["*"]
280
+
281
+ INSTALLED_APPS = [
282
+ "django.contrib.contenttypes",
283
+ "django.contrib.staticfiles",
284
+ "apps.health",
285
+ ]
286
+
287
+ MIDDLEWARE = [
288
+ "django.middleware.common.CommonMiddleware",
289
+ ]
290
+
291
+ ROOT_URLCONF = "config.urls"
292
+
293
+ WSGI_APPLICATION = "config.wsgi.application"
294
+
295
+ DATABASES = {{}}
296
+
297
+ STATIC_URL = "/static/"
298
+
299
+ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
300
+ """
301
+
302
+ DJANGO_URLS_CONTENT = """\
303
+ from django.urls import path, include
304
+
305
+ urlpatterns = [
306
+ path("", include("apps.health.urls")),
307
+ ]
308
+ """
309
+
310
+ DJANGO_ASGI_CONTENT = """\
311
+ import os
312
+ from django.core.asgi import get_asgi_application
313
+
314
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
315
+
316
+ application = get_asgi_application()
317
+ """
318
+
319
+ DJANGO_WSGI_CONTENT = """\
320
+ import os
321
+ from django.core.wsgi import get_wsgi_application
322
+
323
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
324
+
325
+ application = get_wsgi_application()
326
+ """
327
+
328
+ DJANGO_HEALTH_VIEWS_CONTENT = """\
329
+ from django.http import JsonResponse
330
+
331
+
332
+ def health_check(request):
333
+ return JsonResponse({{"status": "running"}})
334
+ """
335
+
336
+ DJANGO_HEALTH_URLS_CONTENT = """\
337
+ from django.urls import path
338
+ from apps.health.views import health_check
339
+
340
+ urlpatterns = [
341
+ path("", health_check, name="health_check"),
342
+ ]
343
+ """
344
+
345
+ DJANGO_HEALTH_TESTS_CONTENT = """\
346
+ from django.test import TestCase, Client
347
+
348
+
349
+ class HealthCheckTestCase(TestCase):
350
+ def setUp(self):
351
+ self.client = Client()
352
+
353
+ def test_health_check(self):
354
+ response = self.client.get("/")
355
+ self.assertEqual(response.status_code, 200)
356
+ self.assertJSONEqual(response.content, {{"status": "running"}})
357
+ """
358
+
359
+ DJANGO_README_CONTENT = """\
360
+ # {project_name}
361
+
362
+ Generated with [Spawn](https://github.com/Abhiix0/spawn).
363
+
364
+ ## Getting Started
365
+
366
+ Install dependencies and start the development server:
367
+
368
+ ```bash
369
+ uv run python manage.py runserver
370
+ ```
371
+
372
+ ## Running Tests
373
+
374
+ ```bash
375
+ uv run python manage.py test
376
+ ```
377
+
378
+ ## Endpoints
379
+
380
+ | Method | Path | Description |
381
+ |--------|------|--------------|
382
+ | GET | / | Health check |
383
+
384
+ ## Project Structure
385
+
386
+ ```
387
+ {project_name}/
388
+ ├── manage.py
389
+ ├── config/
390
+ │ ├── settings.py
391
+ │ ├── urls.py
392
+ │ ├── asgi.py
393
+ │ └── wsgi.py
394
+ ├── apps/
395
+ │ └── health/
396
+ │ ├── views.py
397
+ │ ├── urls.py
398
+ │ └── tests.py
399
+ └── README.md
400
+ ```
401
+ """
402
+
403
+ DJANGO_AGENTS_MD_CONTENT = """\
404
+ # {project_name}
405
+
406
+ Backend API built with Django.
407
+
408
+ ## Run Command
409
+
410
+ ```bash
411
+ uv run python manage.py runserver
412
+ ```
413
+ """
414
+
415
+ # ---------------------------------------------------------------------------
416
+ # Docker
417
+ # ---------------------------------------------------------------------------
418
+
419
+ DOCKERFILE_FASTAPI_CONTENT = """\
420
+ FROM python:3.12-slim
421
+
422
+ WORKDIR /app
423
+
424
+ COPY pyproject.toml .
425
+ RUN pip install uv && uv sync
426
+
427
+ COPY . .
428
+
429
+ EXPOSE 8000
430
+
431
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
432
+ """
433
+
434
+ DOCKERFILE_FLASK_CONTENT = """\
435
+ FROM python:3.12-slim
436
+
437
+ WORKDIR /app
438
+
439
+ COPY pyproject.toml .
440
+ RUN pip install uv && uv sync
441
+
442
+ COPY . .
443
+
444
+ EXPOSE 5000
445
+
446
+ CMD ["python", "run.py"]
447
+ """
448
+
449
+ DOCKERFILE_DJANGO_CONTENT = """\
450
+ FROM python:3.12-slim
451
+
452
+ WORKDIR /app
453
+
454
+ COPY pyproject.toml .
455
+ RUN pip install uv && uv sync
456
+
457
+ COPY . .
458
+
459
+ EXPOSE 8000
460
+
461
+ CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
462
+ """
463
+
464
+ DOCKERIGNORE_CONTENT = """\
465
+ .venv
466
+ __pycache__
467
+ *.pyc
468
+ *.pyo
469
+ .env
470
+ .git
471
+ .gitignore
472
+ """
473
+
474
+ # ---------------------------------------------------------------------------
475
+ # GitHub Actions
476
+ # ---------------------------------------------------------------------------
477
+
478
+ GITHUB_ACTIONS_CI_BASE = """\
479
+ name: CI
480
+
481
+ on:
482
+ push:
483
+ branches: [main]
484
+ pull_request:
485
+ branches: [main]
486
+
487
+ jobs:
488
+ ci:
489
+ runs-on: ubuntu-latest
490
+
491
+ steps:
492
+ - uses: actions/checkout@v4
493
+
494
+ - name: Install uv
495
+ uses: astral-sh/setup-uv@v4
496
+
497
+ - name: Install dependencies
498
+ run: uv sync
499
+ """
500
+
501
+ GITHUB_ACTIONS_CI_RUFF_STEP = """\
502
+ - name: Run Ruff
503
+ run: uv run ruff check .
504
+ """
505
+
506
+ GITHUB_ACTIONS_CI_PYTEST_STEP = """\
507
+ - name: Run Pytest
508
+ run: uv run pytest
509
+ """
@@ -0,0 +1,58 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+
4
+
5
+ @dataclass
6
+ class BaseTemplate:
7
+ name: str
8
+ folders: list[str]
9
+ starter_files: list[tuple[str, str]] = field(default_factory=list)
10
+ next_steps: list[str] = field(default_factory=list)
11
+ # Each tuple: (relative_path_string, content_template_string)
12
+
13
+ def get_dependencies(self) -> list[str]:
14
+ """Return packages to install after uv init. Subclasses override."""
15
+ return []
16
+
17
+ def post_install(self, project_path: Path) -> None:
18
+ """Run post-install actions after packages are installed. Subclasses override."""
19
+ pass
20
+
21
+ def get_readme_content(self, context: dict) -> str | None:
22
+ """
23
+ Return custom README content for this template, or None to use the
24
+ shared README. Subclasses override this to provide template-specific
25
+ README content.
26
+ """
27
+ return None
28
+
29
+ def get_agents_md_content(self, context: dict) -> str | None:
30
+ """
31
+ Return custom AGENTS.md content for this template, or None to use
32
+ the shared default. Subclasses override this to provide
33
+ template-specific agent context — framework, provider, or
34
+ environment-variable details an agent working on this project
35
+ would need.
36
+ """
37
+ return None
38
+
39
+ def generate(self, project_path: Path, context: dict) -> None:
40
+ """
41
+ Create the template's folder structure and starter files.
42
+
43
+ project_path: the already-created root project directory (Path object)
44
+ context: dict with at minimum {"project_name": str}
45
+
46
+ Subclasses may override this in future phases.
47
+ The default implementation creates folders and writes starter_files.
48
+ """
49
+ for folder in self.folders:
50
+ (project_path / folder).mkdir(parents=True, exist_ok=True)
51
+
52
+ for relative_path, content_template in self.starter_files:
53
+ file_path = project_path / relative_path
54
+ file_path.parent.mkdir(parents=True, exist_ok=True)
55
+ file_path.write_text(
56
+ content_template.format_map(context),
57
+ encoding="utf-8",
58
+ )