Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New guidelines for developpers #319

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ The [RABIES license](https://github.com/CoBrALab/RABIES/blob/master/LICENSE) all
## Acknowledgements
This software was developped by the [CoBrALab](https://cobralab.ca/), located at the Cerebral Imaging Center of the Douglas Mental Health University Institute, Montreal, Canada, in affiliation with McGill University, Montreal, Canada. This work was supported by funding from Healthy Brains, Healthy Lives (HBHL), the Fonds de recherche du Québec - Santé (FRQS) and - Nature et technologies (FRQNT), and the Natural Sciences and Engineering Research Council (NSERC) of Canada. [fMRIPrep](https://fmriprep.org/en/stable/) was an important inspirational source for this project, in particular with regards to best practices for software reproducibility and code design using Nipype. We also thank the organizers of [BrainHack School Montreal](https://school.brainhackmtl.org/), which guided the initial steps of this project in 2018.


## Ask for help
If you need support in using the software or experience issues that are not documented, we'll provide support on the [Github discussion](https://github.com/CoBrALab/RABIES/discussions).

## Contributing to RABIES

RABIES is under continuous development to keep up with evolving demand and ongoing research. We welcome suggestions for improvements using the [Github issue system](https://github.com/CoBrALab/RABIES/issues). If you're interested in contributing code, you can reach out on the [Github discussion](https://github.com/CoBrALab/RABIES/discussions) and we welcome contributions as pull requests.
**Read our dedicated [documentation](https://rabies.readthedocs.io/en/latest/contributing.html)**
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'CoBrALab'

# The full version, including alpha/beta/rc tags
release = '0.4.6'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a seperate commit

release = '0.5.0'


# -- General configuration ---------------------------------------------------
Expand Down
135 changes: 135 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Contributing to RABIES

RABIES aims to provide an accessible tool responding to growing needs across the preclinical fMRI community. This effort should be community-driven, and community involvement will be commensurate in achieving this goal in several respects:
- adapting and maintaining accessibility for uses across the broader community
- reproducibility and transparency, as well as scientific scrutiny and rigor
- maintaining best practices across the different aspects of image processing and analysis, as well as quality control
- bringing in appropriate expertise for the integration of new tools

Suggestions for improvements can be shared using the Github [issues system](https://github.com/CoBrALab/RABIES/issues) and [discussion board](https://github.com/CoBrALab/RABIES/discussions). Additionally, contributions from developpers will be important in incorporating novel features as well as addressing revisions. This page provides preliminary guidelines for getting started as a RABIES developper, and covers: setting a developper environment, submitting a pull request, testing and debugging, and basic instructions for adding a new module to the pipeline. We recommend discussing your proposed updates on the Github discussion board or issues prior to creating a pull request. Thank you for your support!

## Dev environment

For development, it is recommend to install RABIES locally, as this will make the testing and debugging process smoother. This requires installing the dependencies listed in dependencies.txt, and then installing RABIES in an appropriate python environment (e.g. using anaconda) from the Github repository. This can be done by cloning the repository, and then running ```python setup.py install```.

### ...using a container

It is possible to do development using an interactive container to avoid installing dependencies manually. An interactive shell can be opened through Docker with ```docker run -it --rm --entrypoint bash ...``` or through Singularity with ```singularity shell ...```. From inside the container, the RABIES package can be upgraded by running ```python setup.py install``` on your local version of the package. It is then possible to run scripts, or test the whole pipeline with ```error_check_rabies.py```. However, it won't be possible to use an interface for debugging (e.g. Spyder).

## Instructions to create a pull request

1. On github, fork the RABIES repository to have your own copy.
2. Clone your repository to carry out local modifications and testing. Use the `--recursive` option to download the submodules together with the main RABIES package.
3. Make your modifications to the code.
4. Testing and debugging: install your updated version of the package with ```python setup.py install```, using a proper dev environment (see above). Your can test the workflow with specific parameters by editing the ```debug_workflow.py``` script, and executing in debug mode with Spyder (see below). Before commiting changes, make sure that running ```error_check_rabies.py``` completes with no error.
5. Commit and push your modifications to Github, and create a pull request from your forked repo to the original.
Comment on lines +21 to +25
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to mention making a branch


### Interactive debugging with Spyder and debug_workflow.py

Here are some recommendations for debugging using Spyder:
1. open the debug_workflow.py file in Spyder
2. find the scrips with your local installation to add breakpoints for debugging. Using `import rabies; os.path.abspath(rabies.__file__)` will provide the path to the __init__.py file of your installed package, and from there you can find file of interest and add a breakpoint where desired.
3. execute debug_workflow.py in debug mode, and run until it finds the breakpoint, and debug from there.


## Creation of a new module and integration within a Nipype workflow

RABIES' workflow is structured using Nipype (for more info on Nipype, see online [documentation](https://nipype.readthedocs.io/en/latest/) and [tutorial](https://miykael.github.io/nipype_tutorial/)). Preferably, a new function should be created as a Nipype interface, which has the following syntax:

```python
from nipype.interfaces.base import (
traits, TraitedSpec, BaseInterfaceInputSpec,
File, BaseInterface
)
class NewInterfaceInputSpec(BaseInterfaceInputSpec):
# you must select an appropriate input type with traits.type (can be Dict, File, Int, ...)
input_str = traits.Str(exists=True, mandatory=True,
desc="An input string.")

class NewInterfaceOutputSpec(TraitedSpec):
out_file = File(
exists=True, desc="An output file.")


class NewInterface(BaseInterface):
"""
Describe your module.
"""

input_spec = NewInterfaceInputSpec
output_spec = NewInterfaceOutputSpec

def _run_interface(self, runtime):
input_str = self.inputs.input_str

'''
YOUR CODE
'''

setattr(self, 'out_file', out_file)

return runtime

def _list_outputs(self):
return {'out_file': getattr(self, 'out_file')}


```

You can then create a Nipype node for your interface:
```python
from .other_script import NewInterface # import your interface if from a different script
from nipype.pipeline import engine as pe

new_interface_node = pe.Node(NewInterface(),
name='new_interface')
```

Instead of an interface, it is also possible to create a Nipype node from any python function:
```python
from nipype.pipeline import engine as pe
from nipype.interfaces.utility import Function

new_function_node = pe.Node(Function(input_names=['input_1', 'input_2', ...],
output_names=['output_1', 'output_2', ...],
function=NewFunction),
name='new_function')
```

After creating a node which can carry the desired operation, it must be integrated within a workflow by linking up the inputs and outputs with other nodes. Below is an example of a simple workflow which conducts slice-timing correction:

```python
from nipype.pipeline import engine as pe
from nipype.interfaces.utility import Function
from nipype.interfaces import utility as niu

# this function creates and return a Nipype workflow which conducts slice timing correction
def init_bold_stc_wf(name='bold_stc_wf'):

workflow = pe.Workflow(name=name) # creating a new Nipype workflow
# creating an intermediate node for storing inputs to the workflow
inputnode = pe.Node(niu.IdentityInterface(
fields=['bold_file']), name='inputnode')
# creating an intermediate node for storing outputs to the workflow
outputnode = pe.Node(niu.IdentityInterface(
fields=['stc_file']), name='outputnode')

# preparing the node conducting STC
slice_timing_correction_node = pe.Node(Function(input_names=['in_file', 'tr', 'tpattern', 'stc_axis',
'interp_method', 'rabies_data_type'],
output_names=[
'out_file'],
function=slice_timing_correction),
name='slice_timing_correction', mem_gb=1.5*opts.scale_min_memory)

# linking up the inputnode to provide inputs to the STC node, and outputs from STC to the outputnode of the workflow
workflow.connect([
(inputnode, slice_timing_correction_node, [('bold_file', 'in_file')]),
(slice_timing_correction_node,
outputnode, [('out_file', 'stc_file')]),
])
return workflow

```

This example demonstrates the basic syntax of a Nipype workflow. Most likely, a new interface will be integrated as part of a pre-existing workflow (instead of creating a new one), in which case the right nodes must be linked up with the new interface.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ analysis.md
analysis_QC.md
outputs.md
metrics.md
additional.md
contributing.md
bibliography.md
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ sphinx-rtd-theme
sphinxcontrib-bibtex
sphinxcontrib-programoutput==0.17
jinja2==3.1.1
rabies==0.4.7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should have a seperate commit with the version changes above

rabies==0.5.0
4 changes: 0 additions & 4 deletions rabies/preprocess_pkg/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import os
import pathlib
import SimpleITK as sitk
import numpy as np
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another separate commit

from nipype.interfaces.base import (
traits, TraitedSpec, BaseInterfaceInputSpec,
File, BaseInterface
Expand Down