zrb 1.0.0a15__py3-none-any.whl → 1.0.0a18__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 (151) hide show
  1. zrb/__main__.py +3 -0
  2. zrb/builtin/__init__.py +2 -2
  3. zrb/builtin/git.py +16 -8
  4. zrb/builtin/git_subtree.py +7 -2
  5. zrb/builtin/llm/tool/rag.py +2 -2
  6. zrb/builtin/project/add/fastapp/fastapp_input.py +16 -0
  7. zrb/builtin/project/add/fastapp/fastapp_task.py +78 -0
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.flake8 +3 -0
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/create_column_task.py +14 -0
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +128 -0
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +213 -0
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +27 -0
  13. zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/my_entity_usecase.py +9 -10
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/factory.py +13 -0
  15. zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/repository/my_entity_db_repository.py +14 -9
  16. zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/repository/my_entity_repository.py +6 -7
  17. zrb/builtin/project/add/{fastapp_template/_zrb/entity/schema.template.py → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py} +8 -0
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +17 -0
  19. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/input.py +1 -4
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +85 -0
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +154 -0
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/any_client.py +7 -0
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +6 -0
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +6 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +9 -0
  26. zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/env.py +2 -4
  27. zrb/builtin/project/add/{fastapp_template/module/auth → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/script.py.mako +1 -0
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +33 -0
  29. zrb/builtin/project/add/{fastapp_template/_zrb/main.py → fastapp/fastapp_template/my_app_name/_zrb/task.py} +12 -14
  30. zrb/builtin/project/add/{fastapp_template/_zrb/helper.py → fastapp/fastapp_template/my_app_name/_zrb/util.py} +1 -1
  31. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/venv_task.py +1 -1
  32. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/app.py +2 -2
  33. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/base_db_repository.py +1 -1
  34. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/base_usecase.py +19 -6
  35. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/db_engine.py +1 -1
  36. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/config.py +1 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +7 -0
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/migrate.py +3 -0
  39. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/client/any_client.py +10 -4
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +7 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +6 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +9 -0
  43. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration/env.py +2 -4
  44. zrb/builtin/project/add/{fastapp_template/module/gateway → fastapp/fastapp_template/my_app_name/module/auth}/migration/script.py.mako +1 -0
  45. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration_metadata.py +1 -1
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +37 -0
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/factory.py +13 -0
  48. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/repository/user_db_repository.py +13 -7
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +42 -0
  50. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/user_usecase.py +13 -8
  51. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration/env.py +2 -4
  52. zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/module/gateway}/migration/script.py.mako +1 -0
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -0
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +0 -0
  55. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/requirements.txt +1 -1
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py +0 -0
  57. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/permission.py +8 -0
  58. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/role.py +8 -0
  59. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/user.py +8 -0
  60. zrb/builtin/project/add/fastapp/fastapp_util.py +46 -0
  61. zrb/builtin/project/create/{create.py → project_task.py} +1 -1
  62. zrb/builtin/python.py +4 -1
  63. zrb/builtin/setup/asdf/asdf_helper.py +4 -8
  64. zrb/builtin/setup/tmux/tmux.py +7 -12
  65. zrb/builtin/todo.py +45 -29
  66. zrb/callback/callback.py +0 -1
  67. zrb/cmd/cmd_val.py +2 -2
  68. zrb/config.py +1 -0
  69. zrb/content_transformer/content_transformer.py +8 -7
  70. zrb/context/any_context.py +6 -6
  71. zrb/group/group.py +0 -1
  72. zrb/input/base_input.py +13 -1
  73. zrb/input/text_input.py +4 -4
  74. zrb/runner/cli.py +0 -1
  75. zrb/runner/web_app.py +5 -2
  76. zrb/runner/web_controller/group_info_ui/controller.py +6 -14
  77. zrb/runner/web_controller/home_page/controller.py +6 -14
  78. zrb/runner/web_controller/task_ui/controller.py +12 -19
  79. zrb/session_state_logger/any_session_state_logger.py +0 -1
  80. zrb/session_state_logger/file_session_state_logger.py +4 -8
  81. zrb/task/base_trigger.py +0 -1
  82. zrb/task/cmd_task.py +1 -1
  83. zrb/task/llm_task.py +3 -6
  84. zrb/task/make_task.py +0 -1
  85. zrb/task/scaffolder.py +18 -4
  86. zrb/task/scheduler.py +0 -1
  87. zrb/util/cmd/command.py +0 -1
  88. zrb/util/codemod/{add_code_to_class.py → append_code_to_class.py} +4 -4
  89. zrb/util/codemod/{add_code_to_function.py → append_code_to_function.py} +5 -3
  90. zrb/util/codemod/{add_code_to_method.py → append_code_to_method.py} +3 -3
  91. zrb/util/codemod/{add_key_to_dict.py → append_key_to_dict.py} +1 -1
  92. zrb/util/codemod/{add_param_to_function_call.py → append_param_to_function_call.py} +1 -1
  93. zrb/util/codemod/{add_code_to_module.py → prepend_code_to_module.py} +2 -2
  94. zrb/util/codemod/{add_parent_to_class.py → prepend_parent_to_class.py} +1 -1
  95. zrb/util/codemod/{add_property_to_class.py → prepend_property_to_class.py} +1 -1
  96. zrb/util/file.py +18 -0
  97. zrb/util/git_subtree.py +3 -4
  98. zrb/util/todo.py +105 -24
  99. zrb/xcom/xcom.py +0 -1
  100. {zrb-1.0.0a15.dist-info → zrb-1.0.0a18.dist-info}/METADATA +2 -2
  101. zrb-1.0.0a18.dist-info/RECORD +240 -0
  102. zrb/builtin/project/add/fastapp.py +0 -87
  103. zrb/builtin/project/add/fastapp_template/_zrb/column/create_column_task.py +0 -11
  104. zrb/builtin/project/add/fastapp_template/_zrb/entity/create_entity_task.py +0 -196
  105. zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/factory.py +0 -13
  106. zrb/builtin/project/add/fastapp_template/_zrb/module/create_module_task.py +0 -136
  107. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/any_client.py +0 -27
  108. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/api_client.py +0 -6
  109. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/direct_client.py +0 -6
  110. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/factory.py +0 -9
  111. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/route.py +0 -19
  112. zrb/builtin/project/add/fastapp_template/main.py +0 -7
  113. zrb/builtin/project/add/fastapp_template/migrate.py +0 -3
  114. zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +0 -7
  115. zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +0 -6
  116. zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +0 -9
  117. zrb/builtin/project/add/fastapp_template/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  118. zrb/builtin/project/add/fastapp_template/module/auth/route.py +0 -22
  119. zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +0 -13
  120. zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/user_repository.py +0 -34
  121. zrb/builtin/project/add/fastapp_template/module/gateway/route.py +0 -27
  122. zrb-1.0.0a15.dist-info/RECORD +0 -231
  123. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/.gitignore +0 -0
  124. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/README.md +0 -0
  125. /zrb/builtin/project/add/{__init__.py → fastapp/fastapp_template/my_app_name/__init__.py} +0 -0
  126. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/config.py +0 -0
  127. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/group.py +0 -0
  128. /zrb/builtin/project/add/{fastapp_template/__init__.py → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py} +0 -0
  129. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/alembic.ini +0 -0
  130. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/README +0 -0
  131. /zrb/builtin/project/add/{fastapp_template/module/gateway → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/versions/.gitkeep +0 -0
  132. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration_metadata.py +0 -0
  133. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/service/__init__.py +0 -0
  134. /zrb/builtin/project/add/{fastapp_template/_zrb/module/run_module.template.py → fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py} +0 -0
  135. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/__init__.py +0 -0
  136. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/error.py +0 -0
  137. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/schema.py +0 -0
  138. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/__init__.py +0 -0
  139. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/alembic.ini +0 -0
  140. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration/README +0 -0
  141. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/module/auth}/migration/versions/3093c7336477_add_user_table.py +0 -0
  142. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/__init__.py +0 -0
  143. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/__init__.py +0 -0
  144. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/repository/__init__.py +0 -0
  145. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/alembic.ini +0 -0
  146. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration/README +0 -0
  147. /zrb/builtin/project/add/{fastapp_template/schema/__init__.py → fastapp/fastapp_template/my_app_name/module/gateway/migration/versions/.gitkeep} +0 -0
  148. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration_metadata.py +0 -0
  149. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/template.env +0 -0
  150. {zrb-1.0.0a15.dist-info → zrb-1.0.0a18.dist-info}/WHEEL +0 -0
  151. {zrb-1.0.0a15.dist-info → zrb-1.0.0a18.dist-info}/entry_points.txt +0 -0
zrb/task/scaffolder.py CHANGED
@@ -30,9 +30,11 @@ class Scaffolder(BaseTask):
30
30
  destination_path: StrAttr | None = None,
31
31
  render_destination_path: bool = True,
32
32
  transform_path: TransformConfig = {},
33
+ render_transform_path: bool = True,
33
34
  transform_content: (
34
35
  list[AnyContentTransformer] | AnyContentTransformer | TransformConfig
35
36
  ) = [],
37
+ render_transform_content: bool = True,
36
38
  execute_condition: BoolAttr = True,
37
39
  retries: int = 2,
38
40
  retry_period: float = 0,
@@ -70,7 +72,9 @@ class Scaffolder(BaseTask):
70
72
  self._destination_path = destination_path
71
73
  self._render_destination_path = render_destination_path
72
74
  self._content_transformers = transform_content
75
+ self._render_content_transformers = render_transform_content
73
76
  self._path_transformer = transform_path
77
+ self._render_path_transformer = render_transform_path
74
78
 
75
79
  def _get_source_path(self, ctx: AnyContext) -> str:
76
80
  return get_str_attr(ctx, self._source_path, "", auto_render=True)
@@ -80,9 +84,17 @@ class Scaffolder(BaseTask):
80
84
 
81
85
  def _get_content_transformers(self) -> list[AnyContentTransformer]:
82
86
  if callable(self._content_transformers):
83
- return [ContentTransformer(match="*", transform=self._content_transformers)]
87
+ return [
88
+ ContentTransformer(match=".*", transform=self._content_transformers)
89
+ ]
84
90
  if isinstance(self._content_transformers, dict):
85
- return [ContentTransformer(match="*", transform=self._content_transformers)]
91
+ return [
92
+ ContentTransformer(
93
+ match=".*",
94
+ transform=self._content_transformers,
95
+ auto_render=self._render_content_transformers,
96
+ )
97
+ ]
86
98
  if isinstance(self._content_transformers, AnyContentTransformer):
87
99
  return [self._content_transformers]
88
100
  return self._content_transformers
@@ -117,17 +129,19 @@ class Scaffolder(BaseTask):
117
129
  dest_file = os.path.join(
118
130
  dest_dir, self._transform_path(ctx, file_name)
119
131
  )
132
+ ctx.log_info(f"Copying {src_file} to {dest_file}")
120
133
  shutil.copy2(src_file, dest_file)
121
- ctx.log_info(f"Copied {src_file} to {dest_file}")
122
134
  else:
135
+ ctx.log_info(f"Copying {source_path} to {destination_path}")
123
136
  shutil.copy2(source_path, destination_path)
124
- ctx.log_info(f"Copied {source_path} to {destination_path}")
125
137
 
126
138
  def _transform_path(self, ctx: AnyContext, file_path: str):
127
139
  if callable(self._path_transformer):
128
140
  return self._path_transformer(ctx, file_path)
129
141
  new_file_path = file_path
130
142
  for keyword, replacement in self._path_transformer.items():
143
+ if self._render_path_transformer:
144
+ replacement = ctx.render(replacement)
131
145
  new_file_path = new_file_path.replace(keyword, replacement)
132
146
  return new_file_path
133
147
 
zrb/task/scheduler.py CHANGED
@@ -16,7 +16,6 @@ from zrb.xcom.xcom import Xcom
16
16
 
17
17
 
18
18
  class Scheduler(BaseTrigger):
19
-
20
19
  def __init__(
21
20
  self,
22
21
  name: str,
zrb/util/cmd/command.py CHANGED
@@ -47,7 +47,6 @@ async def run_command(
47
47
  max_output_line: int = 1000,
48
48
  max_error_line: int = 1000,
49
49
  ) -> tuple[CmdResult, int]:
50
-
51
50
  async def __read_stream(
52
51
  stream, log_method: Callable[..., None], max_lines: int
53
52
  ) -> str:
@@ -4,7 +4,7 @@ import libcst as cst
4
4
  class ClassCodeAdder(cst.CSTTransformer):
5
5
  def __init__(self, class_name: str, new_code: str):
6
6
  self.class_name = class_name
7
- self.new_code = cst.parse_statement(new_code)
7
+ self.new_code = cst.parse_module(new_code).body
8
8
  self.class_found = False
9
9
 
10
10
  def leave_ClassDef(
@@ -15,17 +15,17 @@ class ClassCodeAdder(cst.CSTTransformer):
15
15
  self.class_found = True
16
16
  # Add the method to the class body
17
17
  new_body = updated_node.body.with_changes(
18
- body=updated_node.body.body + (self.new_code,)
18
+ body=updated_node.body.body + tuple(self.new_code)
19
19
  )
20
20
  return updated_node.with_changes(body=new_body)
21
21
  return updated_node
22
22
 
23
23
 
24
- def add_code_to_class(original_code: str, class_name: str, method_code: str) -> str:
24
+ def append_code_to_class(original_code: str, class_name: str, new_code: str) -> str:
25
25
  # Parse the original code into a module
26
26
  module = cst.parse_module(original_code)
27
27
  # Initialize transformer with the class name and method code
28
- transformer = ClassCodeAdder(class_name, method_code)
28
+ transformer = ClassCodeAdder(class_name, new_code)
29
29
  # Apply the transformation
30
30
  modified_module = module.visit(transformer)
31
31
  # Check if the class was found
@@ -5,7 +5,7 @@ class FunctionCodeAdder(cst.CSTTransformer):
5
5
  def __init__(self, function_name: str, new_code: str):
6
6
  self.function_name = function_name
7
7
  # Use parse_module to handle multiple statements
8
- self.new_code = cst.parse_statement(new_code)
8
+ self.new_code = cst.parse_module(new_code).body
9
9
  self.function_found = False
10
10
 
11
11
  def leave_FunctionDef(
@@ -16,13 +16,15 @@ class FunctionCodeAdder(cst.CSTTransformer):
16
16
  self.function_found = True
17
17
  # Add the method to the class body
18
18
  new_body = updated_node.body.with_changes(
19
- body=updated_node.body.body + (self.new_code,)
19
+ body=updated_node.body.body + tuple(self.new_code)
20
20
  )
21
21
  return updated_node.with_changes(body=new_body)
22
22
  return updated_node
23
23
 
24
24
 
25
- def add_code_to_function(original_code: str, function_name: str, new_code: str) -> str:
25
+ def append_code_to_function(
26
+ original_code: str, function_name: str, new_code: str
27
+ ) -> str:
26
28
  # Parse the original code into a module
27
29
  module = cst.parse_module(original_code)
28
30
  # Initialize the transformer with the necessary information
@@ -6,7 +6,7 @@ class MethodCodeAdder(cst.CSTTransformer):
6
6
  self.class_name = class_name
7
7
  self.method_name = method_name
8
8
  # Use parse_module to handle multiple statements
9
- self.new_code = cst.parse_statement(new_code)
9
+ self.new_code = cst.parse_module(new_code).body
10
10
  self.class_found = False
11
11
  self.method_found = False
12
12
 
@@ -27,7 +27,7 @@ class MethodCodeAdder(cst.CSTTransformer):
27
27
  ):
28
28
  # Modify the target function by adding the new code
29
29
  body_with_new_code = item.body.with_changes(
30
- body=item.body.body + (self.new_code,) # Add the new code
30
+ body=item.body.body + tuple(self.new_code) # Add the new code
31
31
  )
32
32
  new_body.append(item.with_changes(body=body_with_new_code))
33
33
  self.method_found = True
@@ -37,7 +37,7 @@ class MethodCodeAdder(cst.CSTTransformer):
37
37
  return updated_node
38
38
 
39
39
 
40
- def add_code_to_method(
40
+ def append_code_to_method(
41
41
  original_code: str, class_name: str, function_name: str, new_code: str
42
42
  ) -> str:
43
43
  # Parse the original code into a module
@@ -33,7 +33,7 @@ class DictionaryModifier(cst.CSTTransformer):
33
33
  return updated_node
34
34
 
35
35
 
36
- def add_key_to_dict(
36
+ def append_key_to_dict(
37
37
  original_code: str, dictionary_name: str, new_key: str, new_value: str
38
38
  ) -> str:
39
39
  # Parse the original code into a module
@@ -21,7 +21,7 @@ class FunctionCallParamAdder(cst.CSTTransformer):
21
21
  return updated_node
22
22
 
23
23
 
24
- def add_param_to_function_call(
24
+ def append_param_to_function_call(
25
25
  original_code: str, func_name: str, new_param: str
26
26
  ) -> str:
27
27
  # Parse the original code into a module
@@ -1,5 +1,5 @@
1
- def add_code_to_module(source_code: str, new_code: str) -> str:
2
- lines = source_code.splitlines()
1
+ def prepend_code_to_module(original_code: str, new_code: str) -> str:
2
+ lines = original_code.splitlines()
3
3
  last_import_index = -1
4
4
  for i, line in enumerate(lines):
5
5
  stripped_line = line.strip()
@@ -22,7 +22,7 @@ class ParentClassAdder(cst.CSTTransformer):
22
22
  return updated_node
23
23
 
24
24
 
25
- def add_parent_to_class(
25
+ def prepend_parent_class(
26
26
  original_code: str, class_name: str, parent_class_name: str
27
27
  ) -> str:
28
28
  # Parse the original code into a module
@@ -33,7 +33,7 @@ class ClassPropertyAdder(cst.CSTTransformer):
33
33
  return updated_node
34
34
 
35
35
 
36
- def add_property_to_class(
36
+ def prepend_property_to_class(
37
37
  original_code: str,
38
38
  class_name: str,
39
39
  property_name: str,
zrb/util/file.py ADDED
@@ -0,0 +1,18 @@
1
+ import os
2
+
3
+
4
+ def read_file(file_path: str, replace_map: dict[str, str] = {}) -> str:
5
+ with open(file_path, "r", encoding="utf-8") as f:
6
+ content = f.read()
7
+ for key, val in replace_map.items():
8
+ content = content.replace(key, val)
9
+ return content
10
+
11
+
12
+ def write_file(file_path: str, content: str | list[str]):
13
+ if isinstance(content, list):
14
+ content = "\n".join([line for line in content if line is not None])
15
+ dir_path = os.path.dirname(file_path)
16
+ os.makedirs(dir_path, exist_ok=True)
17
+ with open(file_path, "w") as f:
18
+ f.write(content.strip())
zrb/util/git_subtree.py CHANGED
@@ -5,6 +5,7 @@ from typing import Any
5
5
  from pydantic import BaseModel
6
6
 
7
7
  from zrb.util.cmd.command import run_command
8
+ from zrb.util.file import read_file, write_file
8
9
 
9
10
 
10
11
  class SingleSubTreeConfig(BaseModel):
@@ -21,14 +22,12 @@ def load_config(repo_dir: str) -> SubTreeConfig:
21
22
  file_path = os.path.join(repo_dir, "subtrees.json")
22
23
  if not os.path.exists(file_path):
23
24
  return SubTreeConfig(data={})
24
- with open(file_path, "r") as f:
25
- return SubTreeConfig.model_validate_json(f.read())
25
+ return SubTreeConfig.model_validate_json(read_file(file_path))
26
26
 
27
27
 
28
28
  def save_config(repo_dir: str, config: SubTreeConfig):
29
29
  file_path = os.path.join(repo_dir, "subtrees.json")
30
- with open(file_path, "w") as f:
31
- f.write(config.model_dump_json(indent=2))
30
+ write_file(file_path, config.model_dump_json(indent=2))
32
31
 
33
32
 
34
33
  async def add_subtree(
zrb/util/todo.py CHANGED
@@ -1,20 +1,27 @@
1
1
  import datetime
2
2
  import re
3
3
  import shutil
4
- from typing import Any
5
4
 
6
5
  from pydantic import BaseModel, Field, model_validator
7
6
 
8
7
  from zrb.util.cli.style import (
9
- stylize_bold_green,
10
8
  stylize_bold_yellow,
11
9
  stylize_cyan,
12
10
  stylize_faint,
13
11
  stylize_magenta,
14
12
  stylize_yellow,
15
13
  )
14
+ from zrb.util.file import read_file, write_file
16
15
  from zrb.util.string.name import get_random_name
17
16
 
17
+ _DATE_TIME_STR_WIDTH = 14
18
+ _MAX_DESCRIPTION_WIDTH = 70
19
+ _PRIORITY_WIDTH = 3
20
+ _COMPLETED_WIDTH = 3
21
+ _COMPLETED_AT_WIDTH = _DATE_TIME_STR_WIDTH
22
+ _CREATED_AT_WIDTH = _DATE_TIME_STR_WIDTH
23
+ _GAP_WIDTH = 2
24
+
18
25
 
19
26
  class TodoTaskModel(BaseModel):
20
27
  priority: str | None = Field("D", pattern=r"^[A-Z]$") # Priority like A, B, ...
@@ -87,8 +94,7 @@ def select_todo_task(
87
94
 
88
95
 
89
96
  def load_todo_list(todo_file_path: str) -> list[TodoTaskModel]:
90
- with open(todo_file_path, "r") as f:
91
- todo_lines = f.read().strip().split("\n")
97
+ todo_lines = read_file(todo_file_path).strip().split("\n")
92
98
  todo_list: list[TodoTaskModel] = []
93
99
  for todo_line in todo_lines:
94
100
  todo_line = todo_line.strip()
@@ -108,9 +114,9 @@ def load_todo_list(todo_file_path: str) -> list[TodoTaskModel]:
108
114
 
109
115
 
110
116
  def save_todo_list(todo_file_path: str, todo_list: list[TodoTaskModel]):
111
- with open(todo_file_path, "w") as f:
112
- for todo_task in todo_list:
113
- f.write(todo_task_to_line(todo_task) + "\n")
117
+ write_file(
118
+ todo_file_path, [todo_task_to_line(todo_task) for todo_task in todo_list]
119
+ )
114
120
 
115
121
 
116
122
  def line_to_todo_task(line: str) -> TodoTaskModel:
@@ -215,8 +221,8 @@ def get_visual_todo_list(todo_list: list[TodoTaskModel], filter: str) -> str:
215
221
  )
216
222
  if max_desc_length < len("DESCRIPTION"):
217
223
  max_desc_length = len("DESCRIPTION")
218
- if max_desc_length > 70:
219
- max_desc_length = 70
224
+ if max_desc_length > _MAX_DESCRIPTION_WIDTH:
225
+ max_desc_length = _MAX_DESCRIPTION_WIDTH
220
226
  max_additional_info_length = max(
221
227
  todo_task.get_additional_info_length() for todo_task in filtered_todo_list
222
228
  )
@@ -243,18 +249,24 @@ def get_visual_todo_list(todo_list: list[TodoTaskModel], filter: str) -> str:
243
249
  def get_visual_todo_header(
244
250
  terminal_width: int, max_desc_length: int, max_additional_info_length: int
245
251
  ) -> str:
246
- priority = "".ljust(3)
247
- completed = "".ljust(3)
248
- completed_at = "COMPLETED AT".rjust(14)
249
- created_at = "CREATED_AT".ljust(14)
250
- description = "DESCRIPTION".ljust(min(max_desc_length, 70))
251
- additional_info = "PROJECT/CONTEXT/OTHERS"
252
- if terminal_width <= 14 + max_desc_length + max_additional_info_length:
253
- return " ".join([priority, completed, description])
254
- if terminal_width <= 36 + max_desc_length + max_additional_info_length:
255
- return " ".join([priority, completed, description, additional_info])
256
- return " ".join(
257
- [priority, completed, completed_at, created_at, description, additional_info]
252
+ priority_caption = "".ljust(_PRIORITY_WIDTH)
253
+ completed_caption = "".ljust(_COMPLETED_WIDTH)
254
+ completed_at_caption = "COMPLETED AT".rjust(_COMPLETED_AT_WIDTH)
255
+ created_at_caption = "CREATED_AT".ljust(_CREATED_AT_WIDTH)
256
+ description_caption = "DESCRIPTION".ljust(
257
+ min(max_desc_length, _MAX_DESCRIPTION_WIDTH)
258
+ )
259
+ additional_info_caption = "PROJECT/CONTEXT/OTHERS".ljust(max_additional_info_length)
260
+ return _get_line_str(
261
+ terminal_width=terminal_width,
262
+ description_width=min(max_desc_length, _MAX_DESCRIPTION_WIDTH),
263
+ additional_info_width=max_additional_info_length,
264
+ priority=priority_caption,
265
+ completed=completed_caption,
266
+ completed_at=completed_at_caption,
267
+ created_at=created_at_caption,
268
+ description=description_caption,
269
+ additional_info=additional_info_caption,
258
270
  )
259
271
 
260
272
 
@@ -282,6 +294,17 @@ def get_visual_todo_line(
282
294
  + [stylize_cyan(f"@{context}") for context in todo_task.contexts]
283
295
  + [stylize_magenta(f"{key}:{val}") for key, val in todo_task.keyval.items()]
284
296
  )
297
+ return _get_line_str(
298
+ terminal_width=terminal_width,
299
+ description_width=min(max_desc_length, _MAX_DESCRIPTION_WIDTH),
300
+ additional_info_width=max_additional_info_length,
301
+ priority=priority,
302
+ completed=completed,
303
+ completed_at=completed_at,
304
+ created_at=created_at,
305
+ description=description,
306
+ additional_info=additional_info,
307
+ )
285
308
  if terminal_width <= 14 + max_desc_length + max_additional_info_length:
286
309
  return " ".join([priority, completed, description])
287
310
  if terminal_width <= 36 + max_desc_length + max_additional_info_length:
@@ -291,6 +314,64 @@ def get_visual_todo_line(
291
314
  )
292
315
 
293
316
 
317
+ def _get_line_str(
318
+ terminal_width: int,
319
+ description_width: int,
320
+ additional_info_width: int,
321
+ priority: str,
322
+ completed: str,
323
+ completed_at: str,
324
+ created_at: str,
325
+ description: str,
326
+ additional_info: str,
327
+ ):
328
+ gap = "".ljust(_GAP_WIDTH)
329
+ if terminal_width >= _get_minimum_width(
330
+ [
331
+ _PRIORITY_WIDTH,
332
+ _COMPLETED_WIDTH,
333
+ _COMPLETED_AT_WIDTH,
334
+ _CREATED_AT_WIDTH,
335
+ description_width,
336
+ additional_info_width,
337
+ ]
338
+ ):
339
+ return gap.join(
340
+ [
341
+ priority,
342
+ completed,
343
+ completed_at,
344
+ created_at,
345
+ description,
346
+ additional_info,
347
+ ]
348
+ )
349
+ if terminal_width >= _get_minimum_width(
350
+ [_PRIORITY_WIDTH, _COMPLETED_WIDTH, description_width, additional_info_width]
351
+ ):
352
+ return gap.join([priority, completed, description, additional_info])
353
+ if terminal_width >= _get_minimum_width(
354
+ [
355
+ _PRIORITY_WIDTH,
356
+ _COMPLETED_WIDTH,
357
+ _COMPLETED_AT_WIDTH,
358
+ _CREATED_AT_WIDTH,
359
+ description_width,
360
+ ]
361
+ ):
362
+ return gap.join([priority, completed, completed_at, created_at, description])
363
+ if terminal_width >= _get_minimum_width(
364
+ [_PRIORITY_WIDTH, _COMPLETED_WIDTH, description_width]
365
+ ):
366
+ return gap.join([priority, completed, description])
367
+ return gap.join([priority, description])
368
+
369
+
370
+ def _get_minimum_width(field_widths: list[int]) -> int:
371
+ gap_width = _GAP_WIDTH * (len(field_widths) - 1)
372
+ return sum(field_width for field_width in field_widths) + gap_width
373
+
374
+
294
375
  def get_visual_todo_card(
295
376
  todo_task: TodoTaskModel, log_work_list: list[dict[str, str]]
296
377
  ) -> str:
@@ -344,13 +425,13 @@ def _date_to_str(date: datetime.date | None) -> str:
344
425
  return date.strftime("%a %Y-%m-%d")
345
426
 
346
427
 
347
- def add_durations(duration1: str, duration2: str) -> str:
348
- total_seconds = _parse_duration(duration1) + _parse_duration(duration2)
428
+ def add_duration(duration1: str, duration2: str) -> str:
429
+ total_seconds = parse_duration(duration1) + parse_duration(duration2)
349
430
  # Format and return the result
350
431
  return _format_duration(total_seconds)
351
432
 
352
433
 
353
- def _parse_duration(duration: str) -> int:
434
+ def parse_duration(duration: str) -> int:
354
435
  """Parse a duration string into total seconds."""
355
436
  units = {"M": 2592000, "w": 604800, "d": 86400, "h": 3600, "m": 60, "s": 1}
356
437
  total_seconds = 0
zrb/xcom/xcom.py CHANGED
@@ -4,7 +4,6 @@ from typing import Any
4
4
 
5
5
 
6
6
  class Xcom(deque):
7
-
8
7
  def __repr__(self):
9
8
  class_name = self.__class__.__name__
10
9
  return f"<{class_name} {list(self)}>"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zrb
3
- Version: 1.0.0a15
3
+ Version: 1.0.0a18
4
4
  Summary: Your Automation Powerhouse
5
5
  Home-page: https://github.com/state-alchemists/zrb
6
6
  License: AGPL-3.0-or-later
@@ -18,7 +18,7 @@ Requires-Dist: autopep8 (>=2.0.4,<3.0.0)
18
18
  Requires-Dist: beautifulsoup4 (>=4.12.3,<5.0.0)
19
19
  Requires-Dist: black (>=24.10.0,<24.11.0)
20
20
  Requires-Dist: chromadb (>=0.5.20,<0.6.0) ; extra == "rag"
21
- Requires-Dist: fastapi[standard] (>=0.115.5,<0.116.0)
21
+ Requires-Dist: fastapi[standard] (>=0.115.6,<0.116.0)
22
22
  Requires-Dist: isort (>=5.13.2,<5.14.0)
23
23
  Requires-Dist: libcst (>=1.5.0,<2.0.0)
24
24
  Requires-Dist: litellm (>=1.52.12,<2.0.0)