This file is indexed.

/usr/lib/python3/dist-packages/nibabel/batteryrunners.py is in python3-nibabel 2.2.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the NiBabel package for the
#   copyright and license terms.
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
''' 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 sitation.  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

'''


class BatteryRunner(object):
    ''' Class to run set of checks '''

    def __init__(self, checks):
        ''' Initialize instance from sequence of `checks`

        Parameters
        ----------
        checks : sequence
           sequence of checks, where checks are callables matching
           signature ``obj, rep = chk(obj, fix=False)``.  Checks are run
           in the order they are passed.

        Examples
        --------
        >>> def chk(obj, fix=False): # minimal check
        ...     return obj, Report()
        >>> btrun = BatteryRunner((chk,))
        '''
        self._checks = checks

    def check_only(self, obj):
        ''' Run checks on `obj` returning reports

        Parameters
        ----------
        obj : anything
           object on which to run checks

        Returns
        -------
        reports : sequence
           sequence of report objects reporting on result of running
           checks (withou fixes) on `obj`
        '''
        reports = []
        for check in self._checks:
            obj, rep = check(obj, False)
            reports.append(rep)
        return reports

    def check_fix(self, obj):
        ''' Run checks, with fixes, on `obj` returning `obj`, reports

        Parameters
        ----------
        obj : anything
           object on which to run checks, fixes

        Returns
        -------
        obj : anything
           possibly modified or replaced `obj`, after fixes
        reports : sequence
           sequence of reports on checks, fixes
        '''
        reports = []
        for check in self._checks:
            obj, report = check(obj, True)
            reports.append(report)
        return obj, reports

    def __len__(self):
        return len(self._checks)


class Report(object):

    def __init__(self,
                 error=Exception,
                 problem_level=0,
                 problem_msg='',
                 fix_msg=''):
        ''' Initialize report with values

        Parameters
        ----------
        error : None or Exception
           Error to raise if raising error for this check.  If None,
           no error can be raised for this check (it was probably
           normal).
        problem_level : int
           level of problem.  From 0 (no problem) to 50 (severe
           problem).  If the report originates from a fix, then this
           is the level of the problem remaining after the fix.
           Default is 0
        problem_msg : string
           String describing problem detected. Default is ''
        fix_msg : string
           String describing any fix applied.  Default is ''.

        Examples
        --------
        >>> rep = Report()
        >>> rep.problem_level
        0
        >>> rep = Report(TypeError, 10)
        >>> rep.problem_level
        10
        '''
        self.error = error
        self.problem_level = problem_level
        self.problem_msg = problem_msg
        self.fix_msg = fix_msg

    def __getstate__(self):
        """ State that defines object

        Returns
        -------
        tup : tuple
        """
        return self.error, self.problem_level, self.problem_msg, self.fix_msg

    def __eq__(self, other):
        ''' are two BatteryRunner-like objects equal?

        Parameters
        ----------
        other : object
           report-like object to test equality

        Examples
        --------
        >>> rep = Report(problem_level=10)
        >>> rep2 = Report(problem_level=10)
        >>> rep == rep2
        True
        >>> rep3 = Report(problem_level=20)
        >>> rep == rep3
        False
        '''
        return self.__getstate__() == other.__getstate__()

    def __ne__(self, other):
        """ are two BatteryRunner-like objects not equal?

        See docstring for __eq__
        """
        return not self == other

    def __str__(self):
        ''' Printable string for object '''
        return self.__dict__.__str__()

    @property
    def message(self):
        ''' formatted message string, including fix message if present
        '''
        if self.fix_msg:
            return '; '.join((self.problem_msg, self.fix_msg))
        return self.problem_msg

    def log_raise(self, logger, error_level=40):
        ''' Log problem, raise error if problem >= `error_level`

        Parameters
        ----------
        logger : log
           log object, implementing ``log`` method
        error_level : int, optional
           If ``self.problem_level`` >= `error_level`, raise error
        '''
        logger.log(self.problem_level, self.message)
        if self.problem_level and self.problem_level >= error_level:
            if self.error:
                raise self.error(self.problem_msg)

    def write_raise(self, stream, error_level=40, log_level=30):
        ''' Write report to `stream`

        Parameters
        ----------
        stream : file-like
           implementing ``write`` method
        error_level : int, optional
           level at which to raise error for problem detected in
           ``self``
        log_level : int, optional
           Such that if `log_level` is >= ``self.problem_level`` we
           write the report to `stream`, otherwise we write nothing.
        '''
        if self.problem_level >= log_level:
            stream.write('Level %s: %s\n' %
                         (self.problem_level, self.message))
        if self.problem_level and self.problem_level >= error_level:
            if self.error:
                raise self.error(self.problem_msg)