Skip to content

Commit 89eea55

Browse files
committed
use nipype's copyfile, create hardlinks if possible
1 parent 34d2cca commit 89eea55

File tree

1 file changed

+89
-78
lines changed

1 file changed

+89
-78
lines changed

fmriprep/viz/reports.py

Lines changed: 89 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,25 @@
1515
import re
1616

1717
import html
18-
import shutil
1918

2019
import jinja2
21-
from niworkflows.nipype.utils.filemanip import loadcrash
20+
from niworkflows.nipype.utils.filemanip import loadcrash, copyfile
2221
from pkg_resources import resource_filename as pkgrf
2322

23+
2424
class Element(object):
25+
"""
26+
Just a basic component of a report
27+
"""
2528
def __init__(self, name, title=None):
2629
self.name = name
2730
self.title = title
2831

2932

3033
class Reportlet(Element):
34+
"""
35+
A reportlet has title, description and a list of graphical components
36+
"""
3137
def __init__(self, name, file_pattern=None, title=None, description=None, raw=False):
3238
self.name = name
3339
self.file_pattern = re.compile(file_pattern)
@@ -39,6 +45,9 @@ def __init__(self, name, file_pattern=None, title=None, description=None, raw=Fa
3945

4046

4147
class SubReport(Element):
48+
"""
49+
SubReports are sections within a Report
50+
"""
4251
def __init__(self, name, reportlets=None, title=''):
4352
self.name = name
4453
self.title = title
@@ -48,74 +57,13 @@ def __init__(self, name, reportlets=None, title=''):
4857
self.isnested = False
4958

5059

51-
def order_by_run(subreport):
52-
ordered = []
53-
run_reps = {}
54-
55-
for element in subreport.reportlets:
56-
if len(element.source_files) == 1 and element.source_files[0]:
57-
ordered.append(element)
58-
continue
59-
60-
for filename, file_contents in zip(element.source_files, element.contents):
61-
name, title = generate_name_title(filename)
62-
if not filename or not name:
63-
continue
64-
65-
new_element = Reportlet(
66-
name=element.name, title=element.title, file_pattern=element.file_pattern,
67-
description=element.description, raw=element.raw)
68-
new_element.contents.append(file_contents)
69-
new_element.source_files.append(filename)
70-
71-
if name not in run_reps:
72-
run_reps[name] = SubReport(name, title=title)
73-
74-
run_reps[name].reportlets.append(new_element)
75-
76-
if run_reps:
77-
keys = list(sorted(run_reps.keys()))
78-
for key in keys:
79-
ordered.append(run_reps[key])
80-
subreport.isnested = True
81-
82-
subreport.reportlets = ordered
83-
return subreport
84-
85-
86-
def generate_name_title(filename):
87-
fname = os.path.basename(filename)
88-
expr = re.compile('^sub-(?P<subject_id>[a-zA-Z0-9]+)(_ses-(?P<session_id>[a-zA-Z0-9]+))?'
89-
'(_task-(?P<task_id>[a-zA-Z0-9]+))?(_acq-(?P<acq_id>[a-zA-Z0-9]+))?'
90-
'(_rec-(?P<rec_id>[a-zA-Z0-9]+))?(_run-(?P<run_id>[a-zA-Z0-9]+))?')
91-
outputs = expr.search(fname)
92-
if outputs:
93-
outputs = outputs.groupdict()
94-
else:
95-
return None, None
96-
97-
name = '{session}{task}{acq}{rec}{run}'.format(
98-
session="_ses-" + outputs['session_id'] if outputs['session_id'] else '',
99-
task="_task-" + outputs['task_id'] if outputs['task_id'] else '',
100-
acq="_acq-" + outputs['acq_id'] if outputs['acq_id'] else '',
101-
rec="_rec-" + outputs['rec_id'] if outputs['rec_id'] else '',
102-
run="_run-" + outputs['run_id'] if outputs['run_id'] else ''
103-
)
104-
title = '{session}{task}{acq}{rec}{run}'.format(
105-
session=" Session: " + outputs['session_id'] if outputs['session_id'] else '',
106-
task=" Task: " + outputs['task_id'] if outputs['task_id'] else '',
107-
acq=" Acquisition: " + outputs['acq_id'] if outputs['acq_id'] else '',
108-
rec=" Reconstruction: " + outputs['rec_id'] if outputs['rec_id'] else '',
109-
run=" Run: " + outputs['run_id'] if outputs['run_id'] else ''
110-
)
111-
return name.strip('_'), title
112-
113-
11460
class Report(object):
115-
61+
"""
62+
The full report object
63+
"""
11664
def __init__(self, path, config, out_dir, run_uuid, out_filename='report.html'):
11765
self.root = path
118-
self.sub_reports = []
66+
self.sections = []
11967
self.errors = []
12068
self.out_dir = out_dir
12169
self.out_filename = out_filename
@@ -127,7 +75,7 @@ def _load_config(self, config):
12775
with open(config, 'r') as configfh:
12876
config = json.load(configfh)
12977

130-
self.index(config['sub_reports'])
78+
self.index(config['sections'])
13179

13280
def index(self, config):
13381
fig_dir = 'figures'
@@ -142,21 +90,21 @@ def index(self, config):
14290
reportlets = []
14391
for reportlet_cfg in subrep_cfg['reportlets']:
14492
rlet = Reportlet(**reportlet_cfg)
145-
for f in reportlet_list:
146-
ext = f.split('.')[-1]
147-
if rlet.file_pattern.search(f):
93+
for src in reportlet_list:
94+
ext = src.split('.')[-1]
95+
if rlet.file_pattern.search(src):
14896
contents = None
14997
if ext == 'html':
150-
with open(f) as fp:
98+
with open(src) as fp:
15199
contents = fp.read().strip()
152100
elif ext == 'svg':
153-
fbase = os.path.basename(f)
154-
newf = os.path.join(svg_dir, fbase)
155-
shutil.copy(f, newf)
101+
fbase = os.path.basename(src)
102+
copyfile(src, os.path.join(svg_dir, fbase),
103+
copy=True, use_hardlink=True)
156104
contents = os.path.join(subject, fig_dir, fbase)
157105

158106
if contents:
159-
rlet.source_files.append(f)
107+
rlet.source_files.append(src)
160108
rlet.contents.append(contents)
161109

162110
if rlet.source_files:
@@ -166,7 +114,7 @@ def index(self, config):
166114
sub_report = SubReport(
167115
subrep_cfg['name'], reportlets=reportlets,
168116
title=subrep_cfg.get('title'))
169-
self.sub_reports.append(order_by_run(sub_report))
117+
self.sections.append(order_by_run(sub_report))
170118

171119
error_dir = os.path.join(self.out_dir, "fmriprep", subject, 'log', self.run_uuid)
172120
if os.path.isdir(error_dir):
@@ -226,12 +174,75 @@ def generate_report(self):
226174
trim_blocks=True, lstrip_blocks=True
227175
)
228176
report_tpl = env.get_template('viz/report.tpl')
229-
report_render = report_tpl.render(sub_reports=self.sub_reports, errors=self.errors)
177+
report_render = report_tpl.render(sub_reports=self.sections, errors=self.errors)
230178
with open(os.path.join(self.out_dir, "fmriprep", self.out_filename), 'w') as fp:
231179
fp.write(report_render)
232180
return len(self.errors)
233181

234182

183+
def order_by_run(subreport):
184+
ordered = []
185+
run_reps = {}
186+
187+
for element in subreport.reportlets:
188+
if len(element.source_files) == 1 and element.source_files[0]:
189+
ordered.append(element)
190+
continue
191+
192+
for filename, file_contents in zip(element.source_files, element.contents):
193+
name, title = generate_name_title(filename)
194+
if not filename or not name:
195+
continue
196+
197+
new_element = Reportlet(
198+
name=element.name, title=element.title, file_pattern=element.file_pattern,
199+
description=element.description, raw=element.raw)
200+
new_element.contents.append(file_contents)
201+
new_element.source_files.append(filename)
202+
203+
if name not in run_reps:
204+
run_reps[name] = SubReport(name, title=title)
205+
206+
run_reps[name].reportlets.append(new_element)
207+
208+
if run_reps:
209+
keys = list(sorted(run_reps.keys()))
210+
for key in keys:
211+
ordered.append(run_reps[key])
212+
subreport.isnested = True
213+
214+
subreport.reportlets = ordered
215+
return subreport
216+
217+
218+
def generate_name_title(filename):
219+
fname = os.path.basename(filename)
220+
expr = re.compile('^sub-(?P<subject_id>[a-zA-Z0-9]+)(_ses-(?P<session_id>[a-zA-Z0-9]+))?'
221+
'(_task-(?P<task_id>[a-zA-Z0-9]+))?(_acq-(?P<acq_id>[a-zA-Z0-9]+))?'
222+
'(_rec-(?P<rec_id>[a-zA-Z0-9]+))?(_run-(?P<run_id>[a-zA-Z0-9]+))?')
223+
outputs = expr.search(fname)
224+
if outputs:
225+
outputs = outputs.groupdict()
226+
else:
227+
return None, None
228+
229+
name = '{session}{task}{acq}{rec}{run}'.format(
230+
session="_ses-" + outputs['session_id'] if outputs['session_id'] else '',
231+
task="_task-" + outputs['task_id'] if outputs['task_id'] else '',
232+
acq="_acq-" + outputs['acq_id'] if outputs['acq_id'] else '',
233+
rec="_rec-" + outputs['rec_id'] if outputs['rec_id'] else '',
234+
run="_run-" + outputs['run_id'] if outputs['run_id'] else ''
235+
)
236+
title = '{session}{task}{acq}{rec}{run}'.format(
237+
session=" Session: " + outputs['session_id'] if outputs['session_id'] else '',
238+
task=" Task: " + outputs['task_id'] if outputs['task_id'] else '',
239+
acq=" Acquisition: " + outputs['acq_id'] if outputs['acq_id'] else '',
240+
rec=" Reconstruction: " + outputs['rec_id'] if outputs['rec_id'] else '',
241+
run=" Run: " + outputs['run_id'] if outputs['run_id'] else ''
242+
)
243+
return name.strip('_'), title
244+
245+
235246
def run_reports(reportlets_dir, out_dir, subject_label, run_uuid):
236247
"""
237248
Runs the reports

0 commit comments

Comments
 (0)