ddeutil-workflow 0.0.3__tar.gz → 0.0.4__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.
- {ddeutil_workflow-0.0.3/src/ddeutil_workflow.egg-info → ddeutil_workflow-0.0.4}/PKG-INFO +1 -1
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/pyproject.toml +2 -2
- ddeutil_workflow-0.0.4/src/ddeutil/workflow/__about__.py +1 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/pipeline.py +42 -17
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/utils.py +7 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4/src/ddeutil_workflow.egg-info}/PKG-INFO +1 -1
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_pipeline_run.py +1 -24
- ddeutil_workflow-0.0.3/src/ddeutil/workflow/__about__.py +0 -1
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/LICENSE +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/README.md +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/__init__.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/__regex.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/__types.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/conn.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/exceptions.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/loader.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/schedule.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/tasks/__init__.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/tasks/_pandas.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/tasks/_polars.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/__dataset.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/__dict.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/__init__.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/__schedule.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/aws.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/az.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/minio.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/pd.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/pg.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/pl.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/sftp.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/SOURCES.txt +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/requires.txt +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_base_data.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_base_local_and_global.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_base_regex.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_conn.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_dataset.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_loader.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_pipeline.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_pipeline_matrix.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_pipeline_params.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_pipeline_task.py +0 -0
- {ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/tests/test_schedule.py +0 -0
@@ -80,8 +80,8 @@ addopts = [
|
|
80
80
|
]
|
81
81
|
filterwarnings = ["error"]
|
82
82
|
log_cli = true
|
83
|
-
log_cli_level = "
|
84
|
-
log_cli_format = "%(asctime)s [%(levelname)
|
83
|
+
log_cli_level = "DEBUG"
|
84
|
+
log_cli_format = "%(asctime)s [%(levelname)7s] %(message)s (%(filename)s:%(lineno)s)"
|
85
85
|
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
|
86
86
|
|
87
87
|
[tool.black]
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__: str = "0.0.4"
|
@@ -5,13 +5,17 @@
|
|
5
5
|
# ------------------------------------------------------------------------------
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
|
+
import contextlib
|
8
9
|
import inspect
|
9
10
|
import itertools
|
10
11
|
import logging
|
11
12
|
import subprocess
|
13
|
+
import sys
|
12
14
|
import time
|
15
|
+
import uuid
|
13
16
|
from abc import ABC, abstractmethod
|
14
17
|
from inspect import Parameter
|
18
|
+
from pathlib import Path
|
15
19
|
from queue import Queue
|
16
20
|
from subprocess import CompletedProcess
|
17
21
|
from typing import Any, Callable, Optional, Union
|
@@ -25,7 +29,7 @@ from .__regex import RegexConf
|
|
25
29
|
from .__types import DictData, DictStr
|
26
30
|
from .exceptions import TaskException
|
27
31
|
from .loader import Loader, map_params
|
28
|
-
from .utils import Params, make_registry
|
32
|
+
from .utils import Params, make_exec, make_registry
|
29
33
|
|
30
34
|
|
31
35
|
class BaseStage(BaseModel, ABC):
|
@@ -78,9 +82,27 @@ class ShellStage(BaseStage):
|
|
78
82
|
env: DictStr = Field(default_factory=dict)
|
79
83
|
|
80
84
|
@staticmethod
|
85
|
+
@contextlib.contextmanager
|
81
86
|
def __prepare_shell(shell: str):
|
82
|
-
"""
|
83
|
-
|
87
|
+
"""Return context of prepared shell statement that want to execute. This
|
88
|
+
step will write the `.sh` file before giving this file name to context.
|
89
|
+
After that, it will auto delete this file automatic.
|
90
|
+
|
91
|
+
:param shell: A shell statement that want to prepare.
|
92
|
+
"""
|
93
|
+
f_name: str = f"{uuid.uuid4()}.sh"
|
94
|
+
f_shebang: str = "bash" if sys.platform.startswith("win") else "sh"
|
95
|
+
with open(f"./{f_name}", mode="w", newline="\n") as f:
|
96
|
+
f.write(f"#!/bin/{f_shebang}\n")
|
97
|
+
|
98
|
+
# NOTE: make sure that shell script file does not have `\r` char.
|
99
|
+
f.write(shell.replace("\r\n", "\n"))
|
100
|
+
|
101
|
+
make_exec(f"./{f_name}")
|
102
|
+
|
103
|
+
yield [f_shebang, f_name]
|
104
|
+
|
105
|
+
Path(f_name).unlink()
|
84
106
|
|
85
107
|
def set_outputs(self, rs: CompletedProcess, params: DictData) -> DictData:
|
86
108
|
"""Set outputs to params"""
|
@@ -95,8 +117,7 @@ class ShellStage(BaseStage):
|
|
95
117
|
# NOTE: The output will fileter unnecessary keys from ``_locals``.
|
96
118
|
"outputs": {
|
97
119
|
"return_code": rs.returncode,
|
98
|
-
"stdout": rs.stdout,
|
99
|
-
"stderr": rs.stderr,
|
120
|
+
"stdout": rs.stdout.rstrip("\n"),
|
100
121
|
},
|
101
122
|
}
|
102
123
|
return params
|
@@ -105,19 +126,21 @@ class ShellStage(BaseStage):
|
|
105
126
|
"""Execute the Shell & Powershell statement with the Python build-in
|
106
127
|
``subprocess`` package.
|
107
128
|
"""
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
129
|
+
with self.__prepare_shell(self.shell) as sh:
|
130
|
+
with open(sh[-1]) as f:
|
131
|
+
logging.debug(f.read())
|
132
|
+
logging.info(f"Shell-Execute: {sh}")
|
133
|
+
rs: CompletedProcess = subprocess.run(
|
134
|
+
sh,
|
135
|
+
shell=False,
|
136
|
+
capture_output=True,
|
137
|
+
text=True,
|
138
|
+
)
|
114
139
|
if rs.returncode > 0:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
# f"{self.shell}"
|
120
|
-
# )
|
140
|
+
logging.error(f"{rs.stderr}\nRunning Statement:\n---\n{self.shell}")
|
141
|
+
raise TaskException(
|
142
|
+
f"{rs.stderr}\nRunning Statement:\n---\n{self.shell}"
|
143
|
+
)
|
121
144
|
self.set_outputs(rs, params)
|
122
145
|
return params
|
123
146
|
|
@@ -472,6 +495,7 @@ class Pipeline(BaseModel):
|
|
472
495
|
job_id: str = jq.get()
|
473
496
|
logging.info(f"[PIPELINE]: Start execute the job: {job_id!r}")
|
474
497
|
job: Job = self.jobs[job_id]
|
498
|
+
|
475
499
|
# TODO: Condition on ``needs`` of this job was set. It should create
|
476
500
|
# multithreading process on this step.
|
477
501
|
# But, I don't know how to handle changes params between each job
|
@@ -480,6 +504,7 @@ class Pipeline(BaseModel):
|
|
480
504
|
# >>> import multiprocessing
|
481
505
|
# >>> with multiprocessing.Pool(processes=3) as pool:
|
482
506
|
# ... results = pool.starmap(merge_names, ('', '', ...))
|
507
|
+
#
|
483
508
|
if any(params["jobs"].get(need) for need in job.needs):
|
484
509
|
jq.put(job_id)
|
485
510
|
job.execute(params=params)
|
@@ -6,10 +6,12 @@
|
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
8
|
import inspect
|
9
|
+
import stat
|
9
10
|
from abc import ABC, abstractmethod
|
10
11
|
from datetime import date, datetime
|
11
12
|
from functools import wraps
|
12
13
|
from importlib import import_module
|
14
|
+
from pathlib import Path
|
13
15
|
from typing import Any, Callable, Literal, Optional, Protocol, Union
|
14
16
|
|
15
17
|
from ddeutil.core import lazy
|
@@ -178,3 +180,8 @@ Params = Union[
|
|
178
180
|
DatetimeParams,
|
179
181
|
StrParams,
|
180
182
|
]
|
183
|
+
|
184
|
+
|
185
|
+
def make_exec(path: str | Path):
|
186
|
+
f: Path = Path(path) if isinstance(path, str) else path
|
187
|
+
f.chmod(f.stat().st_mode | stat.S_IEXEC)
|
@@ -63,7 +63,6 @@ def test_pipe_job_py():
|
|
63
63
|
} == rs
|
64
64
|
|
65
65
|
|
66
|
-
@pytest.mark.skipif(True, reason="Because subprocess call on different OS")
|
67
66
|
def test_pipe_stage_shell():
|
68
67
|
pipeline = pipe.Pipeline.from_loader(name="run_python", externals={})
|
69
68
|
echo_env: pipe.Job = pipeline.job("shell-run").stage("echo-env")
|
@@ -73,35 +72,13 @@ def test_pipe_stage_shell():
|
|
73
72
|
"echo-env": {
|
74
73
|
"outputs": {
|
75
74
|
"return_code": 0,
|
76
|
-
"stdout":
|
77
|
-
"stderr": "",
|
75
|
+
"stdout": "Hello World\nVariable Foo",
|
78
76
|
},
|
79
77
|
},
|
80
78
|
},
|
81
79
|
} == rs
|
82
80
|
|
83
81
|
|
84
|
-
def test_subprocess_shell():
|
85
|
-
import subprocess
|
86
|
-
from textwrap import dedent
|
87
|
-
|
88
|
-
rs = subprocess.run(
|
89
|
-
[
|
90
|
-
"powershell",
|
91
|
-
dedent(
|
92
|
-
"""
|
93
|
-
echo "Hello World";
|
94
|
-
echo "Next line";
|
95
|
-
"""
|
96
|
-
).strip(),
|
97
|
-
],
|
98
|
-
capture_output=True,
|
99
|
-
text=True,
|
100
|
-
shell=True,
|
101
|
-
)
|
102
|
-
print(rs)
|
103
|
-
|
104
|
-
|
105
82
|
def test_pipe_params_py():
|
106
83
|
pipeline = pipe.Pipeline.from_loader(
|
107
84
|
name="run_python_with_params",
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__: str = "0.0.3"
|
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
|
{ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil/workflow/vendors/__schedule.py
RENAMED
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
|
{ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/dependency_links.txt
RENAMED
File without changes
|
{ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/requires.txt
RENAMED
File without changes
|
{ddeutil_workflow-0.0.3 → ddeutil_workflow-0.0.4}/src/ddeutil_workflow.egg-info/top_level.txt
RENAMED
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
|