This file is indexed.

/usr/lib/python2.7/dist-packages/aniso8601/duration.py is in python-aniso8601 2.0.0-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
# -*- coding: utf-8 -*-

# Copyright (c) 2016, Brandon Nielsen
# All rights reserved.
#
# This software may be modified and distributed under the terms
# of the BSD license.  See the LICENSE file for details.

import datetime

from aniso8601.date import parse_date
from aniso8601.time import parse_time
from aniso8601 import compat

def parse_duration(isodurationstr, relative=False):
    #Given a string representing an ISO 8601 duration, return a
    #datetime.timedelta (or dateutil.relativedelta.relativedelta
    #if relative=True) that matches the given duration. Valid formats are:
    #
    #PnYnMnDTnHnMnS (or any reduced precision equivalent)
    #P<date>T<time>

    if isodurationstr[0] != 'P':
        raise ValueError('ISO 8601 duration must start with a P.')

    #If Y, M, D, H, S, or W are in the string, assume it is a specified duration
    if _has_any_component(isodurationstr, ['Y', 'M', 'D', 'H', 'S', 'W']) is True:
        return _parse_duration_prescribed(isodurationstr, relative)
    else:
        return _parse_duration_combined(isodurationstr, relative)

def _parse_duration_prescribed(durationstr, relative):
    #durationstr can be of the form PnYnMnDTnHnMnS or PnW

    #Make sure the end character is valid
    #https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed
    if durationstr[-1] not in ['Y', 'M', 'D', 'H', 'S', 'W']:
        raise ValueError('ISO 8601 duration must end with a valid character.')

    #Make sure only the lowest order element has decimal precision
    if durationstr.count('.') > 1:
        raise ValueError('ISO 8601 allows only lowest order element to have a decimal fraction.')
    elif durationstr.count('.') == 1:
        #There should only ever be 1 letter after a decimal if there is more
        #then one, the string is invalid
        lettercount = 0;

        for character in durationstr.split('.')[1]:
            if character.isalpha() is True:
                lettercount += 1

            if lettercount > 1:
                raise ValueError('ISO 8601 duration must end with a single valid character.')

    #Do not allow W in combination with other designators
    #https://bitbucket.org/nielsenb/aniso8601/issues/2/week-designators-should-not-be-combinable
    if durationstr.find('W') != -1 and _has_any_component(durationstr, ['Y', 'M', 'D', 'H', 'S']) is True:
        raise ValueError('ISO 8601 week designators may not be combined with other time designators.')

    #Parse the elements of the duration
    if durationstr.find('T') == -1:
        years, months, weeks, days, hours, minutes, seconds = _parse_duration_prescribed_notime(durationstr)
    else:
        years, months, weeks, days, hours, minutes, seconds = _parse_duration_prescribed_time(durationstr)

    if relative is True:
        try:
            import dateutil.relativedelta

            if int(years) != years or int(months) != months:
                #https://github.com/dateutil/dateutil/issues/40
                raise ValueError('Fractional months and years are not defined for relative intervals.')

            return dateutil.relativedelta.relativedelta(years=int(years), months=int(months), weeks=weeks, days=days, hours=hours, minutes=minutes, seconds=seconds)
        except ImportError:
            raise RuntimeError('dateutil must be installed for relative duration support.')

    #Note that weeks can be handled without conversion to days
    totaldays = years * 365 + months * 30 + days

    return datetime.timedelta(weeks=weeks, days=totaldays, hours=hours, minutes=minutes, seconds=seconds)

def _parse_duration_prescribed_notime(durationstr):
    #durationstr can be of the form PnYnMnD or PnW

    #Make sure no time portion is included
    #https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t
    if _has_any_component(durationstr, ['H', 'S']):
        raise ValueError('ISO 8601 time components not allowed in duration without prescribed time.')

    if _component_order_correct(durationstr, ['P', 'Y', 'M', 'D', 'W']) is False:
        raise ValueError('ISO 8601 duration components must be in the correct order.')

    if durationstr.find('Y') != -1:
        years = _parse_duration_element(durationstr, 'Y')
    else:
        years = 0

    if durationstr.find('M') != -1:
        months = _parse_duration_element(durationstr, 'M')
    else:
        months = 0

    if durationstr.find('W') != -1:
        weeks = _parse_duration_element(durationstr, 'W')
    else:
        weeks = 0

    if durationstr.find('D') != -1:
        days = _parse_duration_element(durationstr, 'D')
    else:
        days = 0

    #No hours, minutes or seconds
    hours = 0
    minutes = 0
    seconds = 0

    return (years, months, weeks, days, hours, minutes, seconds)

def _parse_duration_prescribed_time(durationstr):
    #durationstr can be of the form PnYnMnDTnHnMnS

    firsthalf = durationstr[:durationstr.find('T')]
    secondhalf = durationstr[durationstr.find('T'):]

    #Make sure no time portion is included in the date half
    #https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t
    if _has_any_component(firsthalf, ['H', 'S']):
        raise ValueError('ISO 8601 time components not allowed in date portion of duration.')

    if _component_order_correct(firsthalf, ['P', 'Y', 'M', 'D', 'W']) is False:
        raise ValueError('ISO 8601 duration components must be in the correct order.')

    #Make sure no date component is included in the time half
    if _has_any_component(secondhalf, ['Y', 'D']):
        raise ValueError('ISO 8601 time components not allowed in date portion of duration.')

    if _component_order_correct(secondhalf, ['T', 'H', 'M', 'S']) is False:
        raise ValueError('ISO 8601 time components in duration must be in the correct order.')

    if firsthalf.find('Y') != -1:
        years = _parse_duration_element(firsthalf, 'Y')
    else:
        years = 0

    if firsthalf.find('M') != -1:
        months = _parse_duration_element(firsthalf, 'M')
    else:
        months = 0

    if firsthalf.find('D') != -1:
        days = _parse_duration_element(firsthalf, 'D')
    else:
        days = 0

    if secondhalf.find('H') != -1:
        hours = _parse_duration_element(secondhalf, 'H')
    else:
        hours = 0

    if secondhalf.find('M') != -1:
        minutes = _parse_duration_element(secondhalf, 'M')
    else:
        minutes = 0

    if secondhalf.find('S') != -1:
        seconds = _parse_duration_element(secondhalf, 'S')
    else:
        seconds = 0

    #Weeks can't be included
    weeks = 0

    return (years, months, weeks, days, hours, minutes, seconds)

def _parse_duration_combined(durationstr, relative):
    #Period of the form P<date>T<time>

    #Split the string in to its component parts
    datepart, timepart = durationstr[1:].split('T') #We skip the 'P'

    datevalue = parse_date(datepart)
    timevalue = parse_time(timepart)

    if relative is True:
        try:
            import dateutil.relativedelta

            return dateutil.relativedelta.relativedelta(years=datevalue.year, months=datevalue.month, days=datevalue.day, hours=timevalue.hour, minutes=timevalue.minute, seconds=timevalue.second, microseconds=timevalue.microsecond)
        except ImportError:
            raise RuntimeError('dateutil must be installed for relative duration support.')
    else:
        totaldays = datevalue.year * 365 + datevalue.month * 30 + datevalue.day

        return datetime.timedelta(days=totaldays, hours=timevalue.hour, minutes=timevalue.minute, seconds=timevalue.second, microseconds=timevalue.microsecond)

def _parse_duration_element(durationstr, elementstr):
    #Extracts the specified portion of a duration, for instance, given:
    #durationstr = 'T4H5M6.1234S'
    #elementstr = 'H'
    #
    #returns 4
    #
    #Note that the string must start with a character, so its assumed the
    #full duration string would be split at the 'T'

    durationstartindex = 0
    durationendindex = durationstr.find(elementstr)

    for characterindex in compat.range(durationendindex - 1, 0, -1):
        if durationstr[characterindex].isalpha() is True:
            durationstartindex = characterindex
            break

    durationstartindex += 1

    if ',' in durationstr:
        #Replace the comma with a 'full-stop'
        durationstr = durationstr.replace(',', '.')

    return float(durationstr[durationstartindex:durationendindex])

def _has_any_component(durationstr, components):
    #Given a duration string, and a list of components, returns True
    #if any of the listed components are present, False otherwise.
    #
    #For instance:
    #durationstr = 'P1Y'
    #components = ['Y', 'M']
    #
    #returns True
    #
    #durationstr = 'P1Y'
    #components = ['M', 'D']
    #
    #returns False

    for component in components:
        if durationstr.find(component) != -1:
            return True

    return False

def _component_order_correct(durationstr, componentorder):
    #Given a duration string, and a list of components, returns
    #True if the components are in the same order as the
    #component order list, False otherwise. Characters that
    #are present in the component order list but not in the
    #duration string are ignored.
    #
    #https://bitbucket.org/nielsenb/aniso8601/issues/8/durations-with-components-in-wrong-order
    #
    #durationstr = 'P1Y1M1D'
    #components = ['P', 'Y', 'M', 'D']
    #
    #returns True
    #
    #durationstr = 'P1Y1M'
    #components = ['P', 'Y', 'M', 'D']
    #
    #returns True
    #
    #durationstr = 'P1D1Y1M'
    #components = ['P', 'Y', 'M', 'D']
    #
    #returns False

    componentindex = 0

    for characterindex in compat.range(len(durationstr)):
        character = durationstr[characterindex]

        if character in componentorder:
            #This is a character we need to check the order of
            if character in componentorder[componentindex:]:
                componentindex = componentorder.index(character)
            else:
                #A character is out of order
                return False

    return True