instant-python 0.20.0__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 (202) hide show
  1. instant_python/__init__.py +1 -0
  2. instant_python/cli/__init__.py +0 -0
  3. instant_python/cli/cli.py +58 -0
  4. instant_python/cli/instant_python_typer.py +35 -0
  5. instant_python/config/__init__.py +0 -0
  6. instant_python/config/application/__init__.py +0 -0
  7. instant_python/config/application/config_generator.py +23 -0
  8. instant_python/config/delivery/__init__.py +0 -0
  9. instant_python/config/delivery/cli.py +19 -0
  10. instant_python/config/domain/__init__.py +0 -0
  11. instant_python/config/domain/question_wizard.py +7 -0
  12. instant_python/config/infra/__init__.py +0 -0
  13. instant_python/config/infra/question_wizard/__init__.py +0 -0
  14. instant_python/config/infra/question_wizard/questionary_console_wizard.py +25 -0
  15. instant_python/config/infra/question_wizard/step/__init__.py +0 -0
  16. instant_python/config/infra/question_wizard/step/dependencies_step.py +64 -0
  17. instant_python/config/infra/question_wizard/step/general_step.py +81 -0
  18. instant_python/config/infra/question_wizard/step/git_step.py +41 -0
  19. instant_python/config/infra/question_wizard/step/questionary.py +17 -0
  20. instant_python/config/infra/question_wizard/step/steps.py +21 -0
  21. instant_python/config/infra/question_wizard/step/template_step.py +63 -0
  22. instant_python/initialize/__init__.py +0 -0
  23. instant_python/initialize/application/__init__.py +0 -0
  24. instant_python/initialize/application/project_initializer.py +47 -0
  25. instant_python/initialize/delivery/__init__.py +0 -0
  26. instant_python/initialize/delivery/cli.py +48 -0
  27. instant_python/initialize/domain/__init__.py +0 -0
  28. instant_python/initialize/domain/env_manager.py +9 -0
  29. instant_python/initialize/domain/node.py +73 -0
  30. instant_python/initialize/domain/project_formatter.py +7 -0
  31. instant_python/initialize/domain/project_renderer.py +10 -0
  32. instant_python/initialize/domain/project_structure.py +77 -0
  33. instant_python/initialize/domain/project_writer.py +20 -0
  34. instant_python/initialize/domain/version_control_configurer.py +9 -0
  35. instant_python/initialize/infra/__init__.py +0 -0
  36. instant_python/initialize/infra/env_manager/__init__.py +0 -0
  37. instant_python/initialize/infra/env_manager/env_manager_factory.py +27 -0
  38. instant_python/initialize/infra/env_manager/pdm_env_manager.py +66 -0
  39. instant_python/initialize/infra/env_manager/system_console.py +65 -0
  40. instant_python/initialize/infra/env_manager/uv_env_manager.py +74 -0
  41. instant_python/initialize/infra/formatter/__init__.py +0 -0
  42. instant_python/initialize/infra/formatter/ruff_project_formatter.py +10 -0
  43. instant_python/initialize/infra/renderer/__init__.py +0 -0
  44. instant_python/initialize/infra/renderer/jinja_environment.py +71 -0
  45. instant_python/initialize/infra/renderer/jinja_project_renderer.py +57 -0
  46. instant_python/initialize/infra/version_control/__init__.py +0 -0
  47. instant_python/initialize/infra/version_control/git_configurer.py +29 -0
  48. instant_python/initialize/infra/writer/__init__.py +0 -0
  49. instant_python/initialize/infra/writer/file_system_project_writer.py +23 -0
  50. instant_python/shared/__init__.py +0 -0
  51. instant_python/shared/application_error.py +8 -0
  52. instant_python/shared/domain/__init__.py +0 -0
  53. instant_python/shared/domain/config_repository.py +18 -0
  54. instant_python/shared/domain/config_schema.py +113 -0
  55. instant_python/shared/domain/dependency_config.py +41 -0
  56. instant_python/shared/domain/general_config.py +71 -0
  57. instant_python/shared/domain/git_config.py +32 -0
  58. instant_python/shared/domain/template_config.py +76 -0
  59. instant_python/shared/infra/__init__.py +0 -0
  60. instant_python/shared/infra/persistence/__init__.py +0 -0
  61. instant_python/shared/infra/persistence/yaml_config_repository.py +39 -0
  62. instant_python/shared/supported_built_in_features.py +20 -0
  63. instant_python/shared/supported_licenses.py +11 -0
  64. instant_python/shared/supported_managers.py +10 -0
  65. instant_python/shared/supported_python_versions.py +12 -0
  66. instant_python/shared/supported_templates.py +12 -0
  67. instant_python/templates/boilerplate/.gitignore +164 -0
  68. instant_python/templates/boilerplate/.pre-commit-config.yml +73 -0
  69. instant_python/templates/boilerplate/.python-version +1 -0
  70. instant_python/templates/boilerplate/CITATION.cff +13 -0
  71. instant_python/templates/boilerplate/LICENSE +896 -0
  72. instant_python/templates/boilerplate/README.md +8 -0
  73. instant_python/templates/boilerplate/SECURITY.md +43 -0
  74. instant_python/templates/boilerplate/event_bus/__init__.py +0 -0
  75. instant_python/templates/boilerplate/event_bus/domain_event.py +15 -0
  76. instant_python/templates/boilerplate/event_bus/domain_event_json_deserializer.py +25 -0
  77. instant_python/templates/boilerplate/event_bus/domain_event_json_serializer.py +16 -0
  78. instant_python/templates/boilerplate/event_bus/domain_event_subscriber.py +33 -0
  79. instant_python/templates/boilerplate/event_bus/event_aggregate.py +19 -0
  80. instant_python/templates/boilerplate/event_bus/event_bus.py +9 -0
  81. instant_python/templates/boilerplate/event_bus/exchange_type.py +14 -0
  82. instant_python/templates/boilerplate/event_bus/mock_event_bus.py +16 -0
  83. instant_python/templates/boilerplate/event_bus/rabbit_mq_configurer.py +45 -0
  84. instant_python/templates/boilerplate/event_bus/rabbit_mq_connection.py +71 -0
  85. instant_python/templates/boilerplate/event_bus/rabbit_mq_consumer.py +56 -0
  86. instant_python/templates/boilerplate/event_bus/rabbit_mq_event_bus.py +26 -0
  87. instant_python/templates/boilerplate/event_bus/rabbit_mq_queue_formatter.py +21 -0
  88. instant_python/templates/boilerplate/event_bus/rabbit_mq_settings.py +8 -0
  89. instant_python/templates/boilerplate/exceptions/__init__.py +0 -0
  90. instant_python/templates/boilerplate/exceptions/base_error.py +13 -0
  91. instant_python/templates/boilerplate/exceptions/domain_error.py +6 -0
  92. instant_python/templates/boilerplate/exceptions/domain_event_type_not_found_error.py +6 -0
  93. instant_python/templates/boilerplate/exceptions/rabbit_mq_connection_not_established_error.py +7 -0
  94. instant_python/templates/boilerplate/exceptions/required_value_error.py +6 -0
  95. instant_python/templates/boilerplate/fastapi/__init__.py +0 -0
  96. instant_python/templates/boilerplate/fastapi/application.py +74 -0
  97. instant_python/templates/boilerplate/fastapi/error_handlers.py +88 -0
  98. instant_python/templates/boilerplate/fastapi/error_response.py +31 -0
  99. instant_python/templates/boilerplate/fastapi/fastapi_log_middleware.py +32 -0
  100. instant_python/templates/boilerplate/fastapi/lifespan.py +13 -0
  101. instant_python/templates/boilerplate/fastapi/success_response.py +13 -0
  102. instant_python/templates/boilerplate/github/action.yml +35 -0
  103. instant_python/templates/boilerplate/github/bug_report.yml +60 -0
  104. instant_python/templates/boilerplate/github/ci.yml +199 -0
  105. instant_python/templates/boilerplate/github/feature_request.yml +21 -0
  106. instant_python/templates/boilerplate/github/release.yml +94 -0
  107. instant_python/templates/boilerplate/logger/__init__.py +0 -0
  108. instant_python/templates/boilerplate/logger/file_logger.py +55 -0
  109. instant_python/templates/boilerplate/logger/file_rotating_handler.py +36 -0
  110. instant_python/templates/boilerplate/logger/json_formatter.py +16 -0
  111. instant_python/templates/boilerplate/mypy.ini +41 -0
  112. instant_python/templates/boilerplate/persistence/__init__.py +0 -0
  113. instant_python/templates/boilerplate/persistence/alembic_migrator.py +19 -0
  114. instant_python/templates/boilerplate/persistence/async/README.md +1 -0
  115. instant_python/templates/boilerplate/persistence/async/__init__.py +0 -0
  116. instant_python/templates/boilerplate/persistence/async/alembic.ini +124 -0
  117. instant_python/templates/boilerplate/persistence/async/async_engine_fixture.py +20 -0
  118. instant_python/templates/boilerplate/persistence/async/async_session.py +20 -0
  119. instant_python/templates/boilerplate/persistence/async/env.py +94 -0
  120. instant_python/templates/boilerplate/persistence/async/models_metadata.py +10 -0
  121. instant_python/templates/boilerplate/persistence/async/postgres_settings.py +15 -0
  122. instant_python/templates/boilerplate/persistence/async/script.py.mako +26 -0
  123. instant_python/templates/boilerplate/persistence/async/sqlalchemy_repository.py +28 -0
  124. instant_python/templates/boilerplate/persistence/base.py +4 -0
  125. instant_python/templates/boilerplate/persistence/synchronous/__init__.py +0 -0
  126. instant_python/templates/boilerplate/persistence/synchronous/session_maker.py +21 -0
  127. instant_python/templates/boilerplate/persistence/synchronous/sqlalchemy_repository.py +40 -0
  128. instant_python/templates/boilerplate/pyproject.toml +134 -0
  129. instant_python/templates/boilerplate/pytest.ini +10 -0
  130. instant_python/templates/boilerplate/scripts/add_dependency.py +45 -0
  131. instant_python/templates/boilerplate/scripts/create_aggregate.py +33 -0
  132. instant_python/templates/boilerplate/scripts/insert_template.py +90 -0
  133. instant_python/templates/boilerplate/scripts/integration.sh +39 -0
  134. instant_python/templates/boilerplate/scripts/local_setup.py +12 -0
  135. instant_python/templates/boilerplate/scripts/makefile +184 -0
  136. instant_python/templates/boilerplate/scripts/post-merge.py +40 -0
  137. instant_python/templates/boilerplate/scripts/pre-commit.py +15 -0
  138. instant_python/templates/boilerplate/scripts/pre-push.py +6 -0
  139. instant_python/templates/boilerplate/scripts/remove_dependency.py +40 -0
  140. instant_python/templates/boilerplate/scripts/unit.sh +40 -0
  141. instant_python/templates/project_structure/clean_architecture/layers/application.yml +3 -0
  142. instant_python/templates/project_structure/clean_architecture/layers/delivery.yml +8 -0
  143. instant_python/templates/project_structure/clean_architecture/layers/domain.yml +10 -0
  144. instant_python/templates/project_structure/clean_architecture/layers/infra.yml +12 -0
  145. instant_python/templates/project_structure/clean_architecture/layers/test_application.yml +3 -0
  146. instant_python/templates/project_structure/clean_architecture/layers/test_delivery.yml +3 -0
  147. instant_python/templates/project_structure/clean_architecture/layers/test_domain.yml +3 -0
  148. instant_python/templates/project_structure/clean_architecture/layers/test_infra.yml +9 -0
  149. instant_python/templates/project_structure/clean_architecture/main_structure.yml +38 -0
  150. instant_python/templates/project_structure/clean_architecture/source.yml +9 -0
  151. instant_python/templates/project_structure/clean_architecture/test.yml +9 -0
  152. instant_python/templates/project_structure/config_files/gitignore.yml +3 -0
  153. instant_python/templates/project_structure/config_files/mypy.yml +4 -0
  154. instant_python/templates/project_structure/config_files/pyproject.yml +4 -0
  155. instant_python/templates/project_structure/config_files/pytest.yml +4 -0
  156. instant_python/templates/project_structure/config_files/python_version.yml +3 -0
  157. instant_python/templates/project_structure/documentation/citation.yml +4 -0
  158. instant_python/templates/project_structure/documentation/license.yml +3 -0
  159. instant_python/templates/project_structure/documentation/readme.yml +4 -0
  160. instant_python/templates/project_structure/documentation/security.yml +4 -0
  161. instant_python/templates/project_structure/domain_driven_design/layers/bounded_context.yml +17 -0
  162. instant_python/templates/project_structure/domain_driven_design/layers/delivery.yml +8 -0
  163. instant_python/templates/project_structure/domain_driven_design/layers/shared.yml +18 -0
  164. instant_python/templates/project_structure/domain_driven_design/layers/shared_domain.yml +10 -0
  165. instant_python/templates/project_structure/domain_driven_design/layers/shared_infra.yml +12 -0
  166. instant_python/templates/project_structure/domain_driven_design/layers/test_shared.yml +8 -0
  167. instant_python/templates/project_structure/domain_driven_design/layers/test_shared_delivery.yml +3 -0
  168. instant_python/templates/project_structure/domain_driven_design/layers/test_shared_domain.yml +3 -0
  169. instant_python/templates/project_structure/domain_driven_design/layers/test_shared_infra.yml +9 -0
  170. instant_python/templates/project_structure/domain_driven_design/main_structure.yml +38 -0
  171. instant_python/templates/project_structure/domain_driven_design/source.yml +10 -0
  172. instant_python/templates/project_structure/domain_driven_design/test.yml +9 -0
  173. instant_python/templates/project_structure/errors.yml +12 -0
  174. instant_python/templates/project_structure/events/event_bus_domain.yml +48 -0
  175. instant_python/templates/project_structure/events/event_bus_infra.yml +40 -0
  176. instant_python/templates/project_structure/events/mock_event_bus.yml +4 -0
  177. instant_python/templates/project_structure/fastapi/fastapi_app.yml +32 -0
  178. instant_python/templates/project_structure/fastapi/fastapi_domain.yml +12 -0
  179. instant_python/templates/project_structure/fastapi/fastapi_infra.yml +12 -0
  180. instant_python/templates/project_structure/github/github_action.yml +24 -0
  181. instant_python/templates/project_structure/github/github_issues_template.yml +14 -0
  182. instant_python/templates/project_structure/github/makefile.yml +3 -0
  183. instant_python/templates/project_structure/github/precommit_hook.yml +4 -0
  184. instant_python/templates/project_structure/logger.yml +16 -0
  185. instant_python/templates/project_structure/macros.j2 +73 -0
  186. instant_python/templates/project_structure/persistence/alembic_migrator.yml +6 -0
  187. instant_python/templates/project_structure/persistence/async_alembic.yml +27 -0
  188. instant_python/templates/project_structure/persistence/async_engine_conftest.yml +4 -0
  189. instant_python/templates/project_structure/persistence/async_sqlalchemy.yml +14 -0
  190. instant_python/templates/project_structure/persistence/persistence.yml +8 -0
  191. instant_python/templates/project_structure/persistence/synchronous_sqlalchemy.yml +20 -0
  192. instant_python/templates/project_structure/standard_project/layers/source_features.yml +13 -0
  193. instant_python/templates/project_structure/standard_project/layers/test_event_bus.yml +6 -0
  194. instant_python/templates/project_structure/standard_project/layers/test_features.yml +6 -0
  195. instant_python/templates/project_structure/standard_project/main_structure.yml +38 -0
  196. instant_python/templates/project_structure/standard_project/source.yml +5 -0
  197. instant_python/templates/project_structure/standard_project/test.yml +5 -0
  198. instant_python-0.20.0.dist-info/METADATA +318 -0
  199. instant_python-0.20.0.dist-info/RECORD +202 -0
  200. instant_python-0.20.0.dist-info/WHEEL +4 -0
  201. instant_python-0.20.0.dist-info/entry_points.txt +2 -0
  202. instant_python-0.20.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ from scripts.templates.aggregate_root_template import aggregate_root_template
6
+ from scripts.templates.errors.incorrect_value_error_template import incorrect_value_type_error_template
7
+ from scripts.templates.errors.required_value_error_template import required_value_error_template
8
+ from scripts.templates.errors.invalid_negative_value_error_template import invalid_negative_value_error_template
9
+ from scripts.templates.value_objects.string_value_object_template import string_value_object_template
10
+ from scripts.templates.value_objects.uuid_template import uuid_template
11
+ from scripts.templates.value_objects.value_object_template import value_object_template
12
+ from scripts.templates.value_objects.int_value_object_template import int_value_object_template
13
+ from scripts.templates.events.domain_event_template import domain_event_template
14
+ from scripts.templates.events.domain_event_subscriber_template import domain_event_subscriber_template
15
+ from scripts.templates.events.event_bus_template import event_bus_template
16
+ from scripts.templates.events.exchange_type_template import exchange_type_template
17
+ from scripts.templates.events.rabbit_mq_configurer_template import rabbit_mq_configurer_template
18
+ from scripts.templates.events.rabbit_mq_connection_template import rabbit_mq_connection_template
19
+ from scripts.templates.events.rabbit_mq_consumer_template import rabbit_mq_consumer_template
20
+ from scripts.templates.events.rabbit_mq_event_bus_template import rabbit_mq_event_bus_template
21
+ from scripts.templates.events.rabbit_mq_queue_formatter_template import rabbit_mq_queue_formatter_template
22
+ from scripts.templates.events.rabbit_mq_settings_template import rabbit_mq_settings_template
23
+ from scripts.templates.events.domain_event_json_deserializer_template import domain_event_json_deserializer_template
24
+ from scripts.templates.events.domain_event_json_serializer_template import domain_event_json_serializer_template
25
+
26
+
27
+ TEMPLATES = {
28
+ "value_object": value_object_template,
29
+ "string_value_object": string_value_object_template,
30
+ "int_value_object": int_value_object_template,
31
+ "uuid": uuid_template,
32
+ "incorrect_value": incorrect_value_type_error_template,
33
+ "required_value": required_value_error_template,
34
+ "invalid_negative_value": invalid_negative_value_error_template,
35
+ "domain_event": domain_event_template,
36
+ "domain_event_subscriber": domain_event_subscriber_template,
37
+ "event_bus": event_bus_template,
38
+ "exchange_type": exchange_type_template,
39
+ "aggregate_root": aggregate_root_template,
40
+ "rabbit_mq_configurer": rabbit_mq_configurer_template,
41
+ "rabbit_mq_connection": rabbit_mq_connection_template,
42
+ "rabbit_mq_consumer": rabbit_mq_consumer_template,
43
+ "rabbit_mq_event_bus": rabbit_mq_event_bus_template,
44
+ "rabbit_mq_queue_formatter": rabbit_mq_queue_formatter_template,
45
+ "rabbit_mq_settings": rabbit_mq_settings_template,
46
+ "domain_event_json_deserializer": domain_event_json_deserializer_template,
47
+ "domain_event_json_serializer": domain_event_json_serializer_template,
48
+ }
49
+
50
+
51
+ def main() -> None:
52
+ list_available_templates()
53
+ template_name = input("Enter the name of the template you want to insert: ")
54
+ ensure_template_exists(template_name)
55
+
56
+ user_path = input("Enter the path where template should be created: ")
57
+ folder_path = generate_folder_path(Path(user_path))
58
+ write_content_at(folder_path, template_name)
59
+
60
+
61
+ def list_available_templates() -> None:
62
+ print(f"Available templates: {', '.join(TEMPLATES.keys())}")
63
+
64
+
65
+ def ensure_template_exists(template_name: str) -> None:
66
+ if template_name not in TEMPLATES:
67
+ print(f"Error: Template '{template_name}' not found.")
68
+ list_available_templates()
69
+ sys.exit(1)
70
+
71
+
72
+ def write_content_at(folder_path: Path, template_name: str) -> None:
73
+ file_name = f"{template_name.replace('_template', '')}.py"
74
+ file_path = folder_path / file_name
75
+
76
+ with open(file_path, "w") as file:
77
+ file.write(TEMPLATES[template_name])
78
+ print(f"Template {template_name} created at {file_path}")
79
+
80
+
81
+ def generate_folder_path(user_path: Path) -> Path:
82
+ project_root = Path(__file__).resolve().parents[1]
83
+ folder_path = project_root / user_path
84
+ folder_path.mkdir(parents=True, exist_ok=True)
85
+ print(f"Folder created at: {folder_path}")
86
+ return folder_path
87
+
88
+
89
+ if __name__ == "__main__":
90
+ main()
@@ -0,0 +1,39 @@
1
+ #!/bin/bash
2
+
3
+ function get_bounded_contexts_with_changes {
4
+ changed_files=$(git diff --name-only HEAD)
5
+ bounded_contexts=$(echo "$changed_files" | grep -E 'instant_python/contexts/([^/]*/)*(infra)' | sed -E 's|instant_python/contexts/([^/]*)/.*|\1|' | sort -u)
6
+ echo "$bounded_contexts"
7
+ }
8
+
9
+ function has_bounded_contexts {
10
+ local contexts="$1"
11
+
12
+ if [[ -z "$contexts" ]]; then
13
+ echo "No changes detected in infra folder of any bounded context."
14
+ return 1
15
+ fi
16
+
17
+ return 0
18
+ }
19
+
20
+ function run_tests {
21
+ local contexts="$1"
22
+
23
+ for context in $contexts; do
24
+ echo "Running integration tests for bounded context: $context"
25
+ infra_folders=$(find tests/contexts/"$context" -type d -name "infra")
26
+ {{ general.dependency_manager }} run pytest $infra_folders -ra
27
+ done
28
+ }
29
+
30
+ function main {
31
+ local bounded_contexts
32
+ bounded_contexts=$(get_bounded_contexts_with_changes)
33
+
34
+ if has_bounded_contexts "$bounded_contexts"; then
35
+ run_tests "$bounded_contexts"
36
+ fi
37
+ }
38
+
39
+ main
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+
4
+
5
+ def main() -> None:
6
+ print("Installing git hooks...")
7
+ subprocess.run(["git", "config", "core.hooksPath", "scripts/hooks"], check=True)
8
+ print("Git hooks installed.")
9
+
10
+
11
+ if __name__ == "__main__":
12
+ main()
@@ -0,0 +1,184 @@
1
+ {% set has_uv = general.dependency_manager == "uv" %}
2
+ {% set has_pdm = general.dependency_manager == "pdm" %}
3
+ {% set has_pre_commit_hooks = "precommit_hook" in template.built_in_features %}
4
+ {% set has_github_actions_or_makefile = ["github_actions", "makefile"] | is_in(template.built_in_features) %}
5
+ .DEFAULT_GOAL := help
6
+
7
+ .PHONY: help
8
+ help: ## Show this help.
9
+ @grep -E '^[a-zA-Z_-]+:.*?## ' $(firstword $(MAKEFILE_LIST)) | \
10
+ awk 'BEGIN {FS = ":.*## "}; {printf "%-30s %s\n", $$1, $$2}'
11
+
12
+ .PHONY: local-setup
13
+ local-setup: ## Setup git hooks and install dependencies.
14
+ @echo "⌛ Setting up the project...\n"
15
+ @make install
16
+ {% if has_pre_commit_hooks %}
17
+ @{{ general.dependency_manager }} run -m pre_commit install --hook-type pre-commit --hook-type commit-msg --hook-type pre-push
18
+ {% endif %}
19
+
20
+ .PHONY: install
21
+ install: ## Install dependencies.
22
+ @echo "⌛ Installing dependencies...\n"
23
+ {% if has_uv %}
24
+ @uv sync --all-groups
25
+ {% elif has_pdm %}
26
+ @pdm install
27
+ {% endif %}
28
+
29
+ .PHONY: update
30
+ update: ## Update dependencies.
31
+ @echo "⌛ Updating dependencies...\n"
32
+ {% if has_uv %}
33
+ @uv sync --upgrade
34
+ {% elif has_pdm %}
35
+ @pdm update
36
+ {% endif %}
37
+
38
+ .PHONY: add-dep
39
+ add-dep: ## Add a new dependency
40
+ @{{ general.dependency_manager }} add $(dep)
41
+
42
+ .PHONY: remove-dep
43
+ remove-dep: ## Remove a dependency
44
+ @{{ general.dependency_manager }} remove $(dep)
45
+
46
+ {% if dependencies | has_dependency("pytest") or has_github_actions_or_makefile %}
47
+ .PHONY: test
48
+ test: ## Run all test.
49
+ @echo "⌛ Running tests...\n"
50
+ @{{ general.dependency_manager }} run pytest test -ra
51
+
52
+ .PHONY: unit
53
+ unit: ## Run all unit test.
54
+ @echo "⌛ Running unit tests...\n"
55
+ @{{ general.dependency_manager }} run pytest -m "unit" -ra
56
+
57
+ .PHONY: integration
58
+ integration: ## Run all integration test.
59
+ @echo "⌛ Running integration tests...\n"
60
+ @{{ general.dependency_manager }} run pytest -m "integration" -ra
61
+
62
+ .PHONY: acceptance
63
+ acceptance: ## Run all acceptance test.
64
+ @echo "⌛ Running acceptance tests...\n"
65
+ @{{ general.dependency_manager }} run pytest -m "acceptance" -ra
66
+
67
+ .PHONY: coverage
68
+ coverage: ## Run all test with coverage.
69
+ @echo "⌛ Running tests with coverage...\n"
70
+ @{{ general.dependency_manager }} run coverage run --branch -m pytest test
71
+ @{{ general.dependency_manager }} run coverage html
72
+ @$(BROWSER) htmlcov/index.html
73
+ {% endif %}
74
+ {% if dependencies | has_dependency("pytest-watch") %}
75
+ .PHONY: watch
76
+ watch: ## Run all test with every change.
77
+ @echo "⌛ Running test in watch mode...\n"
78
+ @{{ general.dependency_manager }} run ptw --runner "pytest test -ra"
79
+ {% endif %}
80
+
81
+ .PHONY: check-typing
82
+ check-typing: ## Run mypy type checking.
83
+ @echo "⌛ Running type checking...\n"
84
+ {% if dependencies | has_dependency("mypy") or has_github_actions_or_makefile %}
85
+ @{{ general.dependency_manager }} run mypy
86
+ {% elif dependencies | has_dependency("ty") or has_github_actions_or_makefile %}
87
+ @{{ general.dependency_manager }} run ty
88
+ {% elif dependencies | has_dependency("pyright") or has_github_actions_or_makefile %}
89
+ @{{ general.dependency_manager }} run pyright
90
+ {% elif dependencies | has_dependency("pyrefly") or has_github_actions_or_makefile %}
91
+ @{{ general.dependency_manager }} run pyrefly
92
+ {% endif %}
93
+
94
+ {% if dependencies | has_dependency("ruff") or has_github_actions_or_makefile %}
95
+ .PHONY: check-lint
96
+ check-lint: ## Run ruff linting check.
97
+ @echo "⌛ Running linting check...\n"
98
+ {% if has_pdm %}
99
+ @pdm run ruff check src test
100
+ {% elif has_uv %}
101
+ @uvx ruff check src test
102
+ {% endif %}
103
+
104
+ .PHONY: lint
105
+ lint: ## Apply ruff linting fix.
106
+ @echo "\n⌛ Applying linting fixes...\n"
107
+ {% if has_pdm %}
108
+ @pdm run ruff check --fix src test
109
+ {% elif has_uv %}
110
+ @uvx ruff check --fix src test
111
+ {% endif %}
112
+
113
+ .PHONY: check-format
114
+ check-format: ## Run ruff format check.
115
+ @echo "⌛ Checking code formatting...\n"
116
+ {% if has_pdm %}
117
+ @pdm run ruff format --check src test
118
+ {% elif has_uv %}
119
+ @uvx ruff format --check src test
120
+ {% endif %}
121
+
122
+ .PHONY: format
123
+ format: ## Apply ruff format fix.
124
+ @echo "⌛ Formatting project code...\n"
125
+ {% if has_pdm %}
126
+ @pdm run ruff format src test
127
+ {% elif has_uv %}
128
+ @uvx ruff format src test
129
+ {% endif %}
130
+
131
+ .PHONY: autostyle
132
+ autostyle: ## Apply all code style fixes.
133
+ @echo "\n⌛ Applying all code style fixes...\n"
134
+ @make format
135
+ @make lint
136
+ @git add . && git commit -m "style: apply code style fixes"
137
+ {% endif %}
138
+ {% if has_pre_commit_hooks %}
139
+ .PHONY: secrets
140
+ secrets: # Check for secrets in the source code
141
+ @echo "⌛ Checking secrets...\n"
142
+ @{{ general.dependency_manager }} run -m pre_commit run gitleaks --all-files
143
+ {% endif %}
144
+
145
+ {% if "github_actions" in template.built_in_features %}
146
+ .PHONY: audit
147
+ audit: # It audits dependencies and source code
148
+ @echo "⌛ Checking for vulnerabilities in dependencies...\n"
149
+ @{{ general.dependency_manager }} run -m pip_audit --progress-spinner off
150
+ {% endif %}
151
+
152
+ .PHONY: clean
153
+ clean: # Clean up the project, removing the virtual environment and some files
154
+ @echo "\n⌛ Cleaning up the project...\n"
155
+
156
+ @{{ general.dependency_manager }} run -m pre_commit clean)
157
+ @{{ general.dependency_manager }} run -m pre_commit uninstall --hook-type pre-commit --hook-type commit-msg)
158
+ @rm --force --recursive .venv
159
+ @rm --force --recursive `find . -type f -name '*.py[co]'`
160
+ @rm --force --recursive `find . -name __pycache__`
161
+ @rm --force --recursive `find . -name .ruff_cache`
162
+ @rm --force --recursive `find . -name .mypy_cache`
163
+ @rm --force --recursive `find . -name .pytest_cache`
164
+ @rm --force --recursive .coverage
165
+ @rm --force --recursive .coverage.*
166
+ @rm --force --recursive coverage.xml
167
+ @rm --force --recursive htmlcov
168
+
169
+ .PHONY: show
170
+ show: ## Show installed dependencies.
171
+ {% if has_pdm %}
172
+ @pdm list
173
+ {% elif has_uv %}
174
+ @uv tree
175
+ {% endif %}
176
+
177
+ .PHONY: search
178
+ search: ## Show package details.
179
+ @read -p "Enter package name to search: " package;\
180
+ {% if has_pdm %}
181
+ @pdm show $$package
182
+ {% elif has_uv %}
183
+ @uv pip show $$package
184
+ {% endif %}
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+ import sys
4
+
5
+
6
+ def main() -> None:
7
+ try:
8
+ changed_files = _get_changed_files_between_last_two_heads()
9
+ changed_files = changed_files.stdout.splitlines()
10
+ files_to_search = ["Dockerfile", "pyproject.toml", "poetry.lock"]
11
+ if any(f in changed_files for f in files_to_search):
12
+ print(" * changes detected in tracked files")
13
+ print(" * running make build and make install")
14
+ subprocess.run(["make", "build"], check=True)
15
+ subprocess.run(["make", "install"], check=True)
16
+ except subprocess.CalledProcessError as e:
17
+ print(f"post-merge hook failed: {e}")
18
+ sys.exit(e.returncode)
19
+
20
+
21
+ def _get_changed_files_between_last_two_heads():
22
+ result = subprocess.run(
23
+ [
24
+ "git",
25
+ "diff-tree",
26
+ "-r",
27
+ "--name-only",
28
+ "--no-commit-id",
29
+ "HEAD@{1}",
30
+ "HEAD",
31
+ ],
32
+ capture_output=True,
33
+ text=True,
34
+ check=True,
35
+ )
36
+ return result
37
+
38
+
39
+ if __name__ == "__main__":
40
+ main()
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+ import sys
4
+
5
+
6
+ def main() -> None:
7
+ try:
8
+ subprocess.run(["make", "pre-commit"], check=True)
9
+ except subprocess.CalledProcessError as e:
10
+ print(f"pre-commit hook failed: {e}")
11
+ sys.exit(e.returncode)
12
+
13
+
14
+ if __name__ == "__main__":
15
+ main()
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ exec < /dev/tty
5
+
6
+ make pre-push
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+
4
+ {% if general.dependency_manager == "pdm" -%}
5
+ def main() -> None:
6
+ dependency = input("Dependency to remove: ")
7
+ is_dev = input(f"Is {dependency} a dev dependency? (y/n): ")
8
+ belongs_to_group = input(f"Does {dependency} belong to a group? (y/n): ")
9
+
10
+ dev_flag=""
11
+ group_flag=""
12
+ if is_dev.lower() == "y":
13
+ dev_flag = "-d"
14
+ if belongs_to_group.lower() == "y":
15
+ group_name = input("Group name: ")
16
+ group_flag = f"-G {group_name}"
17
+
18
+ cmd = f"pdm remove {dev_flag} {group_flag} {dependency}".strip()
19
+ subprocess.run(cmd, shell=True, check=True)
20
+
21
+ {%- elif general.dependency_manager == "uv" -%}
22
+ def main() -> None:
23
+ dependency = input("Dependency to remove: ")
24
+ is_dev = input(f"Is {dependency} a dev dependency? (y/n): ")
25
+ belongs_to_group = input(f"Does {dependency} belong to a group? (y/n): ")
26
+
27
+ flag = ""
28
+ if is_dev.lower() == "y":
29
+ flag = "--dev"
30
+ if belongs_to_group.lower() == "y":
31
+ group_name = input("Group name: ")
32
+ flag = f"--group {group_name}"
33
+
34
+ cmd = f"uv remove {flag} {dependency}".strip()
35
+ subprocess.run(cmd, shell=True, check=True)
36
+ {% endif %}
37
+
38
+
39
+ if __name__ == "__main__":
40
+ main()
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+
3
+ function get_bounded_contexts_with_changes {
4
+ changed_files=$(git diff --name-only HEAD)
5
+ bounded_contexts=$(echo "$changed_files" | grep -E 'instant_python/contexts/([^/]*/)*(application|domain)' | sed -E 's|instant_python/contexts/([^/]*)/.*|\1|' | sort -u)
6
+ echo "$bounded_contexts"
7
+ }
8
+
9
+ function has_bounded_contexts {
10
+ local contexts="$1"
11
+
12
+ if [[ -z "$contexts" ]]; then
13
+ echo "No changes detected in application or domain folders of any bounded context."
14
+ return 1
15
+ fi
16
+
17
+ return 0
18
+ }
19
+
20
+ function run_tests {
21
+ local contexts="$1"
22
+
23
+ for context in $contexts; do
24
+ echo "Running application and domain tests for: $context"
25
+ application_folders=$(find tests/contexts/"$context" -type d -name "application")
26
+ domain_folders=$(find tests/contexts/"$context" -type d -name "domain")
27
+ {{ general.dependency_manager }} run pytest -n auto $application_folders $domain_folders -ra
28
+ done
29
+ }
30
+
31
+ function main {
32
+ local bounded_contexts
33
+ bounded_contexts=$(get_bounded_contexts_with_changes)
34
+
35
+ if has_bounded_contexts "$bounded_contexts"; then
36
+ run_tests "$bounded_contexts"
37
+ fi
38
+ }
39
+
40
+ main
@@ -0,0 +1,3 @@
1
+ - name: application
2
+ type: directory
3
+ python: True
@@ -0,0 +1,8 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ {%- set delivery_features = [
3
+ {"feature": "fastapi_application", "template": "fastapi/fastapi_app.yml"}
4
+ ] %}
5
+ - name: delivery
6
+ type: directory
7
+ python: True
8
+ {{ macros.render_children_for(delivery_features, 2) }}
@@ -0,0 +1,10 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ {%- set domain_features = [
3
+ {"feature": "value_objects", "template": "errors.yml"},
4
+ {"feature": "event_bus", "template": "events/event_bus_domain.yml"},
5
+ {"feature": "fastapi_application", "template": "fastapi/fastapi_domain.yml"}
6
+ ] %}
7
+ - name: domain
8
+ type: directory
9
+ python: True
10
+ {{ macros.render_children_for(domain_features, 2) }}
@@ -0,0 +1,12 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ {%- set infra_features = [
3
+ {"feature": "event_bus", "template": "events/event_bus_infra.yml"},
4
+ {"feature": "logger", "template": "logger.yml"},
5
+ {"feature": "async_sqlalchemy", "template": "persistence/async_sqlalchemy.yml"},
6
+ {"feature": "async_alembic", "template": "persistence/alembic_migrator.yml"},
7
+ {"feature": "fastapi_application", "template": "fastapi/fastapi_infra.yml"}
8
+ ] %}
9
+ - name: infra
10
+ type: directory
11
+ python: True
12
+ {{ macros.render_children_for(infra_features, 2) }}
@@ -0,0 +1,3 @@
1
+ - name: application
2
+ type: directory
3
+ python: True
@@ -0,0 +1,3 @@
1
+ - name: delivery
2
+ type: directory
3
+ python: True
@@ -0,0 +1,3 @@
1
+ - name: domain
2
+ type: directory
3
+ python: True
@@ -0,0 +1,9 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ {%- set infra_features = [
3
+ {"feature": "event_bus", "template": "events/mock_event_bus.yml"},
4
+ {"feature": "async_sqlalchemy", "template": "persistence/async_engine_conftest.yml"},
5
+ ] %}
6
+ - name: infra
7
+ type: directory
8
+ python: True
9
+ {{ macros.render_children_for(infra_features, 2) }}
@@ -0,0 +1,38 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ {# === Core Project Structure === #}
3
+ {{ macros.include_block("clean_architecture/source.yml", 0) }}
4
+ {{ macros.include_block("clean_architecture/test.yml", 0) }}
5
+ {# === Base Configuration Files === #}
6
+ {{ macros.include_block("config_files/pyproject.yml", 0) }}
7
+ {{ macros.include_block("config_files/python_version.yml", 0) }}
8
+ {{ macros.include_block("documentation/license.yml", 0) }}
9
+ {# === CI/CD and Automation Features === #}
10
+ {% set ci_cd_features = [
11
+ {"feature": "github_actions", "template": "github/github_action.yml"},
12
+ {"feature": "github_actions", "template": "github/makefile.yml"},
13
+ {"feature": "github_issues_template", "template": "github/github_issues_template.yml"},
14
+ {"feature": "makefile", "template": "github/makefile.yml"},
15
+ {"feature": "precommit_hook", "template": "github/precommit_hook.yml"},
16
+ {"feature": "precommit_hook", "template": "github/makefile.yml"}
17
+ ] %}
18
+ {{ macros.render_features(ci_cd_features, 0) }}
19
+ {# === Git Features === #}
20
+ {% if git.initialize %}
21
+ {{ macros.include_block("config_files/gitignore.yml", 0) }}
22
+ {{ macros.include_block("documentation/readme.yml", 0) }}
23
+ {% endif %}
24
+ {# === Testing and Type Checking === #}
25
+ {% if dependencies | has_dependency("pytest") %}
26
+ {{ macros.include_block("config_files/pytest.yml", 0) }}
27
+ {% endif %}
28
+ {% if dependencies | has_dependency("mypy") %}
29
+ {{ macros.include_block("config_files/mypy.yml", 0) }}
30
+ {% endif %}
31
+ {# === Database Migration === #}
32
+ {{ macros.render_feature_if_enabled("async_alembic", "persistence/async_alembic.yml", 0) }}
33
+ {# === Documentation and Metadata === #}
34
+ {% set doc_features = [
35
+ {"feature": "citation_file", "template": "documentation/citation.yml"},
36
+ {"feature": "security_file", "template": "documentation/security.yml"}
37
+ ] %}
38
+ {{ macros.render_features(doc_features, 0) }}
@@ -0,0 +1,9 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ - name: {{ general.source_name }}
3
+ type: directory
4
+ python: True
5
+ children:
6
+ {{ macros.include_block("clean_architecture/layers/delivery.yml", 4) }}
7
+ {{ macros.include_block("clean_architecture/layers/domain.yml", 4) }}
8
+ {{ macros.include_block("clean_architecture/layers/application.yml", 4) }}
9
+ {{ macros.include_block("clean_architecture/layers/infra.yml", 4) }}
@@ -0,0 +1,9 @@
1
+ {% import "macros.j2" as macros with context %}
2
+ - name: test
3
+ type: directory
4
+ python: True
5
+ children:
6
+ {{ macros.include_block("clean_architecture/layers/test_delivery.yml", 4) }}
7
+ {{ macros.include_block("clean_architecture/layers/test_domain.yml", 4) }}
8
+ {{ macros.include_block("clean_architecture/layers/test_application.yml", 4) }}
9
+ {{ macros.include_block("clean_architecture/layers/test_infra.yml", 4) }}
@@ -0,0 +1,3 @@
1
+ - name: .gitignore
2
+ type: file
3
+ template: .gitignore
@@ -0,0 +1,4 @@
1
+ - name: mypy
2
+ type: file
3
+ extension: .ini
4
+ template: mypy.ini
@@ -0,0 +1,4 @@
1
+ - name: pyproject
2
+ type: file
3
+ extension: .toml
4
+ template: pyproject.toml
@@ -0,0 +1,4 @@
1
+ - name: pytest
2
+ type: file
3
+ extension: .ini
4
+ template: pytest.ini
@@ -0,0 +1,3 @@
1
+ - name: .python-version
2
+ type: file
3
+ template: .python-version
@@ -0,0 +1,4 @@
1
+ - name: CITATION
2
+ type: file
3
+ extension: .cff
4
+ template: CITATION.cff
@@ -0,0 +1,3 @@
1
+ - name: LICENSE
2
+ type: file
3
+ template: LICENSE
@@ -0,0 +1,4 @@
1
+ - name: README
2
+ type: file
3
+ extension: .md
4
+ template: README.md
@@ -0,0 +1,4 @@
1
+ - name: SECURITY
2
+ type: file
3
+ extension: .md
4
+ template: SECURITY.md