This file is indexed.

/usr/lib/python2.7/dist-packages/isodatetime/dumpers.py is in python-cylc 7.6.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
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------------------
# (C) British Crown Copyright 2013-2017 Met Office.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------

"""This provides data model dumping functionality."""

import re

from . import parser_spec
from . import util


class TimePointDumperBoundsError(ValueError):

    """An error raised when a TimePoint can't be dumped within bounds."""

    MESSAGE = "Cannot dump TimePoint {0}: {1} not in bounds {2} to {3}."

    def __str__(self):
        return self.MESSAGE.format(*self.args)


class TimePointDumper(object):

    """Dump TimePoint instances to strings using particular formats.

    A format can be specified in the self.dump method via the
    formatting_string argument. Unlike Python's datetime strftime
    method, this uses normal/Unicode character patterns to represent
    which pieces of information to output where. A full reference
    of valid patterns is found in the parser_spec module, with lots
    of examples (coincidentally, used to generate the parsing).
    Anything not matched will get left as it is in the string.
    Specifying a particular time zone will result in a time zone
    conversion of the date/time information before it is output.

    For example, the following formatting_string
    'CCYYMMDDThhmmZ' is made up of:
    CC - year (century) information, e.g. 19
    YY - year (decade, year of decade) information, e.g. 85
    MM - month of year information, e.g. 05
    DD - day of month information, e.g. 31
    T - left alone, date/time separator
    hh - hour of day information, e.g. 06
    mm - minute of hour information, e.g. 58
    Z - Zulu or UTC zero-offset time zone, left in, forces time zone
    conversion
    and might dump a TimePoint instance like this: '19850531T0658Z'.

    Keyword arguments:
    num_expanded_year_digits - an integer (default 2) that indicates
    how many extra year digits to apply if appropriate (and if the
    user requests that information).

    """

    def __init__(self, num_expanded_year_digits=2):
        self._rec_formats = {"date": [], "time": [], "time_zone": []}
        self._time_designator = parser_spec.TIME_DESIGNATOR
        self.num_expanded_year_digits = num_expanded_year_digits
        for info, key in [
                (parser_spec.get_date_translate_info(
                    num_expanded_year_digits),
                 "date"),
                (parser_spec.get_time_translate_info(), "time"),
                (parser_spec.get_time_zone_translate_info(), "time_zone")]:
            for regex, regex_sub, format_sub, prop_name in info:
                rec = re.compile(regex)
                self._rec_formats[key].append((rec, format_sub, prop_name))

    def dump(self, timepoint, formatting_string):
        """Dump a timepoint according to formatting_string.

        The syntax for formatting_string is the syntax used for the
        TimePointParser internals. See TimePointParser.*_TRANSLATE_INFO.

        """
        if "%" in formatting_string:
            try:
                return self.strftime(timepoint, formatting_string)
            except TimePointDumperBoundsError:
                raise
            except ValueError:
                pass
        expression, properties, custom_time_zone = (
            self._get_expression_and_properties(formatting_string))
        return self._dump_expression_with_properties(
            timepoint, expression, properties,
            custom_time_zone=custom_time_zone
        )

    def strftime(self, timepoint, formatting_string):
        """Implement equivalent of Python 2's datetime.datetime.strftime.

        Dump timepoint based on the format given in formatting_string.

        """
        split_format = parser_spec.REC_SPLIT_STRFTIME_DIRECTIVE.split(
            formatting_string)
        expression = ""
        properties = []
        for item in split_format:
            if parser_spec.REC_STRFTIME_DIRECTIVE_TOKEN.search(item):
                item_expression, item_properties = (
                    parser_spec.translate_strftime_token(item))
                expression += item_expression
                properties += item_properties
            else:
                expression += item
        return self._dump_expression_with_properties(
            timepoint, expression, properties)

    def _dump_expression_with_properties(self, timepoint, expression,
                                         properties, custom_time_zone=None):
        if not timepoint.truncated:
            if "week_of_year" in properties or "day_of_week" in properties:
                if not ("month_of_year" in properties or
                        "day_of_month" in properties or
                        "day_of_year" in properties):
                    # We need the year to be in week years.
                    timepoint = timepoint.copy().to_week_date()
            elif (timepoint.get_is_week_date() and (
                    "month_of_year" in properties or
                    "day_of_month" in properties or
                    "day_of_year" in properties)):
                # We need the year to be in standard calendar years.
                timepoint = timepoint.copy().to_calendar_date()

        if custom_time_zone is not None:
            timepoint = timepoint.copy()
            if custom_time_zone == (0, 0):
                timepoint.set_time_zone_to_utc()
            else:
                current_time_zone = timepoint.get_time_zone()
                new_time_zone = current_time_zone.copy()
                new_time_zone.hours = int(custom_time_zone[0])
                new_time_zone.minutes = int(custom_time_zone[1])
                new_time_zone.unknown = False
                timepoint.set_time_zone(new_time_zone)
        property_map = {}
        for property_ in properties:
            property_map[property_] = timepoint.get(property_)
            if (property_ == "century" and
                    ("expanded_year_digits" not in properties or
                     not self.num_expanded_year_digits)):
                min_value = 0
                max_value = 9999
            elif property_ == "expanded_year_digits":
                max_value = (10 ** (self.num_expanded_year_digits + 4)) - 1
                min_value = -max_value
            else:
                continue
            value = timepoint.year
            if not (min_value <= value <= max_value):
                raise TimePointDumperBoundsError(
                    "year", value, min_value, max_value)
        return expression % property_map

    @util.cache_results
    def _get_expression_and_properties(self, formatting_string):
        date_time_strings = formatting_string.split(
            self._time_designator)
        date_string = date_time_strings[0]
        time_string = ""
        time_zone_string = ""
        custom_time_zone = None
        if len(date_time_strings) > 1:
            time_string = date_time_strings[1]
            if time_string.endswith("Z"):
                time_string = time_string[:-1]
                time_zone_string = "Z"
                custom_time_zone = (0, 0)
            elif "+hh" in time_string:
                time_string, time_zone_string = time_string.split("+")
                time_zone_string = "+" + time_zone_string
            elif "+" in time_string:
                time_string, time_zone_string = time_string.split("+")
                time_zone_string = "+" + time_zone_string
                custom_time_zone = self.get_time_zone(time_zone_string)
            elif "-" in time_string.lstrip("-"):
                time_string, time_zone_string = time_string.split("-")
                time_zone_string = "-" + time_zone_string
                custom_time_zone = self.get_time_zone(time_zone_string)
        point_prop_list = []
        string_map = {"date": "", "time": "", "time_zone": ""}
        for string, key in [(date_string, "date"),
                            (time_string, "time"),
                            (time_zone_string, "time_zone")]:
            for rec, format_sub, prop in self._rec_formats[key]:
                new_string = rec.sub(format_sub, string)
                if new_string != string and prop is not None:
                    point_prop_list.append(prop)
                string = new_string
            string_map[key] = string
        expression = string_map["date"]
        if string_map["time"]:
            expression += self._time_designator + string_map["time"]
        expression += string_map["time_zone"]
        return expression, tuple(point_prop_list), custom_time_zone

    @util.cache_results
    def get_time_zone(self, time_zone_string):
        from . import parsers
        if not hasattr(self, "_timepoint_parser"):
            self._timepoint_parser = parsers.TimePointParser()
        try:
            (expr, info) = (
                self._timepoint_parser.get_time_zone_info(time_zone_string))
        except parsers.ISO8601SyntaxError as e:
            return None
        info = self._timepoint_parser.process_time_zone_info(info)
        if info.get('time_zone_utc'):
            return (0, 0)
        if "time_zone_hour" not in info and "time_zone_minute" not in info:
            return None
        return info.get("time_zone_hour", 0), info.get("time_zone_minute", 0)