fractal-server 2.14.4__py3-none-any.whl → 2.14.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fractal_server/__init__.py +1 -1
- fractal_server/app/runner/exceptions.py +1 -6
- fractal_server/app/runner/executors/base_runner.py +16 -4
- fractal_server/app/runner/executors/call_command_wrapper.py +52 -0
- fractal_server/app/runner/executors/local/runner.py +52 -13
- fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +87 -52
- fractal_server/app/runner/executors/slurm_common/remote.py +47 -92
- fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +20 -19
- fractal_server/app/runner/executors/slurm_ssh/runner.py +1 -2
- fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +1 -4
- fractal_server/app/runner/executors/slurm_sudo/runner.py +3 -11
- fractal_server/app/runner/task_files.py +0 -8
- fractal_server/app/runner/v2/_slurm_ssh.py +1 -2
- fractal_server/app/runner/v2/_slurm_sudo.py +1 -2
- fractal_server/app/runner/v2/runner_functions.py +16 -30
- fractal_server/app/runner/versions.py +2 -11
- fractal_server/config.py +0 -9
- {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/METADATA +1 -7
- {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/RECORD +22 -23
- fractal_server/app/runner/executors/slurm_common/utils_executors.py +0 -58
- fractal_server/app/runner/v2/runner_functions_low_level.py +0 -122
- {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/LICENSE +0 -0
- {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/WHEEL +0 -0
- {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/entry_points.txt +0 -0
@@ -1,58 +0,0 @@
|
|
1
|
-
from pathlib import Path
|
2
|
-
from typing import Literal
|
3
|
-
from typing import Optional
|
4
|
-
|
5
|
-
|
6
|
-
def get_pickle_file_path(
|
7
|
-
*,
|
8
|
-
arg: str,
|
9
|
-
workflow_dir: Path,
|
10
|
-
subfolder_name: str,
|
11
|
-
in_or_out: Literal["in", "out"],
|
12
|
-
prefix: str,
|
13
|
-
) -> Path:
|
14
|
-
if in_or_out in ["in", "out"]:
|
15
|
-
output = (
|
16
|
-
workflow_dir
|
17
|
-
/ subfolder_name
|
18
|
-
/ f"{prefix}_{in_or_out}_{arg}.pickle"
|
19
|
-
)
|
20
|
-
return output
|
21
|
-
else:
|
22
|
-
raise ValueError(
|
23
|
-
f"Missing or unexpected value in_or_out argument, {in_or_out=}"
|
24
|
-
)
|
25
|
-
|
26
|
-
|
27
|
-
def get_slurm_script_file_path(
|
28
|
-
*, workflow_dir: Path, subfolder_name: str, prefix: Optional[str] = None
|
29
|
-
) -> Path:
|
30
|
-
prefix = prefix or "_temp"
|
31
|
-
return workflow_dir / subfolder_name / f"{prefix}_slurm_submit.sbatch"
|
32
|
-
|
33
|
-
|
34
|
-
def get_slurm_file_path(
|
35
|
-
*,
|
36
|
-
workflow_dir: Path,
|
37
|
-
subfolder_name: str,
|
38
|
-
arg: str = "%j",
|
39
|
-
out_or_err: Literal["out", "err"],
|
40
|
-
prefix: str,
|
41
|
-
) -> Path:
|
42
|
-
if out_or_err == "out":
|
43
|
-
return (
|
44
|
-
workflow_dir
|
45
|
-
/ subfolder_name
|
46
|
-
/ f"{prefix}_slurm_{arg}.{out_or_err}"
|
47
|
-
)
|
48
|
-
elif out_or_err == "err":
|
49
|
-
return (
|
50
|
-
workflow_dir
|
51
|
-
/ subfolder_name
|
52
|
-
/ f"{prefix}_slurm_{arg}.{out_or_err}"
|
53
|
-
)
|
54
|
-
else:
|
55
|
-
raise ValueError(
|
56
|
-
"Missing or unexpected value out_or_err argument, "
|
57
|
-
f"{out_or_err=}"
|
58
|
-
)
|
@@ -1,122 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
import logging
|
3
|
-
import shutil
|
4
|
-
import subprocess # nosec
|
5
|
-
from shlex import split
|
6
|
-
from typing import Any
|
7
|
-
|
8
|
-
from fractal_server.app.runner.exceptions import JobExecutionError
|
9
|
-
from fractal_server.app.runner.exceptions import TaskExecutionError
|
10
|
-
from fractal_server.string_tools import validate_cmd
|
11
|
-
|
12
|
-
|
13
|
-
def _call_command_wrapper(cmd: str, log_path: str) -> None:
|
14
|
-
"""
|
15
|
-
Call a command and write its stdout and stderr to files
|
16
|
-
|
17
|
-
Raises:
|
18
|
-
TaskExecutionError: If the `subprocess.run` call returns a positive
|
19
|
-
exit code
|
20
|
-
JobExecutionError: If the `subprocess.run` call returns a negative
|
21
|
-
exit code (e.g. due to the subprocess receiving a
|
22
|
-
TERM or KILL signal)
|
23
|
-
"""
|
24
|
-
try:
|
25
|
-
validate_cmd(cmd)
|
26
|
-
except ValueError as e:
|
27
|
-
raise TaskExecutionError(f"Invalid command. Original error: {str(e)}")
|
28
|
-
|
29
|
-
# Verify that task command is executable
|
30
|
-
if shutil.which(split(cmd)[0]) is None:
|
31
|
-
msg = (
|
32
|
-
f'Command "{split(cmd)[0]}" is not valid. '
|
33
|
-
"Hint: make sure that it is executable."
|
34
|
-
)
|
35
|
-
raise TaskExecutionError(msg)
|
36
|
-
|
37
|
-
with open(log_path, "w") as fp_log:
|
38
|
-
try:
|
39
|
-
result = subprocess.run( # nosec
|
40
|
-
split(cmd),
|
41
|
-
stderr=fp_log,
|
42
|
-
stdout=fp_log,
|
43
|
-
)
|
44
|
-
except Exception as e:
|
45
|
-
raise e
|
46
|
-
|
47
|
-
if result.returncode > 0:
|
48
|
-
with open(log_path, "r") as fp_stderr:
|
49
|
-
err = fp_stderr.read()
|
50
|
-
raise TaskExecutionError(err)
|
51
|
-
elif result.returncode < 0:
|
52
|
-
raise JobExecutionError(
|
53
|
-
info=f"Task failed with returncode={result.returncode}"
|
54
|
-
)
|
55
|
-
|
56
|
-
|
57
|
-
def run_single_task(
|
58
|
-
# COMMON to all parallel tasks
|
59
|
-
command: str,
|
60
|
-
workflow_task_order: int,
|
61
|
-
workflow_task_id: int,
|
62
|
-
task_name: str,
|
63
|
-
# SPECIAL for each parallel task
|
64
|
-
parameters: dict[str, Any],
|
65
|
-
remote_files: dict[str, str],
|
66
|
-
) -> dict[str, Any]:
|
67
|
-
"""
|
68
|
-
Runs within an executor (AKA on the SLURM cluster).
|
69
|
-
"""
|
70
|
-
|
71
|
-
try:
|
72
|
-
args_file_remote = remote_files["args_file_remote"]
|
73
|
-
metadiff_file_remote = remote_files["metadiff_file_remote"]
|
74
|
-
log_file_remote = remote_files["log_file_remote"]
|
75
|
-
except KeyError:
|
76
|
-
raise TaskExecutionError(
|
77
|
-
f"Invalid {remote_files=}",
|
78
|
-
workflow_task_order=workflow_task_order,
|
79
|
-
workflow_task_id=workflow_task_id,
|
80
|
-
task_name=task_name,
|
81
|
-
)
|
82
|
-
|
83
|
-
logger = logging.getLogger(None)
|
84
|
-
logger.debug(f"Now start running {command=}")
|
85
|
-
|
86
|
-
# Write arguments to args.json file
|
87
|
-
# NOTE: see issue 2346
|
88
|
-
with open(args_file_remote, "w") as f:
|
89
|
-
json.dump(parameters, f, indent=2)
|
90
|
-
|
91
|
-
# Assemble full command
|
92
|
-
# NOTE: this could be assembled backend-side
|
93
|
-
full_command = (
|
94
|
-
f"{command} "
|
95
|
-
f"--args-json {args_file_remote} "
|
96
|
-
f"--out-json {metadiff_file_remote}"
|
97
|
-
)
|
98
|
-
|
99
|
-
try:
|
100
|
-
_call_command_wrapper(
|
101
|
-
full_command,
|
102
|
-
log_path=log_file_remote,
|
103
|
-
)
|
104
|
-
except TaskExecutionError as e:
|
105
|
-
e.workflow_task_order = workflow_task_order
|
106
|
-
e.workflow_task_id = workflow_task_id
|
107
|
-
e.task_name = task_name
|
108
|
-
raise e
|
109
|
-
|
110
|
-
try:
|
111
|
-
with open(metadiff_file_remote, "r") as f:
|
112
|
-
out_meta = json.load(f)
|
113
|
-
except FileNotFoundError as e:
|
114
|
-
logger.debug(
|
115
|
-
"Task did not produce output metadata. "
|
116
|
-
f"Original FileNotFoundError: {str(e)}"
|
117
|
-
)
|
118
|
-
out_meta = None
|
119
|
-
|
120
|
-
if out_meta == {}:
|
121
|
-
return None
|
122
|
-
return out_meta
|
File without changes
|
File without changes
|
File without changes
|