Skip to content

Commit

Permalink
[REFAC][DOC] Creators at interface level instead of nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
bclenet committed Jan 25, 2024
1 parent 601597d commit 8ba6bef
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 146 deletions.
18 changes: 10 additions & 8 deletions docs/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,26 +125,28 @@ This module contains a set of functions dedicated to computations on images.
get_voxel_dimensions('/path/to/the/image.nii.gz')
```

## narps_open.core.nodes
## narps_open.core.interfaces

This module contains a set of node creators inheriting form the `narps_open.core.nodes.NodeCreator` abstract class.
These are responsible for creating nipype `Node` objects (for now, only based on the `Function` interface, with functions defined in the `narps_open.core.common` module) to be used inside pipeline code. This allows to factorize code, hence making code simpler to read inside pipeline definition.
This module contains a set of interface creators inheriting form the `narps_open.core.interfaces.InterfaceCreator` abstract class.
These are responsible for creating nipype `Interface` objects (for now, only `Function` interfaces are used, with functions defined in the `narps_open.core.common` module) to be used inside pipeline code. This allows to factorize code, hence making it simpler to read inside pipeline definition.

Here is an example how to use the node creators :
Here is an example how to use the interface creators :

```python
from narps_open.core.nodes import RemoveDirectoryNodeCreator, RemoveFileNodeCreator
from narps_open.core.interfaces import (
RemoveDirectoryInterfaceCreator, RemoveFileInterfaceCreator
)

# Create a Node to remove a directory
remove_smoothed = RemoveDirectoryNodeCreator.create_node('remove_smoothed')
remove_smoothed = Node(RemoveDirectoryInterfaceCreator.create(), name = 'remove_smoothed')
remove_smoothed.inputs.directory_name = 'my_directory'

# Create a Node to remove a file
remove_gunzip = RemoveFileNodeCreator.create_node('remove_gunzip')
remove_gunzip = Node(RemoveDirectoryInterfaceCreator.create(), name = 'remove_gunzip')
remove_gunzip.inputs.file_name = 'my_file'
```

For your information, this is how an equivalent code would look like without node creators.
For your information, this is how an equivalent code would look like without interface creators.

```python
from nipype import Node
Expand Down
54 changes: 54 additions & 0 deletions narps_open/core/interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/python
# coding: utf-8

""" Generate useful and recurrent interfaces to write pipelines """

from abc import ABC, abstractmethod

from nipype.interfaces.base.core import Interface
from nipype.interfaces.utility import Function

from narps_open.core.common import remove_directory, remove_parent_directory, remove_file

class InterfaceCreator(ABC):
""" An abstract class to shape what interface creators must provide """

@staticmethod
@abstractmethod
def create_interface() -> Interface:
""" Return a new interface (to be defined by specialized classes) """

class RemoveParentDirectoryInterfaceCreator(InterfaceCreator):
""" An interface creator that provides an interface allowing to remove a directory,
given one of its child's file name.
"""

@staticmethod
def create_interface() -> Function:
return Function(
function = remove_parent_directory,
input_names = ['_', 'file_name'],
output_names = []
)

class RemoveDirectoryInterfaceCreator(InterfaceCreator):
""" An interface creator that provides an interface allowing to remove a directory """

@staticmethod
def create_interface() -> Function:
return Function(
function = remove_directory,
input_names = ['_', 'directory_name'],
output_names = []
)

class RemoveFileInterfaceCreator(InterfaceCreator):
""" An interface creator that provides an interface allowing to remove a file """

@staticmethod
def create_interface() -> Function:
return Function(
function = remove_file,
input_names = ['_', 'file_name'],
output_names = []
)
57 changes: 0 additions & 57 deletions narps_open/core/nodes.py

This file was deleted.

85 changes: 85 additions & 0 deletions tests/core/test_interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/python
# coding: utf-8

""" Tests of the 'narps_open.core.interfaces' module.
Launch this test with PyTest
Usage:
======
pytest -q test_interfaces.py
pytest -q test_interfaces.py -k <selected_test>
"""

from pytest import mark

from nipype.interfaces.base.core import Interface
from nipype.interfaces.utility import Select, Function

from narps_open.core import interfaces

class ValidNC(interfaces.InterfaceCreator):
""" A valid implementation of a InterfaceCreator, for test purposes """

@staticmethod
def create_interface() -> Interface:
""" Return a Interface, as expected """
return Select()

class TestInterfaceCreator:
""" A class that contains all the unit tests for the InterfaceCreator class."""

@staticmethod
@mark.unit_test
def test_create_interface():
""" Test the create_interface method """

test_node = ValidNC.create_interface()
assert isinstance(test_node, Select)

class TestRemoveParentDirectoryInterfaceCreator:
""" A class that contains all the unit tests for the
RemoveParentDirectoryInterfaceCreator class.
"""

@staticmethod
@mark.unit_test
def test_create_interface():
""" Test the create_interface method """

test_node = interfaces.RemoveParentDirectoryInterfaceCreator.create_interface()
assert isinstance(test_node, Function)
inputs = str(test_node.inputs)
assert '_ = <undefined>' in inputs
assert 'file_name = <undefined>' in inputs
assert 'function_str = def remove_parent_directory(_, file_name: str) -> None:' in inputs

class TestRemoveDirectoryInterfaceCreator:
""" A class that contains all the unit tests for the RemoveDirectoryInterfaceCreator class."""

@staticmethod
@mark.unit_test
def test_create_interface():
""" Test the create_interface method """

test_node = interfaces.RemoveDirectoryInterfaceCreator.create_interface()
assert isinstance(test_node, Function)
inputs = str(test_node.inputs)
assert '_ = <undefined>' in inputs
assert 'directory_name = <undefined>' in inputs
assert 'function_str = def remove_directory(_, directory_name: str) -> None:' in inputs

class TestRemoveFileInterfaceCreator:
""" A class that contains all the unit tests for the RemoveFileInterfaceCreator class."""

@staticmethod
@mark.unit_test
def test_create_interface():
""" Test the create_interface method """

test_node = interfaces.RemoveFileInterfaceCreator.create_interface()
assert isinstance(test_node, Function)
inputs = str(test_node.inputs)
assert '_ = <undefined>' in inputs
assert 'file_name = <undefined>' in inputs
assert 'function_str = def remove_file(_, file_name: str) -> None:' in inputs
81 changes: 0 additions & 81 deletions tests/core/test_nodes.py

This file was deleted.

0 comments on commit 8ba6bef

Please sign in to comment.