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.
Files changed (24) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/runner/exceptions.py +1 -6
  3. fractal_server/app/runner/executors/base_runner.py +16 -4
  4. fractal_server/app/runner/executors/call_command_wrapper.py +52 -0
  5. fractal_server/app/runner/executors/local/runner.py +52 -13
  6. fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +87 -52
  7. fractal_server/app/runner/executors/slurm_common/remote.py +47 -92
  8. fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +20 -19
  9. fractal_server/app/runner/executors/slurm_ssh/runner.py +1 -2
  10. fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +1 -4
  11. fractal_server/app/runner/executors/slurm_sudo/runner.py +3 -11
  12. fractal_server/app/runner/task_files.py +0 -8
  13. fractal_server/app/runner/v2/_slurm_ssh.py +1 -2
  14. fractal_server/app/runner/v2/_slurm_sudo.py +1 -2
  15. fractal_server/app/runner/v2/runner_functions.py +16 -30
  16. fractal_server/app/runner/versions.py +2 -11
  17. fractal_server/config.py +0 -9
  18. {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/METADATA +1 -7
  19. {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/RECORD +22 -23
  20. fractal_server/app/runner/executors/slurm_common/utils_executors.py +0 -58
  21. fractal_server/app/runner/v2/runner_functions_low_level.py +0 -122
  22. {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/LICENSE +0 -0
  23. {fractal_server-2.14.4.dist-info → fractal_server-2.14.5.dist-info}/WHEEL +0 -0
  24. {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