dotflow 0.16.0.dev1__tar.gz → 0.16.0.dev3__tar.gz
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.
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/PKG-INFO +2 -1
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/__init__.py +1 -1
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/server.py +1 -13
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/start.py +32 -2
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/setup.py +17 -5
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/context.py +5 -5
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/dotflow.py +0 -7
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/engine.py +6 -3
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/exception.py +18 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/task.py +1 -1
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/task.py +6 -8
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/server_api.py +2 -18
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/pyproject.toml +5 -3
- dotflow-0.16.0.dev1/dotflow/constants.py +0 -3
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/LICENSE +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/README.md +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/file.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/flow.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/http.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/log.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/metrics.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/notify.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/scheduler.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/storage.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/tcp.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/tracer.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/command.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/cloud.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/deploy.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/init.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/log.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/schedule.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/storage.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/validators/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/validators/start.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/constants.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/deployers/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/deployers/fc.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/deployers/fc_scheduled.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/services/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/services/cr.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/constants.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/base_lambda.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/ecs.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/ecs_scheduled.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_api.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_s3.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_sqs.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/schedule.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/cloudwatch.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/ecr.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/iam.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/s3.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/core.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/constants.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/deployers/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/deployers/cloudrun.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/apis.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/artifact_registry.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/gcs.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/constants.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/deployers/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/deployers/actions.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/action.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/config.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/decorators/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/decorators/time.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/module.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/transport.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/workflow.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/execution.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/overlap.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/status.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/storage.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/workflow.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/workflow.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/logging.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/main.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/log_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/log_opentelemetry.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/log_sentry.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/metrics_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/metrics_opentelemetry.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/notify_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/notify_discord.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/notify_telegram.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/scheduler_cron.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/scheduler_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/server_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_file.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_gcs.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_s3.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/tracer_default.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/tracer_opentelemetry.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/tracer_sentry.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/settings.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/types.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/__init__.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/basic_functions.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/error_handler.py +0 -0
- {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotflow
|
|
3
|
-
Version: 0.16.0.
|
|
3
|
+
Version: 0.16.0.dev3
|
|
4
4
|
Summary: 🎲 Dotflow turns an idea into flow! Lightweight Python library for execution pipelines with retry, parallel, cron and async support.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -237,6 +237,7 @@ Requires-Dist: google-cloud-storage ; extra == "gcp"
|
|
|
237
237
|
Requires-Dist: opentelemetry-api ; extra == "otel"
|
|
238
238
|
Requires-Dist: opentelemetry-sdk ; extra == "otel"
|
|
239
239
|
Requires-Dist: pydantic
|
|
240
|
+
Requires-Dist: python-ulid (>=3.0)
|
|
240
241
|
Requires-Dist: requests
|
|
241
242
|
Requires-Dist: rich
|
|
242
243
|
Requires-Dist: sentry-sdk ; extra == "sentry"
|
|
@@ -3,17 +3,9 @@
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from dotflow.constants import INITIAL_TASK_ID
|
|
7
|
-
|
|
8
6
|
|
|
9
7
|
class Server(ABC):
|
|
10
|
-
"""Server ABC provider for sending workflow
|
|
11
|
-
data to a remote API.
|
|
12
|
-
|
|
13
|
-
Implementations should handle HTTP communication with
|
|
14
|
-
a server like dotflow-api, sending execution data
|
|
15
|
-
(status, duration, errors, context) in real time.
|
|
16
|
-
"""
|
|
8
|
+
"""Server ABC provider for sending workflow/task data remotely."""
|
|
17
9
|
|
|
18
10
|
@abstractmethod
|
|
19
11
|
def create_workflow(self, workflow: Any) -> None:
|
|
@@ -30,7 +22,3 @@ class Server(ABC):
|
|
|
30
22
|
@abstractmethod
|
|
31
23
|
def update_task(self, task: Any) -> None:
|
|
32
24
|
"""Update task data on the remote server."""
|
|
33
|
-
|
|
34
|
-
def get_next_task_id(self, workflow: Any) -> int:
|
|
35
|
-
"""Return the next task id to use inside an existing workflow."""
|
|
36
|
-
return INITIAL_TASK_ID
|
|
@@ -5,6 +5,8 @@ from os import system
|
|
|
5
5
|
|
|
6
6
|
from dotflow import Config, DotFlow
|
|
7
7
|
from dotflow.cli.command import Command
|
|
8
|
+
from dotflow.core.exception import InvalidWorkflowFactory, WorkflowFlagConflict
|
|
9
|
+
from dotflow.core.module import Module
|
|
8
10
|
from dotflow.core.types.execution import TypeExecution
|
|
9
11
|
from dotflow.providers import (
|
|
10
12
|
ServerAPI,
|
|
@@ -14,10 +16,20 @@ from dotflow.providers import (
|
|
|
14
16
|
StorageGCS,
|
|
15
17
|
StorageS3,
|
|
16
18
|
)
|
|
19
|
+
from dotflow.utils.basic_functions import basic_callback
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
class StartCommand(Command):
|
|
20
23
|
def setup(self):
|
|
24
|
+
if getattr(self.params, "workflow", None):
|
|
25
|
+
self._start_from_factory()
|
|
26
|
+
else:
|
|
27
|
+
self._start_from_step()
|
|
28
|
+
|
|
29
|
+
if self.params.mode == TypeExecution.BACKGROUND:
|
|
30
|
+
system("/bin/bash")
|
|
31
|
+
|
|
32
|
+
def _start_from_step(self):
|
|
21
33
|
workflow = self._new_workflow()
|
|
22
34
|
|
|
23
35
|
workflow.task.add(
|
|
@@ -28,8 +40,26 @@ class StartCommand(Command):
|
|
|
28
40
|
|
|
29
41
|
workflow.start(mode=self.params.mode)
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
|
|
43
|
+
def _start_from_factory(self):
|
|
44
|
+
step_only_flags = {
|
|
45
|
+
"--callback": self.params.callback is not basic_callback,
|
|
46
|
+
"--initial-context": self.params.initial_context is not None,
|
|
47
|
+
}
|
|
48
|
+
for flag, provided in step_only_flags.items():
|
|
49
|
+
if provided:
|
|
50
|
+
raise WorkflowFlagConflict(flag=flag)
|
|
51
|
+
|
|
52
|
+
factory = Module(self.params.workflow)
|
|
53
|
+
|
|
54
|
+
if not callable(factory):
|
|
55
|
+
raise InvalidWorkflowFactory(factory=self.params.workflow)
|
|
56
|
+
|
|
57
|
+
result = factory()
|
|
58
|
+
|
|
59
|
+
if not isinstance(result, DotFlow):
|
|
60
|
+
raise InvalidWorkflowFactory(factory=self.params.workflow)
|
|
61
|
+
|
|
62
|
+
result.start(mode=self.params.mode)
|
|
33
63
|
|
|
34
64
|
def _new_workflow(self):
|
|
35
65
|
config = self._build_config()
|
|
@@ -16,7 +16,9 @@ from dotflow.core.exception import (
|
|
|
16
16
|
MESSAGE_UNKNOWN_ERROR,
|
|
17
17
|
ExecutionModeNotExist,
|
|
18
18
|
ImportModuleError,
|
|
19
|
+
InvalidWorkflowFactory,
|
|
19
20
|
MissingActionDecorator,
|
|
21
|
+
WorkflowFlagConflict,
|
|
20
22
|
)
|
|
21
23
|
from dotflow.core.types import TypeExecution, TypeOverlap, TypeStorage
|
|
22
24
|
from dotflow.logging import logger
|
|
@@ -56,12 +58,16 @@ class Command:
|
|
|
56
58
|
self.cmd_init.set_defaults(exec=InitCommand)
|
|
57
59
|
|
|
58
60
|
def setup_start(self):
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
cmd_start_parser = self.subparsers.add_parser("start", help="Start")
|
|
62
|
+
entry_group = cmd_start_parser.add_mutually_exclusive_group(
|
|
63
|
+
required=True
|
|
62
64
|
)
|
|
65
|
+
entry_group.add_argument("-s", "--step")
|
|
66
|
+
entry_group.add_argument("-w", "--workflow")
|
|
63
67
|
|
|
64
|
-
self.cmd_start.
|
|
68
|
+
self.cmd_start = cmd_start_parser.add_argument_group(
|
|
69
|
+
"Usage: dotflow start [OPTIONS]"
|
|
70
|
+
)
|
|
65
71
|
self.cmd_start.add_argument("-c", "--callback", default=basic_callback)
|
|
66
72
|
self.cmd_start.add_argument("-i", "--initial-context")
|
|
67
73
|
self.cmd_start.add_argument(
|
|
@@ -88,7 +94,7 @@ class Command:
|
|
|
88
94
|
],
|
|
89
95
|
)
|
|
90
96
|
|
|
91
|
-
|
|
97
|
+
cmd_start_parser.set_defaults(exec=StartCommand)
|
|
92
98
|
|
|
93
99
|
def setup_schedule(self):
|
|
94
100
|
self.cmd_schedule = self.subparsers.add_parser(
|
|
@@ -233,6 +239,12 @@ class Command:
|
|
|
233
239
|
except ImportModuleError as err:
|
|
234
240
|
print(settings.WARNING_ALERT, err)
|
|
235
241
|
|
|
242
|
+
except InvalidWorkflowFactory as err:
|
|
243
|
+
print(settings.WARNING_ALERT, err)
|
|
244
|
+
|
|
245
|
+
except WorkflowFlagConflict as err:
|
|
246
|
+
print(settings.WARNING_ALERT, err)
|
|
247
|
+
|
|
236
248
|
except KeyboardInterrupt:
|
|
237
249
|
print("\n", settings.INFO_ALERT, "Aborted.")
|
|
238
250
|
|
|
@@ -37,7 +37,7 @@ class Context(ContextInstance):
|
|
|
37
37
|
Args:
|
|
38
38
|
storage (Any): Attribute where any type of Python object can be stored.
|
|
39
39
|
|
|
40
|
-
task_id (
|
|
40
|
+
task_id (str): Task ID (ULID).
|
|
41
41
|
|
|
42
42
|
workflow_id (UUID): Workflow ID.
|
|
43
43
|
"""
|
|
@@ -45,7 +45,7 @@ class Context(ContextInstance):
|
|
|
45
45
|
def __init__(
|
|
46
46
|
self,
|
|
47
47
|
storage: Any = None,
|
|
48
|
-
task_id:
|
|
48
|
+
task_id: str = "",
|
|
49
49
|
workflow_id: UUID = None,
|
|
50
50
|
) -> None:
|
|
51
51
|
super().__init__(task_id, storage, task_id, workflow_id)
|
|
@@ -67,13 +67,13 @@ class Context(ContextInstance):
|
|
|
67
67
|
return self._task_id
|
|
68
68
|
|
|
69
69
|
@task_id.setter
|
|
70
|
-
def task_id(self, value:
|
|
70
|
+
def task_id(self, value: str):
|
|
71
71
|
if value is None:
|
|
72
72
|
self._task_id = None
|
|
73
73
|
return
|
|
74
|
-
if not isinstance(value,
|
|
74
|
+
if not isinstance(value, str):
|
|
75
75
|
raise TypeError(
|
|
76
|
-
f"task_id must be
|
|
76
|
+
f"task_id must be a str, got {type(value).__name__}: {value!r}"
|
|
77
77
|
)
|
|
78
78
|
self._task_id = value
|
|
79
79
|
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from functools import partial
|
|
6
6
|
from uuid import uuid4
|
|
7
7
|
|
|
8
|
-
from dotflow.constants import INITIAL_TASK_ID
|
|
9
8
|
from dotflow.core.config import Config
|
|
10
9
|
from dotflow.core.task import TaskBuilder
|
|
11
10
|
from dotflow.core.workflow import Manager
|
|
@@ -55,16 +54,10 @@ class DotFlow:
|
|
|
55
54
|
|
|
56
55
|
if not self._externally_provided_id:
|
|
57
56
|
self._config.server.create_workflow(workflow=self.workflow_id)
|
|
58
|
-
initial_task_id = INITIAL_TASK_ID
|
|
59
|
-
else:
|
|
60
|
-
initial_task_id = self._config.server.get_next_task_id(
|
|
61
|
-
workflow=self.workflow_id
|
|
62
|
-
)
|
|
63
57
|
|
|
64
58
|
self.task = TaskBuilder(
|
|
65
59
|
config=self._config,
|
|
66
60
|
workflow_id=self.workflow_id,
|
|
67
|
-
initial_task_id=initial_task_id,
|
|
68
61
|
)
|
|
69
62
|
|
|
70
63
|
self.start = partial(
|
|
@@ -15,6 +15,8 @@ from time import sleep
|
|
|
15
15
|
from types import FunctionType
|
|
16
16
|
from uuid import UUID
|
|
17
17
|
|
|
18
|
+
from ulid import ULID
|
|
19
|
+
|
|
18
20
|
try:
|
|
19
21
|
from types import NoneType
|
|
20
22
|
except ImportError:
|
|
@@ -253,15 +255,16 @@ class TaskEngine:
|
|
|
253
255
|
callable_list=callable_list, class_instance=class_instance
|
|
254
256
|
)
|
|
255
257
|
|
|
256
|
-
for
|
|
258
|
+
for new in ordered_list:
|
|
257
259
|
new_object = getattr(class_instance, new[1])
|
|
260
|
+
task_ulid = str(ULID())
|
|
258
261
|
try:
|
|
259
262
|
subcontext = new_object(
|
|
260
263
|
initial_context=self.task.initial_context,
|
|
261
264
|
previous_context=previous_context,
|
|
262
265
|
task=self.task,
|
|
263
266
|
)
|
|
264
|
-
subcontext.task_id =
|
|
267
|
+
subcontext.task_id = task_ulid
|
|
265
268
|
new_context.storage.append(subcontext)
|
|
266
269
|
previous_context = subcontext
|
|
267
270
|
|
|
@@ -275,7 +278,7 @@ class TaskEngine:
|
|
|
275
278
|
previous_context=previous_context,
|
|
276
279
|
task=self.task,
|
|
277
280
|
)
|
|
278
|
-
subcontext.task_id =
|
|
281
|
+
subcontext.task_id = task_ulid
|
|
279
282
|
new_context.storage.append(subcontext)
|
|
280
283
|
previous_context = subcontext
|
|
281
284
|
|
|
@@ -15,6 +15,12 @@ MESSAGE_PROBLEM_ORDERING = (
|
|
|
15
15
|
MESSAGE_MODULE_NOT_FOUND = (
|
|
16
16
|
"Module '{module}' not found. Please install with 'pip install {library}'"
|
|
17
17
|
)
|
|
18
|
+
MESSAGE_INVALID_WORKFLOW_FACTORY = (
|
|
19
|
+
"'{factory}' must be a callable that returns a DotFlow instance."
|
|
20
|
+
)
|
|
21
|
+
MESSAGE_WORKFLOW_FLAG_CONFLICT = (
|
|
22
|
+
"{flag} is only valid with --step and cannot be used with --workflow."
|
|
23
|
+
)
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
class MissingActionDecorator(Exception):
|
|
@@ -49,6 +55,18 @@ class ModuleNotFound(Exception):
|
|
|
49
55
|
)
|
|
50
56
|
|
|
51
57
|
|
|
58
|
+
class InvalidWorkflowFactory(Exception):
|
|
59
|
+
def __init__(self, factory: str):
|
|
60
|
+
super().__init__(
|
|
61
|
+
MESSAGE_INVALID_WORKFLOW_FACTORY.format(factory=factory)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class WorkflowFlagConflict(Exception):
|
|
66
|
+
def __init__(self, flag: str):
|
|
67
|
+
super().__init__(MESSAGE_WORKFLOW_FLAG_CONFLICT.format(flag=flag))
|
|
68
|
+
|
|
69
|
+
|
|
52
70
|
class ExecutionWithClassError(Exception):
|
|
53
71
|
def __init__(self):
|
|
54
72
|
super().__init__("Unknown")
|
|
@@ -28,7 +28,7 @@ class SerializerTaskError(BaseModel):
|
|
|
28
28
|
class SerializerTask(BaseModel):
|
|
29
29
|
model_config = ConfigDict(title="task")
|
|
30
30
|
|
|
31
|
-
task_id:
|
|
31
|
+
task_id: str = Field(default=None)
|
|
32
32
|
workflow_id: Optional[UUID] = Field(default=None)
|
|
33
33
|
status: str = Field(default=None, alias="_status")
|
|
34
34
|
duration: Optional[float] = Field(default=None, alias="_duration")
|
|
@@ -6,7 +6,8 @@ from datetime import datetime
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
from uuid import UUID
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from ulid import ULID
|
|
10
|
+
|
|
10
11
|
from dotflow.core.action import Action
|
|
11
12
|
from dotflow.core.config import Config
|
|
12
13
|
from dotflow.core.context import Context
|
|
@@ -57,13 +58,13 @@ class Task(TaskInstance):
|
|
|
57
58
|
`class` dotflow.core.task.Task
|
|
58
59
|
|
|
59
60
|
task = Task(
|
|
60
|
-
task_id=
|
|
61
|
+
task_id="01ARZ3NDEKTSV4RRFFQ69G5FAV",
|
|
61
62
|
step=my_step,
|
|
62
63
|
callback=my_callback
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
Args:
|
|
66
|
-
task_id (
|
|
67
|
+
task_id (str): Task ID (ULID).
|
|
67
68
|
|
|
68
69
|
step (Callable):
|
|
69
70
|
A argument that receives an object of the callable type,
|
|
@@ -86,7 +87,7 @@ class Task(TaskInstance):
|
|
|
86
87
|
|
|
87
88
|
def __init__(
|
|
88
89
|
self,
|
|
89
|
-
task_id:
|
|
90
|
+
task_id: str,
|
|
90
91
|
step: Callable,
|
|
91
92
|
callback: Callable = basic_callback,
|
|
92
93
|
initial_context: Any = None,
|
|
@@ -309,12 +310,10 @@ class TaskBuilder:
|
|
|
309
310
|
self,
|
|
310
311
|
config: Config,
|
|
311
312
|
workflow_id: UUID = None,
|
|
312
|
-
initial_task_id: int = INITIAL_TASK_ID,
|
|
313
313
|
) -> None:
|
|
314
314
|
self.queue: list[Callable] = []
|
|
315
315
|
self.workflow_id = workflow_id
|
|
316
316
|
self.config = config
|
|
317
|
-
self._next_id = initial_task_id
|
|
318
317
|
|
|
319
318
|
def add(
|
|
320
319
|
self,
|
|
@@ -354,8 +353,7 @@ class TaskBuilder:
|
|
|
354
353
|
)
|
|
355
354
|
return self
|
|
356
355
|
|
|
357
|
-
task_id =
|
|
358
|
-
self._next_id += 1
|
|
356
|
+
task_id = str(ULID())
|
|
359
357
|
|
|
360
358
|
self.queue.append(
|
|
361
359
|
Task(
|
|
@@ -5,11 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
import logging
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
from requests import
|
|
8
|
+
from requests import patch, post
|
|
9
9
|
from requests.exceptions import RequestException
|
|
10
10
|
|
|
11
11
|
from dotflow.abc.server import Server
|
|
12
|
-
from dotflow.constants import INITIAL_TASK_ID
|
|
13
12
|
|
|
14
13
|
logger = logging.getLogger(__name__)
|
|
15
14
|
|
|
@@ -80,6 +79,7 @@ class ServerAPI(Server):
|
|
|
80
79
|
|
|
81
80
|
def update_task(self, task: Any) -> None:
|
|
82
81
|
data = task.result(max=5_000_000)
|
|
82
|
+
data["id"] = data.pop("task_id", task.task_id)
|
|
83
83
|
self._patch(
|
|
84
84
|
(
|
|
85
85
|
f"{self._base_url}/workflows/{task.workflow_id}"
|
|
@@ -87,19 +87,3 @@ class ServerAPI(Server):
|
|
|
87
87
|
),
|
|
88
88
|
json=data,
|
|
89
89
|
)
|
|
90
|
-
|
|
91
|
-
def get_next_task_id(self, workflow: Any) -> int:
|
|
92
|
-
url = f"{self._base_url}/workflows/{workflow}/tasks/next-id"
|
|
93
|
-
try:
|
|
94
|
-
response = get(
|
|
95
|
-
url,
|
|
96
|
-
headers=self._headers,
|
|
97
|
-
timeout=self._timeout,
|
|
98
|
-
)
|
|
99
|
-
logger.info("GET %s [%s]", url, response.status_code)
|
|
100
|
-
if response.status_code == 200:
|
|
101
|
-
return int(response.json().get("next_id", INITIAL_TASK_ID))
|
|
102
|
-
except (RequestException, ValueError, TypeError) as error:
|
|
103
|
-
logger.error("GET %s failed: %s", url, error)
|
|
104
|
-
|
|
105
|
-
return INITIAL_TASK_ID
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dotflow"
|
|
3
|
-
version = "0.16.0.
|
|
3
|
+
version = "0.16.0.dev3"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name="Fernando Celmer", email="email@fernandocelmer.com" },
|
|
6
6
|
]
|
|
@@ -13,7 +13,8 @@ dependencies = [
|
|
|
13
13
|
"pydantic",
|
|
14
14
|
"typing-extensions",
|
|
15
15
|
"cookiecutter (>=2.0)",
|
|
16
|
-
"requests"
|
|
16
|
+
"requests",
|
|
17
|
+
"python-ulid (>=3.0)"
|
|
17
18
|
]
|
|
18
19
|
keywords = [
|
|
19
20
|
"pipeline",
|
|
@@ -66,7 +67,7 @@ sentry = ["sentry-sdk"]
|
|
|
66
67
|
|
|
67
68
|
[tool.poetry]
|
|
68
69
|
name = "dotflow"
|
|
69
|
-
version = "0.16.0.
|
|
70
|
+
version = "0.16.0.dev3"
|
|
70
71
|
description = "🎲 Dotflow turns an idea into flow! Lightweight Python library for execution pipelines with retry, parallel, cron and async support."
|
|
71
72
|
authors = ["Fernando Celmer <email@fernandocelmer.com>"]
|
|
72
73
|
readme = "README.md"
|
|
@@ -117,6 +118,7 @@ typing-extensions = "^4.14.1"
|
|
|
117
118
|
python-dotenv = "^1.1.0"
|
|
118
119
|
requests = "^2.32.4"
|
|
119
120
|
cookiecutter = "^2.0"
|
|
121
|
+
python-ulid = "^3.0.0"
|
|
120
122
|
|
|
121
123
|
[tool.poetry.group.dev.dependencies]
|
|
122
124
|
build = "^1.2.2.post1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|