summaryrefslogtreecommitdiffstats
path: root/third_party/python/json-e/jsone/shared.py
blob: 0e70e21f8163143077aca48a8502b0e06a6ea207 (plain)
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
from __future__ import absolute_import, print_function, unicode_literals

import re
import datetime


class DeleteMarker:
    pass


class JSONTemplateError(Exception):
    def __init__(self, message):
        super(JSONTemplateError, self).__init__(message)
        self.location = []

    def add_location(self, loc):
        self.location.insert(0, loc)

    def __str__(self):
        location = ' at template' + ''.join(self.location)
        return "{}{}: {}".format(
            self.__class__.__name__,
            location if self.location else '',
            self.args[0])


class TemplateError(JSONTemplateError):
    pass


class InterpreterError(JSONTemplateError):
    pass


# Regular expression matching: X days Y hours Z minutes
# todo: support hr, wk, yr
FROMNOW_RE = re.compile(''.join([
    '^(\s*(?P<years>\d+)\s*y(ears?)?)?',
    '(\s*(?P<months>\d+)\s*mo(nths?)?)?',
    '(\s*(?P<weeks>\d+)\s*w(eeks?)?)?',
    '(\s*(?P<days>\d+)\s*d(ays?)?)?',
    '(\s*(?P<hours>\d+)\s*h(ours?)?)?',
    '(\s*(?P<minutes>\d+)\s*m(in(utes?)?)?)?\s*',
    '(\s*(?P<seconds>\d+)\s*s(ec(onds?)?)?)?\s*$',
]))


def fromNow(offset, reference):
    # copied from taskcluster-client.py
    # We want to handle past dates as well as future
    future = True
    offset = offset.lstrip()
    if offset.startswith('-'):
        future = False
        offset = offset[1:].lstrip()
    if offset.startswith('+'):
        offset = offset[1:].lstrip()

    # Parse offset
    m = FROMNOW_RE.match(offset)
    if m is None:
        raise ValueError("offset string: '%s' does not parse" % offset)

    # In order to calculate years and months we need to calculate how many days
    # to offset the offset by, since timedelta only goes as high as weeks
    days = 0
    hours = 0
    minutes = 0
    seconds = 0
    if m.group('years'):
        # forget leap years, a year is 365 days
        years = int(m.group('years'))
        days += 365 * years
    if m.group('months'):
        # assume "month" means 30 days
        months = int(m.group('months'))
        days += 30 * months
    days += int(m.group('days') or 0)
    hours += int(m.group('hours') or 0)
    minutes += int(m.group('minutes') or 0)
    seconds += int(m.group('seconds') or 0)

    # Offset datetime from utc
    delta = datetime.timedelta(
        weeks=int(m.group('weeks') or 0),
        days=days,
        hours=hours,
        minutes=minutes,
        seconds=seconds,
    )

    if isinstance(reference, string):
        reference = datetime.datetime.strptime(
            reference, '%Y-%m-%dT%H:%M:%S.%fZ')
    elif reference is None:
        reference = datetime.datetime.utcnow()
    return stringDate(reference + delta if future else reference - delta)


datefmt_re = re.compile(r'(\.[0-9]{3})[0-9]*(\+00:00)?')


def to_str(v):
    if isinstance(v, bool):
        return {True: 'true', False: 'false'}[v]
    elif isinstance(v, list):
        return ','.join(to_str(e) for e in v)
    elif v is None:
        return 'null'
    else:
        return str(v)


def stringDate(date):
    # Convert to isoFormat
    try:
        string = date.isoformat(timespec='microseconds')
    # py2.7 to py3.5 does not have timespec
    except TypeError as e:
        string = date.isoformat()
        if string.find('.') == -1:
            string += '.000'
    string = datefmt_re.sub(r'\1Z', string)
    return string


# the base class for strings, regardless of python version
try:
    string = basestring
except NameError:
    string = str