dotflow 0.9.0.dev2__tar.gz → 0.10.0.dev1__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.9.0.dev2 → dotflow-0.10.0.dev1}/PKG-INFO +9 -8
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/README.md +7 -7
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/__init__.py +3 -5
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/abc/file.py +1 -1
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/abc/http.py +1 -1
- dotflow-0.10.0.dev1/dotflow/abc/storage.py +25 -0
- dotflow-0.10.0.dev1/dotflow/cli/commands/start.py +35 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/setup.py +4 -8
- dotflow-0.10.0.dev1/dotflow/core/action.py +129 -0
- dotflow-0.10.0.dev1/dotflow/core/config.py +27 -0
- dotflow-0.10.0.dev1/dotflow/core/context.py +107 -0
- dotflow-0.10.0.dev1/dotflow/core/decorators/__init__.py +8 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/decorators/time.py +1 -0
- dotflow-0.10.0.dev1/dotflow/core/dotflow.py +75 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/exception.py +17 -5
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/execution.py +21 -4
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/module.py +2 -2
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/task.py +94 -59
- dotflow-0.10.0.dev1/dotflow/core/types/execution.py +17 -0
- dotflow-0.10.0.dev1/dotflow/core/types/status.py +19 -0
- dotflow-0.10.0.dev1/dotflow/core/types/worflow.py +14 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/workflow.py +55 -4
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/main.py +1 -0
- dotflow-0.10.0.dev1/dotflow/providers/__init__.py +9 -0
- dotflow-0.10.0.dev1/dotflow/providers/storage_file.py +35 -0
- dotflow-0.10.0.dev1/dotflow/providers/storage_init.py +20 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/settings.py +1 -0
- dotflow-0.10.0.dev1/dotflow/storage.py +28 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/utils/tools.py +10 -4
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/pyproject.toml +7 -3
- dotflow-0.9.0.dev2/dotflow/cli/commands/start.py +0 -31
- dotflow-0.9.0.dev2/dotflow/core/action.py +0 -70
- dotflow-0.9.0.dev2/dotflow/core/config.py +0 -21
- dotflow-0.9.0.dev2/dotflow/core/context.py +0 -15
- dotflow-0.9.0.dev2/dotflow/core/decorators/__init__.py +0 -12
- dotflow-0.9.0.dev2/dotflow/core/decorators/action.py +0 -17
- dotflow-0.9.0.dev2/dotflow/core/decorators/retry.py +0 -29
- dotflow-0.9.0.dev2/dotflow/core/dotflow.py +0 -37
- dotflow-0.9.0.dev2/dotflow/core/types/execution.py +0 -9
- dotflow-0.9.0.dev2/dotflow/core/types/status.py +0 -11
- dotflow-0.9.0.dev2/dotflow/core/types/worflow.py +0 -8
- dotflow-0.9.0.dev2/dotflow/providers/__init__.py +0 -1
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/LICENSE +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/abc/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/abc/tcp.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/command.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/commands/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/commands/init.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/commands/log.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/validators/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/cli/validators/start.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/serializers/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/serializers/task.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/serializers/transport.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/serializers/workflow.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/core/types/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/logging.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/providers/zeromq.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/utils/__init__.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/utils/basic_functions.py +0 -0
- {dotflow-0.9.0.dev2 → dotflow-0.10.0.dev1}/dotflow/utils/error_handler.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: dotflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0.dev1
|
|
4
4
|
Summary: 🎲 Dotflow turns an idea into flow!
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -36,6 +36,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
36
36
|
Classifier: Programming Language :: Python :: 3.12
|
|
37
37
|
Requires-Dist: pydantic
|
|
38
38
|
Requires-Dist: rich
|
|
39
|
+
Requires-Dist: typing-extensions
|
|
39
40
|
Project-URL: Documentation, https://github.com/dotflow-io/dotflow/blob/master/README.md
|
|
40
41
|
Project-URL: Homepage, https://github.com/dotflow-io/dotflow
|
|
41
42
|
Project-URL: Issues, https://github.com/dotflow-io/dotflow/issues
|
|
@@ -106,7 +107,7 @@ workflow.start()
|
|
|
106
107
|
|
|
107
108
|
#### 1 - Import
|
|
108
109
|
|
|
109
|
-
Start with the basics, which is importing the necessary classes and methods. ([DotFlow](https://dotflow-io.github.io/dotflow/nav/reference/dotflow
|
|
110
|
+
Start with the basics, which is importing the necessary classes and methods. ([DotFlow](https://dotflow-io.github.io/dotflow/nav/reference/dotflow/), [action](https://dotflow-io.github.io/dotflow/nav/reference/action/))
|
|
110
111
|
|
|
111
112
|
```python
|
|
112
113
|
from dotflow import DotFlow, action
|
|
@@ -114,7 +115,7 @@ from dotflow import DotFlow, action
|
|
|
114
115
|
|
|
115
116
|
#### 2 - Callback function
|
|
116
117
|
|
|
117
|
-
Create a `my_callback` function to receive execution information of a task. `It is not necessary` to include this function, as you will still have a report at the end of the execution in the instantiated object of the `DotFlow` class. This `my_callback` function is only needed if you need to do something after the execution of the task, for example: sending a message to someone, making a phone call, or sending a letter.
|
|
118
|
+
Create a `my_callback` function to receive execution information of a task. `It is not necessary` to include this function, as you will still have a report at the end of the execution in the instantiated object of the `DotFlow` class. This `my_callback` function is only needed if you need to do something after the execution of the task, for example: sending a message to someone, making a phone call, or sending a letter. [More details](https://dotflow-io.github.io/dotflow/nav/reference/utils/#dotflow.utils.basic_functions.basic_callback)
|
|
118
119
|
|
|
119
120
|
```python
|
|
120
121
|
def my_callback(*args, **kwargs):
|
|
@@ -123,7 +124,7 @@ def my_callback(*args, **kwargs):
|
|
|
123
124
|
|
|
124
125
|
#### 3 - Task function
|
|
125
126
|
|
|
126
|
-
Now, create the function responsible for executing your task. It's very simple; just use the [action](https://dotflow-io.github.io/dotflow/nav/reference/action
|
|
127
|
+
Now, create the function responsible for executing your task. It's very simple; just use the [action](https://dotflow-io.github.io/dotflow/nav/reference/action/) decorator above the function, and that's it—you've created a task. If necessary, you can also add the parameter called `retry` to set the maximum number of execution attempts if the function fails. [More details](https://dotflow-io.github.io/dotflow/nav/reference/utils/#dotflow.utils.basic_functions.basic_function)
|
|
127
128
|
|
|
128
129
|
```python
|
|
129
130
|
@action(retry=5)
|
|
@@ -133,7 +134,7 @@ def my_task():
|
|
|
133
134
|
|
|
134
135
|
#### 4 - DotFlow Class
|
|
135
136
|
|
|
136
|
-
Instantiate the DotFlow class in a `workflow` variable to be used in the following steps. [More details](https://dotflow-io.github.io/dotflow/nav/reference/dotflow
|
|
137
|
+
Instantiate the DotFlow class in a `workflow` variable to be used in the following steps. [More details](https://dotflow-io.github.io/dotflow/nav/reference/dotflow/).
|
|
137
138
|
|
|
138
139
|
```python
|
|
139
140
|
workflow = DotFlow()
|
|
@@ -141,7 +142,7 @@ workflow = DotFlow()
|
|
|
141
142
|
|
|
142
143
|
#### 5 - Add Task
|
|
143
144
|
|
|
144
|
-
Now, simply add the `my_task` and `my_callback` functions you created earlier to the workflow using the code below. This process is necessary to define which tasks will be executed and the order in which they will run. The execution order follows the sequence in which they were added to the workflow.
|
|
145
|
+
Now, simply add the `my_task` and `my_callback` functions you created earlier to the workflow using the code below. This process is necessary to define which tasks will be executed and the order in which they will run. The execution order follows the sequence in which they were added to the workflow. [More details](https://dotflow-io.github.io/dotflow/nav/reference/task-builder/#dotflow.core.task.TaskBuilder.add)
|
|
145
146
|
|
|
146
147
|
```python
|
|
147
148
|
workflow.task.add(step=my_task, callback=my_callback)
|
|
@@ -149,7 +150,7 @@ workflow.task.add(step=my_task, callback=my_callback)
|
|
|
149
150
|
|
|
150
151
|
#### 6 - Start
|
|
151
152
|
|
|
152
|
-
Finally, just execute the workflow with the following code snippet.
|
|
153
|
+
Finally, just execute the workflow with the following code snippet. [More details](https://dotflow-io.github.io/dotflow/nav/reference/workflow/#dotflow.core.workflow.Workflow)
|
|
153
154
|
|
|
154
155
|
```python
|
|
155
156
|
workflow.start()
|
|
@@ -196,7 +197,7 @@ workflow.start()
|
|
|
196
197
|
- ⚠️ SECURITY
|
|
197
198
|
|
|
198
199
|
## License
|
|
199
|
-

|
|
200
201
|
|
|
201
202
|
This project is licensed under the terms of the MIT License.
|
|
202
203
|
|
|
@@ -62,7 +62,7 @@ workflow.start()
|
|
|
62
62
|
|
|
63
63
|
#### 1 - Import
|
|
64
64
|
|
|
65
|
-
Start with the basics, which is importing the necessary classes and methods. ([DotFlow](https://dotflow-io.github.io/dotflow/nav/reference/dotflow
|
|
65
|
+
Start with the basics, which is importing the necessary classes and methods. ([DotFlow](https://dotflow-io.github.io/dotflow/nav/reference/dotflow/), [action](https://dotflow-io.github.io/dotflow/nav/reference/action/))
|
|
66
66
|
|
|
67
67
|
```python
|
|
68
68
|
from dotflow import DotFlow, action
|
|
@@ -70,7 +70,7 @@ from dotflow import DotFlow, action
|
|
|
70
70
|
|
|
71
71
|
#### 2 - Callback function
|
|
72
72
|
|
|
73
|
-
Create a `my_callback` function to receive execution information of a task. `It is not necessary` to include this function, as you will still have a report at the end of the execution in the instantiated object of the `DotFlow` class. This `my_callback` function is only needed if you need to do something after the execution of the task, for example: sending a message to someone, making a phone call, or sending a letter.
|
|
73
|
+
Create a `my_callback` function to receive execution information of a task. `It is not necessary` to include this function, as you will still have a report at the end of the execution in the instantiated object of the `DotFlow` class. This `my_callback` function is only needed if you need to do something after the execution of the task, for example: sending a message to someone, making a phone call, or sending a letter. [More details](https://dotflow-io.github.io/dotflow/nav/reference/utils/#dotflow.utils.basic_functions.basic_callback)
|
|
74
74
|
|
|
75
75
|
```python
|
|
76
76
|
def my_callback(*args, **kwargs):
|
|
@@ -79,7 +79,7 @@ def my_callback(*args, **kwargs):
|
|
|
79
79
|
|
|
80
80
|
#### 3 - Task function
|
|
81
81
|
|
|
82
|
-
Now, create the function responsible for executing your task. It's very simple; just use the [action](https://dotflow-io.github.io/dotflow/nav/reference/action
|
|
82
|
+
Now, create the function responsible for executing your task. It's very simple; just use the [action](https://dotflow-io.github.io/dotflow/nav/reference/action/) decorator above the function, and that's it—you've created a task. If necessary, you can also add the parameter called `retry` to set the maximum number of execution attempts if the function fails. [More details](https://dotflow-io.github.io/dotflow/nav/reference/utils/#dotflow.utils.basic_functions.basic_function)
|
|
83
83
|
|
|
84
84
|
```python
|
|
85
85
|
@action(retry=5)
|
|
@@ -89,7 +89,7 @@ def my_task():
|
|
|
89
89
|
|
|
90
90
|
#### 4 - DotFlow Class
|
|
91
91
|
|
|
92
|
-
Instantiate the DotFlow class in a `workflow` variable to be used in the following steps. [More details](https://dotflow-io.github.io/dotflow/nav/reference/dotflow
|
|
92
|
+
Instantiate the DotFlow class in a `workflow` variable to be used in the following steps. [More details](https://dotflow-io.github.io/dotflow/nav/reference/dotflow/).
|
|
93
93
|
|
|
94
94
|
```python
|
|
95
95
|
workflow = DotFlow()
|
|
@@ -97,7 +97,7 @@ workflow = DotFlow()
|
|
|
97
97
|
|
|
98
98
|
#### 5 - Add Task
|
|
99
99
|
|
|
100
|
-
Now, simply add the `my_task` and `my_callback` functions you created earlier to the workflow using the code below. This process is necessary to define which tasks will be executed and the order in which they will run. The execution order follows the sequence in which they were added to the workflow.
|
|
100
|
+
Now, simply add the `my_task` and `my_callback` functions you created earlier to the workflow using the code below. This process is necessary to define which tasks will be executed and the order in which they will run. The execution order follows the sequence in which they were added to the workflow. [More details](https://dotflow-io.github.io/dotflow/nav/reference/task-builder/#dotflow.core.task.TaskBuilder.add)
|
|
101
101
|
|
|
102
102
|
```python
|
|
103
103
|
workflow.task.add(step=my_task, callback=my_callback)
|
|
@@ -105,7 +105,7 @@ workflow.task.add(step=my_task, callback=my_callback)
|
|
|
105
105
|
|
|
106
106
|
#### 6 - Start
|
|
107
107
|
|
|
108
|
-
Finally, just execute the workflow with the following code snippet.
|
|
108
|
+
Finally, just execute the workflow with the following code snippet. [More details](https://dotflow-io.github.io/dotflow/nav/reference/workflow/#dotflow.core.workflow.Workflow)
|
|
109
109
|
|
|
110
110
|
```python
|
|
111
111
|
workflow.start()
|
|
@@ -152,6 +152,6 @@ workflow.start()
|
|
|
152
152
|
- ⚠️ SECURITY
|
|
153
153
|
|
|
154
154
|
## License
|
|
155
|
-

|
|
156
156
|
|
|
157
157
|
This project is licensed under the terms of the MIT License.
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
"""Dotflow __init__ module."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.
|
|
3
|
+
__version__ = "0.10.0.dev1"
|
|
4
4
|
__description__ = "🎲 Dotflow turns an idea into flow!"
|
|
5
5
|
|
|
6
|
-
from .core.config import Config
|
|
7
6
|
from .core.action import Action as action
|
|
7
|
+
from .core.config import Config
|
|
8
8
|
from .core.context import Context
|
|
9
9
|
from .core.dotflow import DotFlow
|
|
10
10
|
from .core.task import Task
|
|
11
|
-
from .core.decorators import retry # deprecated
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
__all__ = [
|
|
15
14
|
"action",
|
|
16
|
-
"retry",
|
|
17
|
-
"DotFlow",
|
|
18
15
|
"Context",
|
|
19
16
|
"Config",
|
|
17
|
+
"DotFlow",
|
|
20
18
|
"Task"
|
|
21
19
|
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Storage ABC"""
|
|
2
|
+
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
|
|
6
|
+
from dotflow.core.context import Context
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Storage(ABC):
|
|
10
|
+
"""Storage"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, *args, **kwargs):
|
|
13
|
+
super().__init__()
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def post(self, key: str, context: Context) -> None:
|
|
17
|
+
"""Post context somewhere"""
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def get(self, key: str) -> Context:
|
|
21
|
+
"""Get context somewhere"""
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def key(self, task: Callable):
|
|
25
|
+
"""Function that returns a key to get and post storage"""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Command start module"""
|
|
2
|
+
|
|
3
|
+
from os import system
|
|
4
|
+
|
|
5
|
+
from dotflow import DotFlow, Config
|
|
6
|
+
from dotflow.providers import StorageInit, StorageFile
|
|
7
|
+
from dotflow.core.types.execution import TypeExecution
|
|
8
|
+
from dotflow.cli.command import Command
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StartCommand(Command):
|
|
12
|
+
|
|
13
|
+
def setup(self):
|
|
14
|
+
workflow = DotFlow()
|
|
15
|
+
|
|
16
|
+
if self.params.storage:
|
|
17
|
+
storage = {"default": StorageInit, "file": StorageFile}
|
|
18
|
+
|
|
19
|
+
config = Config(
|
|
20
|
+
storage=storage.get(self.params.storage)(
|
|
21
|
+
path=self.params.path,
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
workflow = DotFlow(config=config)
|
|
25
|
+
|
|
26
|
+
workflow.task.add(
|
|
27
|
+
step=self.params.step,
|
|
28
|
+
callback=self.params.callback,
|
|
29
|
+
initial_context=self.params.initial_context,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
workflow.start(mode=self.params.mode)
|
|
33
|
+
|
|
34
|
+
if self.params.mode == TypeExecution.BACKGROUND:
|
|
35
|
+
system("/bin/bash")
|
|
@@ -10,7 +10,7 @@ from dotflow.core.types.execution import TypeExecution
|
|
|
10
10
|
from dotflow.core.exception import (
|
|
11
11
|
MissingActionDecorator,
|
|
12
12
|
ExecutionModeNotExist,
|
|
13
|
-
|
|
13
|
+
ImportModuleError,
|
|
14
14
|
MESSAGE_UNKNOWN_ERROR,
|
|
15
15
|
)
|
|
16
16
|
from dotflow.cli.commands import (
|
|
@@ -56,9 +56,7 @@ class Command:
|
|
|
56
56
|
self.cmd_start.add_argument("-s", "--step", required=True)
|
|
57
57
|
self.cmd_start.add_argument("-c", "--callback", default=basic_callback)
|
|
58
58
|
self.cmd_start.add_argument("-i", "--initial-context")
|
|
59
|
-
self.cmd_start.add_argument(
|
|
60
|
-
"-o", "--output-context", default=False, action="store_true"
|
|
61
|
-
)
|
|
59
|
+
self.cmd_start.add_argument("-o", "--storage", choices=["default", "file"])
|
|
62
60
|
self.cmd_start.add_argument("-p", "--path", default=settings.START_PATH)
|
|
63
61
|
self.cmd_start.add_argument(
|
|
64
62
|
"-m",
|
|
@@ -71,9 +69,7 @@ class Command:
|
|
|
71
69
|
|
|
72
70
|
def setup_logs(self):
|
|
73
71
|
self.cmd_logs = self.subparsers.add_parser("logs", help="Logs")
|
|
74
|
-
self.cmd_logs = self.cmd_logs.add_argument_group(
|
|
75
|
-
"Usage: dotflow log [OPTIONS]"
|
|
76
|
-
)
|
|
72
|
+
self.cmd_logs = self.cmd_logs.add_argument_group("Usage: dotflow log [OPTIONS]")
|
|
77
73
|
self.cmd_logs.set_defaults(exec=LogCommand)
|
|
78
74
|
|
|
79
75
|
def command(self):
|
|
@@ -89,7 +85,7 @@ class Command:
|
|
|
89
85
|
except ExecutionModeNotExist as err:
|
|
90
86
|
print(settings.WARNING_ALERT, err)
|
|
91
87
|
|
|
92
|
-
except
|
|
88
|
+
except ImportModuleError as err:
|
|
93
89
|
print(settings.WARNING_ALERT, err)
|
|
94
90
|
|
|
95
91
|
except Exception as err:
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Action module"""
|
|
2
|
+
|
|
3
|
+
from typing import Callable, Dict
|
|
4
|
+
from types import FunctionType
|
|
5
|
+
|
|
6
|
+
from dotflow.core.context import Context
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Action(object):
|
|
10
|
+
"""
|
|
11
|
+
Import:
|
|
12
|
+
You can import the **action** decorator directly from dotflow:
|
|
13
|
+
|
|
14
|
+
from dotflow import action
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
`class` dotflow.core.action.Action
|
|
18
|
+
|
|
19
|
+
Standard
|
|
20
|
+
|
|
21
|
+
@action
|
|
22
|
+
def my_task():
|
|
23
|
+
print("task")
|
|
24
|
+
|
|
25
|
+
With Retry
|
|
26
|
+
|
|
27
|
+
@action(retry=5)
|
|
28
|
+
def my_task():
|
|
29
|
+
print("task")
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
func (Callable):
|
|
33
|
+
|
|
34
|
+
task (Callable):
|
|
35
|
+
|
|
36
|
+
retry (int):
|
|
37
|
+
Integer-type argument referring to the number of retry attempts
|
|
38
|
+
the function will execute in case of failure.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
func: Callable = None,
|
|
44
|
+
task: Callable = None,
|
|
45
|
+
retry: int = 1
|
|
46
|
+
) -> None:
|
|
47
|
+
self.func = func
|
|
48
|
+
self.task = task
|
|
49
|
+
self.retry = retry
|
|
50
|
+
self.params = []
|
|
51
|
+
|
|
52
|
+
def __call__(self, *args, **kwargs):
|
|
53
|
+
# With parameters
|
|
54
|
+
if self.func:
|
|
55
|
+
self._set_params()
|
|
56
|
+
|
|
57
|
+
task = self._get_task(kwargs=kwargs)
|
|
58
|
+
contexts = self._get_context(kwargs=kwargs)
|
|
59
|
+
|
|
60
|
+
if contexts:
|
|
61
|
+
return Context(
|
|
62
|
+
storage=self._retry(*args, **contexts),
|
|
63
|
+
task_id=task.task_id,
|
|
64
|
+
workflow_id=task.workflow_id
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return Context(
|
|
68
|
+
storage=self._retry(*args),
|
|
69
|
+
task_id=task.task_id,
|
|
70
|
+
workflow_id=task.workflow_id
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# No parameters
|
|
74
|
+
def action(*_args, **_kwargs):
|
|
75
|
+
self.func = args[0]
|
|
76
|
+
self._set_params()
|
|
77
|
+
|
|
78
|
+
task = self._get_task(kwargs=_kwargs)
|
|
79
|
+
contexts = self._get_context(kwargs=_kwargs)
|
|
80
|
+
|
|
81
|
+
if contexts:
|
|
82
|
+
return Context(
|
|
83
|
+
storage=self._retry(*_args, **contexts),
|
|
84
|
+
task_id=task.task_id,
|
|
85
|
+
workflow_id=task.workflow_id
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return Context(
|
|
89
|
+
storage=self._retry(*_args),
|
|
90
|
+
task_id=task.task_id,
|
|
91
|
+
workflow_id=task.workflow_id
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return action
|
|
95
|
+
|
|
96
|
+
def _retry(self, *args, **kwargs):
|
|
97
|
+
attempt = 0
|
|
98
|
+
exception = Exception()
|
|
99
|
+
|
|
100
|
+
while self.retry > attempt:
|
|
101
|
+
try:
|
|
102
|
+
return self.func(*args, **kwargs)
|
|
103
|
+
except Exception as error:
|
|
104
|
+
exception = error
|
|
105
|
+
attempt += 1
|
|
106
|
+
|
|
107
|
+
raise exception
|
|
108
|
+
|
|
109
|
+
def _set_params(self):
|
|
110
|
+
if isinstance(self.func, FunctionType):
|
|
111
|
+
self.params = [param for param in self.func.__code__.co_varnames]
|
|
112
|
+
|
|
113
|
+
if type(self.func) is type:
|
|
114
|
+
if hasattr(self.func, "__init__"):
|
|
115
|
+
if hasattr(self.func.__init__, "__code__"):
|
|
116
|
+
self.params = [param for param in self.func.__init__.__code__.co_varnames]
|
|
117
|
+
|
|
118
|
+
def _get_context(self, kwargs: Dict):
|
|
119
|
+
context = {}
|
|
120
|
+
if "initial_context" in self.params:
|
|
121
|
+
context["initial_context"] = Context(kwargs.get("initial_context"))
|
|
122
|
+
|
|
123
|
+
if "previous_context" in self.params:
|
|
124
|
+
context["previous_context"] = Context(kwargs.get("previous_context"))
|
|
125
|
+
|
|
126
|
+
return context
|
|
127
|
+
|
|
128
|
+
def _get_task(self, kwargs: Dict):
|
|
129
|
+
return kwargs.get("task")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Config module"""
|
|
2
|
+
|
|
3
|
+
from dotflow.abc.storage import Storage
|
|
4
|
+
from dotflow.providers.storage_init import StorageInit
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Config:
|
|
8
|
+
"""
|
|
9
|
+
Import:
|
|
10
|
+
You can import the **Config** class with:
|
|
11
|
+
|
|
12
|
+
from dotflow import Config, StorageInit
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
`class` dotflow.core.config.Config
|
|
16
|
+
|
|
17
|
+
config = Config(storage=StorageInit)
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
storage (Storage): Type of the storage.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
storage (Storage):
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, storage: Storage = StorageInit()) -> None:
|
|
27
|
+
self.storage = storage
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Context module"""
|
|
2
|
+
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContextInstance:
|
|
10
|
+
"""
|
|
11
|
+
Import:
|
|
12
|
+
You can import the **ContextInstance** class with:
|
|
13
|
+
|
|
14
|
+
from dotflow.core.context import ContextInstance
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, *args, **kwargs):
|
|
18
|
+
self._time = None
|
|
19
|
+
self._task_id = None
|
|
20
|
+
self._workflow_id = None
|
|
21
|
+
self._storage = None
|
|
22
|
+
self._current_key = None
|
|
23
|
+
self._previous_key = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Context(ContextInstance):
|
|
27
|
+
"""
|
|
28
|
+
Import:
|
|
29
|
+
You can import the Context class directly from dotflow:
|
|
30
|
+
|
|
31
|
+
from dotflow import Context
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
`class` dotflow.core.context.Context
|
|
35
|
+
|
|
36
|
+
Context(
|
|
37
|
+
storage={"data": [0, 1, 2, 3]}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
storage (Any): Attribute where any type of Python object can be stored.
|
|
42
|
+
|
|
43
|
+
task_id (int): Task ID.
|
|
44
|
+
|
|
45
|
+
workflow_id (UUID): Workflow ID.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
storage: Any = None,
|
|
51
|
+
task_id: int = None,
|
|
52
|
+
workflow_id: UUID = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
super().__init__(
|
|
55
|
+
task_id,
|
|
56
|
+
storage,
|
|
57
|
+
task_id,
|
|
58
|
+
workflow_id
|
|
59
|
+
)
|
|
60
|
+
self.time = datetime.now()
|
|
61
|
+
self.task_id = task_id
|
|
62
|
+
self.workflow_id = workflow_id
|
|
63
|
+
self.storage = storage
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def time(self):
|
|
67
|
+
return self._time
|
|
68
|
+
|
|
69
|
+
@time.setter
|
|
70
|
+
def time(self, value: datetime):
|
|
71
|
+
self._time = value
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def task_id(self):
|
|
75
|
+
return self._task_id
|
|
76
|
+
|
|
77
|
+
@task_id.setter
|
|
78
|
+
def task_id(self, value: int):
|
|
79
|
+
if isinstance(value, int):
|
|
80
|
+
self._task_id = value
|
|
81
|
+
|
|
82
|
+
if not self.task_id:
|
|
83
|
+
self._task_id = value
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def workflow_id(self):
|
|
87
|
+
return self._workflow_id
|
|
88
|
+
|
|
89
|
+
@workflow_id.setter
|
|
90
|
+
def workflow_id(self, value: UUID):
|
|
91
|
+
if isinstance(value, UUID):
|
|
92
|
+
self._workflow_id = value
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def storage(self):
|
|
96
|
+
return self._storage
|
|
97
|
+
|
|
98
|
+
@storage.setter
|
|
99
|
+
def storage(self, value: Any):
|
|
100
|
+
if isinstance(value, Context):
|
|
101
|
+
self._storage = value.storage
|
|
102
|
+
|
|
103
|
+
self.time = value.time
|
|
104
|
+
self.task_id = value.task_id
|
|
105
|
+
self.workflow_id = value.workflow_id
|
|
106
|
+
else:
|
|
107
|
+
self._storage = value
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""DotFlow"""
|
|
2
|
+
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
from functools import partial
|
|
5
|
+
|
|
6
|
+
from dotflow.core.config import Config
|
|
7
|
+
from dotflow.core.workflow import Workflow
|
|
8
|
+
from dotflow.core.task import TaskBuilder
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DotFlow:
|
|
12
|
+
"""
|
|
13
|
+
Import:
|
|
14
|
+
You can import the **Dotflow** class directly from dotflow:
|
|
15
|
+
|
|
16
|
+
from dotflow import DotFlow, Config
|
|
17
|
+
from dotflow.storage import StorageFile
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
`class` dotflow.core.dotflow.Dotflow
|
|
21
|
+
|
|
22
|
+
config = Config(
|
|
23
|
+
storage=StorageFile()
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
workflow = DotFlow(config=config)
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
config (Config): Configuration class.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
workflow_id (UUID):
|
|
33
|
+
|
|
34
|
+
task (List[Task]):
|
|
35
|
+
|
|
36
|
+
start (Workflow):
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
config: Config = Config()
|
|
42
|
+
) -> None:
|
|
43
|
+
self.workflow_id = uuid4()
|
|
44
|
+
|
|
45
|
+
self.task = TaskBuilder(
|
|
46
|
+
config=config,
|
|
47
|
+
workflow_id=self.workflow_id
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
self.start = partial(
|
|
51
|
+
Workflow,
|
|
52
|
+
tasks=self.task.queu,
|
|
53
|
+
id=self.workflow_id
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def result_task(self):
|
|
57
|
+
"""
|
|
58
|
+
Returns:
|
|
59
|
+
list (List[Task]): Returns a list of Task class.
|
|
60
|
+
"""
|
|
61
|
+
return self.task.queu
|
|
62
|
+
|
|
63
|
+
def result_context(self):
|
|
64
|
+
"""
|
|
65
|
+
Returns:
|
|
66
|
+
list (List[Context]): Returns a list of Context class.
|
|
67
|
+
"""
|
|
68
|
+
return [task.current_context for task in self.task.queu]
|
|
69
|
+
|
|
70
|
+
def result_storage(self):
|
|
71
|
+
"""
|
|
72
|
+
Returns:
|
|
73
|
+
list (List[Any]): Returns a list of assorted objects.
|
|
74
|
+
"""
|
|
75
|
+
return [task.current_context.storage for task in self.task.queu]
|
|
@@ -4,8 +4,9 @@ MESSAGE_UNKNOWN_ERROR = "Unknown error, please check logs for more information."
|
|
|
4
4
|
MESSAGE_MISSING_STEP_DECORATOR = "A step function necessarily needs an '@action' decorator to circulate in the workflow. For more implementation details, access the documentation: https://dotflow-io.github.io/dotflow/nav/getting-started/#3-task-function."
|
|
5
5
|
MESSAGE_NOT_CALLABLE_OBJECT = "Problem validating the '{name}' object type; this is not a callable object"
|
|
6
6
|
MESSAGE_EXECUTION_NOT_EXIST = "The execution mode does not exist. Allowed parameter is 'sequential' and 'background'."
|
|
7
|
-
|
|
7
|
+
MESSAGE_IMPORT_MODULE_ERROR = "Error importing Python module '{module}'."
|
|
8
8
|
MESSAGE_PROBLEM_ORDERING = "Problem with correctly ordering functions of the '{name}' class."
|
|
9
|
+
MESSAGE_MODULE_NOT_FOUND = "Module '{module}' not found. Please install with 'pip install {library}'"
|
|
9
10
|
|
|
10
11
|
class MissingActionDecorator(Exception):
|
|
11
12
|
|
|
@@ -23,11 +24,11 @@ class ExecutionModeNotExist(Exception):
|
|
|
23
24
|
)
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
class
|
|
27
|
+
class ImportModuleError(Exception):
|
|
27
28
|
|
|
28
29
|
def __init__(self, module: str):
|
|
29
|
-
super(
|
|
30
|
-
|
|
30
|
+
super(ImportModuleError, self).__init__(
|
|
31
|
+
MESSAGE_IMPORT_MODULE_ERROR.format(
|
|
31
32
|
module=module
|
|
32
33
|
)
|
|
33
34
|
)
|
|
@@ -50,4 +51,15 @@ class ProblemOrdering(Exception):
|
|
|
50
51
|
MESSAGE_PROBLEM_ORDERING.format(
|
|
51
52
|
name=name
|
|
52
53
|
)
|
|
53
|
-
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ModuleNotFound(Exception):
|
|
58
|
+
|
|
59
|
+
def __init__(self, module: str, library: str):
|
|
60
|
+
super(ModuleNotFound, self).__init__(
|
|
61
|
+
MESSAGE_MODULE_NOT_FOUND.format(
|
|
62
|
+
module=module,
|
|
63
|
+
library=library
|
|
64
|
+
)
|
|
65
|
+
)
|