Skip to content

Commit

Permalink
Merge pull request #2 from smoia/Rachael-docs
Browse files Browse the repository at this point in the history
Prettified pagination
  • Loading branch information
RayStick authored Mar 6, 2020
2 parents 9176c3d + 59feca0 commit b72eed1
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 182 deletions.
22 changes: 13 additions & 9 deletions docs/contributorfile.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.. _contributorfile:

==========================
Contributing to `physiopy`
==========================
===============================
How to contribute to `physiopy`
===============================
Welcome to the physiopy organisation! It’s great news you’re thinking about contributing!
Working with many people from many different places is great, but sometimes this means the code can become messy due to the many different ways a contribution can be made. For this reason, we have set up some guidelines for contributions - to help you get along ASAP!
Before you start you'll need to set up a free `GitHub <https://github.com/>`_ account and sign in. Here are some `instructions <https://help.github.com/articles/signing-up-for-a-new-github-account>`_.
Expand Down Expand Up @@ -36,6 +36,7 @@ Aims of physiopy
----------------
physiopy is a **very** young project developed by a bunch of researchers from the two different sides of the Atlantic Ocean (for now).
Our main goal is to help collect, analyse and share physiological data interfacing with (MRI) neuroimaging. We’re trying to do so by:

1. Write packages to make a user-friendly pipeline to deal with physiological data.
2. Organising a documentation containing tips and strategies on how to collect such data and use our packages.
3. Write packages that take into account the use of such data in combination with neuroimaging (MRI) - by getting everything ready for that analysis.
Expand Down Expand Up @@ -175,9 +176,11 @@ When opening a pull request, assign it to at least one label.
We encourage you to open a PR as soon as possible - even before you finish working on them. This is useful especially to you - so that you can receive comments and suggestions early on, rather than having to process a lot of comments in the final review step!
However, if it’s an incomplete PR, please open a **Draft PR**. That helps us process PRs by knowing which one to have a look first - and how picky to be when doing so.
To be merged, PRs have to:

1. Pass all the Travis CI tests.
2. Have the necessary amount of approving reviews, even if you’re a long time contributor. You can ask one (or more) contributor to do that review, if you think they align more with the content of your PR. You need **one** review for documentation, tests, and small changes, and **two** reviews for bugs, refactoring and enhancements.
3. Contain at least a unit test for your contribution, if the PR contains code (it would be better if it contains an integration or function test and all the breaking tests necessary), or an integration test if it contains documentation. If you’re not confident about writing tests, it is possible to refer to an issue that asks for the test to be written, or another (Draft) PR that contains the tests required.
3. Contain at least a unit test for your contribution, if the PR contains code (it would be better if it contains an integration or function test and all the breaking tests necessary). If you’re not confident about writing tests, it is possible to refer to an issue that asks for the test to be written, or another (Draft) PR that contains the tests required.

As we’re trying to maintain at least a 90% code coverance, you’re strongly encouraged to write all the necessary tests not to drop below the threshold. If our coverance becomes too low, you might be asked to add more tests and/or your PR might be rejected.

.. _styling:
Expand All @@ -197,18 +200,19 @@ physiopy uses Continuous Integration (CI) to make life easier. In particular, we
Travis CI uses `pytest <https://docs.pytest.org/en/latest/>`_ to run the tests. The great thing about it is that you can run it in advance on your local version of the code!
We can measure the amount of code that is tested with [codecov]8https://docs.pytest.org/en/latest/), which is an indication of how reliable our packages are! We try to maintain a 90% code coverage, and for this reason, PR should contain tests!
The four main type of tests we use are:

1. Unit tests
Unit tests check that a minimal piece of code is doing what it should be doing. Normally this means calling a function with some mock parameters and checking that the output is equal to the expected output. For example, to test a function that adds two given numbers together (1 and 3), we would call the function with those parameters, and check that the output is 4.
Unit tests check that a minimal piece of code is doing what it should be doing. Normally this means calling a function with some mock parameters and checking that the output is equal to the expected output. For example, to test a function that adds two given numbers together (1 and 3), we would call the function with those parameters, and check that the output is 4.
2. Breaking tests
Breaking tests are what you expect - they check that the program is breaking when it should. This means calling a function with parameters that are expected **not** to work, and check that it raises a proper error or warning.
Breaking tests are what you expect - they check that the program is breaking when it should. This means calling a function with parameters that are expected **not** to work, and check that it raises a proper error or warning.
3. Integration tests
Integration tests check that the code has an expected output, being blind to its content. This means that if the program should output a new file, the file exists - even if it’s empty. This type of tests are normally run on real data and call the program itself. For instance, documentation PRs should check that the documentation page is produced!
Integration tests check that the code has an expected output, being blind to its content. This means that if the program should output a new file, the file exists - even if it’s empty. This type of tests are normally run on real data and call the program itself. For instance, documentation PRs should check that the documentation page is produced!
4. Functional tests
If integration tests and unit tests could have babies, those would be functional tests. In practice, this kind of tests check that an output is produced, and *also* that it contains what it should contain. If a function should output a new file or an object, this test passes only if the file exists *and* it is like we expect it to be. They are run on real or mock data, and call the program itself or a function.
If integration tests and unit tests could have babies, those would be functional tests. In practice, this kind of tests check that an output is produced, and *also* that it contains what it should contain. If a function should output a new file or an object, this test passes only if the file exists *and* it is like we expect it to be. They are run on real or mock data, and call the program itself or a function.

.. _recognising:

Recognizing contributors
Recognising contributors
------------------------
We welcome and recognize `all contributions <https://allcontributors.org/docs/en/specification>`_ from documentation to testing to code development. You can see a list of current contributors in the README (kept up to date by the `all contributors bot <https://allcontributors.org/docs/en/bot/overview>`_).

Expand Down
145 changes: 25 additions & 120 deletions docs/heuristic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,73 +10,19 @@ Anatomy of a heuristic file
---------------------------

Let's have a look under the hood of the heuristic files used in the `tutorial <howto.html>`_.
It's the file ``heur_tutorial.py`` in ``phys2bids/phy2bids/heuristics/``::

import fnmatch


def heur(physinfo, name, task='', acq='', direct='', rec='', run=''):
# ############################## #
# ## Modify here! ## #
# ## ## #
# ## Possible variables are: ## #
# ## -task (required) ## #
# ## -run ## #
# ## -rec ## #
# ## -acq ## #
# ## -direct ## #
# ## ## #
# ## ## #
# ## See example below ## #
# ############################## #

if fnmatch.fnmatchcase(physinfo, '*tutorial*'):
task = 'test'
run = '00'
rec = 'labchart'
elif physinfo == 'Example':
task = 'rest'
run = '01'
acq = 'resp'
# ############################## #
# ## Don't modify below this! ## #
# ############################## #
else:
# #!# Transform sys.exit in debug warnings or raiseexceptions!
# #!# Make all of the above a dictionary
raise Warning(f'The heuristic {__file__} could not deal with {physinfo}')

if not task:
raise KeyError(f'No "task" attribute found')

name = name + '_task-' + task

# filename spec: sub-<label>[_ses-<label>]_task-<label>[_acq-<label>] ...
# ... [_ce-<label>][_dir-<label>][_rec-<label>] ...
# ... [_run-<index>][_recording-<label>]_physio
if acq:
name = name + '_acq-' + acq

if direct:
name = name + '_dir-' + direct

if rec:
name = name + '_rec-' + rec

if run:
name = name + '_run-' + run

return name
It's the file ``heur_tutorial.py`` in ``phys2bids/phy2bids/heuristics/``:

.. literalinclude:: ../phys2bids/heuristics/heur_tutorial.py
:linenos:

We can split this file into three parts: the initialisation, the dictionaries, and the functional code.

Initialisation
^^^^^^^^^^^^^^
::
import fnmatch


def heur(physinfo, name, task='', acq='', direct='', rec='', run=''):
.. literalinclude:: ../phys2bids/heuristics/heur_tutorial.py
:linenos:
:lines: 1-4

It's important **not to modify this part of the file**. Instead, you can copy and paste it into your own heuristic file.

Expand All @@ -90,32 +36,12 @@ The scripts imports ``fnmatch``, a nice python module that lets you use bash-lik

Dictionaries
^^^^^^^^^^^^
::
# ############################## #
# ## Modify here! ## #
# ## ## #
# ## Possible variables are: ## #
# ## -task (required) ## #
# ## -run ## #
# ## -rec ## #
# ## -acq ## #
# ## -direct ## #
# ## ## #
# ## ## #
# ## See example below ## #
# ############################## #

if fnmatch.fnmatchcase(physinfo, '*tutorial*'):
task = 'test'
run = '00'
rec = 'labchart'
elif physinfo == 'Example':
task = 'rest'
run = '01'
acq = 'resp'
# ############################## #
# ## Don't modify below this! ## #
# ############################## #

.. literalinclude:: ../phys2bids/heuristics/heur_tutorial.py
:linenos:
:lines: 5-29
:lineno-start: 5
:dedent: 4

This is the core of the function, and the part that should be adapted to process your files. In practice, it's the beginning of a |statement|_.
| You need an ``if`` or ``elif`` statement for each file that you want to process, that will test if the ``physinfo`` is similar to a string (first case) or exactly matches a string (second case). The content of the statement is a set of `variable initialisations as a string <https://www.w3schools.com/python/python_strings.asp>`_.
Expand All @@ -127,7 +53,7 @@ This is the core of the function, and the part that should be adapted to process
- ``acq`` is the optional entity for the `set of acquisition parameters <https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/01-magnetic-resonance-imaging-data.html#the-acq-entity>`_.
- ``direct`` is the equivalent of the ``dic`` entity, an optional entity for the phase encoding direction (see `here <https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/01-magnetic-resonance-imaging-data.html#task-including-resting-state-imaging-data>`_).

Note that one mandatory BIDs entity is missing: the **``sub`` entity**, corresponding to the subject label. This is because it has to be specified while calling ``phys2bids``, as it's explained in the `tutorial <howto.html#generating-outputs-in-bids-format>`_. The **session entity** can be specified in the same way. Moreover, if you have a **multifrequency file** there will be another entity, ``recording`` automatically added to those specified here, and containing the sample frequency of the different outputs.
Note that one mandatory BIDs entity is missing: the **``sub`` entity**, correspondent to the subject label. This is because it has to be specified while calling ``phys2bids``, as it's explained in the tutorial section `"generating-outputs-in-bids-format" <howto.html#generating-outputs-in-bids-format>`_. The **session entity** can be specified in the same way. Moreover, if you have a **multifrequency file** there will be another entity, ``recording`` automatically added to those specified here, and containing the sample frequency of the different outputs.

Let's try to read the first statement in the example:

Expand All @@ -137,40 +63,16 @@ Note that we used only a subset of possible entities.

.. _statement: https://www.w3resource.com/python/python-if-else-statements.php

.. |covenant| replace:: ``if .. elif .. else`` statement.
.. |statement| replace:: ``if .. elif .. else`` statement.

Functional code
^^^^^^^^^^^^^^^
::
# ############################## #
# ## Don't modify below this! ## #
# ############################## #
else:
# #!# Transform sys.exit in debug warnings or raiseexceptions!
# #!# Make all of the above a dictionary
raise Warning(f'The heuristic {__file__} could not deal with {physinfo}')

if not task:
raise KeyError(f'No "task" attribute found')

name = name + '_task-' + task

# filename spec: sub-<label>[_ses-<label>]_task-<label>[_acq-<label>] ...
# ... [_ce-<label>][_dir-<label>][_rec-<label>] ...
# ... [_run-<index>][_recording-<label>]_physio
if acq:
name = name + '_acq-' + acq

if direct:
name = name + '_dir-' + direct

if rec:
name = name + '_rec-' + rec

if run:
name = name + '_run-' + run

return name
.. literalinclude:: ../phys2bids/heuristics/heur_tutorial.py
:linenos:
:lines: 27-
:lineno-start: 27
:dedent: 4

This part contains some code that composes the heuristic function output.
It's important **not to modify this part of the file**. Instead, you can copy paste it in your own heuristic file.
Expand All @@ -179,9 +81,12 @@ There's a warning that will raise if the file wasn't able to process the input f
Using the heuristic file
------------------------

Once you modified your heuristic file or created a new one, you can save it anywhere you want, as a python script (``somename.py``). Check that the file is **executable**! Then, you will have to call ``phys2bids`` using the ``-heur``, the ``-sub``, and optionally the ``-ses``, arguments::
Once you modified your heuristic file or created a new one, you can save it anywhere you want, as a python script (``somename.py``). Check that the file is **executable**! Then, you will have to call ``phys2bids`` using the ``-heur``, the ``-sub``, and optionally the ``-ses``, arguments:

.. code-block:: shell
phys2bids -in tutorial_file.txt -chtrig 1 -outdir /home/arthurdent/physio_bids -ntp 158 -tr 1.2 -thr 0.735 -heur /home/arthurdent/git/phys2bids/phys2bids/heuristics/heur_tutorial.py -sub 006 -ses 01
Remember to **specify the full path** to the heuristic file. A copy of the heuristic file will be saved in the site folder.
You can find more information in the `tutorial <howto.html#generating-outputs-in-bids-format>`_.

You can find more information in the `relevant tutorial section <howto.html#generating-outputs-in-bids-format>`_.
Loading

0 comments on commit b72eed1

Please sign in to comment.