7.5. Specifying Dependencies#
This section describes how you can tackle different situations when writing your custom Marker and / or Preprocessor and take care of the dependencies for them.
You might have already come across listing out dependencies for your
custom Markers and / or
custom Preprocessors, if not, check them out
first. If you have already gone through them, you are already familiar with using
class attribute _DEPENDENCIES
to keep track of its dependencies. junifer
is a bit more sophisticated about them and we will see here how you can make the
best use of them.
7.5.1. Handling dependencies that come as Python packages#
You have already seen this case handled by having a class attribute
_DEPENDENCIES
whose value is a set of all the package names that the
component depends on. For example, for RSSETSMarker
, we have:
_DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"}
The type annotation is for documentation and static type checking purposes. Although not required, we highly recommend you use them, your future self and others who use it will thank you.
7.5.2. Handling external dependencies from toolboxes#
You can also specify dependencies of external toolboxes like AFIN, FSL and ANTs, by having a class attribute like so:
_EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
{
"name": "afni",
"commands": ["3dReHo", "3dAFNItoNIFTI"],
},
]
The above example is taken from the class which computes regional homogeneity
(ReHo) using AFNI. The general pattern is that you need to have the value of
_EXT_DEPENDENCIES
as a list of dictionary with two keys:
name
(str) : lowercased name of the toolboxcommands
(list of str) : actual names of the commands you need to use
This is simple but powerful as we will see in the following sub-sections.
7.5.3. Handling conditional dependencies#
You might encounter situations where your Marker or Preprocessor needs to have option for the user to either use a dependency that comes as a package or use a dependency that relies on external toolboxes. With the foundation we laid above, it is really simple to solve it while having validation before running and letting the user know if some dependency is missing.
Let’s look at an actual implementation, in this case SpaceWarper
, so
that it shows the problem a bit better and how we solve it:
class SpaceWarper(BasePreprocessor):
# docstring
_CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [
{
"using": "fsl",
"depends_on": FSLWarper,
},
{
"using": "ants",
"depends_on": ANTsWarper,
},
]
def __init__(
self, using: str, reference: str, on: Union[List[str], str]
) -> None:
# validation and setting up
Here, you see a new class attribute _CONDITIONAL_DEPENDENCIES
which is a
list of dictionaries with two keys:
using
(str) : lowercased name of the toolboxdepends_on
(object) : a class which implements the particular tool’s use
It is mandatory to have the using
positional argument in the constructor in
this case as the validation starts with this and moves further. It is also
mandatory to only allow the value of using
argument to be one of them
specified in the using
key of _CONDITIONAL_DEPENDENCIES
entries.
For brevity, we only show the FSLWarper
here but ANTsWarper
looks very
similar. FSLWarper
looks like this (only the relevant part is shown here):
class FSLWarper:
# docstring
_EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
{
"name": "fsl",
"commands": ["flirt", "applywarp"],
},
]
_DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"}
def preprocess(
self,
input: Dict[str, Any],
extra_input: Dict[str, Any],
) -> Dict[str, Any]:
# implementation
Here you can see the familiar _DEPENDENCIES
and _EXT_DEPENDENCIES
class
attributes. The validation process starts by looking up the using
value of
the _CONDITIONAL_DEPENDENCIES
entries and then retrieves the object pointed
by depends_on
. After that, the _DEPENDENCIES
and _EXT_DEPENDENCIES
class attributes are checked.
This might be a bit too much to get it right away so feel free to check the code
for a better understanding. You can also check ALFFBase
for a Marker
having this pattern.