nibabel.batteryrunners¶
Battery runner classes and Report classes
These classes / objects are for generic checking / fixing batteries
The BatteryRunner
class will run a series of checks on a single
object.
A check is a callable, of signature func(obj, fix=False)
which
returns a tuple (obj, Report)
for func(obj, False)
or
func(obj, True)
, where the obj may be a modified object, or a
different object, if fix==True
.
To run checks only, and return problem report objects:
>>> def chk(obj, fix=False): # minimal check
... return obj, Report()
>>> btrun = BatteryRunner((chk,))
>>> reports = btrun.check_only('a string')
To run checks and fixes, returning fixed object and problem report sequence, with possible fix messages:
>>> fixed_obj, report_seq = btrun.check_fix('a string')
Reports are iterable things, where the elements in the iterations are
Problems
, with attributes error
, problem_level
,
problem_msg
, and possibly empty fix_msg
. The problem_level
is an integer, giving the level of problem, from 0 (no problem) to 50
(very bad problem). The levels follow the log levels from the logging
module (e.g 40 equivalent to “error” level, 50 to “critical”). The
error
can be one of None
if no error to suggest, or an Exception
class that the user might consider raising for this situation. The
problem_msg
and fix_msg
are human readable strings that should
explain what happened.
More about checks
¶
Checks are callables returning objects and reports, like chk
below,
such that:
obj, report = chk(obj, fix=False)
obj, report = chk(obj, fix=True)
For example, for the Analyze header, we need to check the datatype:
def chk_datatype(hdr, fix=True):
rep = Report(hdr, HeaderDataError)
code = int(hdr['datatype'])
try:
dtype = AnalyzeHeader._data_type_codes.dtype[code]
except KeyError:
rep.problem_level = 40
rep.problem_msg = 'data code not recognized'
else:
if dtype.type is np.void:
rep.problem_level = 40
rep.problem_msg = 'data code not supported'
else:
return hdr, rep
if fix:
rep.fix_problem_msg = 'not attempting fix'
return hdr, rep
or the bitpix:
def chk_bitpix(hdr, fix=True):
rep = Report(HeaderDataError)
code = int(hdr['datatype'])
try:
dt = AnalyzeHeader._data_type_codes.dtype[code]
except KeyError:
rep.problem_level = 10
rep.problem_msg = 'no valid datatype to fix bitpix'
return hdr, rep
bitpix = dt.itemsize * 8
if bitpix == hdr['bitpix']:
return hdr, rep
rep.problem_level = 10
rep.problem_msg = 'bitpix does not match datatype')
if fix:
hdr['bitpix'] = bitpix # inplace modification
rep.fix_msg = 'setting bitpix to match datatype'
return hdr, ret
or the pixdims:
def chk_pixdims(hdr, fix=True):
rep = Report(hdr, HeaderDataError)
if not np.any(hdr['pixdim'][1:4] < 0):
return hdr, rep
rep.problem_level = 40
rep.problem_msg = 'pixdim[1,2,3] should be positive'
if fix:
hdr['pixdim'][1:4] = np.abs(hdr['pixdim'][1:4])
rep.fix_msg = 'setting to abs of pixdim values'
return hdr, rep
Classes
|
Class to run set of checks |
|
Initialize report with values |