zrb 0.17.2__py3-none-any.whl → 0.21.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 (59) hide show
  1. zrb/__init__.py +2 -0
  2. zrb/builtin/project/add/app/generator/generator.py +1 -0
  3. zrb/builtin/project/add/app/generator/template/src/kebab-zrb-package-name/src/snake_zrb_package_name/snake_zrb_generator_name/_input.py +7 -4
  4. zrb/builtin/project/add/app/generator/template/src/kebab-zrb-package-name/src/snake_zrb_package_name/snake_zrb_generator_name/snake_zrb_generator_name.py +1 -0
  5. zrb/builtin/project/add/app/python/python.py +1 -0
  6. zrb/builtin/project/add/fastapp/app/_input.py +8 -4
  7. zrb/builtin/project/add/fastapp/app/app.py +1 -0
  8. zrb/builtin/project/add/fastapp/app/template/src/kebab-zrb-app-name/src/component/rpc/messagebus/caller.py +1 -1
  9. zrb/builtin/project/add/fastapp/crud/_input.py +2 -1
  10. zrb/builtin/project/add/fastapp/crud/crud.py +1 -0
  11. zrb/builtin/project/add/fastapp/crud/nodejs/codemod/package-lock.json +33 -24
  12. zrb/builtin/project/add/fastapp/field/field.py +1 -0
  13. zrb/builtin/project/add/plugin/plugin.py +5 -1
  14. zrb/builtin/project/add/task/cmd/add.py +1 -0
  15. zrb/builtin/project/add/task/docker_compose/add.py +1 -0
  16. zrb/builtin/project/add/task/python/add.py +1 -0
  17. zrb/config/config.py +1 -0
  18. zrb/helper/multiline.py +13 -0
  19. zrb/task/any_task.py +10 -3
  20. zrb/task/base_remote_cmd_task.py +66 -8
  21. zrb/task/base_task/base_task.py +10 -12
  22. zrb/task/base_task/component/base_task_model.py +1 -1
  23. zrb/task/base_task/component/common_task_model.py +35 -4
  24. zrb/task/checker.py +1 -1
  25. zrb/task/cmd_task.py +22 -9
  26. zrb/task/decorator.py +1 -1
  27. zrb/task/docker_compose_task.py +1 -1
  28. zrb/task/flow_task.py +45 -34
  29. zrb/task/http_checker.py +1 -1
  30. zrb/task/notifier.py +1 -1
  31. zrb/task/path_checker.py +1 -1
  32. zrb/task/path_watcher.py +1 -1
  33. zrb/task/port_checker.py +1 -1
  34. zrb/task/recurring_task.py +2 -2
  35. zrb/task/remote_cmd_task.py +1 -1
  36. zrb/task/resource_maker.py +1 -1
  37. zrb/task/rsync_task.py +5 -5
  38. zrb/task/server.py +25 -18
  39. zrb/task/task.py +35 -1
  40. zrb/task/time_watcher.py +1 -1
  41. zrb/task/watcher.py +5 -2
  42. zrb/task_env/env.py +4 -3
  43. zrb/task_env/env_file.py +3 -2
  44. zrb/task_group/group.py +1 -1
  45. zrb/task_input/any_input.py +5 -3
  46. zrb/task_input/base_input.py +54 -9
  47. zrb/task_input/bool_input.py +9 -6
  48. zrb/task_input/choice_input.py +8 -5
  49. zrb/task_input/float_input.py +8 -5
  50. zrb/task_input/int_input.py +8 -5
  51. zrb/task_input/multiline_input.py +118 -0
  52. zrb/task_input/password_input.py +9 -6
  53. zrb/task_input/str_input.py +18 -15
  54. zrb/task_input/task_input.py +4 -3
  55. {zrb-0.17.2.dist-info → zrb-0.21.0.dist-info}/METADATA +14 -11
  56. {zrb-0.17.2.dist-info → zrb-0.21.0.dist-info}/RECORD +59 -57
  57. {zrb-0.17.2.dist-info → zrb-0.21.0.dist-info}/LICENSE +0 -0
  58. {zrb-0.17.2.dist-info → zrb-0.21.0.dist-info}/WHEEL +0 -0
  59. {zrb-0.17.2.dist-info → zrb-0.21.0.dist-info}/entry_points.txt +0 -0
zrb/__init__.py CHANGED
@@ -45,6 +45,7 @@ from zrb.task_input.bool_input import BoolInput
45
45
  from zrb.task_input.choice_input import ChoiceInput
46
46
  from zrb.task_input.float_input import FloatInput
47
47
  from zrb.task_input.int_input import IntInput
48
+ from zrb.task_input.multiline_input import MultilineInput
48
49
  from zrb.task_input.password_input import PasswordInput
49
50
  from zrb.task_input.str_input import StrInput
50
51
  from zrb.task_input.task_input import Input
@@ -93,6 +94,7 @@ assert BoolInput
93
94
  assert ChoiceInput
94
95
  assert FloatInput
95
96
  assert IntInput
97
+ assert MultilineInput
96
98
  assert PasswordInput
97
99
  assert StrInput
98
100
  assert Env
@@ -26,6 +26,7 @@ _CURRENT_DIR = os.path.dirname(__file__)
26
26
  @python_task(
27
27
  name="validate",
28
28
  inputs=[project_dir_input, package_name_input],
29
+ retry=0,
29
30
  )
30
31
  async def validate(*args: Any, **kwargs: Any):
31
32
  project_dir = kwargs.get("project_dir")
@@ -1,5 +1,6 @@
1
1
  import os
2
2
 
3
+ from zrb.helper.util import coalesce, to_kebab_case, to_snake_case
3
4
  from zrb.task_input.int_input import IntInput
4
5
  from zrb.task_input.str_input import StrInput
5
6
 
@@ -41,9 +42,9 @@ app_image_name_input = StrInput(
41
42
  name="app-image-name",
42
43
  description="App image name",
43
44
  prompt="App image name",
44
- default=app_image_default_namespace
45
- + "/"
46
- + "{{util.to_kebab_case(input.app_name)}}", # noqa
45
+ default=lambda m: "/".join(
46
+ [app_image_default_namespace, to_kebab_case(m.get("app_name"))]
47
+ ),
47
48
  )
48
49
 
49
50
  http_port_input = IntInput(
@@ -58,5 +59,7 @@ env_prefix_input = StrInput(
58
59
  name="env-prefix",
59
60
  description="OS environment prefix",
60
61
  prompt="OS environment prefix",
61
- default='{{util.to_snake_case(util.coalesce(input.app_name, input.task_name, "MY")).upper()}}', # noqa
62
+ default=lambda m: to_snake_case(
63
+ coalesce(m.get("app_name"), m.get("task_name"), "MY")
64
+ ).upper(),
62
65
  )
@@ -32,6 +32,7 @@ _snake_app_name_tpl = "{{util.to_snake_case(input.app_name)}}"
32
32
  @python_task(
33
33
  name="validate",
34
34
  inputs=[project_dir_input, app_name_input],
35
+ retry=0,
35
36
  )
36
37
  async def validate(*args: Any, **kwargs: Any):
37
38
  project_dir = kwargs.get("project_dir")
@@ -31,6 +31,7 @@ _snake_app_name_tpl = "{{util.to_snake_case(input.app_name)}}"
31
31
  @python_task(
32
32
  name="validate",
33
33
  inputs=[project_dir_input, app_name_input],
34
+ retry=0,
34
35
  )
35
36
  async def validate(*args: Any, **kwargs: Any):
36
37
  project_dir = kwargs.get("project_dir")
@@ -1,5 +1,6 @@
1
1
  import os
2
2
 
3
+ from zrb.helper.util import coalesce, to_kebab_case, to_snake_case
3
4
  from zrb.task_input.int_input import IntInput
4
5
  from zrb.task_input.str_input import StrInput
5
6
 
@@ -37,13 +38,14 @@ app_description_input = StrInput(
37
38
  app_image_default_namespace = os.getenv(
38
39
  "PROJECT_IMAGE_DEFAULT_NAMESPACE", "docker.io/" + SYSTEM_USER
39
40
  )
41
+
40
42
  app_image_name_input = StrInput(
41
43
  name="app-image-name",
42
44
  description="App image name",
43
45
  prompt="App image name",
44
- default=app_image_default_namespace
45
- + "/"
46
- + "{{util.to_kebab_case(input.app_name)}}", # noqa
46
+ default=lambda m: "/".join(
47
+ [app_image_default_namespace, to_kebab_case(m.get("app_name"))]
48
+ ),
47
49
  )
48
50
 
49
51
  http_port_input = IntInput(
@@ -58,5 +60,7 @@ env_prefix_input = StrInput(
58
60
  name="env-prefix",
59
61
  description="OS environment prefix",
60
62
  prompt="OS environment prefix",
61
- default='{{util.to_snake_case(util.coalesce(input.app_name, input.task_name, "MY")).upper()}}', # noqa
63
+ default=lambda m: to_snake_case(
64
+ coalesce(m.get("app_name"), m.get("task_name"), "MY")
65
+ ).upper(),
62
66
  )
@@ -35,6 +35,7 @@ _snake_app_name_tpl = "{{util.to_snake_case(input.app_name)}}"
35
35
  @python_task(
36
36
  name="validate",
37
37
  inputs=[project_dir_input, app_name_input],
38
+ retry=0,
38
39
  )
39
40
  async def validate(*args: Any, **kwargs: Any):
40
41
  project_dir = kwargs.get("project_dir")
@@ -15,7 +15,7 @@ class MessagebusCaller(Caller):
15
15
  publisher: Publisher,
16
16
  consumer_factory: Callable[[], Consumer],
17
17
  timeout: float = 30,
18
- check_reply_interval: float = 0.1,
18
+ check_reply_interval: float = 0.05,
19
19
  ):
20
20
  self.logger = logger
21
21
  self.admin = admin
@@ -10,9 +10,10 @@ entity_name_input = StrInput(
10
10
 
11
11
  plural_entity_name_input = StrInput(
12
12
  name="plural-entity-name",
13
+ shortcut="p",
13
14
  description="Plural entity name",
14
15
  prompt="Plural entity name",
15
- default="books",
16
+ default=lambda m: m.get("entity_name") + "s",
16
17
  )
17
18
 
18
19
  main_column_name_input = StrInput(
@@ -35,6 +35,7 @@ _CODEMOD_DIR = os.path.join(_CURRENT_DIR, "nodejs", "codemod")
35
35
  @python_task(
36
36
  name="validate",
37
37
  inputs=[project_dir_input, app_name_input, module_name_input, entity_name_input],
38
+ retry=0,
38
39
  )
39
40
  async def validate(*args: Any, **kwargs: Any):
40
41
  project_dir = kwargs.get("project_dir")
@@ -60,10 +60,13 @@
60
60
  }
61
61
  },
62
62
  "node_modules/@types/node": {
63
- "version": "20.6.0",
64
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz",
65
- "integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==",
66
- "dev": true
63
+ "version": "20.14.2",
64
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
65
+ "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
66
+ "dev": true,
67
+ "dependencies": {
68
+ "undici-types": "~5.26.4"
69
+ }
67
70
  },
68
71
  "node_modules/balanced-match": {
69
72
  "version": "1.0.2",
@@ -79,11 +82,11 @@
79
82
  }
80
83
  },
81
84
  "node_modules/braces": {
82
- "version": "3.0.2",
83
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
84
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
85
+ "version": "3.0.3",
86
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
87
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
85
88
  "dependencies": {
86
- "fill-range": "^7.0.1"
89
+ "fill-range": "^7.1.1"
87
90
  },
88
91
  "engines": {
89
92
  "node": ">=8"
@@ -95,9 +98,9 @@
95
98
  "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w=="
96
99
  },
97
100
  "node_modules/fast-glob": {
98
- "version": "3.3.1",
99
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
100
- "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
101
+ "version": "3.3.2",
102
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
103
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
101
104
  "dependencies": {
102
105
  "@nodelib/fs.stat": "^2.0.2",
103
106
  "@nodelib/fs.walk": "^1.2.3",
@@ -110,17 +113,17 @@
110
113
  }
111
114
  },
112
115
  "node_modules/fastq": {
113
- "version": "1.15.0",
114
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
115
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
116
+ "version": "1.17.1",
117
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
118
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
116
119
  "dependencies": {
117
120
  "reusify": "^1.0.4"
118
121
  }
119
122
  },
120
123
  "node_modules/fill-range": {
121
- "version": "7.0.1",
122
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
123
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
124
+ "version": "7.1.1",
125
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
126
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
124
127
  "dependencies": {
125
128
  "to-regex-range": "^5.0.1"
126
129
  },
@@ -175,11 +178,11 @@
175
178
  }
176
179
  },
177
180
  "node_modules/micromatch": {
178
- "version": "4.0.5",
179
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
180
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
181
+ "version": "4.0.7",
182
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
183
+ "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
181
184
  "dependencies": {
182
- "braces": "^3.0.2",
185
+ "braces": "^3.0.3",
183
186
  "picomatch": "^2.3.1"
184
187
  },
185
188
  "engines": {
@@ -301,9 +304,9 @@
301
304
  }
302
305
  },
303
306
  "node_modules/typescript": {
304
- "version": "5.2.2",
305
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
306
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
307
+ "version": "5.4.5",
308
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
309
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
307
310
  "dev": true,
308
311
  "bin": {
309
312
  "tsc": "bin/tsc",
@@ -312,6 +315,12 @@
312
315
  "engines": {
313
316
  "node": ">=14.17"
314
317
  }
318
+ },
319
+ "node_modules/undici-types": {
320
+ "version": "5.26.5",
321
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
322
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
323
+ "dev": true
315
324
  }
316
325
  }
317
326
  }
@@ -32,6 +32,7 @@ from zrb.task.task import Task
32
32
  @python_task(
33
33
  name="validate",
34
34
  inputs=[project_dir_input, app_name_input, module_name_input, entity_name_input],
35
+ retry=0,
35
36
  )
36
37
  async def validate(*args: Any, **kwargs: Any):
37
38
  project_dir = kwargs.get("project_dir")
@@ -28,7 +28,11 @@ from zrb.task.task import Task
28
28
  _CURRENT_DIR = os.path.dirname(__file__)
29
29
 
30
30
 
31
- @python_task(name="validate", inputs=[project_dir_input, package_name_input])
31
+ @python_task(
32
+ name="validate",
33
+ inputs=[project_dir_input, package_name_input],
34
+ retry=0,
35
+ )
32
36
  async def validate(*args: Any, **kwargs: Any):
33
37
  project_dir = kwargs.get("project_dir")
34
38
  validate_existing_project_dir(project_dir)
@@ -23,6 +23,7 @@ _CURRENT_DIR = os.path.dirname(__file__)
23
23
  project_dir_input,
24
24
  task_name_input,
25
25
  ],
26
+ retry=0,
26
27
  )
27
28
  async def validate(*args: Any, **kwargs: Any):
28
29
  project_dir = kwargs.get("project_dir")
@@ -27,6 +27,7 @@ _CURRENT_DIR = os.path.dirname(__file__)
27
27
  project_dir_input,
28
28
  task_name_input,
29
29
  ],
30
+ retry=0,
30
31
  )
31
32
  async def validate(*args: Any, **kwargs: Any):
32
33
  project_dir = kwargs.get("project_dir")
@@ -23,6 +23,7 @@ _CURRENT_DIR = os.path.dirname(__file__)
23
23
  project_dir_input,
24
24
  task_name_input,
25
25
  ],
26
+ retry=0,
26
27
  )
27
28
  async def validate(*args: Any, **kwargs: Any):
28
29
  project_dir = kwargs.get("project_dir")
zrb/config/config.py CHANGED
@@ -32,6 +32,7 @@ def _get_default_tmp_dir() -> str:
32
32
 
33
33
  tmp_dir = os.getenv("ZRB_TMP_DIR", _get_default_tmp_dir())
34
34
  default_shell = os.getenv("ZRB_SHELL", _get_current_shell())
35
+ default_editor = os.getenv("ZRB_EDITOR", "nano")
35
36
  init_script_str = os.getenv("ZRB_INIT_SCRIPTS", "")
36
37
  init_scripts = init_script_str.split(":") if init_script_str != "" else []
37
38
  logging_level = untyped_to_logging_level(os.getenv("ZRB_LOGGING_LEVEL", "WARNING"))
@@ -0,0 +1,13 @@
1
+ import click
2
+
3
+ from zrb.helper.typecheck import typechecked
4
+
5
+
6
+ @typechecked
7
+ def edit(editor: str, mark_comment: str, text: str, extension: str = "txt") -> str:
8
+ result = click.edit(
9
+ text="\n".join([mark_comment, text]), editor=editor, extension=f".{extension}"
10
+ )
11
+ if result is None:
12
+ result = text
13
+ return "\n".join(result.split(mark_comment)).strip()
zrb/task/any_task.py CHANGED
@@ -25,11 +25,11 @@ TAnyTask = TypeVar("TAnyTask", bound="AnyTask")
25
25
 
26
26
  class AnyTask(ABC):
27
27
  """
28
- Contract/interface for all Zrb Task.
28
+ Abstraction for Zrb Task.
29
29
 
30
- This class acts as a template for creating new Zrb Task types.
30
+ This class acts as a template for creating new Task type.
31
31
 
32
- To define a new Zrb Task, you should extend this class and implement all its methods.
32
+ To define a new Task type, you should extend this class and implement all its methods.
33
33
  The easiest way to do so is by extending `Task`
34
34
  """
35
35
 
@@ -568,6 +568,13 @@ class AnyTask(ABC):
568
568
  """
569
569
  pass
570
570
 
571
+ @abstractmethod
572
+ def _lock_checkers(self):
573
+ """
574
+ Lock checkers so that it cannot be altered anymore
575
+ """
576
+ pass
577
+
571
578
  @abstractmethod
572
579
  def _lock_upstreams(self):
573
580
  """
@@ -1,4 +1,3 @@
1
- import copy
2
1
  import os
3
2
  import pathlib
4
3
 
@@ -50,8 +49,10 @@ class RemoteConfig:
50
49
  password: JinjaTemplate = "",
51
50
  ssh_key: JinjaTemplate = "",
52
51
  port: Union[int, JinjaTemplate] = 22,
52
+ name: Optional[str] = None,
53
53
  config_map: Optional[Mapping[str, JinjaTemplate]] = None,
54
54
  ):
55
+ self.name = name if name is not None else host
55
56
  self.host = host
56
57
  self.user = user
57
58
  self.password = password
@@ -91,7 +92,7 @@ class SingleBaseRemoteCmdTask(CmdTask):
91
92
  on_retry: Optional[OnRetry] = None,
92
93
  on_failed: Optional[OnFailed] = None,
93
94
  checkers: Iterable[AnyTask] = [],
94
- checking_interval: Union[float, int] = 0,
95
+ checking_interval: Union[float, int] = 0.05,
95
96
  retry: int = 2,
96
97
  retry_interval: Union[float, int] = 1,
97
98
  max_output_line: int = 1000,
@@ -146,7 +147,7 @@ class SingleBaseRemoteCmdTask(CmdTask):
146
147
  self._remote_config = remote_config
147
148
 
148
149
  def copy(self) -> TSingleBaseRemoteCmdTask:
149
- return copy.deepcopy(self)
150
+ return super().copy()
150
151
 
151
152
  def inject_envs(self):
152
153
  super().inject_envs()
@@ -227,6 +228,7 @@ class BaseRemoteCmdTask(BaseTask):
227
228
  post_cmd_path: CmdVal = "",
228
229
  cwd: Optional[Union[str, pathlib.Path]] = None,
229
230
  upstreams: Iterable[AnyTask] = [],
231
+ fallbacks: Iterable[AnyTask] = [],
230
232
  on_triggered: Optional[OnTriggered] = None,
231
233
  on_waiting: Optional[OnWaiting] = None,
232
234
  on_skipped: Optional[OnSkipped] = None,
@@ -235,7 +237,7 @@ class BaseRemoteCmdTask(BaseTask):
235
237
  on_retry: Optional[OnRetry] = None,
236
238
  on_failed: Optional[OnFailed] = None,
237
239
  checkers: Iterable[AnyTask] = [],
238
- checking_interval: Union[float, int] = 0,
240
+ checking_interval: Union[float, int] = 0.05,
239
241
  retry: int = 2,
240
242
  retry_interval: Union[float, int] = 1,
241
243
  max_output_line: int = 1000,
@@ -247,9 +249,10 @@ class BaseRemoteCmdTask(BaseTask):
247
249
  should_show_cmd: bool = True,
248
250
  should_show_working_directory: bool = True,
249
251
  ):
250
- sub_tasks = [
252
+ self._remote_configs = list(remote_configs)
253
+ self._sub_tasks = [
251
254
  SingleBaseRemoteCmdTask(
252
- name=f"{name}-{remote_config.host}",
255
+ name=f"{name}-{remote_config.name}",
253
256
  remote_config=remote_config,
254
257
  inputs=inputs,
255
258
  envs=envs,
@@ -264,6 +267,7 @@ class BaseRemoteCmdTask(BaseTask):
264
267
  post_cmd_path=post_cmd_path,
265
268
  cwd=cwd,
266
269
  upstreams=upstreams,
270
+ fallbacks=fallbacks,
267
271
  on_triggered=on_triggered,
268
272
  on_waiting=on_waiting,
269
273
  on_skipped=on_skipped,
@@ -284,7 +288,7 @@ class BaseRemoteCmdTask(BaseTask):
284
288
  should_show_cmd=should_show_cmd,
285
289
  should_show_working_directory=should_show_working_directory,
286
290
  )
287
- for remote_config in list(remote_configs)
291
+ for remote_config in self._remote_configs
288
292
  ]
289
293
  BaseTask.__init__(
290
294
  self,
@@ -293,7 +297,61 @@ class BaseRemoteCmdTask(BaseTask):
293
297
  color=color,
294
298
  group=group,
295
299
  description=description,
296
- upstreams=sub_tasks,
300
+ upstreams=self._sub_tasks,
297
301
  retry=0,
298
302
  return_upstream_result=True,
299
303
  )
304
+
305
+ def insert_input(self, *inputs: AnyInput):
306
+ super().insert_input(*inputs)
307
+ for subtask in self._sub_tasks:
308
+ subtask.insert_input(*inputs)
309
+
310
+ def add_input(self, *inputs: AnyInput):
311
+ super().add_input(*inputs)
312
+ for subtask in self._sub_tasks:
313
+ subtask.add_input(*inputs)
314
+
315
+ def insert_env(self, *envs: Env):
316
+ super().insert_env(*envs)
317
+ for subtask in self._sub_tasks:
318
+ subtask.insert_env(*envs)
319
+
320
+ def add_env(self, *envs: Env):
321
+ super().add_env(*envs)
322
+ for subtask in self._sub_tasks:
323
+ subtask.add_env(*envs)
324
+
325
+ def insert_env_file(self, *env_files: EnvFile):
326
+ super().insert_env_file(*env_files)
327
+ for subtask in self._sub_tasks:
328
+ subtask.insert_env_file(*env_files)
329
+
330
+ def add_env_file(self, *env_files: Env):
331
+ super().add_env_file(*env_files)
332
+ for subtask in self._sub_tasks:
333
+ subtask.add_env_file(*env_files)
334
+
335
+ def insert_upstream(self, *upstreams: AnyTask):
336
+ for subtask in self._sub_tasks:
337
+ subtask.insert_upstream(*upstreams)
338
+
339
+ def add_upstream(self, *upstreams: AnyTask):
340
+ for subtask in self._sub_tasks:
341
+ subtask.add_upstream(*upstreams)
342
+
343
+ def insert_fallback(self, *fallbacks: AnyTask):
344
+ for subtask in self._sub_tasks:
345
+ subtask.insert_fallbacks(*fallbacks)
346
+
347
+ def add_fallback(self, *fallbacks: AnyTask):
348
+ for subtask in self._sub_tasks:
349
+ subtask.add_fallback(*fallbacks)
350
+
351
+ def insert_checker(self, *checkers: AnyTask):
352
+ for subtask in self._sub_tasks:
353
+ subtask.insert_checkers(*checkers)
354
+
355
+ def add_checker(self, *checkers: AnyTask):
356
+ for subtask in self._sub_tasks:
357
+ subtask.add_checker(*checkers)
@@ -37,8 +37,8 @@ from zrb.task_input.any_input import AnyInput
37
37
  @typechecked
38
38
  class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
39
39
  """
40
- Base class for all tasks.
41
- Every task definition should be extended from this class.
40
+ Base class for all Tasks.
41
+ Every Task definition should be extended from this class.
42
42
  """
43
43
 
44
44
  __running_tasks: List[AnyTask] = []
@@ -58,7 +58,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
58
58
  upstreams: Iterable[AnyTask] = [],
59
59
  fallbacks: Iterable[AnyTask] = [],
60
60
  checkers: Iterable[AnyTask] = [],
61
- checking_interval: Union[float, int] = 0,
61
+ checking_interval: Union[float, int] = 0.05,
62
62
  run: Optional[Callable[..., Any]] = None,
63
63
  on_triggered: Optional[OnTriggered] = None,
64
64
  on_waiting: Optional[OnWaiting] = None,
@@ -72,7 +72,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
72
72
  ):
73
73
  # init properties
74
74
  retry_interval = retry_interval if retry_interval >= 0 else 0
75
- checking_interval = checking_interval if checking_interval > 0 else 0.05
75
+ checking_interval = checking_interval if checking_interval > 0 else 0
76
76
  retry = retry if retry >= 0 else 0
77
77
  # init parent classes
78
78
  FinishTracker.__init__(self, checking_interval=checking_interval)
@@ -270,18 +270,17 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
270
270
  new_kwargs = self.get_input_map()
271
271
  # make sure args and kwargs['_args'] are the same
272
272
  self.log_info("Set run args")
273
- new_args = copy.deepcopy(args)
273
+ new_args = list(args)
274
274
  if len(args) == 0 and "_args" in kwargs:
275
275
  new_args = kwargs["_args"]
276
- new_kwargs["_args"] = new_args
277
- # inject self as input_map['_task']
278
- new_kwargs["_task"] = self
279
276
  self._set_args(new_args)
280
277
  self._set_kwargs(new_kwargs)
281
278
  # run the task
282
279
  coroutines = [
283
280
  asyncio.create_task(self._loop_check(show_done_info=show_done_info)),
284
- asyncio.create_task(self._run_all(*new_args, **new_kwargs)),
281
+ asyncio.create_task(
282
+ self._run_all(*new_args, _args=new_args, _task=self, **new_kwargs)
283
+ ),
285
284
  ]
286
285
  results = await asyncio.gather(*coroutines)
287
286
  result = results[-1]
@@ -456,7 +455,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
456
455
  # set current task local keyval
457
456
  await self._set_local_keyval(kwargs=kwargs, env_prefix=env_prefix)
458
457
  # get new_kwargs for upstream and checkers
459
- new_kwargs = copy.deepcopy(kwargs)
458
+ new_kwargs = {key: kwargs[key] for key in kwargs}
460
459
  new_kwargs.update(self.get_input_map())
461
460
  upstream_coroutines = []
462
461
  # set upstreams keyval
@@ -468,10 +467,9 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
468
467
  )
469
468
  )
470
469
  # set checker keyval
470
+ self._lock_checkers()
471
471
  checker_coroutines = []
472
472
  for checker_task in self._get_checkers():
473
- checker_task.add_input(*self._get_inputs())
474
- checker_task.add_env(*self._get_envs())
475
473
  checker_coroutines.append(
476
474
  asyncio.create_task(
477
475
  checker_task._set_keyval(kwargs=new_kwargs, env_prefix=env_prefix)
@@ -58,7 +58,7 @@ class BaseTaskModel(CommonTaskModel, PidModel, TimeTracker):
58
58
  upstreams: Iterable[AnyTask] = [],
59
59
  fallbacks: Iterable[AnyTask] = [],
60
60
  checkers: Iterable[AnyTask] = [],
61
- checking_interval: Union[int, float] = 0,
61
+ checking_interval: Union[int, float] = 0.05,
62
62
  run: Optional[Callable[..., Any]] = None,
63
63
  on_triggered: Optional[OnTriggered] = None,
64
64
  on_waiting: Optional[OnWaiting] = None,