zrb 1.2.2__py3-none-any.whl → 1.3.1__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 (34) hide show
  1. zrb/builtin/llm/llm_chat.py +42 -6
  2. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_task.py +39 -3
  3. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_util.py +28 -6
  4. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/gateway/view/content/my-module/my-entity.html +206 -178
  5. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +3 -1
  6. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +18 -1
  7. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +4 -0
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +20 -11
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +17 -2
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +4 -0
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +19 -11
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/auth/permission.html +209 -180
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/auth/role.html +362 -0
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/auth/user.html +377 -0
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/common/util.js +76 -13
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/crud/util.js +50 -29
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +3 -1
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +6 -5
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +9 -3
  20. zrb/input/any_input.py +5 -0
  21. zrb/input/base_input.py +6 -0
  22. zrb/input/bool_input.py +2 -0
  23. zrb/input/float_input.py +2 -0
  24. zrb/input/int_input.py +2 -0
  25. zrb/input/option_input.py +2 -0
  26. zrb/input/password_input.py +2 -0
  27. zrb/input/text_input.py +2 -0
  28. zrb/runner/cli.py +1 -1
  29. zrb/runner/common_util.py +3 -3
  30. zrb/runner/web_route/task_input_api_route.py +1 -1
  31. {zrb-1.2.2.dist-info → zrb-1.3.1.dist-info}/METADATA +84 -17
  32. {zrb-1.2.2.dist-info → zrb-1.3.1.dist-info}/RECORD +34 -34
  33. {zrb-1.2.2.dist-info → zrb-1.3.1.dist-info}/WHEEL +0 -0
  34. {zrb-1.2.2.dist-info → zrb-1.3.1.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,8 @@ import json
2
2
  import os
3
3
  from typing import Any
4
4
 
5
+ from pydantic_ai.models import Model
6
+
5
7
  from zrb.builtin.group import llm_group
6
8
  from zrb.builtin.llm.tool.api import get_current_location, get_current_weather
7
9
  from zrb.builtin.llm.tool.cli import run_shell_command
@@ -26,11 +28,14 @@ from zrb.config import (
26
28
  LLM_SYSTEM_PROMPT,
27
29
  SERP_API_KEY,
28
30
  )
31
+ from zrb.context.any_context import AnyContext
29
32
  from zrb.context.any_shared_context import AnySharedContext
33
+ from zrb.input.any_input import AnyInput
30
34
  from zrb.input.bool_input import BoolInput
31
35
  from zrb.input.str_input import StrInput
32
36
  from zrb.input.text_input import TextInput
33
37
  from zrb.task.llm_task import LLMTask
38
+ from zrb.util.attr import get_attr
34
39
  from zrb.util.file import read_file, write_file
35
40
  from zrb.util.string.conversion import to_pascal_case
36
41
 
@@ -85,23 +90,53 @@ def _write_chat_conversation(
85
90
  write_file(last_session_file_path, current_session_name)
86
91
 
87
92
 
88
- llm_chat: LLMTask = llm_group.add_task(
89
- LLMTask(
90
- name="llm-chat",
91
- input=[
93
+ class _LLMChat(LLMTask):
94
+
95
+ _default_model: Model | str | None = None
96
+
97
+ def set_default_model(self, model: Model | str):
98
+ self._default_model = model
99
+
100
+ @property
101
+ def inputs(self) -> list[AnyInput]:
102
+ task_inputs = super().inputs
103
+ model_input_default = LLM_MODEL if self._default_model is None else "default"
104
+ return [
92
105
  StrInput(
93
106
  "model",
94
107
  description="LLM Model",
95
108
  prompt="LLM Model",
96
- default=LLM_MODEL,
109
+ default=model_input_default,
97
110
  allow_positional_parsing=False,
111
+ always_prompt=False,
98
112
  ),
113
+ *task_inputs,
114
+ ]
115
+
116
+ def _get_model(self, ctx: AnyContext) -> str | Model | None:
117
+ if ctx.input.model == "default":
118
+ if self._default_model is not None:
119
+ return self._default_model
120
+ return super()._get_model(ctx)
121
+ model = get_attr(
122
+ ctx, ctx.input.model, "ollama_chat/llama3.1", auto_render=self._render_model
123
+ )
124
+ if isinstance(model, (Model, str)) or model is None:
125
+ return model
126
+ raise ValueError("Invalid model")
127
+
128
+
129
+ llm_chat: LLMTask = llm_group.add_task(
130
+ _LLMChat(
131
+ name="llm-chat",
132
+ input=[
99
133
  TextInput(
100
134
  "system-prompt",
101
135
  description="System prompt",
102
136
  prompt="System prompt",
103
137
  default=LLM_SYSTEM_PROMPT,
104
138
  allow_positional_parsing=False,
139
+ always_prompt=False,
105
140
  ),
106
141
  BoolInput(
107
142
  "start-new",
@@ -109,6 +144,7 @@ llm_chat: LLMTask = llm_group.add_task(
109
144
  prompt="Start new conversation (LLM will forget everything)",
110
145
  default=False,
111
146
  allow_positional_parsing=False,
147
+ always_prompt=False,
112
148
  ),
113
149
  TextInput("message", description="User message", prompt="Your message"),
114
150
  PreviousSessionInput(
@@ -117,12 +153,12 @@ llm_chat: LLMTask = llm_group.add_task(
117
153
  prompt="Previous conversation session (can be empty)",
118
154
  allow_positional_parsing=False,
119
155
  allow_empty=True,
156
+ always_prompt=False,
120
157
  ),
121
158
  ],
122
159
  conversation_history_reader=_read_chat_conversation,
123
160
  conversation_history_writer=_write_chat_conversation,
124
161
  description="Chat with LLM",
125
- model="{ctx.input.model}",
126
162
  system_prompt="{ctx.input['system-prompt']}",
127
163
  message="{ctx.input.message}",
128
164
  retries=0,
@@ -8,7 +8,7 @@ from my_app_name._zrb.column.add_column_util import (
8
8
  update_my_app_name_test_update,
9
9
  update_my_app_name_ui,
10
10
  )
11
- from my_app_name._zrb.config import APP_DIR
11
+ from my_app_name._zrb.config import ACTIVATE_VENV_SCRIPT, APP_DIR
12
12
  from my_app_name._zrb.format_task import format_my_app_name_code
13
13
  from my_app_name._zrb.group import app_create_group
14
14
  from my_app_name._zrb.input import (
@@ -17,9 +17,16 @@ from my_app_name._zrb.input import (
17
17
  new_column_input,
18
18
  new_column_type_input,
19
19
  )
20
- from my_app_name._zrb.util import get_existing_module_names, get_existing_schema_names
20
+ from my_app_name._zrb.util import (
21
+ cd_module_script,
22
+ get_existing_module_names,
23
+ get_existing_schema_names,
24
+ set_create_migration_db_url_env,
25
+ set_env,
26
+ )
27
+ from my_app_name._zrb.venv_task import prepare_venv
21
28
 
22
- from zrb import AnyContext, Task, make_task
29
+ from zrb import AnyContext, Cmd, CmdTask, EnvFile, Task, make_task
23
30
 
24
31
 
25
32
  @make_task(
@@ -118,6 +125,34 @@ update_my_app_name_test_delete_task = Task(
118
125
  )
119
126
 
120
127
 
128
+ create_my_app_name_entity_migration = CmdTask(
129
+ name="create-my-app-name-entity-migration",
130
+ input=[
131
+ existing_module_input,
132
+ existing_entity_input,
133
+ new_column_input,
134
+ ],
135
+ env=EnvFile(path=os.path.join(APP_DIR, "template.env")),
136
+ cwd=APP_DIR,
137
+ cmd=[
138
+ ACTIVATE_VENV_SCRIPT,
139
+ Cmd(lambda ctx: set_create_migration_db_url_env(ctx.input.module)),
140
+ Cmd(lambda ctx: set_env("MY_APP_NAME_MODULES", ctx.input.module)),
141
+ Cmd(lambda ctx: cd_module_script(ctx.input.module)),
142
+ "alembic upgrade head",
143
+ Cmd(
144
+ 'alembic revision --autogenerate -m "create_{to_snake_case(ctx.input.entity)}_{to_snake_case(ctx.input.column)}_column"', # noqa
145
+ ),
146
+ ],
147
+ render_cmd=False,
148
+ retries=0,
149
+ upstream=[
150
+ prepare_venv,
151
+ update_my_app_name_schema_task,
152
+ ],
153
+ )
154
+
155
+
121
156
  add_my_app_name_column = app_create_group.add_task(
122
157
  Task(
123
158
  name="add-my-app-name-column",
@@ -129,6 +164,7 @@ add_my_app_name_column = app_create_group.add_task(
129
164
  update_my_app_name_test_read_task,
130
165
  update_my_app_name_test_update_task,
131
166
  update_my_app_name_test_delete_task,
167
+ create_my_app_name_entity_migration,
132
168
  ],
133
169
  successor=format_my_app_name_code,
134
170
  retries=0,
@@ -2,7 +2,7 @@ import os
2
2
  import re
3
3
  import textwrap
4
4
 
5
- from bs4 import BeautifulSoup, formatter
5
+ from bs4 import BeautifulSoup, Tag, formatter
6
6
  from my_app_name._zrb.config import APP_DIR
7
7
 
8
8
  from zrb.context.any_context import AnyContext
@@ -65,6 +65,7 @@ def update_my_app_name_ui(ctx: AnyContext):
65
65
  kebab_entity_name = to_kebab_case(ctx.input.entity)
66
66
  snake_column_name = to_snake_case(ctx.input.column)
67
67
  human_column_name = to_human_case(ctx.input.column).title()
68
+ column_type = ctx.input.type
68
69
  subroute_file_path = os.path.join(
69
70
  APP_DIR,
70
71
  "module",
@@ -85,18 +86,21 @@ def update_my_app_name_ui(ctx: AnyContext):
85
86
  form_id="crud-create-form",
86
87
  column_label=human_column_name,
87
88
  column_name=snake_column_name,
89
+ column_type=column_type,
88
90
  )
89
91
  new_code = _add_input_to_form(
90
92
  new_code,
91
93
  form_id="crud-update-form",
92
94
  column_label=human_column_name,
93
95
  column_name=snake_column_name,
96
+ column_type=column_type,
94
97
  )
95
98
  new_code = _add_input_to_form(
96
99
  new_code,
97
100
  form_id="crud-delete-form",
98
101
  column_label=human_column_name,
99
102
  column_name=snake_column_name,
103
+ column_type=column_type,
100
104
  )
101
105
  # JS Function
102
106
  new_code = _alter_js_function_returned_array(
@@ -140,7 +144,7 @@ def _add_th_before_last(html_str, table_id, th_content):
140
144
 
141
145
 
142
146
  def _add_input_to_form(
143
- html_str: str, form_id: str, column_label: str, column_name: str
147
+ html_str: str, form_id: str, column_label: str, column_name: str, column_type: str
144
148
  ) -> str:
145
149
  soup = BeautifulSoup(html_str, "html.parser")
146
150
  # Find the form by id.
@@ -151,9 +155,7 @@ def _add_input_to_form(
151
155
  new_label = soup.new_tag("label")
152
156
  new_label.append(f"{column_label}: ")
153
157
  # Create a new input element with the provided column name.
154
- new_input = soup.new_tag(
155
- "input", attrs={"type": "text", "name": column_name, "required": "required"}
156
- )
158
+ new_input = _get_html_input(soup, column_name, column_type)
157
159
  new_label.append(new_input)
158
160
  # Look for a footer element inside the form.
159
161
  footer = form.find("footer")
@@ -168,6 +170,26 @@ def _add_input_to_form(
168
170
  )
169
171
 
170
172
 
173
+ def _get_html_input(soup: BeautifulSoup, column_name: str, column_type: str) -> Tag:
174
+ # Map your custom types to HTML input types.
175
+ type_mapping = {
176
+ "str": "text",
177
+ "int": "number",
178
+ "float": "number",
179
+ "bool": "checkbox",
180
+ "datetime": "datetime-local",
181
+ "date": "date",
182
+ }
183
+ # Get the corresponding HTML input type; default to "text" if not found.
184
+ html_input_type = type_mapping.get(column_type, "text")
185
+ # Create the new input tag with the appropriate attributes.
186
+ new_input = soup.new_tag(
187
+ "input",
188
+ attrs={"type": html_input_type, "name": column_name, "required": "required"},
189
+ )
190
+ return new_input
191
+
192
+
171
193
  def _infer_html_indent_width(html_str: str) -> int:
172
194
  """
173
195
  Infer the indentation width (number of spaces) from the HTML string.
@@ -208,7 +230,7 @@ def _alter_js_function_returned_array(
208
230
  # 3. Captures the newline and leading whitespace (indent) of the return statement.
209
231
  # 4. Captures the rest of the return line.
210
232
  pattern = (
211
- r"(function\s+"
233
+ r"("
212
234
  + re.escape(js_function_name)
213
235
  + r"\s*\([^)]*\)\s*\{)" # group1: function header
214
236
  r"([\s\S]*?)" # group2: code before return