csrd-utils 0.3.16__tar.gz → 0.3.17__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 (87) hide show
  1. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/PKG-INFO +1 -1
  2. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/pyproject.toml +1 -1
  3. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/__main__.py +11 -3
  4. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/cluster.py +11 -2
  5. csrd_utils-0.3.17/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/.gitignore +64 -0
  6. csrd_utils-0.3.17/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/pyproject.toml +61 -0
  7. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/views/unversioned/items_view.py +4 -4
  8. csrd_utils-0.3.17/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/__init__.py +0 -0
  9. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/.gitignore +0 -0
  10. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/README.md +0 -0
  11. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/__init__.py +0 -0
  12. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/audit.py +0 -0
  13. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/augmentor.py +0 -0
  14. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/doctor.py +0 -0
  15. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
  16. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
  17. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/manifest.yaml +0 -0
  18. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/requirements.fragment +0 -0
  19. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
  20. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
  21. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
  22. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
  23. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/logging/manifest.yaml +0 -0
  24. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/logging/requirements.fragment +0 -0
  25. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
  26. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
  27. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
  28. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
  29. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
  30. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
  31. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
  32. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
  33. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
  34. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
  35. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
  36. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
  37. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
  38. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
  39. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
  40. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
  41. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
  42. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
  43. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/manifest.yaml +0 -0
  44. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/requirements.fragment +0 -0
  45. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
  46. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
  47. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
  48. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
  49. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
  50. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/fragments.py +0 -0
  51. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/generator.py +0 -0
  52. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/resources.py +0 -0
  53. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
  54. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
  55. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
  56. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/.dockerignore +0 -0
  57. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/.env.example +0 -0
  58. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/Dockerfile +0 -0
  59. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/README.md +0 -0
  60. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/docker-compose.yml +0 -0
  61. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/requirements.txt +0 -0
  62. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/__init__.py +0 -0
  63. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/cache.py +0 -0
  64. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/delegates/__init__.py +0 -0
  65. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/delegates/upstreams.py +0 -0
  66. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/dependencies/__init__.py +0 -0
  67. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/dependencies/delegates.py +0 -0
  68. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/dependencies/item_repository.py +0 -0
  69. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/dependencies/worker_broker.py +0 -0
  70. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/middleware/__init__.py +0 -0
  71. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/middleware/logging.py +0 -0
  72. /csrd_utils-0.3.16/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/__init__.py → /csrd_utils-0.3.17/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/py.typed +0 -0
  73. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/repositories/__init__.py +0 -0
  74. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/repositories/item_repository.py +0 -0
  75. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/settings.py +0 -0
  76. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/views/__init__.py +0 -0
  77. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/views/unversioned/__init__.py +0 -0
  78. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/views/unversioned/health_view.py +0 -0
  79. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/workers/__init__.py +0 -0
  80. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/src/app/workers/tasks.py +0 -0
  81. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/acceptance/test_logging_middleware.py +0 -0
  82. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/conftest.py +0 -0
  83. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/test_items.py +0 -0
  84. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/unit/test_cache.py +0 -0
  85. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/unit/test_database_settings.py +0 -0
  86. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/unit/test_delegates.py +0 -0
  87. {csrd_utils-0.3.16 → csrd_utils-0.3.17}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.service_name}}/tests/unit/test_worker_broker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csrd-utils
3
- Version: 0.3.16
3
+ Version: 0.3.17
4
4
  Summary: CLI utilities for csrd service generation and feature augmentation
5
5
  Project-URL: Repository, https://github.com/csrd-api/fastapi-common
6
6
  Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csrd-utils"
3
- version = "0.3.16"
3
+ version = "0.3.17"
4
4
  description = "CLI utilities for csrd service generation and feature augmentation"
5
5
  license = { text = "MIT" }
6
6
  requires-python = ">=3.12"
@@ -82,7 +82,15 @@ def _prompt_choice(label: str, choices: list[str], default: str) -> str:
82
82
  return default
83
83
  if value in choices:
84
84
  return value
85
- print(f"ERROR: Invalid choice '{value}'. Expected one of: {rendered}")
85
+ # Try prefix matching
86
+ matching = [choice for choice in choices if choice.startswith(value)]
87
+ if len(matching) == 1:
88
+ return matching[0]
89
+ if len(matching) > 1:
90
+ matching_str = ", ".join(matching)
91
+ print(f"ERROR: Ambiguous choice '{value}'. Matches: {matching_str}")
92
+ else:
93
+ print(f"ERROR: Invalid choice '{value}'. Expected one of: {rendered}")
86
94
 
87
95
 
88
96
  def _prompt_int(label: str, default: int) -> int:
@@ -555,7 +563,7 @@ def _maybe_update_workspace_cluster(
555
563
  spec_path = _workspace_cluster_spec_path(workspace_root)
556
564
  if spec_path.is_file():
557
565
  updated_spec = _append_service_to_workspace_cluster(workspace_root, service_config)
558
- return generate_cluster(updated_spec, workspace_root, force=True)
566
+ return generate_cluster(updated_spec, workspace_root, force=True, workspace_mode=True)
559
567
 
560
568
  service_roots = _workspace_service_roots(workspace_root)
561
569
  if len(service_roots) < 2:
@@ -575,7 +583,7 @@ def _maybe_update_workspace_cluster(
575
583
  }
576
584
  normalized = normalize_cluster_spec(bootstrap_spec)
577
585
  _save_workspace_cluster_spec(workspace_root, normalized)
578
- return generate_cluster(normalized, workspace_root, force=True)
586
+ return generate_cluster(normalized, workspace_root, force=True, workspace_mode=True)
579
587
 
580
588
 
581
589
  def _build_parser() -> argparse.ArgumentParser:
@@ -452,9 +452,18 @@ def _build_smoke(spec: ClusterSpec) -> str:
452
452
  return "\n".join(lines) + "\n"
453
453
 
454
454
 
455
- def generate_cluster(spec: ClusterSpec, output_dir: Path, force: bool = False) -> Path:
455
+ def generate_cluster(
456
+ spec: ClusterSpec, output_dir: Path, force: bool = False, workspace_mode: bool = False
457
+ ) -> Path:
456
458
  normalized = normalize_cluster_spec(spec)
457
- cluster_root = output_dir.resolve() / normalized["cluster"]["name"]
459
+
460
+ if workspace_mode:
461
+ # In workspace mode, write files directly to output_dir (workspace root)
462
+ cluster_root = output_dir.resolve()
463
+ else:
464
+ # In standalone mode, create a subdirectory with cluster name
465
+ cluster_root = output_dir.resolve() / normalized["cluster"]["name"]
466
+
458
467
  cluster_root.mkdir(parents=True, exist_ok=True)
459
468
 
460
469
  if any(cluster_root.iterdir()) and not force:
@@ -0,0 +1,64 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ pip-wheel-metadata/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # Virtual environments
27
+ .venv
28
+ venv/
29
+ ENV/
30
+ env/
31
+
32
+ # IDEs
33
+ .vscode/
34
+ .idea/
35
+ *.swp
36
+ *.swo
37
+ *~
38
+ .DS_Store
39
+
40
+ # Testing
41
+ .pytest_cache/
42
+ .coverage
43
+ htmlcov/
44
+ .tox/
45
+ .hypothesis/
46
+
47
+ # Type checking
48
+ .mypy_cache/
49
+ .dmypy.json
50
+ dmypy.json
51
+
52
+ # Development
53
+ *.log
54
+ .env
55
+ .env.local
56
+ .env.*.local
57
+
58
+ # Docker
59
+ .dockerignore
60
+ Dockerfile
61
+
62
+ # Services
63
+ .csrd-workspace
64
+ .csrd/
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "{{ cookiecutter.service_name }}"
7
+ version = "0.1.0"
8
+ description = "{{ cookiecutter.service_description }}"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = {text = "MIT"}
12
+ authors = [{name = "Generated by csrd", email = "generated@csrd.local"}]
13
+ keywords = ["fastapi", "microservice", "csrd"]
14
+
15
+ dependencies = [
16
+ "fastapi>=0.110",
17
+ "uvicorn[standard]>=0.27",
18
+ "pydantic[email]>=2.5",
19
+ "csrd-versioning @ git+https://github.com/csrd-api/fastapi-common.git#subdirectory=packages/versioning",
20
+ "csrd-lifespan @ git+https://github.com/csrd-api/fastapi-common.git#subdirectory=packages/lifespan",
21
+ "csrd-repository @ git+https://github.com/csrd-api/fastapi-common.git#subdirectory=packages/repository",
22
+ "csrd-context @ git+https://github.com/csrd-api/fastapi-common.git#subdirectory=packages/context",
23
+ "httpx>=0.25",
24
+ "celery[redis]>=5.3",
25
+ "celery[amqp]>=5.3",
26
+ "redis>=5.0",
27
+ "csrd-logging @ git+https://github.com/csrd-api/fastapi-common.git#subdirectory=packages/logging",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "pytest>=7.4",
33
+ "pytest-asyncio>=0.21",
34
+ "mypy>=1.7",
35
+ "ruff>=0.1",
36
+ ]
37
+
38
+ [tool.hatch.build.targets.wheel]
39
+ packages = ["src/app"]
40
+
41
+ [tool.pytest.ini_options]
42
+ asyncio_mode = "auto"
43
+ testpaths = ["tests"]
44
+
45
+ [tool.mypy]
46
+ python_version = "3.12"
47
+ warn_return_any = true
48
+ warn_unused_configs = true
49
+ disallow_untyped_defs = true
50
+ strict = true
51
+
52
+ [tool.ruff]
53
+ target-version = "py312"
54
+ line-length = 100
55
+
56
+ [tool.ruff.lint]
57
+ select = ["E", "F", "W", "I", "N", "UP", "BLE", "FBT", "A", "C4", "PIE", "SIM", "RUF"]
58
+ ignore = ["E501"]
59
+
60
+ [tool.ruff.lint.isort]
61
+ known-first-party = ["app"]
@@ -104,7 +104,7 @@ async def list_{{ cookiecutter.model_name_plural | lower | replace(' ', '_') }}(
104
104
  {%- endif %}
105
105
 
106
106
 
107
- @router.get(f"{ITEMS_ROUTE}/{entity_id}")
107
+ @router.get(f"{ITEMS_ROUTE}" + "/{entity_id}")
108
108
  async def get_{{ cookiecutter.model_name | lower }}(
109
109
  entity_id: str,
110
110
  {%- if cookiecutter.has_database %}
@@ -128,7 +128,7 @@ async def get_{{ cookiecutter.model_name | lower }}(
128
128
  return item
129
129
 
130
130
 
131
- @router.put(f"{ITEMS_ROUTE}/{entity_id}")
131
+ @router.put(f"{ITEMS_ROUTE}" + "/{entity_id}")
132
132
  async def update_{{ cookiecutter.model_name | lower }}(
133
133
  entity_id: str,
134
134
  payload: Update{{ cookiecutter.model_name }}Request,
@@ -161,7 +161,7 @@ async def update_{{ cookiecutter.model_name | lower }}(
161
161
  return {"id": entity_id, "name": payload.name, "updated": True}
162
162
 
163
163
 
164
- @router.put(f"{ITEMS_ROUTE}/{entity_id}/upsert")
164
+ @router.put(f"{ITEMS_ROUTE}" + "/{entity_id}/upsert")
165
165
  async def upsert_{{ cookiecutter.model_name | lower }}(
166
166
  entity_id: str,
167
167
  payload: Update{{ cookiecutter.model_name }}Request,
@@ -194,7 +194,7 @@ async def upsert_{{ cookiecutter.model_name | lower }}(
194
194
  return {"id": entity_id, "name": payload.name, "rows_affected": rows}
195
195
 
196
196
 
197
- @router.delete(f"{ITEMS_ROUTE}/{entity_id}")
197
+ @router.delete(f"{ITEMS_ROUTE}" + "/{entity_id}")
198
198
  async def delete_{{ cookiecutter.model_name | lower }}(
199
199
  entity_id: str,
200
200
  {%- if cookiecutter.has_database %}
File without changes
File without changes