diff --git a/fsl/wrappers/__init__.py b/fsl/wrappers/__init__.py index c86358e4f65dff5eaec95fcbbfa31d7dd0058fa9..12bab90daa6632276c06bdb069e88929343abe63 100644 --- a/fsl/wrappers/__init__.py +++ b/fsl/wrappers/__init__.py @@ -8,10 +8,16 @@ them to be called from Python. -Most of these wrapper functions strive to provide as-close an interface to the -command-line tool as possible. Most functions use positional arguments for -required options, and keyword arguments for all other options, with argument -names equivalent to command line option names. +For example, you can call BET like so:: + + from fsl.wrappers import bet + bet('struct', 'struct_brain') + + +Most of these wrapper functions strive to provide an interface which is as +close as possible to the underlying command-line tool. Most functions use +positional arguments for required options, and keyword arguments for all other +options, with argument names equivalent to command line option names. For options where this is not possible (e.g. ``flirt -2D``),an alias is used @@ -19,6 +25,13 @@ instead. Aliases may also be used to provide a more readable interface (e.g. the :func:`.bet` function uses ``mask`` instead of ``m``). +One exception to the above is :class:`.fslmaths`, which provides a more +object-oriented interface:: + + from fsl.wrappers import fslmaths + fslmaths('image.nii').mas('mask.nii').bin().run('output.nii') + + Wrapper functions for commands which accept NIfTI image or numeric text files will for the most part accept either in-memory ``nibabel`` images/Numpy arrays or file names as inputs. For commands which produce image or numeric text file @@ -31,11 +44,23 @@ if we want to FLIRT two images and get the result, we can do this:: src = nib.load('src.nii') ref = nib.load('ref.nii') - aligned = flirt(src, ref, out=LOAD)['out'] + init = np.eye(4) + aligned = flirt(src, ref, init=init, out=LOAD)['out'] + + +Similarly, we can run a ``fslmaths`` command on in-memory images:: + + import nibabel as nib + from fsl.wrappers import fslmaths, LOAD + + image = nib.load('image.nii') + mask = nib.load('mask.nii') + output = fslmaths(image).mas(mask).bin().run(LOAD) -If you are writing wrapper functions, read through the :mod:`.wrapperutils` -module - it contains several useful functions and decorators. +If you are *writing* wrapper functions, take a look at the +:mod:`.wrapperutils` module - it contains several useful functions and +decorators. """ diff --git a/fsl/wrappers/wrapperutils.py b/fsl/wrappers/wrapperutils.py index 8e22f7ad156fbc9f9bad0149e33ad505690ea42c..5ceb2cee24baf032844105db478a5a0489990cc4 100644 --- a/fsl/wrappers/wrapperutils.py +++ b/fsl/wrappers/wrapperutils.py @@ -24,10 +24,6 @@ When this ``fslreorient2std`` function is called, the ``fslwrapper`` decorator will take care of invoking the command in a standardised way. -.. note:: The :func:`fslwrapper` and :func:`cmdwrapper` should always be - the _first_ decorator applied to a function. - - The :func:`applyArgStyle` function can be used to automatically generate keyword arguments into command-line arguments, based on a set of standard patterns. For example:: @@ -56,6 +52,19 @@ Now this ``flirt`` function can be called either with file names, or ``nibabel`` images. +.. note:: Because the :func:`fileOrImage` and :func:`fileOrArray` decorators + manipulate the return value of the decorated function, they should + be applied *after* any other decorators. Furthermore, if you need to + apply both a ``fileOrImage`` and ``fileOrArray`` decorator to a + function, they should be grouped together, e.g.:: + + @fileOrImage('a', 'b') + @fileOrArray('c', 'd) + @fslwrapper + def func(**kwargs): + ... + + Command outputs can also be loaded back into memory by using the special :data:`LOAD` value when calling a wrapper function. For example:: @@ -99,7 +108,7 @@ def _update_wrapper(wrapper, wrapped, *args, **kwargs): implementation ensures that the wrapper function has an attribute called ``__wrapped__``, which refers to the ``wrapped`` function. - This behaviour is only required in Python versions < 3.4. + This custom function is only needed in Python versions < 3.4. """ wrapper = functools.update_wrapper(wrapper, wrapped, *args, **kwargs) @@ -292,26 +301,6 @@ def applyArgStyle(style, valsep=None, argmap=None, valmap=None, **kwargs): return args -def required(*reqargs): - """Decorator which makes sure that all specified arguments are present - before calling the decorated function. Arguments which are not present - will result in an :exc:`AssertionError`. Use as follows:: - - @required('foo') - def funcWhichRequires_foo(**kwargs): - foo = kwargs['foo'] - """ - - def decorator(func): - def wrapper(*args, **kwargs): - argnames = namedPositionals(func, args) - for reqarg in reqargs: - assert (reqarg in kwargs) or (reqarg in argnames) - return func(**kwargs) - return _update_wrapper(wrapper, func) - return decorator - - def namedPositionals(func, args): """Given a function, and a sequence of positional arguments destined for that function, identiifes the name for each positional argument. @@ -480,7 +469,7 @@ class _FileOrThing(object): ``_FileOrThing`` decorators can be used with any other decorators - __as long as__ they do not manipulate the return value. + **as long as** they do not manipulate the return value. """