Skip to content

Commit 38d6e04

Browse files
authored
Merge pull request #1024 from oesteban/enh/dynamic-boilerplate
[ENH] Dynamic citation boilerplate
2 parents 1b47e55 + fdf14ad commit 38d6e04

29 files changed

+849
-132
lines changed

.circleci/ds005_outputs.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
fmriprep
22
fmriprep/logs
3+
fmriprep/logs/CITATION.html
4+
fmriprep/logs/CITATION.md
5+
fmriprep/logs/CITATION.tex
36
fmriprep/sub-01
47
fmriprep/sub-01/anat
58
fmriprep/sub-01/anat/sub-01_T1w_brainmask.nii.gz

.circleci/ds005_partial_outputs.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
fmriprep
22
fmriprep/logs
3+
fmriprep/logs/CITATION.html
4+
fmriprep/logs/CITATION.md
5+
fmriprep/logs/CITATION.tex
36
fmriprep/sub-01
47
fmriprep/sub-01/anat
58
fmriprep/sub-01/anat/sub-01_T1w_brainmask.nii.gz

.circleci/ds054_outputs.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
fmriprep
22
fmriprep/logs
3+
fmriprep/logs/CITATION.html
4+
fmriprep/logs/CITATION.md
5+
fmriprep/logs/CITATION.tex
36
fmriprep/sub-100185
47
fmriprep/sub-100185/anat
58
fmriprep/sub-100185/anat/sub-100185_T1w_brainmask.nii.gz

.circleci/ds210_outputs.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
fmriprep
22
fmriprep/logs
3+
fmriprep/logs/CITATION.html
4+
fmriprep/logs/CITATION.md
5+
fmriprep/logs/CITATION.tex
36
fmriprep/sub-02
47
fmriprep/sub-02/anat
58
fmriprep/sub-02/anat/sub-02_T1w_brainmask.nii.gz

Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ RUN conda install -y mkl=2018.0.3 mkl-service; sync &&\
113113
matplotlib=2.2.0 \
114114
pandas=0.23.0 \
115115
libxml2=2.9.4 \
116-
libxslt=1.1.29\
116+
libxslt=1.1.29 \
117117
traits=4.6.0; sync && \
118118
chmod -R a+rX /usr/local/miniconda; sync && \
119119
chmod +x /usr/local/miniconda/bin/*; sync && \
@@ -131,6 +131,11 @@ RUN apt-get update && \
131131
graphviz=2.38.0-12ubuntu2 && \
132132
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
133133

134+
# Install latest pandoc
135+
RUN curl -o pandoc-2.2.2.1-1-amd64.deb -sSL "https://github.com/jgm/pandoc/releases/download/2.2.2.1/pandoc-2.2.2.1-1-amd64.deb" && \
136+
dpkg -i pandoc-2.2.2.1-1-amd64.deb && \
137+
rm pandoc-2.2.2.1-1-amd64.deb
138+
134139
# Unless otherwise specified each process should only use one thread - nipype
135140
# will handle parallelization
136141
ENV MKL_NUM_THREADS=1 \

docs/contributors.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,39 @@ This image may be accessed by the `fmriprep-docker`_ wrapper via the
121121
``-i`` flag, e.g. ::
122122

123123
$ fmriprep-docker -i fmriprep --shell
124+
125+
126+
Adding new features to the citation boilerplate
127+
===============================================
128+
129+
The citation boilerplate is built by adding two dunder attributes
130+
of workflow objects: ``__desc__`` and ``__postdesc__``.
131+
Once the full *fMRIPrep* workflow is built, starting from the
132+
outer workflow and visiting all sub-workflows in topological
133+
order, all defined ``__desc__`` are appended to the citation
134+
boilerplate before descending into sub-workflows.
135+
Once all the sub-workflows of a given workflow have
136+
been visited, then the ``__postdesc__`` attribute is appended
137+
and the execution pops out to higher level workflows.
138+
The dunder attributes are written in Markdown language, and may contain
139+
references.
140+
To add a reference, just add a new Bibtex entry to the references
141+
database (``/fmriprep/data/boilerplate.bib``).
142+
You can then use the Bibtex handle within the Markdown text.
143+
For example, if the Bibtex handle is ``myreference``, a citation
144+
will be generated in Markdown language with ``@myreference``.
145+
To generate citations with parenthesis and/or additional content,
146+
brackets should be used: e.g. ``[see @myreference]`` will produce
147+
a citation like *(see Doe J. et al 2018)*.
148+
149+
150+
An example of how this works is shown here: ::
151+
152+
workflow = Workflow(name=name)
153+
workflow.__desc__ = """\
154+
Head-motion parameters with respect to the BOLD reference
155+
(transformation matrices, and six corresponding rotation and translation
156+
parameters) are estimated before any spatiotemporal filtering using
157+
`mcflirt` [FSL {fsl_ver}, @mcflirt].
158+
""".format(fsl_ver=fsl.Info().version() or '<ver>')
159+

fmriprep/cli/run.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import os
1010
import os.path as op
11+
from pathlib import Path
1112
import logging
1213
import sys
1314
import gc
@@ -93,6 +94,8 @@ def get_parser():
9394
help='nipype plugin configuration file')
9495
g_perfm.add_argument('--anat-only', action='store_true',
9596
help='run anatomical workflows only')
97+
g_perfm.add_argument('--boilerplate', action='store_true',
98+
help='generate boilerplate only')
9699
g_perfm.add_argument('--ignore-aroma-denoising-errors', action='store_true',
97100
default=False,
98101
help='ignores the errors ICA_AROMA returns when there '
@@ -249,7 +252,7 @@ def main():
249252
opts = get_parser().parse_args()
250253

251254
# FreeSurfer license
252-
default_license = op.join(os.getenv('FREESURFER_HOME', ''), 'license.txt')
255+
default_license = str(Path(os.getenv('FREESURFER_HOME')) / 'license.txt')
253256
# Precedence: --fs-license-file, $FS_LICENSE, default_license
254257
license_file = opts.fs_license_file or os.getenv('FS_LICENSE', default_license)
255258
if not os.path.exists(license_file):
@@ -299,6 +302,9 @@ def main():
299302
if opts.reports_only:
300303
sys.exit(int(retcode > 0))
301304

305+
if opts.boilerplate:
306+
sys.exit(int(retcode > 0))
307+
302308
# Sentry tracking
303309
if not opts.notrack:
304310
try:
@@ -354,6 +360,9 @@ def build_workflow(opts, retval):
354360
a hard-limited memory-scope.
355361
356362
"""
363+
from subprocess import check_call, CalledProcessError, TimeoutExpired
364+
from pkg_resources import resource_filename as pkgrf
365+
357366
from nipype import logging, config as ncfg
358367
from ..info import __version__
359368
from ..workflows.base import init_fmriprep_wf
@@ -397,7 +406,7 @@ def build_workflow(opts, retval):
397406
run_uuid = '%s_%s' % (strftime('%Y%m%d-%H%M%S'), uuid.uuid4())
398407

399408
# First check that bids_dir looks like a BIDS folder
400-
bids_dir = op.abspath(opts.bids_dir)
409+
bids_dir = os.path.abspath(opts.bids_dir)
401410
subject_list = collect_participants(
402411
bids_dir, participant_label=opts.participant_label)
403412

@@ -529,6 +538,35 @@ def build_workflow(opts, retval):
529538
ignore_aroma_err=opts.ignore_aroma_denoising_errors,
530539
)
531540
retval['return_code'] = 0
541+
542+
logs_path = Path(output_dir) / 'fmriprep' / 'logs'
543+
boilerplate = retval['workflow'].visit_desc()
544+
(logs_path / 'CITATION.md').write_text(boilerplate)
545+
logger.log(25, 'Works derived from this fMRIPrep execution should '
546+
'include the following boilerplate:\n\n%s', boilerplate)
547+
548+
# Generate HTML file resolving citations
549+
cmd = ['pandoc', '-s', '--bibliography',
550+
pkgrf('fmriprep', 'data/boilerplate.bib'),
551+
'--filter', 'pandoc-citeproc',
552+
str(logs_path / 'CITATION.md'),
553+
'-o', str(logs_path / 'CITATION.html')]
554+
try:
555+
check_call(cmd, timeout=10)
556+
except (FileNotFoundError, CalledProcessError, TimeoutExpired):
557+
logger.warning('Could not generate CITATION.html file:\n%s',
558+
' '.join(cmd))
559+
560+
# Generate LaTex file resolving citations
561+
cmd = ['pandoc', '-s', '--bibliography',
562+
pkgrf('fmriprep', 'data/boilerplate.bib'),
563+
'--natbib', str(logs_path / 'CITATION.md'),
564+
'-o', str(logs_path / 'CITATION.tex')]
565+
try:
566+
check_call(cmd, timeout=10)
567+
except (FileNotFoundError, CalledProcessError, TimeoutExpired):
568+
logger.warning('Could not generate CITATION.tex file:\n%s',
569+
' '.join(cmd))
532570
return retval
533571

534572

0 commit comments

Comments
 (0)