pyworkflow-engine 0.1.17__py3-none-any.whl → 0.1.19__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.
pyworkflow/__init__.py CHANGED
@@ -29,7 +29,7 @@ Quick Start:
29
29
  >>> run_id = await start(my_workflow, "Alice")
30
30
  """
31
31
 
32
- __version__ = "0.1.17"
32
+ __version__ = "0.1.19"
33
33
 
34
34
  # Configuration
35
35
  from pyworkflow.config import (
pyworkflow/aws/context.py CHANGED
@@ -209,7 +209,7 @@ class AWSWorkflowContext(WorkflowContext):
209
209
  """Request cancellation (AWS manages this internally)."""
210
210
  logger.warning("Cancellation not supported in AWS context")
211
211
 
212
- def check_cancellation(self) -> None:
212
+ async def check_cancellation(self) -> None:
213
213
  """Check cancellation (AWS manages this internally)."""
214
214
  pass # AWS handles this
215
215
 
@@ -207,6 +207,9 @@ def execute_step_task(
207
207
  context_class = _resolve_context_class(context_class_name)
208
208
  if context_class is not None:
209
209
  step_ctx = context_class.from_dict(context_data)
210
+ # Inject cancellation metadata so check_cancellation() works on workers
211
+ object.__setattr__(step_ctx, "_cancellation_run_id", run_id)
212
+ object.__setattr__(step_ctx, "_cancellation_storage", storage)
210
213
  step_context_token = _set_step_context_internal(step_ctx)
211
214
  # Set readonly mode to prevent mutation in steps
212
215
  readonly_token = _set_step_context_readonly(True)
@@ -239,12 +239,15 @@ class WorkflowContext(ABC):
239
239
  ...
240
240
 
241
241
  @abstractmethod
242
- def check_cancellation(self) -> None:
242
+ async def check_cancellation(self) -> None:
243
243
  """
244
244
  Check for cancellation and raise if requested.
245
245
 
246
246
  This should be called at interruptible points (before steps,
247
- during sleeps, etc.) to allow graceful cancellation.
247
+ during sleeps, etc.) to allow graceful cancellation. In durable
248
+ mode, this also checks the storage backend's cancellation flag
249
+ to detect external cancellation requests (e.g., from
250
+ ``cancel_workflow()``).
248
251
 
249
252
  Raises:
250
253
  CancellationError: If cancellation was requested and not blocked
@@ -744,7 +744,7 @@ class LocalContext(WorkflowContext):
744
744
  return
745
745
 
746
746
  # Check for cancellation before sleeping
747
- self.check_cancellation()
747
+ await self.check_cancellation()
748
748
 
749
749
  # Durable mode - suspend workflow
750
750
  sleep_id = self._generate_sleep_id(duration_seconds)
@@ -913,7 +913,7 @@ class LocalContext(WorkflowContext):
913
913
  )
914
914
 
915
915
  # Check for cancellation before waiting for hook
916
- self.check_cancellation()
916
+ await self.check_cancellation()
917
917
 
918
918
  # Generate deterministic hook_id
919
919
  self._step_counter += 1
@@ -1038,19 +1038,22 @@ class LocalContext(WorkflowContext):
1038
1038
  reason=reason,
1039
1039
  )
1040
1040
 
1041
- def check_cancellation(self) -> None:
1041
+ async def check_cancellation(self) -> None:
1042
1042
  """
1043
1043
  Check for cancellation and raise if requested.
1044
1044
 
1045
1045
  This should be called at interruptible points (before steps,
1046
- during sleeps, etc.) to allow graceful cancellation.
1046
+ during sleeps, etc.) to allow graceful cancellation. In durable
1047
+ mode, this also queries the storage backend to detect external
1048
+ cancellation requests (e.g., from ``cancel_workflow()``).
1047
1049
 
1048
1050
  Raises:
1049
1051
  CancellationError: If cancellation was requested and not blocked
1050
1052
  """
1051
- if self._cancellation_requested and not self._cancellation_blocked:
1052
- from pyworkflow.core.exceptions import CancellationError
1053
+ from pyworkflow.core.exceptions import CancellationError
1053
1054
 
1055
+ # Fast path: in-memory flag
1056
+ if self._cancellation_requested and not self._cancellation_blocked:
1054
1057
  logger.info(
1055
1058
  "Cancellation check triggered - raising CancellationError",
1056
1059
  run_id=self._run_id,
@@ -1061,6 +1064,27 @@ class LocalContext(WorkflowContext):
1061
1064
  reason=self._cancellation_reason,
1062
1065
  )
1063
1066
 
1067
+ # Storage check: detect external cancellation (durable mode only)
1068
+ if not self._cancellation_blocked and self._durable and self._storage is not None:
1069
+ try:
1070
+ if await self._storage.check_cancellation_flag(self._run_id):
1071
+ self._cancellation_requested = True
1072
+ logger.info(
1073
+ "Cancellation detected via storage flag - raising CancellationError",
1074
+ run_id=self._run_id,
1075
+ )
1076
+ raise CancellationError(
1077
+ message="Workflow was cancelled: detected via storage flag",
1078
+ reason=self._cancellation_reason,
1079
+ )
1080
+ except CancellationError:
1081
+ raise
1082
+ except Exception as e:
1083
+ logger.warning(
1084
+ f"Failed to check cancellation flag in storage: {e}",
1085
+ run_id=self._run_id,
1086
+ )
1087
+
1064
1088
  @property
1065
1089
  def cancellation_blocked(self) -> bool:
1066
1090
  """
@@ -322,7 +322,7 @@ class MockContext(WorkflowContext):
322
322
  self._cancellation_requested = True
323
323
  self._cancellation_reason = reason
324
324
 
325
- def check_cancellation(self) -> None:
325
+ async def check_cancellation(self) -> None:
326
326
  """Check if cancellation was requested and raise if not blocked."""
327
327
  from pyworkflow.core.exceptions import CancellationError
328
328
 
@@ -47,11 +47,17 @@ Usage:
47
47
  return {"valid": True}
48
48
  """
49
49
 
50
+ from __future__ import annotations
51
+
50
52
  from contextvars import ContextVar, Token
51
- from typing import Any, Self
53
+ from typing import TYPE_CHECKING, Any, Self
52
54
 
55
+ from loguru import logger
53
56
  from pydantic import BaseModel, ConfigDict
54
57
 
58
+ if TYPE_CHECKING:
59
+ from pyworkflow.storage.base import StorageBackend
60
+
55
61
 
56
62
  class StepContext(BaseModel):
57
63
  """
@@ -80,6 +86,61 @@ class StepContext(BaseModel):
80
86
 
81
87
  model_config = ConfigDict(frozen=True, extra="forbid")
82
88
 
89
+ # Private attributes injected by the framework (not serialized).
90
+ # These enable check_cancellation() to work even when WorkflowContext
91
+ # is not available (e.g., on Celery workers, inside LangGraph tools).
92
+ _cancellation_run_id: str | None = None
93
+ _cancellation_storage: StorageBackend | None = None
94
+
95
+ async def check_cancellation(self) -> None:
96
+ """
97
+ Check for cancellation and raise CancellationError if requested.
98
+
99
+ This works in all execution contexts:
100
+ - If a WorkflowContext is available, delegates to it (checks both
101
+ in-memory flag and storage).
102
+ - Otherwise, checks the storage cancellation flag directly using
103
+ the run_id and storage injected by the framework.
104
+
105
+ This is especially useful for long-running operations inside steps
106
+ or tool adapters where WorkflowContext may not be available (e.g.,
107
+ on Celery workers, inside LangGraph tool execution).
108
+
109
+ Raises:
110
+ CancellationError: If cancellation was requested
111
+
112
+ Example:
113
+ @step()
114
+ async def long_running_step():
115
+ ctx = get_step_context()
116
+ for chunk in chunks:
117
+ await ctx.check_cancellation()
118
+ await process(chunk)
119
+ """
120
+ from pyworkflow.context import get_context, has_context
121
+ from pyworkflow.core.exceptions import CancellationError
122
+
123
+ # Fast path: delegate to WorkflowContext if available
124
+ if has_context():
125
+ await get_context().check_cancellation()
126
+ return
127
+
128
+ # Fallback: check storage flag directly
129
+ if self._cancellation_run_id is not None and self._cancellation_storage is not None:
130
+ try:
131
+ if await self._cancellation_storage.check_cancellation_flag(
132
+ self._cancellation_run_id
133
+ ):
134
+ raise CancellationError(
135
+ message="Workflow was cancelled: detected via storage flag",
136
+ )
137
+ except CancellationError:
138
+ raise
139
+ except Exception as e:
140
+ logger.warning(
141
+ f"Failed to check cancellation flag in storage: {e}",
142
+ )
143
+
83
144
  def with_updates(self: Self, **kwargs: Any) -> Self:
84
145
  """
85
146
  Create a new context with updated values.
@@ -203,12 +264,21 @@ async def set_step_context(ctx: StepContext) -> None:
203
264
  if not isinstance(ctx, StepContext):
204
265
  raise TypeError(f"Expected StepContext instance, got {type(ctx).__name__}")
205
266
 
267
+ # Inject cancellation metadata from WorkflowContext if available.
268
+ # This enables check_cancellation() to work even when WorkflowContext
269
+ # is not accessible (e.g., on Celery workers, inside LangGraph tools).
270
+ from pyworkflow.context import get_context, has_context
271
+
272
+ if has_context():
273
+ workflow_ctx = get_context()
274
+ object.__setattr__(ctx, "_cancellation_run_id", workflow_ctx.run_id)
275
+ if workflow_ctx.is_durable and workflow_ctx.storage is not None:
276
+ object.__setattr__(ctx, "_cancellation_storage", workflow_ctx.storage)
277
+
206
278
  # Set the context in the contextvar
207
279
  _step_context.set(ctx)
208
280
 
209
281
  # Persist to storage if we're in a durable workflow
210
- from pyworkflow.context import get_context, has_context
211
-
212
282
  if has_context():
213
283
  workflow_ctx = get_context()
214
284
  if workflow_ctx.is_durable and workflow_ctx.storage is not None:
@@ -47,7 +47,7 @@ class CancellationError(WorkflowError):
47
47
  Note:
48
48
  CancellationError is raised at checkpoint boundaries (before steps,
49
49
  sleeps, hooks), not during step execution. Long-running steps can
50
- call ``ctx.check_cancellation()`` for cooperative cancellation.
50
+ call ``await ctx.check_cancellation()`` for cooperative cancellation.
51
51
 
52
52
  Example:
53
53
  @workflow
pyworkflow/core/step.py CHANGED
@@ -110,7 +110,7 @@ def step(
110
110
  ctx = get_context()
111
111
 
112
112
  # Check for cancellation before executing step
113
- ctx.check_cancellation()
113
+ await ctx.check_cancellation()
114
114
 
115
115
  # Transient mode: execute directly without event sourcing
116
116
  # Retries are still supported via direct execution
@@ -243,7 +243,7 @@ def step(
243
243
  )
244
244
 
245
245
  # Check for cancellation before executing step
246
- ctx.check_cancellation()
246
+ await ctx.check_cancellation()
247
247
 
248
248
  # Validate parameters before execution
249
249
  validate_step_parameters(func, args, kwargs, step_name)
@@ -233,6 +233,9 @@ async def execute_workflow_with_context(
233
233
  context_data = await storage.get_run_context(run_id)
234
234
  if context_data:
235
235
  step_ctx = context_class.from_dict(context_data)
236
+ # Inject cancellation metadata so check_cancellation() works
237
+ object.__setattr__(step_ctx, "_cancellation_run_id", run_id)
238
+ object.__setattr__(step_ctx, "_cancellation_storage", storage)
236
239
  step_context_token = _set_step_context_internal(step_ctx)
237
240
 
238
241
  try:
@@ -566,7 +566,7 @@ async def cancel_workflow(
566
566
  Cancellation does NOT interrupt a step that is already executing.
567
567
  If a step takes a long time, cancellation will only be detected after
568
568
  the step completes. For long-running steps that need mid-execution
569
- cancellation, call ``ctx.check_cancellation()`` periodically within
569
+ cancellation, call ``await ctx.check_cancellation()`` periodically within
570
570
  the step function.
571
571
 
572
572
  Args:
@@ -649,9 +649,14 @@ async def cancel_workflow(
649
649
  current_status=run.status.value,
650
650
  )
651
651
 
652
+ # Always set the cancellation flag in storage so that distributed
653
+ # components (Celery workers, LangGraph tools, StepContext.check_cancellation())
654
+ # can detect the cancellation regardless of workflow status.
655
+ await storage.set_cancellation_flag(run_id)
656
+
652
657
  # Handle based on current status
653
658
  if run.status == RunStatus.SUSPENDED:
654
- # For suspended workflows, update status to CANCELLED immediately
659
+ # For suspended workflows, also update status to CANCELLED immediately
655
660
  # The workflow will see cancellation when it tries to resume
656
661
  cancelled_event = create_workflow_cancelled_event(
657
662
  run_id=run_id,
@@ -667,10 +672,6 @@ async def cancel_workflow(
667
672
  )
668
673
 
669
674
  elif run.status in {RunStatus.RUNNING, RunStatus.PENDING}:
670
- # For running/pending workflows, set cancellation flag
671
- # The workflow will detect this at the next check point
672
- await storage.set_cancellation_flag(run_id)
673
-
674
675
  logger.info(
675
676
  "Cancellation flag set for running workflow",
676
677
  run_id=run_id,
@@ -98,7 +98,7 @@ async def start_child_workflow(
98
98
  )
99
99
 
100
100
  # Check for cancellation before starting child
101
- ctx.check_cancellation()
101
+ await ctx.check_cancellation()
102
102
 
103
103
  # Get workflow metadata
104
104
  workflow_meta = get_workflow_by_func(workflow_func)
@@ -14,7 +14,7 @@ from pyworkflow.context import get_context, has_context
14
14
  from pyworkflow.core.exceptions import ContinueAsNewSignal
15
15
 
16
16
 
17
- def continue_as_new(*args: Any, **kwargs: Any) -> NoReturn:
17
+ async def continue_as_new(*args: Any, **kwargs: Any) -> NoReturn:
18
18
  """
19
19
  Complete current workflow and start a new execution with fresh event history.
20
20
 
@@ -48,7 +48,7 @@ def continue_as_new(*args: Any, **kwargs: Any) -> NoReturn:
48
48
 
49
49
  # Continue with new cursor if more items
50
50
  if new_cursor:
51
- continue_as_new(cursor=new_cursor)
51
+ await continue_as_new(cursor=new_cursor)
52
52
 
53
53
  return "done"
54
54
 
@@ -59,7 +59,7 @@ def continue_as_new(*args: Any, **kwargs: Any) -> NoReturn:
59
59
 
60
60
  # Continue with next day
61
61
  next_date = get_next_date(date)
62
- continue_as_new(date=next_date)
62
+ await continue_as_new(date=next_date)
63
63
 
64
64
  @workflow
65
65
  async def batch_processor(offset: int = 0, batch_size: int = 100):
@@ -69,7 +69,7 @@ def continue_as_new(*args: Any, **kwargs: Any) -> NoReturn:
69
69
  for item in items:
70
70
  await process_item(item)
71
71
  # Continue with next batch
72
- continue_as_new(offset=offset + batch_size, batch_size=batch_size)
72
+ await continue_as_new(offset=offset + batch_size, batch_size=batch_size)
73
73
 
74
74
  return f"Processed {offset} items total"
75
75
  """
@@ -88,7 +88,7 @@ def continue_as_new(*args: Any, **kwargs: Any) -> NoReturn:
88
88
  ctx = get_context()
89
89
 
90
90
  # Check for cancellation - don't continue if cancelled
91
- ctx.check_cancellation()
91
+ await ctx.check_cancellation()
92
92
 
93
93
  logger.info(
94
94
  "Workflow continuing as new execution",
@@ -15,7 +15,7 @@ Note:
15
15
  Cancellation does NOT interrupt a step mid-execution. If a step takes
16
16
  a long time, cancellation will only be detected after it completes.
17
17
  For cooperative cancellation within long-running steps, call
18
- ``ctx.check_cancellation()`` periodically.
18
+ ``await ctx.check_cancellation()`` periodically.
19
19
 
20
20
  Example:
21
21
  @workflow
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyworkflow-engine
3
- Version: 0.1.17
3
+ Version: 0.1.19
4
4
  Summary: A Python implementation of durable, event-sourced workflows inspired by Vercel Workflow
5
5
  Author: PyWorkflow Contributors
6
6
  License: MIT
@@ -1,8 +1,8 @@
1
- pyworkflow/__init__.py,sha256=IDkVaqj1HNXn5kLqUGlLetTFpM_moNQdvCZS2aPQdR8,6281
1
+ pyworkflow/__init__.py,sha256=f5YtGeV9RATqNziHuyUJVPHhg2LVzqWDuwNL3bqdtAI,6281
2
2
  pyworkflow/config.py,sha256=pKwPrpCwBJiDpB-MIjM0U7GW1TFmQFO341pihL5-vTM,14455
3
3
  pyworkflow/discovery.py,sha256=snW3l4nvY3Nc067TGlwtn_qdzTU9ybN7YPr8FbvY8iM,8066
4
4
  pyworkflow/aws/__init__.py,sha256=Ak_xHcR9LTRX-CwcS0XecYmzrXZw4EM3V9aKBBDEmIk,1741
5
- pyworkflow/aws/context.py,sha256=Vjyjip6U1Emg-WA5TlBaxFhcg15rf9mVJiPfT4VywHc,8217
5
+ pyworkflow/aws/context.py,sha256=C_wBr_YRUYT4IHyaAGPdiqRPNbH8mDLkoMpVtQVIg28,8223
6
6
  pyworkflow/aws/handler.py,sha256=0SnQuIfQVD99QKMCRFPtrsrV_l1LYKFkzPIRx_2UkSI,5849
7
7
  pyworkflow/aws/testing.py,sha256=WrRk9wjbycM-UyHFQWNnA83UE9IrYnhfT38WrbxQT2U,8844
8
8
  pyworkflow/celery/__init__.py,sha256=FywVyqnT8AYz9cXkr-wel7_-N7dHFsPNASEPMFESf4Q,1179
@@ -10,7 +10,7 @@ pyworkflow/celery/app.py,sha256=QXpPXVVuwJv3ToylT0pyz9SgmwjC9hW-9WaIO4wH5OQ,1434
10
10
  pyworkflow/celery/loop.py,sha256=mu8cIfMJYgHAoGCN_DdDoNoXK3QHzHpLmrPCyFDQYIY,3016
11
11
  pyworkflow/celery/scheduler.py,sha256=Ms4rqRpdpMiLM8l4y3DK-Divunj9afYuUaGGoNQe7P4,11288
12
12
  pyworkflow/celery/singleton.py,sha256=9gdVHzqFjShZ9OJOJlJNABUg9oqnl6ITGROtomcOtsg,16070
13
- pyworkflow/celery/tasks.py,sha256=BNHZwWTSRc3q8EgAy4tEmXAm6O0vtVLgrG7MrO0ZZXA,86049
13
+ pyworkflow/celery/tasks.py,sha256=uUfV6aGerd2mTIw11TX5zgFE6DpqQnmaqUASSw4ap3g,86293
14
14
  pyworkflow/cli/__init__.py,sha256=tcbe-fcZmyeEKUy_aEo8bsEF40HsNKOwvyMBZIJZPwc,3844
15
15
  pyworkflow/cli/__main__.py,sha256=LxLLS4FEEPXa5rWpLTtKuivn6Xp9pGia-QKGoxt9SS0,148
16
16
  pyworkflow/cli/commands/__init__.py,sha256=IXvnTgukALckkO8fTlZhVRq80ojSqpnIIgboAg_-yZU,39
@@ -35,32 +35,32 @@ pyworkflow/cli/utils/interactive.py,sha256=S2Ell-rUzzt3V10diGo5XCgiDcYFYSxoXNYkJ
35
35
  pyworkflow/cli/utils/storage.py,sha256=a5Iu2Xe1_mPgBVYc8B6I63MFfW12ko7wURqcpq3RBPA,4018
36
36
  pyworkflow/context/__init__.py,sha256=dI5zW1lAFGw68jI2UpKUqyADozDboGNl-RmhEvSTuCI,2150
37
37
  pyworkflow/context/aws.py,sha256=MYxrFsRzCgaZ0YQAyE26UOT_ryxuag5DwiDSodclQIg,7571
38
- pyworkflow/context/base.py,sha256=Hlfm5MNHh_BVbRCgEcILmHiqsn81iYFqt0GSLkFGo00,13772
39
- pyworkflow/context/local.py,sha256=eKBF-e_WSkVIqbynVysQy6rH02rXmPts29KtjY41IQI,38853
40
- pyworkflow/context/mock.py,sha256=TJzQ3P3_ZHm1lCJZJACIFFvz2ydFxz2cT9eEGOQS5I0,12061
41
- pyworkflow/context/step_context.py,sha256=6P2jn1v7MTlYaWCTt6DBq7Nkmxm7nvna4oGpTZJeMbg,8862
38
+ pyworkflow/context/base.py,sha256=uCKpXnRUON9EgAk8miUl06tDVpmLe1dZ_7FhwCO8lE0,13953
39
+ pyworkflow/context/local.py,sha256=qjsmLE7pzw_OUcrPSzrbNBCPuMDZ8DR9USDqki7RcCA,40032
40
+ pyworkflow/context/mock.py,sha256=tPB0KIWsMRlUjgteWdLKyJcX5U8tHajLCkolVGFbJxc,12067
41
+ pyworkflow/context/step_context.py,sha256=Ufp1Mu0sX5i2reWEALHnlN7U7XIcyqjqZtgWaJpc-Vc,11785
42
42
  pyworkflow/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
- pyworkflow/core/exceptions.py,sha256=F2nbXyoed7wlIJMeGfpgsIC8ZyWcYN0iKtOnBA7-xnQ,10719
43
+ pyworkflow/core/exceptions.py,sha256=rL0SlRWymoLItOdbcbfMnAysq5F0IjmAls2CzzI6AWE,10725
44
44
  pyworkflow/core/registry.py,sha256=ZUf2YTpBvWpC9EehRbMF8soXOk9VsjNruoi6lR4O33M,9361
45
45
  pyworkflow/core/scheduled.py,sha256=479A7IvjHiMob7ZrZtfE6VqtypG6DLIGMGhh16jLIWM,10522
46
- pyworkflow/core/step.py,sha256=9JG9udEDph_6ecfruVdY0qC3ruoC6bjd0F91chg8QZM,23913
46
+ pyworkflow/core/step.py,sha256=Ez4-nEASR9bUkHAFN3GCkrDo9Nx_aiwyPXqaEVTYp6Q,23925
47
47
  pyworkflow/core/validation.py,sha256=0VaZyQ9YGK8WFy4ZG4Bjt9MYAp0vz6xEOe80kcgaP5g,3362
48
- pyworkflow/core/workflow.py,sha256=dlcICq1B69-nxUJth_n-H8U9TjP3QZyjvquQXxWHcxs,12076
48
+ pyworkflow/core/workflow.py,sha256=tBRMRYBmQZoCWjVEXDT4W-4VZLG6q-iRFqC-_qZW-Uc,12309
49
49
  pyworkflow/engine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  pyworkflow/engine/events.py,sha256=KFtyIqQjr1B9Frtd5V1Zq0ph1iwg_Ky3uPzmTYZ1Tnk,25827
51
- pyworkflow/engine/executor.py,sha256=l2HlpQfqzSL_0WuTFb1c4pEIgYU9JcN792hkGICqCAk,21109
51
+ pyworkflow/engine/executor.py,sha256=oTG8ZGAlbCHxuEPuXxjyyGRAvF9oUdm9qe1I-fh67xQ,21209
52
52
  pyworkflow/engine/replay.py,sha256=bmMb4wzPKaZwPOage3Z-g_5DndYNoSmavMZ9sPiFzYI,9386
53
53
  pyworkflow/observability/__init__.py,sha256=M_Uc3WdtshQSxLnj3T8D0M7f4zcCuFzVs8e8PKCuXDc,380
54
54
  pyworkflow/observability/logging.py,sha256=4WYR188z8NppWWpgsUkkJfBLWZp5St6ro3i7DJq4LP4,8803
55
55
  pyworkflow/primitives/__init__.py,sha256=rEahSVLhG3nSxvcRhJeM1LBSBIV7AkcRTnxuMLmZMTM,1041
56
56
  pyworkflow/primitives/child_handle.py,sha256=7NcIaNUQdZEoxmk5gQH1CJ6uQzpro3eFo-sEaM6l6w0,5466
57
- pyworkflow/primitives/child_workflow.py,sha256=_T7PCqiH0tjIm_lpJ6NmfUPWCFx-MjH6t-C1orwohKs,13134
58
- pyworkflow/primitives/continue_as_new.py,sha256=NKcimHsgr5ExkvRvfO28hxgPw_I7Q74Vz9WL8r0PhPc,3329
57
+ pyworkflow/primitives/child_workflow.py,sha256=s1DGqdpvyGMqzeBbd7HKnZ0UW__VyexUGJN_8hRq05w,13140
58
+ pyworkflow/primitives/continue_as_new.py,sha256=YGAAsjEY6DgGMZSDftw9Y_ml2nlwCfIVEjbjC0rrBOQ,3359
59
59
  pyworkflow/primitives/define_hook.py,sha256=gNzk7DuObfWG1T9AdHnDnGLHNKjnApiVRlCKPObugfY,4443
60
60
  pyworkflow/primitives/hooks.py,sha256=ws9U81ymsY8M4FFTvJ2X4EMGmIrilb3vCKZ0V_EGZdE,3085
61
61
  pyworkflow/primitives/resume_hook.py,sha256=vwa0znU1DuasStzQVTES-jp9XUzbVq4vimmbpiZH6yg,6245
62
62
  pyworkflow/primitives/schedule.py,sha256=2hVM2Swl9dRx3RHd5nblJLaU8HaSy-NHYue2Cf9TOcU,14961
63
- pyworkflow/primitives/shield.py,sha256=MUYakU0euZoYNb6MbFyRfJN8GEXsRFkIbZEo84vRN9c,2924
63
+ pyworkflow/primitives/shield.py,sha256=aRlW_Guwv6P1rvZS9dVidlevIKGRqRMSruoG018vHRs,2930
64
64
  pyworkflow/primitives/sleep.py,sha256=iH1e5CoWY-jZbYNAU3GRW1xR_8EtCuPIcIohzU4jWJo,3097
65
65
  pyworkflow/runtime/__init__.py,sha256=DkwTgFCMRGyyW8NGcW7Nyy9beOg5kO1TXhqhysj1-aY,649
66
66
  pyworkflow/runtime/base.py,sha256=ATlPeheYzUMlk_v-9abLyUQf4y4iYB53VpaoQ73pYsc,5465
@@ -86,9 +86,9 @@ pyworkflow/storage/sqlite.py,sha256=qDhFjyFAenwYq6MF_66FFhDaBG7CEr7ni9Uy72X7MvQ,
86
86
  pyworkflow/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
87
  pyworkflow/utils/duration.py,sha256=C-itmiSQQlplw7j6XB679hLF9xYGnyCwm7twO88OF8U,3978
88
88
  pyworkflow/utils/schedule.py,sha256=dO_MkGFyfwZpb0LDlW6BGyZzlPuQIA6dc6j9nk9lc4Y,10691
89
- pyworkflow_engine-0.1.17.dist-info/licenses/LICENSE,sha256=Y49RCTZ5ayn_yzBcRxnyIFdcMCyuYm150aty_FIznfY,1080
90
- pyworkflow_engine-0.1.17.dist-info/METADATA,sha256=UGSPGJCOnw56WxwhgnC9-Tb29GvC7WZIxEBGymjSDh8,19628
91
- pyworkflow_engine-0.1.17.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
92
- pyworkflow_engine-0.1.17.dist-info/entry_points.txt,sha256=3IGAfuylnS39U0YX0pxnjrj54kB4iT_bNYrmsiDB-dE,51
93
- pyworkflow_engine-0.1.17.dist-info/top_level.txt,sha256=FLTv9pQmLDBXrQdLOhTMIS3njFibliMsQEfumqmdzBE,11
94
- pyworkflow_engine-0.1.17.dist-info/RECORD,,
89
+ pyworkflow_engine-0.1.19.dist-info/licenses/LICENSE,sha256=Y49RCTZ5ayn_yzBcRxnyIFdcMCyuYm150aty_FIznfY,1080
90
+ pyworkflow_engine-0.1.19.dist-info/METADATA,sha256=ZLi6b7vK2sLOgq20OBvMfjXHwyOx70Vai19f2Essj4Q,19628
91
+ pyworkflow_engine-0.1.19.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
92
+ pyworkflow_engine-0.1.19.dist-info/entry_points.txt,sha256=3IGAfuylnS39U0YX0pxnjrj54kB4iT_bNYrmsiDB-dE,51
93
+ pyworkflow_engine-0.1.19.dist-info/top_level.txt,sha256=FLTv9pQmLDBXrQdLOhTMIS3njFibliMsQEfumqmdzBE,11
94
+ pyworkflow_engine-0.1.19.dist-info/RECORD,,