zrb 0.15.0__py3-none-any.whl → 0.17.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 (97) hide show
  1. zrb/__init__.py +5 -0
  2. zrb/__main__.py +0 -3
  3. zrb/action/runner.py +12 -3
  4. zrb/advertisement.py +4 -0
  5. zrb/builtin/_helper/reccuring_action.py +0 -23
  6. zrb/builtin/devtool/install/_input.py +2 -4
  7. zrb/builtin/devtool/install/helix/resource/config.toml +2 -1
  8. zrb/builtin/process/pid/get_by_name.py +1 -1
  9. zrb/builtin/project/create/template/project.sh +1 -0
  10. zrb/builtin/schedule.py +14 -10
  11. zrb/builtin/watch_changes.py +15 -14
  12. zrb/config/config.py +21 -14
  13. zrb/helper/accessories/color.py +5 -2
  14. zrb/helper/accessories/icon.py +4 -0
  15. zrb/helper/accessories/name.py +4 -0
  16. zrb/helper/accessories/untyped_color.py +10 -0
  17. zrb/helper/advertisement.py +3 -0
  18. zrb/helper/callable.py +9 -1
  19. zrb/helper/cli.py +2 -0
  20. zrb/helper/codemod/add_argument_to_function.py +6 -0
  21. zrb/helper/codemod/add_argument_to_function_call.py +6 -0
  22. zrb/helper/codemod/add_assert_resource.py +4 -0
  23. zrb/helper/codemod/add_function_call.py +4 -0
  24. zrb/helper/codemod/add_import_module.py +4 -0
  25. zrb/helper/codemod/add_key_value_to_dict.py +6 -0
  26. zrb/helper/codemod/add_property_to_class.py +6 -0
  27. zrb/helper/codemod/add_upstream_to_task.py +4 -0
  28. zrb/helper/codemod/append_code_to_function.py +6 -0
  29. zrb/helper/codemod/format_code.py +4 -0
  30. zrb/helper/default_env.py +2 -0
  31. zrb/helper/docker_compose/fetch_external_env.py +6 -0
  32. zrb/helper/docker_compose/file.py +4 -0
  33. zrb/helper/docstring.py +5 -0
  34. zrb/helper/env_map/fetch.py +4 -0
  35. zrb/helper/file/copy_tree.py +3 -0
  36. zrb/helper/file/match.py +4 -0
  37. zrb/helper/file/text.py +4 -0
  38. zrb/helper/git/detect_changes.py +4 -0
  39. zrb/helper/loader/load_module.py +2 -0
  40. zrb/helper/log.py +1 -1
  41. zrb/helper/map/conversion.py +4 -0
  42. zrb/helper/python_task.py +3 -0
  43. zrb/helper/render_data.py +4 -0
  44. zrb/helper/string/conversion.py +13 -36
  45. zrb/helper/string/jinja.py +4 -0
  46. zrb/helper/string/modification.py +4 -0
  47. zrb/helper/string/parse_replacement.py +4 -0
  48. zrb/helper/string/untyped_conversion.py +49 -0
  49. zrb/helper/task.py +4 -0
  50. zrb/helper/typecheck.py +6 -7
  51. zrb/helper/typing.py +32 -12
  52. zrb/helper/util.py +4 -0
  53. zrb/runner.py +3 -0
  54. zrb/task/any_task.py +5 -0
  55. zrb/task/any_task_event_handler.py +4 -0
  56. zrb/task/base_remote_cmd_task.py +4 -0
  57. zrb/task/base_task/base_task.py +5 -1
  58. zrb/task/checker.py +7 -3
  59. zrb/task/cmd_task.py +14 -2
  60. zrb/task/decorator.py +4 -0
  61. zrb/task/docker_compose_task.py +4 -0
  62. zrb/task/flow_task.py +4 -0
  63. zrb/task/http_checker.py +14 -1
  64. zrb/task/looper.py +40 -0
  65. zrb/task/notifier.py +4 -0
  66. zrb/task/parallel.py +4 -0
  67. zrb/task/path_checker.py +14 -1
  68. zrb/task/path_watcher.py +65 -41
  69. zrb/task/port_checker.py +14 -1
  70. zrb/task/recurring_task.py +5 -0
  71. zrb/task/remote_cmd_task.py +4 -0
  72. zrb/task/resource_maker.py +14 -1
  73. zrb/task/rsync_task.py +4 -0
  74. zrb/task/server.py +190 -0
  75. zrb/task/task.py +4 -0
  76. zrb/task/time_watcher.py +50 -18
  77. zrb/task/watcher.py +100 -0
  78. zrb/task/wiki_task.py +4 -0
  79. zrb/task_env/constant.py +5 -0
  80. zrb/task_env/env.py +4 -0
  81. zrb/task_env/env_file.py +4 -0
  82. zrb/task_group/group.py +4 -0
  83. zrb/task_input/any_input.py +4 -0
  84. zrb/task_input/base_input.py +4 -0
  85. zrb/task_input/bool_input.py +4 -0
  86. zrb/task_input/choice_input.py +4 -0
  87. zrb/task_input/constant.py +5 -0
  88. zrb/task_input/float_input.py +4 -0
  89. zrb/task_input/int_input.py +4 -0
  90. zrb/task_input/password_input.py +4 -0
  91. zrb/task_input/str_input.py +4 -0
  92. zrb/task_input/task_input.py +4 -0
  93. {zrb-0.15.0.dist-info → zrb-0.17.0.dist-info}/METADATA +1 -1
  94. {zrb-0.15.0.dist-info → zrb-0.17.0.dist-info}/RECORD +97 -92
  95. {zrb-0.15.0.dist-info → zrb-0.17.0.dist-info}/LICENSE +0 -0
  96. {zrb-0.15.0.dist-info → zrb-0.17.0.dist-info}/WHEEL +0 -0
  97. {zrb-0.15.0.dist-info → zrb-0.17.0.dist-info}/entry_points.txt +0 -0
zrb/task/notifier.py CHANGED
@@ -1,7 +1,9 @@
1
1
  import os
2
2
  import subprocess
3
3
 
4
+ from zrb.helper.accessories.color import colored
4
5
  from zrb.helper.accessories.icon import get_random_icon
6
+ from zrb.helper.log import logger
5
7
  from zrb.helper.string.modification import double_quote
6
8
  from zrb.helper.typecheck import typechecked
7
9
  from zrb.helper.typing import Any, Callable, Iterable, JinjaTemplate, Optional, Union
@@ -21,6 +23,8 @@ from zrb.task_env.env_file import EnvFile
21
23
  from zrb.task_group.group import Group
22
24
  from zrb.task_input.any_input import AnyInput
23
25
 
26
+ logger.debug(colored("Loading zrb.task.notifier", attrs=["dark"]))
27
+
24
28
  _CURRENT_DIR = os.path.dirname(__file__)
25
29
  _NOTIFY_PS1_PATH = os.path.realpath(
26
30
  os.path.abspath(
zrb/task/parallel.py CHANGED
@@ -1,9 +1,13 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
+ from zrb.helper.accessories.color import colored
4
+ from zrb.helper.log import logger
3
5
  from zrb.helper.typecheck import typechecked
4
6
  from zrb.helper.typing import List, TypeVar, Union
5
7
  from zrb.task.any_task import AnyTask
6
8
 
9
+ logger.debug(colored("Loading zrb.task.parallel", attrs=["dark"]))
10
+
7
11
  TParallel = TypeVar("TParallel", bound="Parallel")
8
12
 
9
13
 
zrb/task/path_checker.py CHANGED
@@ -1,4 +1,6 @@
1
+ from zrb.helper.accessories.color import colored
1
2
  from zrb.helper.file.match import get_file_names
3
+ from zrb.helper.log import logger
2
4
  from zrb.helper.typecheck import typechecked
3
5
  from zrb.helper.typing import (
4
6
  Any,
@@ -26,6 +28,8 @@ from zrb.task_env.env_file import EnvFile
26
28
  from zrb.task_group.group import Group
27
29
  from zrb.task_input.any_input import AnyInput
28
30
 
31
+ logger.debug(colored("Loading zrb.task.path_checker", attrs=["dark"]))
32
+
29
33
  TPathChecker = TypeVar("TPathChecker", bound="PathChecker")
30
34
 
31
35
 
@@ -95,8 +99,17 @@ class PathChecker(Checker):
95
99
  raise_error: bool = True,
96
100
  is_async: bool = False,
97
101
  show_done_info: bool = True,
102
+ should_clear_xcom: bool = False,
103
+ should_stop_looper: bool = False,
98
104
  ) -> Callable[..., bool]:
99
- return super().to_function(env_prefix, raise_error, is_async, show_done_info)
105
+ return super().to_function(
106
+ env_prefix=env_prefix,
107
+ raise_error=raise_error,
108
+ is_async=is_async,
109
+ show_done_info=show_done_info,
110
+ should_clear_xcom=should_clear_xcom,
111
+ should_stop_looper=should_stop_looper,
112
+ )
100
113
 
101
114
  async def run(self, *args: Any, **kwargs: Any) -> bool:
102
115
  self._rendered_path = self.render_str(self._path)
zrb/task/path_watcher.py CHANGED
@@ -1,6 +1,8 @@
1
1
  import os
2
2
 
3
+ from zrb.helper.accessories.color import colored
3
4
  from zrb.helper.file.match import get_file_names
5
+ from zrb.helper.log import logger
4
6
  from zrb.helper.typecheck import typechecked
5
7
  from zrb.helper.typing import (
6
8
  Any,
@@ -23,17 +25,19 @@ from zrb.task.any_task_event_handler import (
23
25
  OnTriggered,
24
26
  OnWaiting,
25
27
  )
26
- from zrb.task.checker import Checker
28
+ from zrb.task.watcher import Watcher
27
29
  from zrb.task_env.env import Env
28
30
  from zrb.task_env.env_file import EnvFile
29
31
  from zrb.task_group.group import Group
30
32
  from zrb.task_input.any_input import AnyInput
31
33
 
34
+ logger.debug(colored("Loading zrb.task.path_watcher", attrs=["dark"]))
35
+
32
36
  TPathWatcher = TypeVar("TPathWatcher", bound="PathWatcher")
33
37
 
34
38
 
35
39
  @typechecked
36
- class PathWatcher(Checker):
40
+ class PathWatcher(Watcher):
37
41
  """
38
42
  PathWatcher will wait for any changes specified on path.
39
43
 
@@ -45,6 +49,8 @@ class PathWatcher(Checker):
45
49
  - <task-name>.deleted-file
46
50
  """
47
51
 
52
+ __init_times: Mapping[str, Mapping[str, float]] = {}
53
+
48
54
  def __init__(
49
55
  self,
50
56
  name: str = "watch-path",
@@ -73,7 +79,7 @@ class PathWatcher(Checker):
73
79
  watch_deleted_files: bool = True,
74
80
  should_execute: Union[bool, JinjaTemplate, Callable[..., bool]] = True,
75
81
  ):
76
- Checker.__init__(
82
+ Watcher.__init__(
77
83
  self,
78
84
  name=name,
79
85
  group=group,
@@ -103,7 +109,6 @@ class PathWatcher(Checker):
103
109
  self._watch_deleted_files = watch_deleted_files
104
110
  self._rendered_path: str = ""
105
111
  self._rendered_ignored_paths: List[str] = []
106
- self._init_times: Mapping[str, float] = {}
107
112
 
108
113
  def copy(self) -> TPathWatcher:
109
114
  return super().copy()
@@ -114,8 +119,17 @@ class PathWatcher(Checker):
114
119
  raise_error: bool = True,
115
120
  is_async: bool = False,
116
121
  show_done_info: bool = True,
122
+ should_clear_xcom: bool = False,
123
+ should_stop_looper: bool = False,
117
124
  ) -> Callable[..., bool]:
118
- return super().to_function(env_prefix, raise_error, is_async, show_done_info)
125
+ return super().to_function(
126
+ env_prefix=env_prefix,
127
+ raise_error=raise_error,
128
+ is_async=is_async,
129
+ show_done_info=show_done_info,
130
+ should_clear_xcom=should_clear_xcom,
131
+ should_stop_looper=should_stop_looper,
132
+ )
119
133
 
120
134
  async def run(self, *args: Any, **kwargs: Any) -> bool:
121
135
  self._rendered_path = self.render_str(self._path)
@@ -124,7 +138,9 @@ class PathWatcher(Checker):
124
138
  for ignored_path in self._get_rendered_ignored_paths()
125
139
  if ignored_path != ""
126
140
  ]
127
- self._init_times = self._get_mod_times()
141
+ identifier = self.get_identifier()
142
+ if identifier not in self.__init_times:
143
+ self.__init_times[identifier] = self._get_mod_times()
128
144
  return await super().run(*args, **kwargs)
129
145
 
130
146
  def _get_rendered_ignored_paths(self) -> List[str]:
@@ -132,41 +148,49 @@ class PathWatcher(Checker):
132
148
  return [self.render_str(self._ignored_path)]
133
149
  return [self.render_str(ignored_path) for ignored_path in self._ignored_path]
134
150
 
135
- async def inspect(self, *args: Any, **kwargs: Any) -> bool:
136
- label = f"Watching {self._rendered_path}"
137
- try:
138
- mod_times = self._get_mod_times()
139
- except Exception as e:
140
- self.show_progress(f"{label} Cannot inspect")
141
- raise e
142
- # watch changes
143
- if self._watch_new_files:
144
- new_files = mod_times.keys() - self._init_times.keys()
145
- for file in new_files:
146
- self.print_out_dark(f"{label} [+] New file detected: {file}")
147
- self.set_task_xcom("new-file", file)
148
- self.set_task_xcom("file", file)
149
- return True
150
- if self._watch_deleted_files:
151
- deleted_files = self._init_times.keys() - mod_times.keys()
152
- for file in deleted_files:
153
- self.print_out_dark(f"{label} [-] File deleted: {file}")
154
- self.set_task_xcom("deleted-file", file)
155
- self.set_task_xcom("file", file)
156
- return True
157
- if self._watch_modified_files:
158
- modified_files = {
159
- file
160
- for file, mod_time in mod_times.items()
161
- if file in mod_times and self._init_times[file] != mod_time
162
- }
163
- for file in modified_files:
164
- self.print_out_dark(f"{label} [/] File modified: {file}")
165
- self.set_task_xcom("modified-file", file)
166
- self.set_task_xcom("file", file)
167
- return True
168
- self.show_progress(f"{label} (Nothing changed)")
169
- return False
151
+ def create_loop_inspector(self) -> Callable[..., Optional[bool]]:
152
+ def loop_inspect() -> bool:
153
+ label = f"Watching {self._rendered_path}"
154
+ identifier = self.get_identifier()
155
+ try:
156
+ init_times = self.__init_times[identifier]
157
+ mod_times = self._get_mod_times()
158
+ except Exception as e:
159
+ self.show_progress(f"{label} Cannot inspect")
160
+ raise e
161
+ # watch changes
162
+ if self._watch_new_files:
163
+ new_files = mod_times.keys() - init_times.keys()
164
+ for file in new_files:
165
+ self.print_out_dark(f"{label} [+] New file detected: {file}")
166
+ self.set_task_xcom("new-file", file)
167
+ self.set_task_xcom("file", file)
168
+ self.__init_times[identifier] = self._get_mod_times()
169
+ return True
170
+ if self._watch_deleted_files:
171
+ deleted_files = init_times.keys() - mod_times.keys()
172
+ for file in deleted_files:
173
+ self.print_out_dark(f"{label} [-] File deleted: {file}")
174
+ self.set_task_xcom("deleted-file", file)
175
+ self.set_task_xcom("file", file)
176
+ self.__init_times[identifier] = self._get_mod_times()
177
+ return True
178
+ if self._watch_modified_files:
179
+ modified_files = {
180
+ file
181
+ for file, mod_time in mod_times.items()
182
+ if file in mod_times and init_times[file] != mod_time
183
+ }
184
+ for file in modified_files:
185
+ self.print_out_dark(f"{label} [/] File modified: {file}")
186
+ self.set_task_xcom("modified-file", file)
187
+ self.set_task_xcom("file", file)
188
+ self.__init_times[identifier] = self._get_mod_times()
189
+ return True
190
+ self.show_progress(f"{label} (Nothing changed)")
191
+ return False
192
+
193
+ return loop_inspect
170
194
 
171
195
  def _get_mod_times(self) -> Mapping[str, float]:
172
196
  matches = get_file_names(
zrb/task/port_checker.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import socket
2
2
 
3
+ from zrb.helper.accessories.color import colored
4
+ from zrb.helper.log import logger
3
5
  from zrb.helper.typecheck import typechecked
4
6
  from zrb.helper.typing import (
5
7
  Any,
@@ -26,6 +28,8 @@ from zrb.task_env.env_file import EnvFile
26
28
  from zrb.task_group.group import Group
27
29
  from zrb.task_input.any_input import AnyInput
28
30
 
31
+ logger.debug(colored("Loading zrb.task.port_checker", attrs=["dark"]))
32
+
29
33
  TPortChecker = TypeVar("TPortChecker", bound="PortChecker")
30
34
 
31
35
 
@@ -105,8 +109,17 @@ class PortChecker(Checker):
105
109
  raise_error: bool = True,
106
110
  is_async: bool = False,
107
111
  show_done_info: bool = True,
112
+ should_clear_xcom: bool = False,
113
+ should_stop_looper: bool = False,
108
114
  ) -> Callable[..., bool]:
109
- return super().to_function(env_prefix, raise_error, is_async, show_done_info)
115
+ return super().to_function(
116
+ env_prefix=env_prefix,
117
+ raise_error=raise_error,
118
+ is_async=is_async,
119
+ show_done_info=show_done_info,
120
+ should_clear_xcom=should_clear_xcom,
121
+ should_stop_looper=should_stop_looper,
122
+ )
110
123
 
111
124
  async def run(self, *args: Any, **kwargs: Any) -> bool:
112
125
  self._config = PortConfig(
@@ -1,7 +1,9 @@
1
1
  import asyncio
2
2
  import copy
3
3
 
4
+ from zrb.helper.accessories.color import colored
4
5
  from zrb.helper.accessories.name import get_random_name
6
+ from zrb.helper.log import logger
5
7
  from zrb.helper.typecheck import typechecked
6
8
  from zrb.helper.typing import Any, Callable, Iterable, List, Mapping, Optional, Union
7
9
  from zrb.task.any_task import AnyTask
@@ -20,6 +22,8 @@ from zrb.task_env.env_file import EnvFile
20
22
  from zrb.task_group.group import Group
21
23
  from zrb.task_input.any_input import AnyInput
22
24
 
25
+ logger.debug(colored("Loading zrb.task.recurring_task", attrs=["dark"]))
26
+
23
27
 
24
28
  class RunConfig:
25
29
  def __init__(
@@ -111,6 +115,7 @@ class RecurringTask(BaseTask):
111
115
  self._triggers: List[AnyTask] = [trigger.copy() for trigger in triggers]
112
116
  self._run_configs: List[RunConfig] = []
113
117
  self._single_execution = single_execution
118
+ self.print_err("Deprecated, please use Server instead")
114
119
 
115
120
  async def _set_keyval(self, kwargs: Mapping[str, Any], env_prefix: str):
116
121
  await super()._set_keyval(kwargs=kwargs, env_prefix=env_prefix)
@@ -1,6 +1,8 @@
1
1
  import os
2
2
  import pathlib
3
3
 
4
+ from zrb.helper.accessories.color import colored
5
+ from zrb.helper.log import logger
4
6
  from zrb.helper.typecheck import typechecked
5
7
  from zrb.helper.typing import Any, Callable, Iterable, Optional, Union
6
8
  from zrb.task.any_task import AnyTask
@@ -20,6 +22,8 @@ from zrb.task_env.env_file import EnvFile
20
22
  from zrb.task_group.group import Group
21
23
  from zrb.task_input.any_input import AnyInput
22
24
 
25
+ logger.debug(colored("Loading zrb.task.remote_cmd_task", attrs=["dark"]))
26
+
23
27
  _CURRENT_DIR = os.path.dirname(__file__)
24
28
  _SHELL_SCRIPT_DIR = os.path.join(_CURRENT_DIR, "..", "shell-scripts")
25
29
  with open(os.path.join(_SHELL_SCRIPT_DIR, "ssh-util.sh")) as file:
@@ -1,4 +1,6 @@
1
+ from zrb.helper.accessories.color import colored
1
2
  from zrb.helper.file.copy_tree import copy_tree
3
+ from zrb.helper.log import logger
2
4
  from zrb.helper.typecheck import typechecked
3
5
  from zrb.helper.typing import (
4
6
  Any,
@@ -35,6 +37,8 @@ from zrb.task_env.env_file import EnvFile
35
37
  from zrb.task_group.group import Group
36
38
  from zrb.task_input.any_input import AnyInput
37
39
 
40
+ logger.debug(colored("Loading zrb.task.resource_maker", attrs=["dark"]))
41
+
38
42
  Replacement = Mapping[str, JinjaTemplate]
39
43
  ReplacementMutator = Callable[[AnyTask, Replacement], Replacement]
40
44
  TResourceMaker = TypeVar("TResourceMaker", bound="ResourceMaker")
@@ -140,8 +144,17 @@ class ResourceMaker(BaseTask):
140
144
  raise_error: bool = True,
141
145
  is_async: bool = False,
142
146
  show_done_info: bool = True,
147
+ should_clear_xcom: bool = False,
148
+ should_stop_looper: bool = False,
143
149
  ) -> Callable[..., bool]:
144
- return super().to_function(env_prefix, raise_error, is_async, show_done_info)
150
+ return super().to_function(
151
+ env_prefix=env_prefix,
152
+ raise_error=raise_error,
153
+ is_async=is_async,
154
+ show_done_info=show_done_info,
155
+ should_clear_xcom=should_clear_xcom,
156
+ should_stop_looper=should_stop_looper,
157
+ )
145
158
 
146
159
  async def run(self, *args: Any, **kwargs: Any) -> bool:
147
160
  # render parameters
zrb/task/rsync_task.py CHANGED
@@ -1,6 +1,8 @@
1
1
  import os
2
2
  import pathlib
3
3
 
4
+ from zrb.helper.accessories.color import colored
5
+ from zrb.helper.log import logger
4
6
  from zrb.helper.typecheck import typechecked
5
7
  from zrb.helper.typing import Any, Callable, Iterable, JinjaTemplate, Optional, Union
6
8
  from zrb.task.any_task import AnyTask
@@ -20,6 +22,8 @@ from zrb.task_env.env_file import EnvFile
20
22
  from zrb.task_group.group import Group
21
23
  from zrb.task_input.any_input import AnyInput
22
24
 
25
+ logger.debug(colored("Loading zrb.task.rsync_task", attrs=["dark"]))
26
+
23
27
  _CURRENT_DIR = os.path.dirname(__file__)
24
28
  _SHELL_SCRIPT_DIR = os.path.join(_CURRENT_DIR, "..", "shell-scripts")
25
29
  with open(os.path.join(_SHELL_SCRIPT_DIR, "rsync-util.sh")) as file:
zrb/task/server.py ADDED
@@ -0,0 +1,190 @@
1
+ import asyncio
2
+
3
+ from zrb.helper.accessories.color import colored
4
+ from zrb.helper.accessories.name import get_random_name
5
+ from zrb.helper.log import logger
6
+ from zrb.helper.typecheck import typechecked
7
+ from zrb.helper.typing import Any, Callable, Iterable, List, Mapping, Optional, Union
8
+ from zrb.helper.util import to_kebab_case
9
+ from zrb.task.any_task import AnyTask
10
+ from zrb.task.any_task_event_handler import (
11
+ OnFailed,
12
+ OnReady,
13
+ OnRetry,
14
+ OnSkipped,
15
+ OnStarted,
16
+ OnTriggered,
17
+ OnWaiting,
18
+ )
19
+ from zrb.task.base_task.base_task import BaseTask
20
+ from zrb.task.flow_task import FlowTask
21
+ from zrb.task_env.env import Env
22
+ from zrb.task_env.env_file import EnvFile
23
+ from zrb.task_group.group import Group
24
+ from zrb.task_input.any_input import AnyInput
25
+
26
+ logger.debug(colored("Loading zrb.task.server", attrs=["dark"]))
27
+
28
+
29
+ @typechecked
30
+ class Controller:
31
+ def __init__(
32
+ self,
33
+ trigger: Union[AnyTask, List[AnyTask]],
34
+ action: Union[AnyTask, List[AnyTask]],
35
+ name: Optional[str] = None,
36
+ ):
37
+ self._name = get_random_name() if name is None else name
38
+ self._triggers = [trigger] if isinstance(trigger, AnyTask) else trigger
39
+ self._actions = [action] if isinstance(action, AnyTask) else action
40
+ self._args: List[Any] = []
41
+ self._kwargs: Mapping[str, Any] = {}
42
+ self._inputs: List[AnyInput] = []
43
+ self._envs: List[Env] = []
44
+ self._env_files: List[EnvFile] = []
45
+
46
+ def set_args(self, args: List[Any]):
47
+ self._args = args
48
+
49
+ def set_kwargs(self, kwargs: Mapping[str, Any]):
50
+ self._kwargs = kwargs
51
+
52
+ def set_inputs(self, inputs: List[AnyInput]):
53
+ self._inputs = inputs
54
+
55
+ def set_envs(self, envs: List[Env]):
56
+ self._envs = envs
57
+
58
+ def set_env_files(self, env_files: List[EnvFile]):
59
+ self._env_files = env_files
60
+
61
+ def get_sub_env_files(self) -> Iterable[EnvFile]:
62
+ env_files = []
63
+ for trigger in self._triggers:
64
+ env_files += trigger.copy()._get_env_files()
65
+ for action in self._actions:
66
+ env_files += action.copy()._get_env_files()
67
+ return env_files
68
+
69
+ def get_sub_envs(self) -> Iterable[Env]:
70
+ envs = []
71
+ for trigger in self._triggers:
72
+ envs += trigger.copy()._get_envs()
73
+ for action in self._actions:
74
+ envs += action.copy()._get_envs()
75
+ return envs
76
+
77
+ def get_sub_inputs(self) -> Iterable[AnyInput]:
78
+ inputs = []
79
+ for trigger in self._triggers:
80
+ inputs += trigger.copy()._get_combined_inputs()
81
+ for action in self._actions:
82
+ inputs += action.copy()._get_combined_inputs()
83
+ return inputs
84
+
85
+ def to_function(self) -> Callable[..., Any]:
86
+ task = self._get_task()
87
+
88
+ async def fn() -> Any:
89
+ task_fn = task.to_function(is_async=True)
90
+ return await task_fn(*self._args, **self._kwargs)
91
+
92
+ return fn
93
+
94
+ def _get_task(self) -> AnyTask:
95
+ actions = [action.copy() for action in self._actions]
96
+ actions.insert(0, self._get_remonitor_task())
97
+ triggers = [trigger.copy() for trigger in self._triggers]
98
+ task: AnyTask = FlowTask(
99
+ name=to_kebab_case(self._name),
100
+ inputs=self._inputs,
101
+ envs=self._envs,
102
+ env_files=self._env_files,
103
+ steps=[triggers, actions],
104
+ )
105
+ return task
106
+
107
+ def _get_remonitor_task(self) -> AnyTask:
108
+ async def on_ready(task: AnyTask):
109
+ task = self._get_task()
110
+ fn = task.to_function(is_async=True)
111
+ await fn()
112
+
113
+ return BaseTask(
114
+ name=f"monitor-{to_kebab_case(self._name)}",
115
+ on_ready=on_ready,
116
+ )
117
+
118
+
119
+ @typechecked
120
+ class Server(BaseTask):
121
+
122
+ def __init__(
123
+ self,
124
+ name: str,
125
+ controllers: List[Controller],
126
+ group: Optional[Group] = None,
127
+ inputs: Iterable[AnyInput] = [],
128
+ envs: Iterable[Env] = [],
129
+ env_files: Iterable[EnvFile] = [],
130
+ icon: Optional[str] = None,
131
+ color: Optional[str] = None,
132
+ description: str = "",
133
+ upstreams: Iterable[AnyTask] = [],
134
+ fallbacks: Iterable[AnyTask] = [],
135
+ on_triggered: Optional[OnTriggered] = None,
136
+ on_waiting: Optional[OnWaiting] = None,
137
+ on_skipped: Optional[OnSkipped] = None,
138
+ on_started: Optional[OnStarted] = None,
139
+ on_ready: Optional[OnReady] = None,
140
+ on_retry: Optional[OnRetry] = None,
141
+ on_failed: Optional[OnFailed] = None,
142
+ checkers: Iterable[AnyTask] = [],
143
+ checking_interval: float = 0,
144
+ retry: int = 0,
145
+ retry_interval: float = 1,
146
+ should_execute: Union[bool, str, Callable[..., bool]] = True,
147
+ return_upstream_result: bool = False,
148
+ ):
149
+ inputs, envs, env_files = list(inputs), list(envs), list(env_files)
150
+ for controller in controllers:
151
+ inputs += controller.get_sub_inputs()
152
+ envs += controller.get_sub_envs()
153
+ env_files += controller.get_sub_env_files()
154
+ BaseTask.__init__(
155
+ self,
156
+ name=name,
157
+ group=group,
158
+ inputs=inputs,
159
+ envs=envs,
160
+ env_files=env_files,
161
+ icon=icon,
162
+ color=color,
163
+ description=description,
164
+ upstreams=upstreams,
165
+ fallbacks=fallbacks,
166
+ on_triggered=on_triggered,
167
+ on_waiting=on_waiting,
168
+ on_skipped=on_skipped,
169
+ on_started=on_started,
170
+ on_ready=on_ready,
171
+ on_retry=on_retry,
172
+ on_failed=on_failed,
173
+ checkers=checkers,
174
+ checking_interval=checking_interval,
175
+ retry=retry,
176
+ retry_interval=retry_interval,
177
+ should_execute=should_execute,
178
+ return_upstream_result=return_upstream_result,
179
+ )
180
+ self._controllers = controllers
181
+
182
+ async def run(self, *args: Any, **kwargs: Any):
183
+ for controller in self._controllers:
184
+ controller.set_envs(self._get_envs())
185
+ controller.set_env_files(self._get_env_files())
186
+ controller.set_inputs(self._get_inputs())
187
+ controller.set_args(args)
188
+ controller.set_kwargs(kwargs)
189
+ functions = [controller.to_function() for controller in self._controllers]
190
+ await asyncio.gather(*[fn() for fn in functions])
zrb/task/task.py CHANGED
@@ -1,6 +1,10 @@
1
+ from zrb.helper.accessories.color import colored
2
+ from zrb.helper.log import logger
1
3
  from zrb.helper.typecheck import typechecked
2
4
  from zrb.task.base_task.base_task import BaseTask
3
5
 
6
+ logger.debug(colored("Loading zrb.task.task", attrs=["dark"]))
7
+
4
8
 
5
9
  @typechecked
6
10
  class Task(BaseTask):