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.
Files changed (118) hide show
  1. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/PKG-INFO +2 -1
  2. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/__init__.py +1 -1
  3. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/server.py +1 -13
  4. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/start.py +32 -2
  5. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/setup.py +17 -5
  6. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/context.py +5 -5
  7. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/dotflow.py +0 -7
  8. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/engine.py +6 -3
  9. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/exception.py +18 -0
  10. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/task.py +1 -1
  11. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/task.py +6 -8
  12. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/server_api.py +2 -18
  13. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/pyproject.toml +5 -3
  14. dotflow-0.16.0.dev1/dotflow/constants.py +0 -3
  15. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/LICENSE +0 -0
  16. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/README.md +0 -0
  17. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/__init__.py +0 -0
  18. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/file.py +0 -0
  19. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/flow.py +0 -0
  20. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/http.py +0 -0
  21. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/log.py +0 -0
  22. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/metrics.py +0 -0
  23. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/notify.py +0 -0
  24. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/scheduler.py +0 -0
  25. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/storage.py +0 -0
  26. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/tcp.py +0 -0
  27. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/abc/tracer.py +0 -0
  28. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/__init__.py +0 -0
  29. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/command.py +0 -0
  30. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/__init__.py +0 -0
  31. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/cloud.py +0 -0
  32. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/deploy.py +0 -0
  33. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/init.py +0 -0
  34. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/log.py +0 -0
  35. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/schedule.py +0 -0
  36. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/commands/storage.py +0 -0
  37. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/validators/__init__.py +0 -0
  38. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cli/validators/start.py +0 -0
  39. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/__init__.py +0 -0
  40. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/__init__.py +0 -0
  41. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/constants.py +0 -0
  42. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/deployers/__init__.py +0 -0
  43. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/deployers/fc.py +0 -0
  44. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/deployers/fc_scheduled.py +0 -0
  45. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/services/__init__.py +0 -0
  46. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/alibaba/services/cr.py +0 -0
  47. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/__init__.py +0 -0
  48. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/constants.py +0 -0
  49. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/__init__.py +0 -0
  50. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/base_lambda.py +0 -0
  51. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/ecs.py +0 -0
  52. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/ecs_scheduled.py +0 -0
  53. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_.py +0 -0
  54. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_api.py +0 -0
  55. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_s3.py +0 -0
  56. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/deployers/lambda_sqs.py +0 -0
  57. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/schedule.py +0 -0
  58. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/__init__.py +0 -0
  59. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/cloudwatch.py +0 -0
  60. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/ecr.py +0 -0
  61. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/iam.py +0 -0
  62. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/aws/services/s3.py +0 -0
  63. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/core.py +0 -0
  64. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/__init__.py +0 -0
  65. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/constants.py +0 -0
  66. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/deployers/__init__.py +0 -0
  67. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/deployers/cloudrun.py +0 -0
  68. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/__init__.py +0 -0
  69. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/apis.py +0 -0
  70. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/artifact_registry.py +0 -0
  71. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/gcp/services/gcs.py +0 -0
  72. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/__init__.py +0 -0
  73. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/constants.py +0 -0
  74. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/deployers/__init__.py +0 -0
  75. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/cloud/github/deployers/actions.py +0 -0
  76. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/__init__.py +0 -0
  77. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/action.py +0 -0
  78. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/config.py +0 -0
  79. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/decorators/__init__.py +0 -0
  80. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/decorators/time.py +0 -0
  81. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/module.py +0 -0
  82. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/__init__.py +0 -0
  83. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/transport.py +0 -0
  84. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/serializers/workflow.py +0 -0
  85. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/__init__.py +0 -0
  86. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/execution.py +0 -0
  87. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/overlap.py +0 -0
  88. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/status.py +0 -0
  89. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/storage.py +0 -0
  90. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/types/workflow.py +0 -0
  91. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/core/workflow.py +0 -0
  92. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/logging.py +0 -0
  93. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/main.py +0 -0
  94. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/__init__.py +0 -0
  95. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/log_default.py +0 -0
  96. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/log_opentelemetry.py +0 -0
  97. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/log_sentry.py +0 -0
  98. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/metrics_default.py +0 -0
  99. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/metrics_opentelemetry.py +0 -0
  100. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/notify_default.py +0 -0
  101. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/notify_discord.py +0 -0
  102. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/notify_telegram.py +0 -0
  103. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/scheduler_cron.py +0 -0
  104. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/scheduler_default.py +0 -0
  105. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/server_default.py +0 -0
  106. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_default.py +0 -0
  107. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_file.py +0 -0
  108. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_gcs.py +0 -0
  109. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/storage_s3.py +0 -0
  110. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/tracer_default.py +0 -0
  111. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/tracer_opentelemetry.py +0 -0
  112. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/providers/tracer_sentry.py +0 -0
  113. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/settings.py +0 -0
  114. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/types.py +0 -0
  115. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/__init__.py +0 -0
  116. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/basic_functions.py +0 -0
  117. {dotflow-0.16.0.dev1 → dotflow-0.16.0.dev3}/dotflow/utils/error_handler.py +0 -0
  118. {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.dev1
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"
@@ -1,6 +1,6 @@
1
1
  """Dotflow __init__ module."""
2
2
 
3
- __version__ = "0.16.0.dev1"
3
+ __version__ = "0.16.0.dev3"
4
4
  __description__ = "🎲 Dotflow turns an idea into flow!"
5
5
 
6
6
  from .core.action import Action as action
@@ -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 and task
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
- if self.params.mode == TypeExecution.BACKGROUND:
32
- system("/bin/bash")
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
- self.cmd_start = self.subparsers.add_parser("start", help="Start")
60
- self.cmd_start = self.cmd_start.add_argument_group(
61
- "Usage: dotflow start [OPTIONS]"
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.add_argument("-s", "--step", required=True)
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
- self.cmd_start.set_defaults(exec=StartCommand)
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 (int): 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: int = 0,
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: int):
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, int):
74
+ if not isinstance(value, str):
75
75
  raise TypeError(
76
- f"task_id must be an int, got {type(value).__name__}: {value!r}"
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 index, new in enumerate(ordered_list):
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 = index
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 = index
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: int = Field(default=None)
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 dotflow.constants import INITIAL_TASK_ID
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=1,
61
+ task_id="01ARZ3NDEKTSV4RRFFQ69G5FAV",
61
62
  step=my_step,
62
63
  callback=my_callback
63
64
  )
64
65
 
65
66
  Args:
66
- task_id (int): 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: int,
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 = self._next_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 get, patch, post
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.dev1"
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.dev1"
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"
@@ -1,3 +0,0 @@
1
- """Project-wide constants."""
2
-
3
- INITIAL_TASK_ID: int = 1
File without changes
File without changes