This file is indexed.

/usr/lib/python2.7/dist-packages/pyferret/feraxis.py is in python-ferret 7.3-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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
'''
Represents Ferret axes in Python.
'''

import numbers
import time
import numpy
import pyferret

# set of valid axis types
_VALID_AXIS_TYPES = frozenset( (pyferret.AXISTYPE_LONGITUDE, 
                                pyferret.AXISTYPE_LATITUDE, 
                                pyferret.AXISTYPE_LEVEL, 
                                pyferret.AXISTYPE_TIME, 
                                pyferret.AXISTYPE_CUSTOM, 
                                pyferret.AXISTYPE_ABSTRACT, 
                                pyferret.AXISTYPE_NORMAL) )

# Supported formats for time.strptime
_TIME_PARSE_FORMATS = ( 
    '%d-%b-%Y %H:%M:%S',
    '%d-%b-%Y %H:%M',
    '%d-%b-%Y',
    '%Y-%m-%dT%H:%M:%S',
    '%Y-%m-%dT%H:%M',
    '%Y-%m-%d %H:%M:%S',
    '%Y-%m-%d %H:%M',
    '%Y-%m-%d', 
)
_TIME_NOYEAR_PARSE_FORMATS = (
    '%d-%b %H:%M:%S',
    '%d-%b',
)


class FerAxis(object):
    '''
    Ferret axis object
    '''

    def __init__(self, coords=None, axtype=None, unit=None, name=None):
        '''
        Describe a Ferret axis using the given information about the axis.
            axtype (int): type of the axis; valid values are
                    pyferret.AXISTYPE_LONGITUDE
                    pyferret.AXISTYPE_LATITUDE
                    pyferret.AXISTYPE_LEVEL
                    pyferret.AXISTYPE_TIME
                    pyferret.AXISTYPE_CUSTOM   (axis unit not recognized by Ferret)
                    pyferret.AXISTYPE_ABSTRACT (axis is unit-less integer values)
                    pyferret.AXISTYPE_NORMAL   (axis is normal to the data)
                if not given but coords is given, AXISTYPE_CUSTOM is used,
                if not given and coords is not given, AXISTYPE_NORMAL is used.
            coords (sequence of numeric): coordinate values of the axis; 
                for an axis that is neither a time axis, an abstract axis, nor normal 
                to the data, a 1-D array of numeric values; 
                for a time axis, an (n,6) 2D array of integers where each time step is 
                formed from the six integers for the day, month, year, hour, minute, 
                and second in the index given by
                    pyferret.TIMEARRAY_DAYINDEX
                    pyferret.TIMEARRAY_MONTHINDEX
                    pyferret.TIMEARRAY_YEARINDEX
                    pyferret.TIMEARRAY_HOURINDEX
                    pyferret.TIMEARRAY_MINUTEINDEX
                    pyferret.TIMEARRAY_SECONDINDEX
                (Thus, coords[t, TIMEARRAY_YEARINDEX] gives the year of time t.)
                Note: a relative time axis will be of type AXISTYPE_CUSTOM, with a unit
                      indicating the starting point, such as 'days since 01-JAN-2000'
                For an abstract axis or an axis normal to the data, this argument is ignored.
            unit (string): unit of the axis; for a time axis, this gives the calendar 
                    as one of
                    pyferret.CALTYPE_360DAY
                    pyferret.CALTYPE_NOLEAP
                    pyferret.CALTYPE_GREGORIAN
                    pyferret.CALTYPE_JULIAN
                    pyferret.CALTYPE_ALLLEAP
                    pyferret.CALTYPE_NONE    (calendar not specified)
                For abstract axes, or axes normal to the data, this argument is ignored.
            name (string): Ferret name for the axis
                For an axis normal to the data, this argument is ignored.
        '''
        # axis type
        if axtype:
            if not axtype in _VALID_AXIS_TYPES:
                raise ValueError('axis type %s is not valid' % str(axtype))
            self._axtype = axtype
        elif coords is not None:
            self._axtype = pyferret.AXISTYPE_CUSTOM
        else:
            self._axtype = pyferret.AXISTYPE_NORMAL
        # axis name
        if name and (self._axtype != pyferret.AXISTYPE_NORMAL):
            if not isinstance(name, str): 
                raise ValueError('axis name %s is not valid' % str(name))
            self._name = name.strip()
        else:
            self._name = ''
        # axis unit
        if unit and (self._axtype != pyferret.AXISTYPE_NORMAL) \
                    and (self._axtype != pyferret.AXISTYPE_ABSTRACT):
            if not isinstance(unit, str): 
                raise ValueError('axis unit %s is not valid' % str(unit))
            self._unit = unit.strip()
        else:
            self._unit = ''
        # axis coordinates
        if (coords is not None) and (self._axtype != pyferret.AXISTYPE_NORMAL) \
                                and (self._axtype != pyferret.AXISTYPE_ABSTRACT):
            if self._axtype == pyferret.AXISTYPE_TIME:
                try:
                    self._coords = numpy.array(coords, dtype=numpy.int32, copy=True)
                except ValueError:
                    raise ValueError('coordinates for a time axis is not an integer array')
                if self._coords.ndim != 2:
                    raise ValueError('coordinates for a time axis is not a 2-D array')
                if self._coords.shape[1] != 6:
                    raise ValueError('second dimenstion of coordinates for a time axis is not 6')
            else:
                try:
                    self._coords = numpy.array(coords, dtype=numpy.float64, copy=True)
                except ValueError:
                    raise ValueError('coordinates for an axis is not a numeric array')
                if self._coords.ndim != 1:
                    raise ValueError('coordinates for a lon/lat/level/custom axis is not a 1-D array' % k)
        else:
            self._coords = None


    def __repr__(self):
        '''
        Representation to recreate this FerAxis
        '''
        # Not elegant, but will do
        infostr = "FerAxis(coords=" + repr(self._coords) + \
                  ", axtype=" + repr(self._axtype) + \
                  ", unit='" + self._unit + \
                  "', name='" + self._name + "')"
        return infostr


    def __eq__(self, other):
        '''
        Two FerAxis objects are equal is all their contents are the same.  
        All string values are compared case-insensitive.
        '''
        if not isinstance(other, FerAxis):
            return NotImplemented
        # _axtype is an integer
        if self._axtype != other._axtype:
            return False
        # _name is a string
        if self._name.upper() != other._name.upper():
            return False
        # _unit is a string
        if self._unit.upper() != other._unit.upper():
            return False
        # _coords is an ndarray or None
        if (self._coords is None) and (other._coords is None):
            return True
        if (self._coords is None) or (other._coords is None):
            return False
        if not numpy.allclose(self._coords, other._coords):
            return False
        return True


    def __ne__(self, other):
        '''
        Two FerAxis obect are not equal is any of their contents are not 
        the same.  All string values are compared case-insensitive.
        '''
        if not isinstance(other, FerAxis):
            return NotImplemented
        return not self.__eq__(other)


    def __getitem__(self, name):
        '''
        Return the axis type (if name='axtype'), unit (if name='unit'), 
        name (if name='name'), or a copy of the coordinates (if name='coords')
        '''
        if name == 'axtype':
            return self.getaxtype()
        if name == 'unit':
            return self.getunit()
        if name == 'name':
            return self.getname()
        if name == 'coords':
            return self.getcoords()
        raise KeyError("unknown key '%s'" % str(name))


    def __getattr__(self, name):
        '''
        Return the axis type (if name='axtype'), unit (if name='unit'), 
        name (if name='name'), or a copy of the coordinates (if name='coords')
        Note that this method is only called when the parent object 
        does not have an attribute with this name.
        '''
        try:
            return self.__getitem__(name)
        except KeyError:
            raise AttributeError("unknown attribute '%s'" % name)


    def __dir__(self):
        '''
        Returns a list of known attributes, including those added 
        by the __getattr__ method.
        '''
        mydir = [ 'axtype', 'coords', 'name', 'unit' ]
        mydir.extend( dir(super(FerAxis, self)) )
        return mydir


    def copy(self):
        '''
        Returns a copy of this FerAxis object.  The FerAxis object returned
        does not share any mutable values (namely, the coordinates array)
        with this FerAxis object.
        '''
        # __init__ forces a copy of the coordinates array
        duplicate = FerAxis(axtype=self._axtype, coords=self._coords,
                            unit=self._unit, name=self._name)
        return duplicate


    def getaxtype(self):
        '''
        Returns the type of this axis as one of the integer constants
            pyferret.AXISTYPE_LONGITUDE
            pyferret.AXISTYPE_LATITUDE
            pyferret.AXISTYPE_LEVEL
            pyferret.AXISTYPE_TIME
            pyferret.AXISTYPE_CUSTOM   (axis unit not recognized by Ferret)
            pyferret.AXISTYPE_ABSTRACT (axis is unit-less integer values)
            pyferret.AXISTYPE_NORMAL   (axis is normal to the data)
        '''
        return self._axtype


    def getcoords(self):
        '''
        Returns a copy of the coordinates ndarray for this axis, 
        or None if there is no coordinates array for this axis.
        '''
        if self._coords is not None:
            coords = self._coords.copy('A')
        else:
            coords = None
        return coords


    def getunit(self):
        '''
        Returns the unit string for this axis.  May be an empty string.
        '''
        return self._unit


    def getname(self):
        '''
        Returns the name string for this axis.  May be an empty string.
        '''
        return self._name


    @staticmethod
    def _parsegeoslice(geoslice):
        '''
        Parses the contents of the slice attributes, interpreting any geo- or time-references
        and returns a tuple with the resulting interpreted axis type, start, stop, and step values.

           geoslice (slice): slice that can contain georeferences or time references

           returns (axtype, start, stop, step) where:
              axtype is one of:
                  pyferret.AXISTYPE_LONGITUDE  (longitude units detected)
                  pyferret.AXISTYPE_LATITUDE   (latitude units detected)
                  pyferret.AXISTYPE_LEVEL      (level units detected)
                  pyferret.AXISTYPE_TIME       (time units detected)
                  pyferret.AXISTYPE_ABSTRACT   (no units)
              start, stop, and step are:
                  None if the correspond geoslice attribute is not given; otherwise,
                  a list of six numbers if axtype is pyferret.AXISTYPE_TIME, or
                  a number if axtype is not pyferret.AXISTYPE_TIME

        The list of six numbers for time values are ordered according to the indices:
            pyferret.TIMEARRAY_DAYINDEX
            pyferret.TIMEARRAY_MONTHINDEX
            pyferret.TIMEARRAY_YEARINDEX
            pyferret.TIMEARRAY_HOURINDEX
            pyferret.TIMEARRAY_MINUTEINDEX
            pyferret.TIMEARRAY_SECONDINDEX
        For non-time values, the start, stop, and step values are int objects 
            if only if corresponding slice objects were int objects.  Thus, int 
            objects should be interpreted as axis indices and float objects 
            should be interpreted as axis values.
        Raises a ValueError if start and stop indicate different axes; i.e., 
            "10E":"20N" or 10:"20N" or 10:"20-JAN-2000", or if the value contain 
            unrecognized units.  If not a time slice, it is acceptable for step to 
            have no units even when start and stop do.  If a time slice, the step 
            must have a unit of y, d, h, m, or s, which corresponds to year, day, 
            hour, minute, or second; there is no month time step unit.
        Raises a TypeError if geoslice is not a slice or None, or if the values 
            in the slice are not None and cannot be interpreted.
        '''
        if geoslice is None:
            return (pyferret.AXISTYPE_ABSTRACT, None, None, None)
        if not isinstance(geoslice, slice):
            raise TypeError('not a slice object: %s' % repr(geoslice))
        (starttype, start) = FerAxis._parsegeoval(geoslice.start)
        (stoptype, stop) = FerAxis._parsegeoval(geoslice.stop)
        # start and stop types must match (so 10:"25E" also fails)
        if starttype != stoptype:
            raise ValueError('mismatch of units: %s and %s' % (geoslice.start, geoslice.stop))
        axtype = starttype
        if axtype == pyferret.AXISTYPE_TIME:
            (steptype, step) = FerAxis._parsegeoval(geoslice.step, istimestep=True)
            if (step is not None) and (steptype != pyferret.AXISTYPE_TIME):
               raise ValueError('a time unit y, d, h, m, or s must be given with time slice steps')
        else:
            (steptype, step) = FerAxis._parsegeoval(geoslice.step)
            if (steptype != pyferret.AXISTYPE_ABSTRACT) and (steptype != axtype):
               raise ValueError('mismatch of units: %s, %s' % (geoslice.start, geoslice.step))
        return (axtype, start, stop, step)


    @staticmethod
    def _parsegeoval(val, istimestep=False):
        '''
        Parses the value as either a longitude, latitude, level, time, or abstract number.
        If val is a numeric value, the tuple (pyferret.AXISTYPE_ABSTRACT, val) is returned.
        If val is None, the tuple (pyferret.AXISTYPE_ABSTRACT, None) is returned.
        If val is a longitude string (unit E or W when istimestep is false), 
            (pyferret.AXISTYPE_LONGITUDE, fval) is returned where fval 
            is the floating point longitude value.
        If val is a latitude string (unit N or S when istimestep is false), 
            (pyferret.AXISTYPE_LATITUDE, fval) is returned where fval 
            is the floating point latitude value.
        If val is a level string (unit m when istimestep is False), 
            (pyferret.AXISTYPE_LEVEL, fval) is returned where fval 
            is the floating point level value.
        If val is a date and, optionally, time string matching one of the formats given
            in _TIME_PARSE_FORMATS or _TIME_NOYEAR_PARSE_FORMATS, 
            (pyferret.AXISTYPE_TIME, tval) is returned where
            tval is a list of six numbers ordered by the indices:
                pyferret.TIMEARRAY_DAYINDEX
                pyferret.TIMEARRAY_MONTHINDEX
                pyferret.TIMEARRAY_YEARINDEX
                pyferret.TIMEARRAY_HOURINDEX
                pyferret.TIMEARRAY_MINUTEINDEX
                pyferret.TIMEARRAY_SECONDINDEX
        If istimestep is true and val is a time step string (unit y, d, h, m, or s),
            (pyferret.AXISTYPE_TIME, tval) is returned where tval is a list of six values 
            ordered by the above TIMEARRAY indices.  
            Note that m is minutes; there is no month timestep.
        If val is a string of a unitless number, (pyferret.AXISTYPE_ABSTACT, fval) is 
            returned where fval is the floating point value specified by val.
        If val is not numeric or a string, a TypeError is raised.
        If val is a string that cannot be parsed, a ValueError is raised.
        '''
        # if just a number, return it with abstract axis type
        if isinstance(val, numbers.Real):
            return (pyferret.AXISTYPE_ABSTRACT, val)
        # if None or empty, return None with abstract axis type
        if not val:
            return (pyferret.AXISTYPE_ABSTRACT, None)
        if not isinstance(val, str):
            raise TypeError('not a string: %s' % repr(val))
        if not istimestep:
            # not a time *step* - first try parsing as a date/time string using the accepted formats
            for fmt in _TIME_PARSE_FORMATS:
                try:
                    tval = time.strptime(val, fmt)
                    tlist = [ 0, 0, 0, 0, 0, 0 ]
                    tlist[pyferret.TIMEARRAY_DAYINDEX] = tval.tm_mday
                    tlist[pyferret.TIMEARRAY_MONTHINDEX] = tval.tm_mon
                    tlist[pyferret.TIMEARRAY_YEARINDEX] = tval.tm_year
                    tlist[pyferret.TIMEARRAY_HOURINDEX] = tval.tm_hour
                    tlist[pyferret.TIMEARRAY_MINUTEINDEX] = tval.tm_min
                    tlist[pyferret.TIMEARRAY_SECONDINDEX] = tval.tm_sec
                    return (pyferret.AXISTYPE_TIME, tlist)
                except ValueError:
                    pass
            for fmt in _TIME_NOYEAR_PARSE_FORMATS:
                try:
                    tval = time.strptime(val, fmt)
                    tlist = [ 0, 0, 0, 0, 0, 0 ]
                    tlist[pyferret.TIMEARRAY_DAYINDEX] = tval.tm_mday
                    tlist[pyferret.TIMEARRAY_MONTHINDEX] = tval.tm_mon
                    # leave the year as zero - time.strptime assigns 1900
                    tlist[pyferret.TIMEARRAY_HOURINDEX] = tval.tm_hour
                    tlist[pyferret.TIMEARRAY_MINUTEINDEX] = tval.tm_min
                    tlist[pyferret.TIMEARRAY_SECONDINDEX] = tval.tm_sec
                    return (pyferret.AXISTYPE_TIME, tlist)
                except ValueError:
                    pass
        # not a date/time, so parse as a number with possibly a final letter for the unit
        try:
            lastchar = val[-1].upper()
            if (not istimestep) and (lastchar == 'E'): # degrees E
                # make sure the rest is just numeric
                fval = float(val[:-1])
                return(pyferret.AXISTYPE_LONGITUDE, val.upper())
            elif (not istimestep) and (lastchar == 'W'): # degrees W
                # make sure the rest is just numeric
                fval = float(val[:-1])
                return(pyferret.AXISTYPE_LONGITUDE, val.upper())
            elif (not istimestep) and (lastchar == 'N'): # degrees N
                # make sure the rest is just numeric
                fval = float(val[:-1])
                return(pyferret.AXISTYPE_LATITUDE, val.upper())
            elif (not istimestep) and (lastchar == 'S'): # degrees S
                # make sure the rest is just numeric
                fval = float(val[:-1])
                return(pyferret.AXISTYPE_LATITUDE, val.upper())
            elif (not istimestep) and (lastchar == 'M'): # meters (or kilometers, etc.)
                return(pyferret.AXISTYPE_LEVEL, val.upper())
            elif istimestep and (lastchar == 'Y'): # years
                fval = float(val[:-1])
                tlist = [ 0, 0, 0, 0, 0, 0 ]
                tlist[pyferret.TIMEARRAY_YEARINDEX] = fval
                return (pyferret.AXISTYPE_TIME, tlist)
            elif istimestep and (lastchar == 'D'): # days
                fval = float(val[:-1])
                tlist = [ 0, 0, 0, 0, 0, 0 ]
                tlist[pyferret.TIMEARRAY_DAYINDEX] = fval
                return (pyferret.AXISTYPE_TIME, tlist)
            elif istimestep and (lastchar == 'H'): # hours
                fval = float(val[:-1])
                tlist = [ 0, 0, 0, 0, 0, 0 ]
                tlist[pyferret.TIMEARRAY_HOURINDEX] = fval
                return (pyferret.AXISTYPE_TIME, tlist)
            elif istimestep and (lastchar == 'M'): # minutes
                fval = float(val[:-1])
                tlist = [ 0, 0, 0, 0, 0, 0 ]
                tlist[pyferret.TIMEARRAY_MINUTEINDEX] = fval
                return (pyferret.AXISTYPE_TIME, tlist)
            elif istimestep and (lastchar == 'S'): # seconds
                fval = float(val[:-1])
                tlist = [ 0, 0, 0, 0, 0, 0 ]
                tlist[pyferret.TIMEARRAY_SECONDINDEX] = fval
                return (pyferret.AXISTYPE_TIME, tlist)
            else:
                # maybe just numeric string; if not, will raise an exception
                fval = float(val)
                return(pyferret.AXISTYPE_ABSTRACT, fval)
        except Exception:
            raise ValueError('unable to parse: %s' % val)


    @staticmethod
    def _makedatestring(timearray):
        '''
        Creates a date and time string for the format DD-MON-YYYY HH:MM:SS 
        corresponding the values in the given time array.  If the year is 
        zero, -YYYY is omitted.  If the seconds is zero, :SS is omitted; 
        if hours, minutes, and seconds are all zero, HH:MM:SS is omitted.
            timearray: tuple of six int with time values given by the indices
                pyferret.TIMEARRAY_DAYINDEX
                pyferret.TIMEARRAY_MONTHINDEX
                pyferret.TIMEARRAY_YEARINDEX
                pyferret.TIMEARRAY_HOURINDEX
                pyferret.TIMEARRAY_MINUTEINDEX
                pyferret.TIMEARRAY_SECONDINDEX
        '''
        day = timearray[pyferret.TIMEARRAY_DAYINDEX]
        monthstr = pyferret.datamethods._UC_MONTH_NAMES[timearray[pyferret.TIMEARRAY_MONTHINDEX]]
        year = timearray[pyferret.TIMEARRAY_YEARINDEX]
        hour = timearray[pyferret.TIMEARRAY_HOURINDEX]
        minute = timearray[pyferret.TIMEARRAY_MINUTEINDEX]
        second = timearray[pyferret.TIMEARRAY_SECONDINDEX]
        if year > 0:
            datestr = '%02d-%3s-%04d' % (day, monthstr, year)
        else:
            datestr = '%02d-%3s' % (day, monthstr)
        if second > 0:
            timestr = ' %02d:%02d:%02d' % (hour, minute, second)
        elif (minute > 0) or (hour > 0):
            timestr = ' %02d:%02d' % (hour, minute)
        else:
            timestr = ''
        return datestr + timestr