Completed
Pull Request — master (#31)
by
unknown
44s
created

queues()   A

Complexity

Conditions 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 11
Bugs 1 Features 0
Metric Value
cc 3
c 11
b 1
f 0
dl 0
loc 10
rs 9.4285
1
2
import os
3
import re
4
import math
5
from string import Template
0 ignored issues
show
Unused Code introduced by
Unused Template imported from string
Loading history...
6
from datetime import timedelta
7
from subprocess import Popen, PIPE, check_output
0 ignored issues
show
Unused Code introduced by
Unused PIPE imported from subprocess
Loading history...
Unused Code introduced by
Unused Popen imported from subprocess
Loading history...
8
from mycluster.mycluster import get_data
9
from mycluster.mycluster import load_template
10
11
"""
12
13
bjobs -u all -q emerald
14
bqueues -l emerald
15
16
"""
0 ignored issues
show
Unused Code introduced by
This string statement has no effect and could be removed.
Loading history...
17
18
19
def scheduler_type():
20
    return 'lsf'
21
22
def name():
23
    lsid_output = check_output(['lsid']).splitlines()
24
    for line in lsid_output:
25
        if line.startswith('My cluster name is'):
26
            return line.rsplit(' ',1)[1].strip()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
return line.rsplit(' ',1)[1].strip()
^
Loading history...
27
28
    return 'undefined'
29
30
def queues():
31
    queue_list = []
32
33
    with os.popen('bqueues -w -u `whoami`') as f:
34
        f.readline()  # read header
35
        for line in f:
36
            q = line.split(' ')[0].strip()
37
            queue_list.append(q)
38
39
    return queue_list
40
41
42
def accounts():
43
    return []
44
45
46
def available_tasks(queue_id):
47
48
    # split queue id into queue and parallel env
49
    # list free slots
50
    free_tasks = 0
51
    max_tasks = 0
52
    run_tasks = 0
53
    queue_name   = queue_id
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
queue_name = queue_id
^
Loading history...
54
    q_output = check_output(['bqueues',queue_name]).splitlines()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
q_output = check_output(['bqueues',queue_name]).splitlines()
^
Loading history...
55
    for line in q_output:
56
        if line.startswith(queue_name):
57
            new_line = re.sub(' +',' ',line).strip()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line).strip()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line).strip()
^
Loading history...
58
            try:
59
                max_tasks = int(new_line.split(' ')[4])
60
            except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
61
                pass
62
            pen_tasks   = int(new_line.split(' ')[8])
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
pen_tasks = int(new_line.split(' ')[8])
^
Loading history...
63
            run_tasks   = int(new_line.split(' ')[9])
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
run_tasks = int(new_line.split(' ')[9])
^
Loading history...
64
            sus_tasks   = int(new_line.split(' ')[10])
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
sus_tasks = int(new_line.split(' ')[10])
^
Loading history...
65
66
67
    return {'available' : max_tasks-run_tasks, 'max tasks' : max_tasks}
68
69
def tasks_per_node(queue_id):
70
    host_list = None
71
    q_output = check_output(['bqueues','-l',queue_id]).splitlines()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
q_output = check_output(['bqueues','-l',queue_id]).splitlines()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
q_output = check_output(['bqueues','-l',queue_id]).splitlines()
^
Loading history...
72
    for line in q_output:
73
        if line.startswith('HOSTS:'):
74
            host_list = line.strip().rsplit(' ',1)[1].replace('/','')
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
host_list = line.strip().rsplit(' ',1)[1].replace('/','')
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
host_list = line.strip().rsplit(' ',1)[1].replace('/','')
^
Loading history...
75
            if host_list == 'none':
76
                return 0
77
    bhosts_output = check_output(['bhosts','-l',host_list]).splitlines()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
bhosts_output = check_output(['bhosts','-l',host_list]).splitlines()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
bhosts_output = check_output(['bhosts','-l',host_list]).splitlines()
^
Loading history...
78
    line = re.sub(' +',' ',bhosts_output[2]).strip()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
line = re.sub(' +',' ',bhosts_output[2]).strip()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
line = re.sub(' +',' ',bhosts_output[2]).strip()
^
Loading history...
79
    tasks = int(line.split(' ')[3])
80
81
    return tasks
82
83
def node_config(queue_id):
84
    # Find first node with queue and record node config
85
    #bqueues -l queue_id
86
    host_list = None
87
    config = {}
88
    q_output = check_output(['bqueues','-l',queue_id]).splitlines()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
q_output = check_output(['bqueues','-l',queue_id]).splitlines()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
q_output = check_output(['bqueues','-l',queue_id]).splitlines()
^
Loading history...
89
    for line in q_output:
90
        if line.startswith('HOSTS:'):
91
            host_list = line.strip().rsplit(' ',1)[1].replace('/','')
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
host_list = line.strip().rsplit(' ',1)[1].replace('/','')
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
host_list = line.strip().rsplit(' ',1)[1].replace('/','')
^
Loading history...
92
            if host_list == 'none':
93
                config['max task']   = 0
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
config['max task'] = 0
^
Loading history...
94
                config['max thread'] = 0
95
                config['max memory'] = 0
96
                return config
97
    bhosts_output = check_output(['bhosts','-l',host_list]).splitlines()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
bhosts_output = check_output(['bhosts','-l',host_list]).splitlines()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
bhosts_output = check_output(['bhosts','-l',host_list]).splitlines()
^
Loading history...
98
    line = re.sub(' +',' ',bhosts_output[2]).strip()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
line = re.sub(' +',' ',bhosts_output[2]).strip()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
line = re.sub(' +',' ',bhosts_output[2]).strip()
^
Loading history...
99
    tasks = int(line.split(' ')[3])
100
    line = re.sub(' +',' ',bhosts_output[6]).strip()
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
line = re.sub(' +',' ',bhosts_output[6]).strip()
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
line = re.sub(' +',' ',bhosts_output[6]).strip()
^
Loading history...
101
    memory = float(line.split(' ')[11].replace('G',''))
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
memory = float(line.split(' ')[11].replace('G',''))
^
Loading history...
102
    config['max task']   = tasks
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
config['max task'] = tasks
^
Loading history...
103
    config['max thread'] = tasks
104
    config['max memory'] = memory
105
106
    return config
107
108
109
def create_submit(queue_id,**kwargs):
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
def create_submit(queue_id,**kwargs):
^
Loading history...
110
    queue_name   = queue_id
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
queue_name = queue_id
^
Loading history...
111
    num_tasks = 1
112
    if 'num_tasks' in kwargs:
113
        num_tasks = kwargs['num_tasks']
114
115
    tpn = tasks_per_node(queue_id)
116
    queue_tpn = tpn
117
    if 'tasks_per_node' in kwargs:
118
        tpn = min(tpn,kwargs['tasks_per_node'])
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
tpn = min(tpn,kwargs['tasks_per_node'])
^
Loading history...
119
120
    nc = node_config(queue_id)
121
    qc = available_tasks(queue_id)
122
123
    if qc['max tasks'] > 0:
124
        num_tasks = min(num_tasks,qc['max tasks'])
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
num_tasks = min(num_tasks,qc['max tasks'])
^
Loading history...
125
126
    num_threads_per_task = nc['max thread']
127
    if 'num_threads_per_task' in kwargs:
128
        num_threads_per_task = kwargs['num_threads_per_task']
129
    num_threads_per_task = min(num_threads_per_task,int(math.ceil(float(nc['max thread'])/float(tpn))))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
Exactly one space required after comma
num_threads_per_task = min(num_threads_per_task,int(math.ceil(float(nc['max thread'])/float(tpn))))
^
Loading history...
130
131
    my_name = kwargs.get('my_name', "myclusterjob")
132
    my_output = kwargs.get('my_output', "myclusterjob.out")
133
    my_script = kwargs.get('my_script', None)
134
    if 'mycluster-' in my_script:
135
        my_script = get_data(my_script)
136
137
    user_email = kwargs.get('user_email', None)
138
    project_name = kwargs.get('project_name', 'default')
139
140
    wall_clock = kwargs.get('wall_clock', '12:00')
141
    if ':' not in wall_clock:
142
        wall_clock = wall_clock + ':00'
143
144
    num_nodes = int(math.ceil(float(num_tasks)/float(tpn)))
145
146
    num_queue_slots = num_nodes*queue_tpn
147
148
    no_syscribe = kwargs.get('no_syscribe', False)
149
150
    record_job = not no_syscribe
151
152
    openmpi_args = kwargs.get('openmpi_args', "-bysocket -bind-to-socket")
153
154
    qos = kwargs.get('qos', None)
155
156
    template = load_template('lsf.jinja')
157
158
    script_str = template.render(my_name = my_name,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
script_str = template.render(my_name = my_name,
^
Loading history...
159
                                 my_script = my_script,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
my_script = my_script,
^
Loading history...
160
                                 my_output = my_output,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
my_output = my_output,
^
Loading history...
161
                                 user_email = user_email,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
user_email = user_email,
^
Loading history...
162
                                 queue_name = queue_name,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
queue_name = queue_name,
^
Loading history...
163
                                 num_queue_slots = num_queue_slots,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
num_queue_slots = num_queue_slots,
^
Loading history...
164
                                 num_tasks = num_tasks,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
num_tasks = num_tasks,
^
Loading history...
165
                                 tpn = tpn,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
tpn = tpn,
^
Loading history...
166
                                 num_threads_per_task = num_threads_per_task,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
num_threads_per_task = num_threads_per_task,
^
Loading history...
167
                                 num_nodes = num_nodes,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
num_nodes = num_nodes,
^
Loading history...
168
                                 project_name =  project_name,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
project_name = project_name,
^
Loading history...
169
                                 wall_clock = wall_clock,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
wall_clock = wall_clock,
^
Loading history...
170
                                 record_job = record_job,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
record_job = record_job,
^
Loading history...
171
                                 openmpi_args =  openmpi_args,
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
openmpi_args = openmpi_args,
^
Loading history...
172
                                 qos = qos)
0 ignored issues
show
Coding Style introduced by
No space allowed around keyword argument assignment
qos = qos)
^
Loading history...
173
174
    return script_str
175
176
177
def submit(script_name,immediate, depends_on = None, depends_on_always_run = False):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (84/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
Exactly one space required after comma
def submit(script_name,immediate, depends_on = None, depends_on_always_run = False):
^
Loading history...
Coding Style introduced by
No space allowed around keyword argument assignment
def submit(script_name,immediate, depends_on = None, depends_on_always_run = False):
^
Loading history...
Coding Style introduced by
No space allowed around keyword argument assignment
def submit(script_name,immediate, depends_on = None, depends_on_always_run = False):
^
Loading history...
178
    job_id = None
179
180 View Code Duplication
    if depends_on and depends_on_always_run:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
181
        with os.popen('bsub -w "ended(%s)" < %s ' % (depends_on, script_name)) as f:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (84/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
182
            output = f.readline()
183
            try:
184
                job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (82/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
Exactly one space required after comma
job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
^
Loading history...
185
            except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
186
                print('Job submission failed: ' + output)
187
    elif depends_on is not None:
188
        with os.popen('bsub -w "done(%s)" < %s ' % (depends_on, script_name)) as f:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
189
            output = f.readline()
190
            try:
191
                job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (82/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
Exactly one space required after comma
job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
^
Loading history...
192
            except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
193
                print('Job submission failed: ' + output)
194
    else:
195
        with os.popen('bsub <'+script_name) as f:
196
            output = f.readline()
197
            try:
198
                job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (82/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Coding Style introduced by
Exactly one space required after comma
job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
job_id = int(output.split(' ')[1].replace('<','').replace('>',''))
^
Loading history...
199
            except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
200
                print('Job submission failed: ' + output)
201
    return job_id
202
203
204
def delete(job_id):
205
    with os.popen('bkill '+job_id) as f:
206
        pass
207
208
209 View Code Duplication
def status():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
210
    status_dict = {}
211
    with os.popen('bjobs -w') as f:
212
        try:
213
            f.readline()  # read header
214
            for line in f:
215
                new_line = re.sub(' +',' ',line.strip())
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
216
                job_id = int(new_line.split(' ')[0])
217
                state = new_line.split(' ')[2]
218
                if state == 'RUN':
219
                    status_dict[job_id] = 'r'
220
                else:
221
                    status_dict[job_id] = state
222
        except e:
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'e'
Loading history...
223
            print(e)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'e'
Loading history...
224
225
    return status_dict
226
227
228
def job_stats(job_id):
229
    stats_dict = {}
230
    with os.popen('bacct -l '+str(job_id)) as f:
231
        try:
232
            line = f.readline()
233
            new_line = re.sub(' +',' ',line.strip())
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
234
            stats_dict['wallclock'] = new_line.split(' ')[0]
235
            stats_dict['cpu'] = new_line.split(' ')[1]
236
            stats_dict['queue'] = new_line.split(' ')[2]
237
            stats_dict['mem'] = '-'  # float(new_line.split(' ')[4])*int(new_line.split(' ')[3])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (96/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
238
        except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
239
            print('LSF: Error reading job stats')
240
241
    return stats_dict
242
243
244
def job_stats_enhanced(job_id):
245
    """
246
    Get full job and step stats for job_id
247
    """
248
    stats_dict = {}
249
    with os.popen('bjobs -o "jobid run_time cpu_used  queue slots  stat exit_code start_time estimated_start_time finish_time delimiter=\'|\'" -noheader '+str(job_id)) as f:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (173/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
250
        try:
251
            line = f.readline()
252
            cols = line.split('|')
253
            stats_dict['job_id'] = cols[0]
254
            if cols[1] != '-':
255
                stats_dict['wallclock'] = timedelta(seconds=float(cols[1].split(' ')[0]))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (89/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
256
            if cols[2] != '-':
257
                stats_dict['cpu'] = timedelta(seconds=float(cols[2].split(' ')[0]))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
258
            stats_dict['queue'] = cols[3]
259
            stats_dict['status'] = cols[5]
260
            stats_dict['exit_code'] = cols[6]
261
            stats_dict['start'] = cols[7]
262
            stats_dict['start_time'] = cols[8]
263
            if stats_dict['status'] in ['DONE', 'EXIT']:
264
                stats_dict['end'] = cols[9]
265
266
            steps = []
267
            stats_dict['steps'] = steps
268
        except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
269
            with os.popen('bhist -l '+str(job_id)) as f:
270
                try:
271
                    output = f.readlines()
272
                    for line in output:
273
                        if "Done successfully" in line:
274
                            stats_dict['status'] = 'DONE'
275
                            return stats_dict
276
                        elif "Completed <exit>" in line:
277
                            stats_dict['status'] = 'EXIT'
278
                            return stats_dict
279
                        else:
280
                            stats_dict['status'] = 'UNKNOWN'
281
                except Exception as e:
282
                    print(e)
283
                    print('LSF: Error reading job stats')
284
                    stats_dict['status'] = 'UNKNOWN'
285
    return stats_dict
286
287
288
def running_stats(job_id):
289
    stats_dict = {}
290
    with os.popen('bjobs -W '+str(job_id)) as f:
291
        try:
292
            line = f.readline()
293
            new_line = re.sub(' +',' ',line.strip())
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
294
            stats_dict['wallclock']  = new_line.split(' ')[0]
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
stats_dict['wallclock'] = new_line.split(' ')[0]
^
Loading history...
295
        except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
296
            pass
297
298
    with os.popen('bjobs -W '+str(job_id)) as f:
299
        try:
300
            line = f.readline()
301
            new_line = re.sub(' +',' ',line.strip())
0 ignored issues
show
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
Coding Style introduced by
Exactly one space required after comma
new_line = re.sub(' +',' ',line.strip())
^
Loading history...
302
            ntasks = int(new_line.split(' ')[2])
303
            stats_dict['mem']  = float(new_line.split(' ')[1])*ntasks
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
stats_dict['mem'] = float(new_line.split(' ')[1])*ntasks
^
Loading history...
304
            stats_dict['cpu']  = float(new_line.split(' ')[0])*ntasks
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
stats_dict['cpu'] = float(new_line.split(' ')[0])*ntasks
^
Loading history...
305
        except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
306
            pass
307
308
    return stats_dict
309