# NiBabel

### Access a cacophony of neuro-imaging file formats

# `wrapstruct`

Class to wrap numpy structured array

## wrapstruct

The `WrapStruct` class is a wrapper around a numpy structured array type.

It implements:

- Mappingness from the underlying structured array fields

- `from_fileobj`, `write_to` methods to read and write data to fileobj

- A mechanism for setting checks and fixes to the data on object creation

- Endianness guessing, and on-the-fly swapping

The `LabeledWrapStruct` subclass adds:

- A pretty printing mechanism whereby field values can be displayed as corresponding strings (see `LabeledWrapStruct.get_value_label()` and `LabeledWrapStruct.__str_()`)

### Mappingness

You can access and set fields of the contained structarr using standard __getitem__ / __setitem__ syntax:

> wrapped[‘field’] = 10

Wrapped structures also implement general mappingness:

> wrapped.keys() wrapped.items() wrapped.values()

Properties:

    .endianness (read only)
    .binaryblock (read only)
    .structarr (read only)

Methods:

    .as_byteswapped(endianness)
    .check_fix()
    .__str__
    .__eq__
    .__ne__
    .get_value_label(name)

Class methods:

    .diagnose_binaryblock
    .as_byteswapped(endianness)
    .write_to(fileobj)
    .from_fileobj(fileobj)
    .default_structarr() - return default structured array
    .guessed_endian(structarr) - return guessed endian code from this structarr

Class variables:

  template_dtype - native endian version of dtype for contained structarr

### Consistency checks

We have a file, and we would like information as to whether there are any problems with the binary data in this file, and whether they are fixable. `WrapStruct` can hold checks for internal consistency of the contained data:

    wrapped = WrapStruct.from_fileobj(open('myfile.bin'), check=False)
    dx_result = WrapStruct.diagnose_binaryblock(wrapped.binaryblock)

This will run all known checks, with no fixes, returning a string with diagnostic output. See below for the `check=False` flag.

In creating a `WrapStruct` object, we often want to check the consistency of the contained data. The checks can test for problems of various levels of severity. If the problem is severe enough, it should raise an Error. So, with data that is consistent - no error:

    wrapped = WrapStruct.from_fileobj(good_fileobj)

whereas:

    wrapped = WrapStruct.from_fileobj(bad_fileobj)

would raise some error, with output to logging (see below).

If we want the created object, come what may:

    hdr = WrapStruct.from_fileobj(bad_fileobj, check=False)

We set the error level (the level of problem that the `check=True` versions will accept as OK) from global defaults:

    import nibabel as nib
    nib.imageglobals.error_level = 30

The same for logging:

    nib.imageglobals.logger = logger

`LabeledWrapStruct`([binaryblock, endianness, ...]) | A WrapStruct with some fields having value labels for printing etc
`WrapStruct`([binaryblock, endianness, check]) | Initialize WrapStruct from binary data block
`WrapStructError` |

## `LabeledWrapStruct`

class nibabel.wrapstruct.LabeledWrapStruct(binaryblock=None, endianness=None, check=True)

  Bases: `WrapStruct`

  A WrapStruct with some fields having value labels for printing etc

  Initialize WrapStruct from binary data block

  Parameters:
    binaryblock{None, string} optional

      binary block to set into object. By default, None, in which case we insert the default empty block

    endianness{None, ‘<’,’>’, other endian code} string, optional

      endianness of the binaryblock. If None, guess endianness from the data.

    check bool, optional

      Whether to check content of binary data in initialization. Default is True.

  Examples

      >>> wstr1 = WrapStruct() # a default structure
      >>> wstr1.endianness == native_code
      True
      >>> wstr1['integer']
      array(0, dtype=int16)
      >>> wstr1['integer'] = 1
      >>> wstr1['integer']
      array(1, dtype=int16)

  __init__(binaryblock=None, endianness=None, check=True)

    Initialize WrapStruct from binary data block

    Parameters:
      binaryblock{None, string} optional

        binary block to set into object. By default, None, in which case we insert the default empty block

      endianness{None, ‘<’,’>’, other endian code} string, optional

        endianness of the binaryblock. If None, guess endianness from the data.

      check bool, optional

        Whether to check content of binary data in initialization. Default is True.

    Examples

        >>> wstr1 = WrapStruct() # a default structure
        >>> wstr1.endianness == native_code
        True
        >>> wstr1['integer']
        array(0, dtype=int16)
        >>> wstr1['integer'] = 1
        >>> wstr1['integer']
        array(1, dtype=int16)

  get_value_label(fieldname)

    Returns label for coded field

    A coded field is an int field containing codes that stand for discrete values that also have string labels.

    Parameters:
      fieldname str

        name of header field to get label for

    Returns:
      label str

        label for code value in header field fieldname

    Raises:
      ValueError

        if field is not coded.

    Examples

        >>> from nibabel.volumeutils import Recoder
        >>> recoder = Recoder(((1, 'one'), (2, 'two')), ('code', 'label'))
        >>> class C(LabeledWrapStruct):
        ...     template_dtype = np.dtype([('datatype', 'i2')])
        ...     _field_recoders = dict(datatype = recoder)
        >>> hdr  = C()
        >>> hdr.get_value_label('datatype')
        '<unknown code 0>'
        >>> hdr['datatype'] = 2
        >>> hdr.get_value_label('datatype')
        'two'

## `WrapStruct`

class nibabel.wrapstruct.WrapStruct(binaryblock=None, endianness=None, check=True)

  Bases: `object`

  Initialize WrapStruct from binary data block

  Parameters:
    binaryblock{None, string} optional

      binary block to set into object. By default, None, in which case we insert the default empty block

    endianness{None, ‘<’,’>’, other endian code} string, optional

      endianness of the binaryblock. If None, guess endianness from the data.

    check bool, optional

      Whether to check content of binary data in initialization. Default is True.

  Examples

      >>> wstr1 = WrapStruct() # a default structure
      >>> wstr1.endianness == native_code
      True
      >>> wstr1['integer']
      array(0, dtype=int16)
      >>> wstr1['integer'] = 1
      >>> wstr1['integer']
      array(1, dtype=int16)

  __init__(binaryblock=None, endianness=None, check=True)

    Initialize WrapStruct from binary data block

    Parameters:
      binaryblock{None, string} optional

        binary block to set into object. By default, None, in which case we insert the default empty block

      endianness{None, ‘<’,’>’, other endian code} string, optional

        endianness of the binaryblock. If None, guess endianness from the data.

      check bool, optional

        Whether to check content of binary data in initialization. Default is True.

    Examples

        >>> wstr1 = WrapStruct() # a default structure
        >>> wstr1.endianness == native_code
        True
        >>> wstr1['integer']
        array(0, dtype=int16)
        >>> wstr1['integer'] = 1
        >>> wstr1['integer']
        array(1, dtype=int16)

  as_byteswapped(endianness=None)

    return new byteswapped object with given `endianness`

    Guaranteed to make a copy even if endianness is the same as the current endianness.

    Parameters:
      endianness None or string, optional

        endian code to which to swap. None means swap from current endianness, and is the default

    Returns:
      wstr `WrapStruct`

        `WrapStruct` object with given endianness

    Examples

        >>> wstr = WrapStruct()
        >>> wstr.endianness == native_code
        True
        >>> bs_wstr = wstr.as_byteswapped()
        >>> bs_wstr.endianness == swapped_code
        True
        >>> bs_wstr = wstr.as_byteswapped(swapped_code)
        >>> bs_wstr.endianness == swapped_code
        True
        >>> bs_wstr is wstr
        False
        >>> bs_wstr == wstr
        True

    If you write to the resulting byteswapped data, it does not change the original.

        >>> bs_wstr['integer'] = 3
        >>> bs_wstr == wstr
        False

    If you swap to the same endianness, it returns a copy

        >>> nbs_wstr = wstr.as_byteswapped(native_code)
        >>> nbs_wstr.endianness == native_code
        True
        >>> nbs_wstr is wstr
        False

  property binaryblock

    binary block of data as string

    Returns:
      binaryblock string

        string giving binary data block

    Examples

        >>> # Make default empty structure
        >>> wstr = WrapStruct()
        >>> len(wstr.binaryblock)
        2

  check_fix(logger=None, error_level=None)

    Check structured data with checks

    Parameters:
      logger None or logging.Logger
      error_level None or int

        Level of error severity at which to raise error. Any error of severity >= error_level will cause an exception.

  copy()

    Return copy of structure

        >>> wstr = WrapStruct()
        >>> wstr['integer'] = 3
        >>> wstr2 = wstr.copy()
        >>> wstr2 is wstr
        False
        >>> wstr2['integer']
        array(3, dtype=int16)

  classmethod default_structarr(endianness=None)

    Return structured array for default structure with given endianness

  classmethod diagnose_binaryblock(binaryblock, endianness=None)

    Run checks over binary data, return string

  property endianness

    endian code of binary data

    The endianness code gives the current byte order interpretation of the binary data.

    Notes

    Endianness gives endian interpretation of binary data. It is read only because the only common use case is to set the endianness on initialization, or occasionally byteswapping the data - but this is done via the as_byteswapped method

    Examples

        >>> wstr = WrapStruct()
        >>> code = wstr.endianness
        >>> code == native_code
        True

  classmethod from_fileobj(fileobj, endianness=None, check=True)

    Return read structure with given or guessed endiancode

    Parameters:
      fileobj file-like object

        Needs to implement `read` method

      endianness None or endian code, optional

        Code specifying endianness of read data

    Returns:
      wstr WrapStruct object

        WrapStruct object initialized from data in fileobj

  get(k, d=None)

    Return value for the key k if present or d otherwise

  classmethod guessed_endian(mapping)

    Guess intended endianness from mapping-like `mapping`

    Parameters:
      wstr mapping-like

        Something implementing a mapping. We will guess the endianness from looking at the field values

    Returns:
      endianness{‘<’, ‘>’}

        Guessed endianness of binary data in `wstr`

  items()

    Return items from structured data

  keys()

    Return keys from structured data

  property structarr

    Structured data, with data fields

    Examples

        >>> wstr1 = WrapStruct() # with default data
        >>> an_int = wstr1.structarr['integer']
        >>> wstr1.structarr = None
        Traceback (most recent call last):
           ...
        AttributeError: ...

  template_dtype = dtype([('integer', '<i2')])
  values()

    Return values from structured data

  write_to(fileobj)

    Write structure to fileobj

    Write starts at fileobj current file position.

    Parameters:
      fileobj file-like object

        Should implement `write` method

    Returns:
      None

    Examples

        >>> wstr = WrapStruct()
        >>> from io import BytesIO
        >>> str_io = BytesIO()
        >>> wstr.write_to(str_io)
        >>> wstr.binaryblock == str_io.getvalue()
        True

## `WrapStructError`

class nibabel.wrapstruct.WrapStructError

  Bases: `Exception`

  __init__(*args, **kwargs)