oh-my-batch 0.1.1__py3-none-any.whl → 0.2.0__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.
- oh_my_batch/batch.py +46 -16
- oh_my_batch/job.py +4 -3
- oh_my_batch/util.py +15 -1
- {oh_my_batch-0.1.1.dist-info → oh_my_batch-0.2.0.dist-info}/METADATA +4 -4
- {oh_my_batch-0.1.1.dist-info → oh_my_batch-0.2.0.dist-info}/RECORD +8 -8
- {oh_my_batch-0.1.1.dist-info → oh_my_batch-0.2.0.dist-info}/LICENSE +0 -0
- {oh_my_batch-0.1.1.dist-info → oh_my_batch-0.2.0.dist-info}/WHEEL +0 -0
- {oh_my_batch-0.1.1.dist-info → oh_my_batch-0.2.0.dist-info}/entry_points.txt +0 -0
oh_my_batch/batch.py
CHANGED
@@ -13,7 +13,7 @@ class BatchMaker:
|
|
13
13
|
self._script_bottom = []
|
14
14
|
self._command = []
|
15
15
|
|
16
|
-
def
|
16
|
+
def add_work_dirs(self, *dir: str):
|
17
17
|
"""
|
18
18
|
Add working directories
|
19
19
|
|
@@ -22,39 +22,55 @@ class BatchMaker:
|
|
22
22
|
self._work_dirs.extend(expand_globs(dir))
|
23
23
|
return self
|
24
24
|
|
25
|
-
def
|
25
|
+
def add_header_files(self, *file: str, encoding='utf-8'):
|
26
26
|
"""
|
27
27
|
Add script header from files
|
28
28
|
|
29
29
|
:param file: File path
|
30
30
|
:param encoding: File encoding
|
31
31
|
"""
|
32
|
-
|
33
|
-
self._script_header.append(f.read())
|
32
|
+
self._script_header.extend(load_files(*file, encoding=encoding))
|
34
33
|
return self
|
35
34
|
|
36
|
-
def
|
35
|
+
def add_headers(self, *header: str):
|
36
|
+
"""
|
37
|
+
Add script header
|
38
|
+
|
39
|
+
:param header: Header lines
|
40
|
+
"""
|
41
|
+
self._script_header.extend(header)
|
42
|
+
return self
|
43
|
+
|
44
|
+
def add_bottom_files(self, *file: str, encoding='utf-8'):
|
37
45
|
"""
|
38
46
|
Add script bottom from files
|
39
47
|
|
40
48
|
:param file: File path
|
41
49
|
:param encoding: File encoding
|
42
50
|
"""
|
43
|
-
|
44
|
-
|
51
|
+
self._script_bottom.extend(load_files(*file, encoding=encoding))
|
52
|
+
return self
|
53
|
+
|
54
|
+
def add_bottoms(self, *bottom: str):
|
55
|
+
"""
|
56
|
+
Add script bottom
|
45
57
|
|
46
|
-
|
58
|
+
:param bottom: Bottom lines
|
59
|
+
"""
|
60
|
+
self._script_bottom.extend(bottom)
|
61
|
+
return self
|
62
|
+
|
63
|
+
def add_cmd_files(self, *file: str, encoding='utf-8'):
|
47
64
|
"""
|
48
65
|
Add commands from files to run under every working directory
|
49
66
|
|
50
67
|
:param file: File path
|
51
68
|
:param encoding: File encoding
|
52
69
|
"""
|
53
|
-
|
54
|
-
self._command.append(f.read())
|
70
|
+
self._command.extend(load_files(*file, encoding=encoding))
|
55
71
|
return self
|
56
72
|
|
57
|
-
def
|
73
|
+
def add_cmds(self, *cmd: str):
|
58
74
|
"""
|
59
75
|
add commands to run under every working directory
|
60
76
|
|
@@ -68,10 +84,10 @@ class BatchMaker:
|
|
68
84
|
Make batch script files from the previous setup
|
69
85
|
|
70
86
|
:param path: Path to save batch script files, use {i} to represent index
|
71
|
-
:param concurrency: Number of
|
87
|
+
:param concurrency: Number of scripts to to make
|
72
88
|
"""
|
73
89
|
# inject pre-defined functions
|
74
|
-
self.
|
90
|
+
self.add_header_files(get_asset('functions.sh'))
|
75
91
|
|
76
92
|
header = '\n'.join(self._script_header)
|
77
93
|
bottom = '\n'.join(self._script_bottom)
|
@@ -80,10 +96,10 @@ class BatchMaker:
|
|
80
96
|
work_dirs_arr = "\n".join(shlex.quote(w) for w in work_dirs)
|
81
97
|
body.extend([
|
82
98
|
'[ -n "$PBS_O_WORKDIR" ] && cd $PBS_O_WORKDIR # fix PBS',
|
83
|
-
f'
|
99
|
+
f'WORK_DIRS=({work_dirs_arr})',
|
84
100
|
'',
|
85
|
-
'for
|
86
|
-
'pushd $
|
101
|
+
'for WORK_DIR in "${WORK_DIRS[@]}"; do',
|
102
|
+
'pushd $WORK_DIR',
|
87
103
|
*self._command,
|
88
104
|
'popd',
|
89
105
|
'done'
|
@@ -94,3 +110,17 @@ class BatchMaker:
|
|
94
110
|
with open(out_path, 'w', encoding=encoding) as f:
|
95
111
|
f.write(script)
|
96
112
|
os.chmod(out_path, mode_translate(str(mode)))
|
113
|
+
|
114
|
+
|
115
|
+
def load_files(*file, encoding='utf-8', raise_invalid=False):
|
116
|
+
"""
|
117
|
+
Load files from paths
|
118
|
+
|
119
|
+
:param files: List of file paths
|
120
|
+
:return: List of file contents
|
121
|
+
"""
|
122
|
+
result = []
|
123
|
+
for file in expand_globs(file, raise_invalid=raise_invalid):
|
124
|
+
with open(file, 'r', encoding=encoding) as f:
|
125
|
+
result.append(f.read())
|
126
|
+
return result
|
oh_my_batch/job.py
CHANGED
@@ -6,7 +6,7 @@ import time
|
|
6
6
|
import os
|
7
7
|
import re
|
8
8
|
|
9
|
-
from .util import expand_globs, shell_run, parse_csv
|
9
|
+
from .util import expand_globs, shell_run, parse_csv, ensure_dir, log_cp
|
10
10
|
|
11
11
|
|
12
12
|
logger = logging.getLogger(__name__)
|
@@ -70,6 +70,7 @@ class BaseJobManager:
|
|
70
70
|
while True:
|
71
71
|
self._update_jobs(jobs, max_tries, opts)
|
72
72
|
if recovery:
|
73
|
+
ensure_dir(recovery)
|
73
74
|
with open(recovery, 'w', encoding='utf-8') as f:
|
74
75
|
json.dump(jobs, f, indent=2)
|
75
76
|
|
@@ -103,7 +104,7 @@ class Slurm(BaseJobManager):
|
|
103
104
|
query_cmd = f'{self._sacct_bin} -X -P --format=JobID,JobName,State -j {",".join(job_ids)}'
|
104
105
|
cp = shell_run(query_cmd)
|
105
106
|
if cp.returncode != 0:
|
106
|
-
logger.error('Failed to query job status: %s', cp
|
107
|
+
logger.error('Failed to query job status: %s', log_cp(cp))
|
107
108
|
return jobs
|
108
109
|
logger.info('Job status:\n%s', cp.stdout.decode('utf-8'))
|
109
110
|
new_state = parse_csv(cp.stdout.decode('utf-8'))
|
@@ -132,7 +133,7 @@ class Slurm(BaseJobManager):
|
|
132
133
|
cp = shell_run(submit_cmd)
|
133
134
|
if cp.returncode != 0:
|
134
135
|
job['state'] = JobState.FAILED
|
135
|
-
logger.error('Failed to submit job: %s', cp
|
136
|
+
logger.error('Failed to submit job: %s', log_cp(cp))
|
136
137
|
else:
|
137
138
|
job['id'] = self._parse_job_id(cp.stdout.decode('utf-8'))
|
138
139
|
assert job['id'], 'Failed to parse job id'
|
oh_my_batch/util.py
CHANGED
@@ -83,4 +83,18 @@ def parse_csv(text: str, delimiter="|"):
|
|
83
83
|
Parse CSV text to list of dictionaries
|
84
84
|
"""
|
85
85
|
reader = csv.DictReader(text.splitlines(), delimiter=delimiter)
|
86
|
-
return list(reader)
|
86
|
+
return list(reader)
|
87
|
+
|
88
|
+
|
89
|
+
def log_cp(cp):
|
90
|
+
"""
|
91
|
+
Log child process
|
92
|
+
"""
|
93
|
+
log = f'Command: {cp.args}\nReturn code: {cp.returncode}'
|
94
|
+
|
95
|
+
out = cp.stdout.decode('utf-8').strip()
|
96
|
+
if out:
|
97
|
+
log += f'\nSTDOUT:\n{out}'
|
98
|
+
err = cp.stderr.decode('utf-8').strip()
|
99
|
+
if err:
|
100
|
+
log += f'\nSTDERR:\n{err}'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: oh-my-batch
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary:
|
5
5
|
License: GPL
|
6
6
|
Author: weihong.xu
|
@@ -99,9 +99,9 @@ cat > tmp/lammps_header.sh <<EOF
|
|
99
99
|
EOF
|
100
100
|
|
101
101
|
omb batch \
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
add_work_dirs tmp/tasks/* - \
|
103
|
+
add_header_files tmp/lammps_header.sh - \
|
104
|
+
add_cmds "checkpoint lmp.done ./run.sh" - \
|
105
105
|
make tmp/lmp-{i}.slurm --concurrency 2
|
106
106
|
```
|
107
107
|
|
@@ -2,13 +2,13 @@ oh_my_batch/__init__.py,sha256=BsRNxZbqDWfaIZJGxzIDqCubRWztMGFDceW08TECuFs,98
|
|
2
2
|
oh_my_batch/__main__.py,sha256=sWyFZMwWNvhkanwZSJRGfBBDoIevhC028dTSB67i6yI,61
|
3
3
|
oh_my_batch/assets/__init__.py,sha256=Exub46UbQaz2V2eXpQeiVfnThQpXaNeuyjlGY6gBSZc,130
|
4
4
|
oh_my_batch/assets/functions.sh,sha256=eORxFefV-XrWbG-2I6u-c8uf1XxOQ31LaeVHBumwzJ4,708
|
5
|
-
oh_my_batch/batch.py,sha256=
|
5
|
+
oh_my_batch/batch.py,sha256=6qnaXEVyA493heGzzbCrdZXCcnYk8zgl7WP0rmo7KlU,3690
|
6
6
|
oh_my_batch/cli.py,sha256=uelW9ms1N30DipJOcsiuG5K-5VN8O6yu1RNEqex00GY,475
|
7
7
|
oh_my_batch/combo.py,sha256=R_WTO4v-LWHIQ0O46bIgeRlL_RGrFcf8305S9auqeQk,7679
|
8
|
-
oh_my_batch/job.py,sha256=
|
9
|
-
oh_my_batch/util.py,sha256=
|
10
|
-
oh_my_batch-0.
|
11
|
-
oh_my_batch-0.
|
12
|
-
oh_my_batch-0.
|
13
|
-
oh_my_batch-0.
|
14
|
-
oh_my_batch-0.
|
8
|
+
oh_my_batch/job.py,sha256=8kZnWtvpr1rAl4tc9I_Vlhi-T0o3rh4RQZZgMNBCGho,5800
|
9
|
+
oh_my_batch/util.py,sha256=okg_kY8dJouyJ2BYCXRl7bxDUAtNH6GLh2UjXRnkoW0,2385
|
10
|
+
oh_my_batch-0.2.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
11
|
+
oh_my_batch-0.2.0.dist-info/METADATA,sha256=_qeLyk6LEg2--NU9NqgMoV2WU96125A0eiIOdJFY760,4759
|
12
|
+
oh_my_batch-0.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
13
|
+
oh_my_batch-0.2.0.dist-info/entry_points.txt,sha256=ZY2GutSoNjjSyJ4qO2pTeseKUFgoTYdvmgkuZZkwi68,77
|
14
|
+
oh_my_batch-0.2.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|