/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)
|