zrb 0.15.1__py3-none-any.whl → 0.17.2__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.
zrb/__init__.py CHANGED
@@ -32,8 +32,10 @@ from zrb.task.resource_maker import (
32
32
  get_default_resource_skip_parsing,
33
33
  )
34
34
  from zrb.task.rsync_task import RsyncTask
35
+ from zrb.task.server import Controller, Server
35
36
  from zrb.task.task import Task
36
37
  from zrb.task.time_watcher import TimeWatcher
38
+ from zrb.task.watcher import Watcher
37
39
  from zrb.task.wiki_task import create_wiki_tasks
38
40
  from zrb.task_env.env import Env
39
41
  from zrb.task_env.env_file import EnvFile
@@ -74,6 +76,9 @@ assert HTTPChecker
74
76
  assert PortChecker
75
77
  assert PathChecker
76
78
  assert PathWatcher
79
+ assert Controller
80
+ assert Server
81
+ assert Watcher
77
82
  assert TimeWatcher
78
83
  assert ResourceMaker
79
84
  assert FlowTask
zrb/action/runner.py CHANGED
@@ -110,7 +110,12 @@ class Runner:
110
110
 
111
111
  def __get_wrapped_task_function(self, task: AnyTask) -> Callable[..., Any]:
112
112
  def wrapped_function(*args: Any, **kwargs: Any) -> Any:
113
- function = task.to_function(env_prefix=self.__env_prefix, raise_error=True)
113
+ function = task.to_function(
114
+ env_prefix=self.__env_prefix,
115
+ raise_error=True,
116
+ should_clear_xcom=True,
117
+ should_stop_looper=True,
118
+ )
114
119
  try:
115
120
  function(*args, **kwargs)
116
121
  except Exception:
@@ -1,6 +1,4 @@
1
- from zrb.helper.typing import Any
2
1
  from zrb.task.cmd_task import CmdTask
3
- from zrb.task.decorator import python_task
4
2
  from zrb.task.notifier import Notifier
5
3
  from zrb.task.task import Task
6
4
  from zrb.task_input.str_input import StrInput
@@ -8,8 +6,6 @@ from zrb.task_input.str_input import StrInput
8
6
 
9
7
  def create_recurring_action(
10
8
  notif_title: str,
11
- trigger_caption: str,
12
- trigger_xcom_key: str,
13
9
  default_message: str = "👋",
14
10
  ) -> Task:
15
11
  # define inputs
@@ -23,16 +19,11 @@ def create_recurring_action(
23
19
  default="",
24
20
  prompt="Command to be executed",
25
21
  )
26
- # define tasks
27
- show_trigger_info = _create_show_trigger_info(
28
- trigger_caption=trigger_caption, trigger_xcom_key=trigger_xcom_key
29
- )
30
22
  run_command = CmdTask(
31
23
  name="run-command",
32
24
  icon="⚙️",
33
25
  color="blue",
34
26
  inputs=[command_input],
35
- upstreams=[show_trigger_info],
36
27
  should_execute='{{ input.command != "" }}',
37
28
  cmd="{{ input.command }}",
38
29
  )
@@ -43,7 +34,6 @@ def create_recurring_action(
43
34
  inputs=[message_input],
44
35
  title=notif_title,
45
36
  message="{{ input.message }}",
46
- upstreams=[show_trigger_info],
47
37
  should_execute='{{ input.message != "" }}',
48
38
  )
49
39
  # return aggregator task
@@ -53,16 +43,3 @@ def create_recurring_action(
53
43
  upstreams=[run_command, notify],
54
44
  retry=0,
55
45
  )
56
-
57
-
58
- def _create_show_trigger_info(trigger_caption: str, trigger_xcom_key: str) -> Task:
59
- @python_task(
60
- name="show-trigger-info",
61
- icon="🔍",
62
- color="magenta",
63
- )
64
- def show_trigger_info(*args: Any, **kwargs: Any):
65
- task: Task = kwargs.get("_task")
66
- task.print_out(f"{trigger_caption}: {task.get_xcom(trigger_xcom_key)}")
67
-
68
- return show_trigger_info
@@ -29,7 +29,6 @@ install_helix = FlowTask(
29
29
  run=write_config(
30
30
  template_file=os.path.join(
31
31
  _CURRENT_DIR,
32
- "helix",
33
32
  "resource",
34
33
  "themes",
35
34
  "gruvbox_transparent.toml", # noqa
@@ -41,9 +40,7 @@ install_helix = FlowTask(
41
40
  Task(
42
41
  name="configure-helix",
43
42
  run=write_config(
44
- template_file=os.path.join(
45
- _CURRENT_DIR, "helix", "resource", "config.toml"
46
- ),
43
+ template_file=os.path.join(_CURRENT_DIR, "resource", "config.toml"),
47
44
  config_file="~/.config/helix/config.toml",
48
45
  remove_old_config=True,
49
46
  ),
@@ -3,6 +3,7 @@ theme = "gruvbox_transparent"
3
3
  [editor]
4
4
  line-number = "relative"
5
5
  mouse = true
6
+ bufferline = "always"
6
7
 
7
8
  [editor.cursor-shape]
8
9
  insert = "bar"
@@ -16,4 +17,4 @@ enable = true
16
17
  hidden = false
17
18
  git-ignore = false
18
19
  git-global = false
19
- git-exclude = false
20
+ git-exclude = false
@@ -16,7 +16,7 @@ get_process_pid_by_name = CmdTask(
16
16
  prompt="Process name to be checked",
17
17
  )
18
18
  ],
19
- cmd="pgrep {{ input.name }}",
19
+ cmd='pgrep "{{ input.name }}" || exit 0',
20
20
  checking_interval=3,
21
21
  )
22
22
  runner.register(get_process_pid_by_name)
zrb/builtin/schedule.py CHANGED
@@ -1,10 +1,10 @@
1
1
  from zrb.builtin._helper.reccuring_action import create_recurring_action
2
2
  from zrb.runner import runner
3
- from zrb.task.recurring_task import RecurringTask
3
+ from zrb.task.server import Controller, Server
4
4
  from zrb.task.time_watcher import TimeWatcher
5
5
  from zrb.task_input.str_input import StrInput
6
6
 
7
- schedule = RecurringTask(
7
+ schedule = Server(
8
8
  name="schedule",
9
9
  icon="📅",
10
10
  color="yellow",
@@ -17,15 +17,19 @@ schedule = RecurringTask(
17
17
  description="Schedule cron pattern to show the message",
18
18
  ),
19
19
  ],
20
- triggers=[
21
- TimeWatcher(
22
- name="watch-time", color="cyan", icon="⏰", schedule="{{input.schedule}}"
20
+ controllers=[
21
+ Controller(
22
+ name="periodic",
23
+ trigger=TimeWatcher(
24
+ name="watch-time",
25
+ color="cyan",
26
+ icon="⏰",
27
+ schedule="{{input.schedule}}",
28
+ ),
29
+ action=create_recurring_action(
30
+ notif_title="Schedule",
31
+ ),
23
32
  )
24
33
  ],
25
- task=create_recurring_action(
26
- notif_title="Schedule",
27
- trigger_caption="Schedule",
28
- trigger_xcom_key="watch-time.scheduled-time",
29
- ),
30
34
  )
31
35
  runner.register(schedule)
@@ -1,10 +1,10 @@
1
1
  from zrb.builtin._helper.reccuring_action import create_recurring_action
2
2
  from zrb.runner import runner
3
3
  from zrb.task.path_watcher import PathWatcher
4
- from zrb.task.recurring_task import RecurringTask
4
+ from zrb.task.server import Controller, Server
5
5
  from zrb.task_input.str_input import StrInput
6
6
 
7
- watch_changes = RecurringTask(
7
+ watch_changes = Server(
8
8
  name="watch-changes",
9
9
  icon="🕵️",
10
10
  color="yellow",
@@ -23,19 +23,20 @@ watch_changes = RecurringTask(
23
23
  description="Ignored file pattern",
24
24
  ),
25
25
  ],
26
- triggers=[
27
- PathWatcher(
28
- name="watch-path",
29
- color="cyan",
30
- icon="👀",
31
- path="{{input.pattern}}",
32
- ignored_path="{{input.ignored_pattern}}",
26
+ controllers=[
27
+ Controller(
28
+ name="watch",
29
+ trigger=PathWatcher(
30
+ name="watch-path",
31
+ color="cyan",
32
+ icon="👀",
33
+ path="{{input.pattern}}",
34
+ ignored_path="{{input.ignored_pattern}}",
35
+ ),
36
+ action=create_recurring_action(
37
+ notif_title="Watch",
38
+ ),
33
39
  )
34
40
  ],
35
- task=create_recurring_action(
36
- notif_title="Watch",
37
- trigger_caption="File changes",
38
- trigger_xcom_key="watch-path.file",
39
- ),
40
41
  )
41
42
  runner.register(watch_changes)
zrb/helper/callable.py CHANGED
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import inspect
2
3
  from typing import Any, Callable
3
4
 
@@ -10,4 +11,6 @@ logger.debug(colored("Loading zrb.helper.callable", attrs=["dark"]))
10
11
  async def run_async(fn: Callable, *args: Any, **kwargs: Any) -> Any:
11
12
  if inspect.iscoroutinefunction(fn):
12
13
  return await fn(*args, **kwargs)
13
- return fn(*args, **kwargs)
14
+ coro = asyncio.to_thread(fn, *args, **kwargs)
15
+ task = asyncio.create_task(coro)
16
+ return await task
zrb/task/any_task.py CHANGED
@@ -25,14 +25,12 @@ TAnyTask = TypeVar("TAnyTask", bound="AnyTask")
25
25
 
26
26
  class AnyTask(ABC):
27
27
  """
28
- Abstract base class for defining tasks in a task management system.
28
+ Contract/interface for all Zrb Task.
29
29
 
30
- This class acts as a template for creating new task types. To define a new task,
31
- extend this class and implement all its abstract methods. The `AnyTask` class is
32
- considered atomic and is not broken into multiple interfaces.
30
+ This class acts as a template for creating new Zrb Task types.
33
31
 
34
- Subclasses should implement the abstract methods to define custom behavior for
35
- task execution, state transitions, and other functionalities.
32
+ To define a new Zrb Task, you should extend this class and implement all its methods.
33
+ The easiest way to do so is by extending `Task`
36
34
  """
37
35
 
38
36
  @abstractmethod
@@ -74,7 +72,7 @@ class AnyTask(ABC):
74
72
  Examples:
75
73
  >>> from zrb import Task
76
74
  >>> class MyTask(Task):
77
- >>> async def run(self, *args: Any, **kwargs: Any) -> int:
75
+ >>> def run(self, *args: Any, **kwargs: Any) -> int:
78
76
  >>> self.print_out('Doing some calculation')
79
77
  >>> return 42
80
78
  """
@@ -88,8 +86,7 @@ class AnyTask(ABC):
88
86
  Any other tasks depends on the current task, will be `started` once the current task is `ready`.
89
87
 
90
88
  This method should be implemented to define the criteria for considering the task
91
- `ready`. The specifics of this completion depend on the task's
92
- nature and the subclass implementation.
89
+ `ready`. The specifics of this completion depend on the task's nature and the subclass implementation.
93
90
 
94
91
  Returns:
95
92
  bool: True if the task is completed, False otherwise.
@@ -308,6 +305,7 @@ class AnyTask(ABC):
308
305
  is_async: bool = False,
309
306
  show_done_info: bool = True,
310
307
  should_clear_xcom: bool = False,
308
+ should_stop_looper: bool = False,
311
309
  ) -> Callable[..., Any]:
312
310
  """
313
311
  Converts the current task into a callable function.
@@ -26,6 +26,7 @@ from zrb.task.any_task_event_handler import (
26
26
  from zrb.task.base_task.component.base_task_model import BaseTaskModel
27
27
  from zrb.task.base_task.component.renderer import Renderer
28
28
  from zrb.task.base_task.component.trackers import AttemptTracker, FinishTracker
29
+ from zrb.task.looper import looper
29
30
  from zrb.task.parallel import AnyParallel
30
31
  from zrb.task_env.env import Env, PrivateEnv
31
32
  from zrb.task_env.env_file import EnvFile
@@ -71,10 +72,10 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
71
72
  ):
72
73
  # init properties
73
74
  retry_interval = retry_interval if retry_interval >= 0 else 0
74
- checking_interval = checking_interval if checking_interval > 0 else 0.1
75
+ checking_interval = checking_interval if checking_interval > 0 else 0.05
75
76
  retry = retry if retry >= 0 else 0
76
77
  # init parent classes
77
- FinishTracker.__init__(self)
78
+ FinishTracker.__init__(self, checking_interval=checking_interval)
78
79
  Renderer.__init__(self)
79
80
  AttemptTracker.__init__(self, retry=retry)
80
81
  BaseTaskModel.__init__(
@@ -140,7 +141,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
140
141
  xcom_dir = self.__get_xcom_dir()
141
142
  xcom_file = os.path.join(xcom_dir, key)
142
143
  with open(xcom_file, "w") as f:
143
- f.write(value)
144
+ f.write(f"{value}")
144
145
 
145
146
  def get_xcom(self, key: str) -> str:
146
147
  self.__ensure_xcom_dir_exists()
@@ -164,6 +165,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
164
165
  is_async: bool = False,
165
166
  show_done_info: bool = True,
166
167
  should_clear_xcom: bool = False,
168
+ should_stop_looper: bool = False,
167
169
  ) -> Callable[..., Any]:
168
170
  async def function(*args: Any, **kwargs: Any) -> Any:
169
171
  self.log_info("Copy task")
@@ -175,6 +177,8 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
175
177
  kwargs=kwargs,
176
178
  show_done_info=show_done_info,
177
179
  )
180
+ if should_stop_looper:
181
+ looper.stop()
178
182
  if should_clear_xcom:
179
183
  self_cp.clear_xcom()
180
184
  return result
@@ -229,7 +233,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
229
233
  await run_async(self._on_retry, self)
230
234
 
231
235
  async def check(self) -> bool:
232
- return await self._is_done()
236
+ return await run_async(self._is_done)
233
237
 
234
238
  def inject_envs(self):
235
239
  super().inject_envs()
@@ -311,7 +315,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
311
315
  if self.__is_check_triggered:
312
316
  self.log_debug("Waiting readiness flag to be set")
313
317
  while not self.__is_ready:
314
- await asyncio.sleep(0.1)
318
+ await asyncio.sleep(self._checking_interval)
315
319
  return True
316
320
  self.__is_check_triggered = True
317
321
  check_result = await self._check()
@@ -332,7 +336,7 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
332
336
  self.log_debug("Waiting execution to be started")
333
337
  while not self.__is_execution_started:
334
338
  # Don't start checking before the execution itself has been started
335
- await asyncio.sleep(0.05)
339
+ await asyncio.sleep(self._checking_interval / 2.0)
336
340
  check_coroutines: Iterable[asyncio.Task] = []
337
341
  for checker_task in self._get_checkers():
338
342
  checker_task._set_execution_id(self.get_execution_id())
@@ -2,7 +2,7 @@ import asyncio
2
2
  import time
3
3
 
4
4
  from zrb.helper.typecheck import typechecked
5
- from zrb.helper.typing import Optional
5
+ from zrb.helper.typing import Optional, Union
6
6
 
7
7
  LOG_NAME_LENGTH = 20
8
8
 
@@ -51,9 +51,10 @@ class AttemptTracker:
51
51
 
52
52
  @typechecked
53
53
  class FinishTracker:
54
- def __init__(self):
54
+ def __init__(self, checking_interval: Union[float, int]):
55
55
  self.__execution_queue: Optional[asyncio.Queue] = None
56
56
  self.__counter = 0
57
+ self.__checking_interval = checking_interval
57
58
 
58
59
  async def _mark_awaited(self):
59
60
  if self.__execution_queue is None:
@@ -69,5 +70,5 @@ class FinishTracker:
69
70
 
70
71
  async def _is_done(self) -> bool:
71
72
  while self.__execution_queue is None:
72
- await asyncio.sleep(0.05)
73
+ await asyncio.sleep(self.__checking_interval / 2.0)
73
74
  return await self.__execution_queue.get()
zrb/task/checker.py CHANGED
@@ -44,7 +44,7 @@ class Checker(BaseTask):
44
44
  on_ready: Optional[OnReady] = None,
45
45
  on_retry: Optional[OnRetry] = None,
46
46
  on_failed: Optional[OnFailed] = None,
47
- checking_interval: Union[int, float] = 0.1,
47
+ checking_interval: Union[int, float] = 0,
48
48
  progress_interval: Union[int, float] = 30,
49
49
  expected_result: bool = True,
50
50
  should_execute: Union[bool, str, Callable[..., bool]] = True,
@@ -83,15 +83,15 @@ class Checker(BaseTask):
83
83
  while True:
84
84
  self._should_show_progress = wait_time >= self._progress_interval
85
85
  inspect_result = await self.inspect(*args, **kwargs)
86
- if inspect_result == self._expected_result:
86
+ if inspect_result is not None and inspect_result == self._expected_result:
87
87
  return True
88
88
  if wait_time >= self._progress_interval:
89
89
  wait_time = 0
90
90
  await asyncio.sleep(self._checking_interval)
91
91
  wait_time += self._checking_interval
92
92
 
93
- async def inspect(self, *args: Any, **kwargs: Any) -> bool:
94
- return False
93
+ async def inspect(self, *args: Any, **kwargs: Any) -> Optional[bool]:
94
+ return None
95
95
 
96
96
  def show_progress(self, message: str):
97
97
  if self._should_show_progress:
zrb/task/cmd_task.py CHANGED
@@ -199,8 +199,17 @@ class CmdTask(BaseTask):
199
199
  raise_error: bool = True,
200
200
  is_async: bool = False,
201
201
  show_done_info: bool = True,
202
+ should_clear_xcom: bool = False,
203
+ should_stop_looper: bool = False,
202
204
  ) -> Callable[..., CmdResult]:
203
- return super().to_function(env_prefix, raise_error, is_async, show_done_info)
205
+ return super().to_function(
206
+ env_prefix=env_prefix,
207
+ raise_error=raise_error,
208
+ is_async=is_async,
209
+ show_done_info=show_done_info,
210
+ should_clear_xcom=should_clear_xcom,
211
+ should_stop_looper=should_stop_looper,
212
+ )
204
213
 
205
214
  def print_result(self, result: CmdResult):
206
215
  if not self._should_print_cmd_result or result.output == "":
zrb/task/decorator.py CHANGED
@@ -43,9 +43,9 @@ def python_task(
43
43
  on_retry: Optional[OnRetry] = None,
44
44
  on_failed: Optional[OnFailed] = None,
45
45
  checkers: Iterable[AnyTask] = [],
46
- checking_interval: float = 0.1,
46
+ checking_interval: Union[float, int] = 0,
47
47
  retry: int = 2,
48
- retry_interval: float = 1,
48
+ retry_interval: Union[float, int] = 1,
49
49
  should_execute: Union[bool, str, Callable[..., bool]] = True,
50
50
  return_upstream_result: bool = False,
51
51
  runner: Optional[Runner] = None,
@@ -115,9 +115,9 @@ class DockerComposeTask(CmdTask):
115
115
  on_retry: Optional[OnRetry] = None,
116
116
  on_failed: Optional[OnFailed] = None,
117
117
  checkers: Iterable[AnyTask] = [],
118
- checking_interval: float = 0.1,
118
+ checking_interval: Union[float, int] = 0,
119
119
  retry: int = 2,
120
- retry_interval: float = 1,
120
+ retry_interval: Union[float, int] = 1,
121
121
  max_output_line: int = 1000,
122
122
  max_error_line: int = 1000,
123
123
  preexec_fn: Optional[Callable[[], Any]] = os.setsid,
zrb/task/http_checker.py CHANGED
@@ -87,7 +87,7 @@ class HTTPChecker(Checker):
87
87
  on_ready: Optional[OnReady] = None,
88
88
  on_retry: Optional[OnRetry] = None,
89
89
  on_failed: Optional[OnFailed] = None,
90
- checking_interval: Union[int, float] = 0.1,
90
+ checking_interval: Union[int, float] = 0,
91
91
  progress_interval: Union[int, float] = 5,
92
92
  expected_result: bool = True,
93
93
  should_execute: Union[bool, JinjaTemplate, Callable[..., bool]] = True,
@@ -133,8 +133,17 @@ class HTTPChecker(Checker):
133
133
  raise_error: bool = True,
134
134
  is_async: bool = False,
135
135
  show_done_info: bool = True,
136
+ should_clear_xcom: bool = False,
137
+ should_stop_looper: bool = False,
136
138
  ) -> Callable[..., bool]:
137
- return super().to_function(env_prefix, raise_error, is_async, show_done_info)
139
+ return super().to_function(
140
+ env_prefix=env_prefix,
141
+ raise_error=raise_error,
142
+ is_async=is_async,
143
+ show_done_info=show_done_info,
144
+ should_clear_xcom=should_clear_xcom,
145
+ should_stop_looper=should_stop_looper,
146
+ )
138
147
 
139
148
  async def run(self, *args: Any, **kwargs: Any) -> bool:
140
149
  self._config = HttpConnectionConfig(
zrb/task/looper.py ADDED
@@ -0,0 +1,43 @@
1
+ from zrb.helper.accessories.color import colored
2
+ from zrb.helper.callable import run_async
3
+ from zrb.helper.log import logger
4
+ from zrb.helper.typing import Callable, List, Mapping, Optional
5
+
6
+ logger.debug(colored("Loading zrb.task.looper", attrs=["dark"]))
7
+
8
+
9
+ class Looper:
10
+ def __init__(self):
11
+ self._queue: Mapping[str, List[Optional[bool]]] = {}
12
+ self._should_stop = False
13
+
14
+ async def pop(self, identifier: str) -> Optional[bool]:
15
+ if identifier not in self._queue or len(self._queue[identifier]) == 0:
16
+ return None
17
+ return self._queue[identifier].pop(0)
18
+
19
+ def stop(self):
20
+ self._should_stop = True
21
+
22
+ def is_registered(self, identifier: str) -> bool:
23
+ return identifier in self._queue
24
+
25
+ async def register(self, identifier: str, function: Callable[..., Optional[bool]]):
26
+ if identifier in self._queue:
27
+ return
28
+ self._queue[identifier] = []
29
+ while not self._should_stop:
30
+ try:
31
+ result = await run_async(function)
32
+ if result is not None:
33
+ if not result:
34
+ continue
35
+ while len(self._queue[identifier]) > 1000:
36
+ self._queue[identifier].pop(0)
37
+ self._queue[identifier].append(result)
38
+ except KeyboardInterrupt:
39
+ self.stop()
40
+ break
41
+
42
+
43
+ looper = Looper()
zrb/task/path_checker.py CHANGED
@@ -56,7 +56,7 @@ class PathChecker(Checker):
56
56
  on_failed: Optional[OnFailed] = None,
57
57
  path: JinjaTemplate = "",
58
58
  ignored_path: Union[JinjaTemplate, Iterable[JinjaTemplate]] = [],
59
- checking_interval: Union[int, float] = 0.1,
59
+ checking_interval: Union[int, float] = 0,
60
60
  progress_interval: Union[int, float] = 5,
61
61
  expected_result: bool = True,
62
62
  should_execute: Union[bool, JinjaTemplate, Callable[..., bool]] = True,
@@ -99,8 +99,17 @@ class PathChecker(Checker):
99
99
  raise_error: bool = True,
100
100
  is_async: bool = False,
101
101
  show_done_info: bool = True,
102
+ should_clear_xcom: bool = False,
103
+ should_stop_looper: bool = False,
102
104
  ) -> Callable[..., bool]:
103
- 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
+ )
104
113
 
105
114
  async def run(self, *args: Any, **kwargs: Any) -> bool:
106
115
  self._rendered_path = self.render_str(self._path)