zrb 1.0.0a21__py3-none-any.whl → 1.0.0b1__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 (132) hide show
  1. zrb/__init__.py +2 -1
  2. zrb/builtin/llm/llm_chat.py +2 -2
  3. zrb/builtin/llm/tool/web.py +1 -1
  4. zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
  5. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +4 -1
  6. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +16 -1
  7. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +91 -9
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/{my_entity_usecase.py → my_entity_service.py} +7 -13
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service_factory.py +8 -0
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +37 -0
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +22 -0
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -0
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +1 -1
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +1 -2
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +3 -3
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +10 -10
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +4 -4
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +42 -5
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{base_usecase.py → base_service.py} +3 -3
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/view.py +37 -0
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +24 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +2 -2
  26. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +2 -2
  27. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +2 -2
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/{user_usecase.py → user_service.py} +7 -7
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +6 -0
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +42 -13
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +74 -0
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
  57. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
  58. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
  59. zrb/builtin/python.py +1 -1
  60. zrb/content_transformer/any_content_transformer.py +7 -0
  61. zrb/content_transformer/content_transformer.py +6 -0
  62. zrb/runner/cli.py +4 -6
  63. zrb/runner/web_app.py +28 -280
  64. zrb/runner/web_config/config.py +91 -0
  65. zrb/runner/web_config/config_factory.py +26 -0
  66. zrb/runner/web_route/docs_route.py +17 -0
  67. zrb/runner/web_route/error_page/serve_default_404.py +28 -0
  68. zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +2 -2
  69. zrb/runner/{web_controller → web_route}/error_page/view.html +5 -0
  70. zrb/runner/web_route/home_page/home_page_route.py +51 -0
  71. zrb/runner/web_route/login_api_route.py +31 -0
  72. zrb/runner/web_route/login_page/login_page_route.py +39 -0
  73. zrb/runner/web_route/logout_api_route.py +18 -0
  74. zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
  75. zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
  76. zrb/runner/web_route/node_page/node_page_route.py +50 -0
  77. zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +3 -3
  78. zrb/runner/web_route/refresh_token_api_route.py +38 -0
  79. zrb/runner/web_route/static/static_route.py +44 -0
  80. zrb/runner/web_route/task_input_api_route.py +47 -0
  81. zrb/runner/web_route/task_session_api_route.py +102 -0
  82. zrb/runner/web_schema/session.py +5 -0
  83. zrb/runner/web_schema/token.py +11 -0
  84. zrb/runner/web_schema/user.py +32 -0
  85. zrb/runner/web_util/cookie.py +29 -0
  86. zrb/runner/{web_util.py → web_util/html.py} +1 -23
  87. zrb/runner/web_util/token.py +68 -0
  88. zrb/runner/web_util/user.py +63 -0
  89. zrb/session/session.py +6 -4
  90. zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
  91. zrb/task/base_task.py +29 -4
  92. zrb/task/base_trigger.py +2 -0
  93. zrb/task/cmd_task.py +2 -0
  94. zrb/task/http_check.py +2 -0
  95. zrb/task/llm_task.py +2 -0
  96. zrb/task/make_task.py +2 -0
  97. zrb/task/rsync_task.py +2 -0
  98. zrb/task/scaffolder.py +8 -5
  99. zrb/task/scheduler.py +2 -0
  100. zrb/task/tcp_check.py +2 -0
  101. zrb/task_status/task_status.py +4 -3
  102. {zrb-1.0.0a21.dist-info → zrb-1.0.0b1.dist-info}/METADATA +1 -1
  103. {zrb-1.0.0a21.dist-info → zrb-1.0.0b1.dist-info}/RECORD +125 -81
  104. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
  105. zrb/runner/web_config.py +0 -274
  106. zrb/runner/web_controller/home_page/__init__.py +0 -0
  107. zrb/runner/web_controller/home_page/controller.py +0 -33
  108. zrb/runner/web_controller/login_page/controller.py +0 -25
  109. zrb/runner/web_controller/logout_page/controller.py +0 -26
  110. zrb/runner/web_controller/session_page/__init__.py +0 -0
  111. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
  112. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/{factory.py → my_entity_repository_factory.py} +0 -0
  113. /zrb/runner/{web_controller → web_route}/__init__.py +0 -0
  114. /zrb/runner/{web_controller/group_info_page → web_route/home_page}/__init__.py +0 -0
  115. /zrb/runner/{web_controller → web_route}/home_page/view.html +0 -0
  116. /zrb/runner/{web_controller → web_route}/login_page/view.html +0 -0
  117. /zrb/runner/{web_controller → web_route}/logout_page/view.html +0 -0
  118. /zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +0 -0
  119. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
  120. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +0 -0
  121. /zrb/runner/{refresh-token.template.js → web_route/static/refresh-token.template.js} +0 -0
  122. /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
  123. /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
  124. /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
  125. /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
  126. /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
  127. /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
  128. /zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +0 -0
  129. /zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +0 -0
  130. /zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +0 -0
  131. {zrb-1.0.0a21.dist-info → zrb-1.0.0b1.dist-info}/WHEEL +0 -0
  132. {zrb-1.0.0a21.dist-info → zrb-1.0.0b1.dist-info}/entry_points.txt +0 -0
zrb/__init__.py CHANGED
@@ -34,7 +34,8 @@ from zrb.input.password_input import PasswordInput
34
34
  from zrb.input.str_input import StrInput
35
35
  from zrb.input.text_input import TextInput
36
36
  from zrb.runner.cli import cli
37
- from zrb.runner.web_config import User, web_config
37
+ from zrb.runner.web_config.config_factory import web_config
38
+ from zrb.runner.web_schema.user import User
38
39
  from zrb.session.session import Session
39
40
  from zrb.task.any_task import AnyTask
40
41
  from zrb.task.base_task import BaseTask
@@ -1,6 +1,6 @@
1
1
  from zrb.builtin.group import llm_group
2
2
  from zrb.builtin.llm.tool.cli import run_shell_command
3
- from zrb.builtin.llm.tool.web import open_web_page, query_internet
3
+ from zrb.builtin.llm.tool.web import open_web_route, query_internet
4
4
  from zrb.config import (
5
5
  LLM_ALLOW_ACCESS_SHELL,
6
6
  LLM_ALLOW_ACCESS_WEB,
@@ -43,5 +43,5 @@ if LLM_ALLOW_ACCESS_SHELL:
43
43
  llm_chat.add_tool(run_shell_command)
44
44
 
45
45
  if LLM_ALLOW_ACCESS_WEB:
46
- llm_chat.add_tool(open_web_page)
46
+ llm_chat.add_tool(open_web_route)
47
47
  llm_chat.add_tool(query_internet)
@@ -2,7 +2,7 @@ import json
2
2
  from typing import Annotated
3
3
 
4
4
 
5
- def open_web_page(url: str) -> str:
5
+ def open_web_route(url: str) -> str:
6
6
  """Get content from a web page."""
7
7
  import requests
8
8
 
@@ -49,6 +49,7 @@ scaffold_fastapp = Scaffolder(
49
49
  transform_content=[
50
50
  # Common transformation (project_dir/app_dir/**/*)
51
51
  ContentTransformer(
52
+ name="transform-app-dir",
52
53
  match=is_in_project_app_dir,
53
54
  transform={
54
55
  "My App Name": "{ctx.input.app.title()}",
@@ -60,6 +61,7 @@ scaffold_fastapp = Scaffolder(
60
61
  ),
61
62
  # Register fastapp's tasks to project's zrb_init (project_dir/zrb_init.py)
62
63
  ContentTransformer(
64
+ name="trasnform-zrb-init",
63
65
  match=is_project_zrb_init_file,
64
66
  transform=update_project_zrb_init_file,
65
67
  ),
@@ -9,7 +9,10 @@ MICROSERVICES_ENV_VARS = {
9
9
  "MY_APP_NAME_MODE": "microservices",
10
10
  "MY_APP_NAME_AUTH_BASE_URL": "http://localhost:3002",
11
11
  }
12
- MONOLITH_ENV_VARS = {"MY_APP_NAME_MODE": "monolith"}
12
+ MONOLITH_ENV_VARS = {
13
+ "MY_APP_NAME_MODE": "monolith",
14
+ "MY_APP_NAME_MODULES": "",
15
+ }
13
16
 
14
17
  if platform.system() == "Windows":
15
18
  ACTIVATE_VENV_SCRIPT = "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser; . .venv\\Scripts\\Activate" # noqa
@@ -7,11 +7,13 @@ from my_app_name._zrb.entity.add_entity_util import (
7
7
  is_module_any_client_file,
8
8
  is_module_api_client_file,
9
9
  is_module_direct_client_file,
10
+ is_module_gateway_subroute_file,
10
11
  is_module_migration_metadata_file,
11
12
  is_module_route_file,
12
13
  update_any_client,
13
14
  update_api_client,
14
15
  update_direct_client,
16
+ update_gateway_subroute,
15
17
  update_migration_metadata,
16
18
  update_route,
17
19
  )
@@ -66,6 +68,7 @@ scaffold_my_app_name_entity = Scaffolder(
66
68
  transform_content=[
67
69
  # Schema tranformation (my_app_name/schema/snake_entity_name)
68
70
  ContentTransformer(
71
+ name="transform-schema-file",
69
72
  match=is_in_app_schema_dir,
70
73
  transform={
71
74
  "MyEntity": "{to_pascal_case(ctx.input.entity)}",
@@ -75,6 +78,7 @@ scaffold_my_app_name_entity = Scaffolder(
75
78
  # Common module's entity transformation
76
79
  # (my_app_name/module/snake_module_name/service/snake_entity_name)
77
80
  ContentTransformer(
81
+ name="transform-module-entity-dir",
78
82
  match=is_in_module_entity_dir,
79
83
  transform={
80
84
  "my_module": "{to_snake_case(ctx.input.module)}",
@@ -87,30 +91,41 @@ scaffold_my_app_name_entity = Scaffolder(
87
91
  # Add entity to migration metadata
88
92
  # (my_app_name/module/snake_module_name/migration_metadata.py)
89
93
  ContentTransformer(
94
+ name="transform-module-migration-metadata",
90
95
  match=is_module_migration_metadata_file,
91
96
  transform=update_migration_metadata,
92
97
  ),
93
98
  # Update API Client (my_app_name/module/snake_module_name/client/api_client.py)
94
99
  ContentTransformer(
100
+ name="transform-module-api-client",
95
101
  match=is_module_api_client_file,
96
102
  transform=update_api_client,
97
103
  ),
98
104
  # Update Direct Client (my_app_name/module/snake_module_name/client/direct_client.py)
99
105
  ContentTransformer(
106
+ name="transform-module-direct-client",
100
107
  match=is_module_direct_client_file,
101
108
  transform=update_direct_client,
102
109
  ),
103
110
  # Update Any Client (my_app_name/module/snake_module_name/client/any_client.py)
104
111
  ContentTransformer(
112
+ name="transform-module-any-client",
105
113
  match=is_module_any_client_file,
106
114
  transform=update_any_client,
107
115
  ),
108
116
  # Update module route (my_app_name/module/route.py)
109
117
  ContentTransformer(
118
+ name="transform-module-route",
110
119
  match=is_module_route_file,
111
120
  transform=update_route,
112
121
  ),
113
- # TODO: Register gateway route
122
+ # Update module gateway subroute
123
+ # (my_app_name/module/gateway/subroute/snake_module_name.py)
124
+ ContentTransformer(
125
+ name="transform-module-gateway-subroute",
126
+ match=is_module_gateway_subroute_file,
127
+ transform=update_gateway_subroute,
128
+ ),
114
129
  ],
115
130
  retries=0,
116
131
  upstream=validate_create_my_app_name_entity,
@@ -82,6 +82,17 @@ def is_module_direct_client_file(ctx: AnyContext, file_path: str) -> bool:
82
82
  return file_path == module_direct_client_file
83
83
 
84
84
 
85
+ def is_module_gateway_subroute_file(ctx: AnyContext, file_path: str) -> bool:
86
+ module_gateway_subroute_file = os.path.join(
87
+ APP_DIR,
88
+ "module",
89
+ "gateway",
90
+ "subroute",
91
+ f"{to_snake_case(ctx.input.module)}.py",
92
+ )
93
+ return file_path == module_gateway_subroute_file
94
+
95
+
85
96
  def update_migration_metadata(ctx: AnyContext, migration_metadata_file_path: str):
86
97
  app_name = os.path.basename(APP_DIR)
87
98
  existing_migration_metadata_code = read_file(migration_metadata_file_path)
@@ -148,7 +159,7 @@ def update_any_client(ctx: AnyContext, any_client_file_path: str):
148
159
  write_file(
149
160
  file_path=any_client_file_path,
150
161
  content=[
151
- f"from {app_name}.schema.{snake_entity_name}.{snake_entity_name} import (",
162
+ f"from {app_name}.schema.{snake_entity_name} import (",
152
163
  f" {pascal_entity_name}CreateWithAudit, {pascal_entity_name}Response, {pascal_entity_name}UpdateWithAudit", # noqa
153
164
  ")",
154
165
  new_code.strip(),
@@ -165,12 +176,14 @@ def update_api_client(ctx: AnyContext, api_client_file_path: str):
165
176
  write_file(
166
177
  file_path=api_client_file_path,
167
178
  content=[
168
- f"from {app_name}.module.{snake_module_name}.service.{snake_entity_name}.{snake_entity_name}_usecase import {snake_entity_name}_usecase", # noqa
179
+ f"from {app_name}.module.{snake_module_name}.service.{snake_entity_name}.{snake_entity_name}_service_factory import {snake_entity_name}_service", # noqa
169
180
  prepend_code_to_module(
170
181
  prepend_parent_class(
171
- existing_api_client_code, "APIClient", "user_api_client"
182
+ original_code=existing_api_client_code,
183
+ class_name="APIClient",
184
+ parent_class_name=f"{snake_entity_name}_api_client",
172
185
  ),
173
- f"user_api_client = user_usecase.as_api_client(base_url=APP_{upper_snake_module_name}_BASE_URL)", # noqa
186
+ f"{snake_entity_name}_api_client = {snake_entity_name}_service.as_api_client(base_url=APP_{upper_snake_module_name}_BASE_URL)", # noqa
174
187
  ),
175
188
  ],
176
189
  )
@@ -184,12 +197,14 @@ def update_direct_client(ctx: AnyContext, direct_client_file_path: str):
184
197
  write_file(
185
198
  file_path=direct_client_file_path,
186
199
  content=[
187
- f"from {app_name}.module.{snake_module_name}.service.{snake_entity_name}.{snake_entity_name}_usecase import {snake_entity_name}_usecase", # noqa
200
+ f"from {app_name}.module.{snake_module_name}.service.{snake_entity_name}.{snake_entity_name}_service_factory import {snake_entity_name}_service", # noqa
188
201
  prepend_code_to_module(
189
202
  prepend_parent_class(
190
- existing_direct_client_code, "DirectClient", "user_direct_client"
203
+ original_code=existing_direct_client_code,
204
+ class_name="DirectClient",
205
+ parent_class_name=f"{snake_entity_name}_direct_client",
191
206
  ),
192
- "user_direct_client = user_usecase.as_direct_client()",
207
+ f"{snake_entity_name}_direct_client = {snake_entity_name}_service.as_direct_client()", # noqa
193
208
  ).strip(),
194
209
  ],
195
210
  )
@@ -203,11 +218,78 @@ def update_route(ctx: AnyContext, route_file_path: str):
203
218
  write_file(
204
219
  file_path=route_file_path,
205
220
  content=[
206
- f"from {app_name}.module.{module_name}.service.{entity_name}.{entity_name}_usecase import {entity_name}_usecase", # noqa
221
+ f"from {app_name}.module.{module_name}.service.{entity_name}.{entity_name}_service_factory import {entity_name}_service", # noqa
207
222
  append_code_to_function(
208
223
  existing_route_code,
209
224
  "serve_route",
210
- f"{entity_name}_usecase.serve_route(app)",
225
+ f"{entity_name}_service.serve_route(app)",
211
226
  ),
212
227
  ],
213
228
  )
229
+
230
+
231
+ def update_gateway_subroute(ctx: AnyContext, module_gateway_subroute_path: str):
232
+ snake_module_name = to_snake_case(ctx.input.module)
233
+ snake_entity_name = to_snake_case(ctx.input.entity)
234
+ snake_plural_entity_name = to_snake_case(ctx.input.plural)
235
+ pascal_entity_name = to_pascal_case(ctx.input.entity)
236
+ existing_gateway_subroute_code = read_file(module_gateway_subroute_path)
237
+ write_file(
238
+ file_path=module_gateway_subroute_path,
239
+ content=[
240
+ _get_import_client_for_gateway_subroute_code(
241
+ existing_gateway_subroute_code, module_name=ctx.input.module
242
+ ),
243
+ _get_import_schema_for_gateway_subroute_code(
244
+ existing_gateway_subroute_code, entity_name=ctx.input.entity
245
+ ),
246
+ append_code_to_function(
247
+ original_code=existing_gateway_subroute_code,
248
+ function_name=f"serve_{snake_module_name}_route",
249
+ new_code=read_file(
250
+ file_path=os.path.join(
251
+ os.path.dirname(__file__), "template", "gateway_subroute.py"
252
+ ),
253
+ replace_map={
254
+ "my_module": snake_module_name,
255
+ "my_entity": snake_entity_name,
256
+ "my_entities": snake_plural_entity_name,
257
+ "MyEntity": pascal_entity_name,
258
+ },
259
+ ),
260
+ ),
261
+ ],
262
+ )
263
+
264
+
265
+ def _get_import_client_for_gateway_subroute_code(
266
+ existing_code: str, module_name: str
267
+ ) -> str | None:
268
+ snake_module_name = to_snake_case(module_name)
269
+ client_import_path = f"my_app_name.module.{snake_module_name}.client.factory"
270
+ new_code = f"from {client_import_path} import client as {snake_module_name}_client"
271
+ if new_code in existing_code:
272
+ return None
273
+ return new_code
274
+
275
+
276
+ def _get_import_schema_for_gateway_subroute_code(
277
+ existing_code: str, entity_name: str
278
+ ) -> str | None:
279
+ snake_entity_name = to_snake_case(entity_name)
280
+ pascal_entity_name = to_pascal_case(entity_name)
281
+ schema_import_path = f"my_app_name.schema.{snake_entity_name}"
282
+ new_code = "\n".join(
283
+ [
284
+ f"from {schema_import_path} import (",
285
+ f" {pascal_entity_name}Create,",
286
+ f" {pascal_entity_name}CreateWithAudit,",
287
+ f" {pascal_entity_name}Response,",
288
+ f" {pascal_entity_name}Update,",
289
+ f" {pascal_entity_name}UpdateWithAudit,",
290
+ ")",
291
+ ]
292
+ )
293
+ if new_code in existing_code:
294
+ return None
295
+ return new_code
@@ -1,7 +1,4 @@
1
- from my_app_name.common.base_usecase import BaseUsecase
2
- from my_app_name.module.my_module.service.my_entity.repository.factory import (
3
- my_entity_repository,
4
- )
1
+ from my_app_name.common.base_service import BaseService
5
2
  from my_app_name.module.my_module.service.my_entity.repository.my_entity_repository import (
6
3
  MyEntityRepository,
7
4
  )
@@ -12,12 +9,12 @@ from my_app_name.schema.my_entity import (
12
9
  )
13
10
 
14
11
 
15
- class MyEntityUsecase(BaseUsecase):
12
+ class MyEntityService(BaseService):
16
13
  def __init__(self, my_entity_repository: MyEntityRepository):
17
14
  super().__init__()
18
15
  self.my_entity_repository = my_entity_repository
19
16
 
20
- @BaseUsecase.route(
17
+ @BaseService.route(
21
18
  "/api/v1/my-entities/{my_entity_id}",
22
19
  methods=["get"],
23
20
  response_model=MyEntityResponse,
@@ -25,13 +22,13 @@ class MyEntityUsecase(BaseUsecase):
25
22
  async def get_my_entity_by_id(self, my_entity_id: str) -> MyEntityResponse:
26
23
  return await self.my_entity_repository.get_by_id(my_entity_id)
27
24
 
28
- @BaseUsecase.route(
25
+ @BaseService.route(
29
26
  "/api/v1/my-entities", methods=["get"], response_model=list[MyEntityResponse]
30
27
  )
31
28
  async def get_all_my_entities(self) -> list[MyEntityResponse]:
32
29
  return await self.my_entity_repository.get_all()
33
30
 
34
- @BaseUsecase.route(
31
+ @BaseService.route(
35
32
  "/api/v1/my-entities",
36
33
  methods=["post"],
37
34
  response_model=MyEntityResponse | list[MyEntityResponse],
@@ -43,7 +40,7 @@ class MyEntityUsecase(BaseUsecase):
43
40
  return await self.my_entity_repository.create(data)
44
41
  return await self.my_entity_repository.create_bulk(data)
45
42
 
46
- @BaseUsecase.route(
43
+ @BaseService.route(
47
44
  "/api/v1/my-entities/{my_entity_id}",
48
45
  methods=["put"],
49
46
  response_model=MyEntityResponse,
@@ -53,13 +50,10 @@ class MyEntityUsecase(BaseUsecase):
53
50
  ) -> MyEntityResponse:
54
51
  return await self.my_entity_repository.update(my_entity_id, data)
55
52
 
56
- @BaseUsecase.route(
53
+ @BaseService.route(
57
54
  "/api/v1/my-entities/{my_entity_id}",
58
55
  methods=["delete"],
59
56
  response_model=MyEntityResponse,
60
57
  )
61
58
  async def delete_my_entity(self, my_entity_id: str) -> MyEntityResponse:
62
59
  return await self.my_entity_repository.delete(my_entity_id)
63
-
64
-
65
- my_entity_usecase = MyEntityUsecase(my_entity_repository=my_entity_repository)
@@ -0,0 +1,8 @@
1
+ from my_app_name.module.my_module.service.my_entity.my_entity_service import (
2
+ MyEntityService,
3
+ )
4
+ from my_app_name.module.my_module.service.my_entity.repository.my_entity_repository_factory import (
5
+ my_entity_repository,
6
+ )
7
+
8
+ my_entity_service = MyEntityService(my_entity_repository=my_entity_repository)
@@ -0,0 +1,37 @@
1
+ @app.get("/api/v1/my_entities", response_model=list[MyEntityResponse])
2
+ async def get_all_my_entities() -> MyEntityResponse:
3
+ return await my_module_client.get_all_my_entities()
4
+
5
+
6
+ @app.get("/api/v1/my_entities/{my_entity_id}", response_model=MyEntityResponse)
7
+ async def get_my_entity_by_id(my_entity_id: str) -> MyEntityResponse:
8
+ return await my_module_client.get_my_entity_by_id(my_entity_id)
9
+
10
+
11
+ @app.post(
12
+ "/api/v1/my_entities", response_model=MyEntityResponse | list[MyEntityResponse]
13
+ )
14
+ async def create_my_entity(data: MyEntityCreate | list[MyEntityCreate]):
15
+ if isinstance(data, MyEntityCreate):
16
+ data_dict = data.model_dump(exclude_unset=True)
17
+ audited_data = MyEntityCreateWithAudit(**data_dict, created_by="system")
18
+ return await my_module_client.create_my_entity(audited_data)
19
+ audited_data = [
20
+ MyEntityCreateWithAudit(
21
+ **row.model_dump(exclude_unset=True), created_by="system"
22
+ )
23
+ for row in data
24
+ ]
25
+ return await my_module_client.create_my_entity(audited_data)
26
+
27
+
28
+ @app.put("/api/v1/my_entities/{my_entity_id}", response_model=MyEntityResponse)
29
+ async def update_my_entity(my_entity_id: str, data: MyEntityUpdate) -> MyEntityResponse:
30
+ data_dict = data.model_dump(exclude_unset=True)
31
+ audited_data = MyEntityUpdateWithAudit(**data_dict, updated_by="system")
32
+ return await my_module_client.update_my_entity(my_entity_id, audited_data)
33
+
34
+
35
+ @app.delete("/api/v1/my_entities/{my_entity_id}", response_model=MyEntityResponse)
36
+ async def delete_my_entity(my_entity_id: str) -> MyEntityResponse:
37
+ return await my_module_client.delete_my_entity(my_entity_id, deleted_by="system")
@@ -6,7 +6,7 @@ from zrb.task.cmd_task import CmdTask
6
6
  format_my_app_name_code = app_group.add_task(
7
7
  CmdTask(
8
8
  name="format-my-app-name-code",
9
- description="✏️ Format Python code",
9
+ description=" Format Python code",
10
10
  cmd=[
11
11
  "isort . --profile black --force-grid-wrap 0",
12
12
  "black .",
@@ -38,3 +38,16 @@ new_entity_column_input = StrInput(
38
38
  prompt="New entity's column name",
39
39
  default_str="name",
40
40
  )
41
+
42
+ new_column_input = StrInput(
43
+ name="column",
44
+ description="Column name",
45
+ prompt="New column name",
46
+ )
47
+
48
+ new_column_type_input = OptionInput(
49
+ name="type",
50
+ description="Column type",
51
+ prompt="Column type",
52
+ options=["str", "int", "float", "bool", "datetime", "date"],
53
+ )
@@ -9,11 +9,14 @@ from my_app_name._zrb.module.add_module_util import (
9
9
  is_app_main_file,
10
10
  is_app_zrb_config_file,
11
11
  is_app_zrb_task_file,
12
+ is_gateway_module_subroute_file,
13
+ is_gateway_route_file,
12
14
  is_in_module_dir,
13
15
  update_app_config_file,
14
16
  update_app_main_file,
15
17
  update_app_zrb_config_file,
16
18
  update_app_zrb_task_file,
19
+ update_gateway_route_file,
17
20
  )
18
21
  from my_app_name._zrb.util import get_existing_module_names
19
22
 
@@ -42,32 +45,51 @@ scaffold_my_app_name_module = Scaffolder(
42
45
  transform_content=[
43
46
  # Common transformation (my_app_name/module/snake_module_name)
44
47
  ContentTransformer(
48
+ name="transform-module-dir",
45
49
  match=is_in_module_dir,
46
50
  transform={
47
51
  "MY_MODULE": "{to_snake_case(ctx.input.module).upper()}",
48
52
  "my_module": "{to_snake_case(ctx.input.module)}",
49
53
  },
50
54
  ),
55
+ # Gateway's module subroute (my_app_name/module/gateway/subroute/snake_module_name.py)
56
+ ContentTransformer(
57
+ name="transform-gateway-subroute",
58
+ match=is_gateway_module_subroute_file,
59
+ transform={
60
+ "my_module": "{to_snake_case(ctx.input.module)}",
61
+ },
62
+ ),
51
63
  # Register module config to my_app_name/config.py
52
64
  ContentTransformer(
65
+ name="transform-app-config",
53
66
  match=is_app_config_file,
54
67
  transform=update_app_config_file,
55
68
  ),
56
69
  # Register module route to my_app_name/main.py
57
70
  ContentTransformer(
71
+ name="transform-app-main",
58
72
  match=is_app_main_file,
59
73
  transform=update_app_main_file,
60
74
  ),
61
75
  # Register module's tasks to my_app_name/_zrb/task.py
62
76
  ContentTransformer(
77
+ name="transform-zrb-task",
63
78
  match=is_app_zrb_task_file,
64
79
  transform=update_app_zrb_task_file,
65
80
  ),
66
81
  # Register module's base url to my_app_name/_zrb/config.py
67
82
  ContentTransformer(
83
+ name="transform-zrb-config",
68
84
  match=is_app_zrb_config_file,
69
85
  transform=update_app_zrb_config_file,
70
86
  ),
87
+ # Register module's subroute to my_app_name/gateway/route.py
88
+ ContentTransformer(
89
+ name="transform-gateway-route",
90
+ match=is_gateway_route_file,
91
+ transform=update_gateway_route_file,
92
+ ),
71
93
  ],
72
94
  retries=0,
73
95
  upstream=validate_create_my_app_name_module,
@@ -4,6 +4,7 @@ from my_app_name._zrb.config import APP_DIR
4
4
  from my_app_name._zrb.util import get_existing_module_names
5
5
 
6
6
  from zrb.context.any_context import AnyContext
7
+ from zrb.util.codemod.append_code_to_function import append_code_to_function
7
8
  from zrb.util.codemod.append_key_to_dict import append_key_to_dict
8
9
  from zrb.util.file import read_file, write_file
9
10
  from zrb.util.string.conversion import to_kebab_case, to_pascal_case, to_snake_case
@@ -17,6 +18,10 @@ def is_app_main_file(ctx: AnyContext, file_path: str) -> bool:
17
18
  return file_path == os.path.join(APP_DIR, "main.py")
18
19
 
19
20
 
21
+ def is_gateway_route_file(ctx: AnyContext, file_path: str) -> bool:
22
+ return file_path == os.path.join(APP_DIR, "module", "gateway", "route.py")
23
+
24
+
20
25
  def is_app_zrb_task_file(ctx: AnyContext, file_path: str) -> bool:
21
26
  return file_path == os.path.join(APP_DIR, "_zrb", "task.py")
22
27
 
@@ -31,6 +36,13 @@ def is_in_module_dir(ctx: AnyContext, file_path: str) -> bool:
31
36
  )
32
37
 
33
38
 
39
+ def is_gateway_module_subroute_file(ctx: AnyContext, file_path: str) -> bool:
40
+ module_subroute_file_name = f"{to_snake_case(ctx.input.module)}.py"
41
+ return file_path == os.path.join(
42
+ APP_DIR, "module", "gateway", "subroute", module_subroute_file_name
43
+ )
44
+
45
+
34
46
  def update_app_zrb_config_file(ctx: AnyContext, zrb_config_file_path: str):
35
47
  existing_zrb_config_code = read_file(zrb_config_file_path)
36
48
  module_name = ctx.input.module
@@ -152,3 +164,33 @@ def _get_new_module_config_code(existing_code: str, module_name: str) -> str | N
152
164
  if config_code in existing_code:
153
165
  return None
154
166
  return config_code
167
+
168
+
169
+ def update_gateway_route_file(ctx: AnyContext, gateway_route_file_path: str):
170
+ existing_gateway_route_code = read_file(gateway_route_file_path)
171
+ snake_module_name = to_snake_case(ctx.input.module)
172
+ write_file(
173
+ file_path=gateway_route_file_path,
174
+ content=[
175
+ _get_module_subroute_import(existing_gateway_route_code, ctx.input.module),
176
+ append_code_to_function(
177
+ original_code=existing_gateway_route_code,
178
+ function_name="serve_route",
179
+ new_code="\n".join(
180
+ [
181
+ f"# Serve {snake_module_name} route",
182
+ f"serve_{snake_module_name}_route(app)",
183
+ ]
184
+ ),
185
+ ),
186
+ ],
187
+ )
188
+
189
+
190
+ def _get_module_subroute_import(existing_code: str, module_name: str) -> str | None:
191
+ snake_module_name = to_snake_case(module_name)
192
+ import_module_path = f"my_app_name.module.gateway.subroute.{snake_module_name}"
193
+ import_code = f"from {import_module_path} import serve_{snake_module_name}_route"
194
+ if import_code in existing_code:
195
+ return None
196
+ return import_code
@@ -0,0 +1,7 @@
1
+ from fastapi import FastAPI
2
+
3
+
4
+ def serve_my_module_route(app: FastAPI):
5
+ """
6
+ Serving routes for my_module
7
+ """
@@ -1,5 +1,5 @@
1
1
  from my_app_name.config import APP_MY_MODULE_BASE_URL
2
- from my_app_name.module.module_template.client.any_client import AnyClient
2
+ from my_app_name.module.my_module.client.any_client import AnyClient
3
3
 
4
4
 
5
5
  class APIClient(AnyClient):
@@ -1,5 +1,4 @@
1
- from my_app_name.module.module_template.client.any_client import AnyClient
2
- from my_app_name.module.module_template.service.user.usecase import user_usecase
1
+ from my_app_name.module.my_module.client.any_client import AnyClient
3
2
 
4
3
 
5
4
  class DirectClient(AnyClient):
@@ -1,7 +1,7 @@
1
1
  from my_app_name.config import APP_COMMUNICATION
2
- from my_app_name.module.module_template.client.any_client import AnyClient
3
- from my_app_name.module.module_template.client.api_client import APIClient
4
- from my_app_name.module.module_template.client.direct_client import DirectClient
2
+ from my_app_name.module.my_module.client.any_client import AnyClient
3
+ from my_app_name.module.my_module.client.api_client import APIClient
4
+ from my_app_name.module.my_module.client.direct_client import DirectClient
5
5
 
6
6
  if APP_COMMUNICATION == "direct":
7
7
  client: AnyClient = DirectClient()
@@ -4,7 +4,15 @@ from my_app_name.common.schema import BasicResponse
4
4
  from my_app_name.config import APP_MAIN_MODULE, APP_MODE, APP_MODULES
5
5
 
6
6
 
7
- def serve_health_check(app: FastAPI):
7
+ def serve_route(app: FastAPI):
8
+ if APP_MODE != "microservices" or "my_module" not in APP_MODULES:
9
+ return
10
+ if APP_MAIN_MODULE == "my_module":
11
+ _serve_health_check(app)
12
+ _serve_readiness_check(app)
13
+
14
+
15
+ def _serve_health_check(app: FastAPI):
8
16
  @app.api_route("/health", methods=["GET", "HEAD"], response_model=BasicResponse)
9
17
  async def health():
10
18
  """
@@ -13,7 +21,7 @@ def serve_health_check(app: FastAPI):
13
21
  return BasicResponse(message="ok")
14
22
 
15
23
 
16
- def serve_readiness_check(app: FastAPI):
24
+ def _serve_readiness_check(app: FastAPI):
17
25
  @app.api_route("/readiness", methods=["GET", "HEAD"], response_model=BasicResponse)
18
26
  async def readiness():
19
27
  """
@@ -22,12 +30,4 @@ def serve_readiness_check(app: FastAPI):
22
30
  return BasicResponse(message="ok")
23
31
 
24
32
 
25
- def serve_route(app: FastAPI):
26
- if APP_MODE != "microservices" or "my_module" not in APP_MODULES:
27
- return
28
- if APP_MAIN_MODULE == "my_module":
29
- serve_health_check(app)
30
- serve_readiness_check(app)
31
-
32
-
33
33
  serve_route(app)
@@ -1,7 +1,7 @@
1
1
  import os
2
2
 
3
- from my_app_name._zrb.column.create_column_task import add_my_app_name_column
4
- from my_app_name._zrb.config import ACTIVATE_VENV_SCRIPT, APP_DIR
3
+ from my_app_name._zrb.column.add_column_task import add_my_app_name_column
4
+ from my_app_name._zrb.config import ACTIVATE_VENV_SCRIPT, APP_DIR, MONOLITH_ENV_VARS
5
5
  from my_app_name._zrb.entity.add_entity_task import add_my_app_name_entity
6
6
  from my_app_name._zrb.format_task import format_my_app_name_code
7
7
  from my_app_name._zrb.group import (
@@ -13,7 +13,7 @@ from my_app_name._zrb.module.add_module_task import add_my_app_name_module
13
13
  from my_app_name._zrb.util import create_migration, migrate_module, run_microservice
14
14
  from my_app_name._zrb.venv_task import prepare_venv
15
15
 
16
- from zrb import CmdTask, Env, EnvFile, Task
16
+ from zrb import CmdTask, EnvFile, EnvMap, Task
17
17
 
18
18
  assert add_my_app_name_entity
19
19
  assert add_my_app_name_module
@@ -54,7 +54,7 @@ run_monolith = app_run_group.add_task(
54
54
  description="🗿 Run My App Name as a monolith",
55
55
  env=[
56
56
  EnvFile(path=os.path.join(APP_DIR, "template.env")),
57
- Env(name="MY_APP_NAME_MODE", default="monolith"),
57
+ EnvMap(vars=MONOLITH_ENV_VARS),
58
58
  ],
59
59
  cwd=APP_DIR,
60
60
  cmd=[