Module update: dateutil
This commit is contained in:
1 parent
1bfe948a45
commit
dbbbbb2f84
11 files changed
+634
-217
No files matched your search
@@ -1,9 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__author__ = "Tomi Pieviläinen <tomi.pievilainen@iki.fi>"
|
||||||
__license__ = "PSF License"
|
__license__ = "Simplified BSD"
|
||||||
__version__ = "1.5"
|
__version__ = "2.1"
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ def easter(year, method=EASTER_WESTERN):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not (1 <= method <= 3):
|
if not (1 <= method <= 3):
|
||||||
raise ValueError, "invalid method"
|
raise ValueError("invalid method")
|
||||||
|
|
||||||
# g - Golden year - 1
|
# g - Golden year - 1
|
||||||
# c - Century
|
# c - Century
|
||||||
|
|||||||
+41
-20
@@ -2,25 +2,27 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
from __future__ import unicode_literals
|
||||||
__license__ = "PSF License"
|
__license__ = "Simplified BSD"
|
||||||
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import string
|
import string
|
||||||
import time
|
import time
|
||||||
import sys
|
import collections
|
||||||
import os
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from io import StringIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from StringIO import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
import relativedelta
|
from six import text_type, binary_type, integer_types
|
||||||
import tz
|
|
||||||
|
from . import relativedelta
|
||||||
|
from . import tz
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["parse", "parserinfo"]
|
__all__ = ["parse", "parserinfo"]
|
||||||
@@ -39,7 +41,7 @@ __all__ = ["parse", "parserinfo"]
|
|||||||
class _timelex(object):
|
class _timelex(object):
|
||||||
|
|
||||||
def __init__(self, instream):
|
def __init__(self, instream):
|
||||||
if isinstance(instream, basestring):
|
if isinstance(instream, text_type):
|
||||||
instream = StringIO(instream)
|
instream = StringIO(instream)
|
||||||
self.instream = instream
|
self.instream = instream
|
||||||
self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
|
self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
|
||||||
@@ -133,12 +135,15 @@ class _timelex(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def next(self):
|
def __next__(self):
|
||||||
token = self.get_token()
|
token = self.get_token()
|
||||||
if token is None:
|
if token is None:
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return self.__next__() # Python 2.x support
|
||||||
|
|
||||||
def split(cls, s):
|
def split(cls, s):
|
||||||
return list(cls(s))
|
return list(cls(s))
|
||||||
split = classmethod(split)
|
split = classmethod(split)
|
||||||
@@ -155,7 +160,7 @@ class _resultbase(object):
|
|||||||
for attr in self.__slots__:
|
for attr in self.__slots__:
|
||||||
value = getattr(self, attr)
|
value = getattr(self, attr)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append("%s=%s" % (attr, `value`))
|
l.append("%s=%s" % (attr, repr(value)))
|
||||||
return "%s(%s)" % (classname, ", ".join(l))
|
return "%s(%s)" % (classname, ", ".join(l))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -184,7 +189,7 @@ class parserinfo(object):
|
|||||||
("Jun", "June"),
|
("Jun", "June"),
|
||||||
("Jul", "July"),
|
("Jul", "July"),
|
||||||
("Aug", "August"),
|
("Aug", "August"),
|
||||||
("Sep", "September"),
|
("Sep", "Sept", "September"),
|
||||||
("Oct", "October"),
|
("Oct", "October"),
|
||||||
("Nov", "November"),
|
("Nov", "November"),
|
||||||
("Dec", "December")]
|
("Dec", "December")]
|
||||||
@@ -300,7 +305,7 @@ class parser(object):
|
|||||||
second = 0, microsecond = 0)
|
second = 0, microsecond = 0)
|
||||||
res = self._parse(timestr, **kwargs)
|
res = self._parse(timestr, **kwargs)
|
||||||
if res is None:
|
if res is None:
|
||||||
raise ValueError, "unknown string format"
|
raise ValueError("unknown string format")
|
||||||
repl = {}
|
repl = {}
|
||||||
for attr in ["year", "month", "day", "hour",
|
for attr in ["year", "month", "day", "hour",
|
||||||
"minute", "second", "microsecond"]:
|
"minute", "second", "microsecond"]:
|
||||||
@@ -311,20 +316,20 @@ class parser(object):
|
|||||||
if res.weekday is not None and not res.day:
|
if res.weekday is not None and not res.day:
|
||||||
ret = ret + relativedelta.relativedelta(weekday = res.weekday)
|
ret = ret + relativedelta.relativedelta(weekday = res.weekday)
|
||||||
if not ignoretz:
|
if not ignoretz:
|
||||||
if callable(tzinfos) or tzinfos and res.tzname in tzinfos:
|
if isinstance(tzinfos, collections.Callable) or tzinfos and res.tzname in tzinfos:
|
||||||
if callable(tzinfos):
|
if isinstance(tzinfos, collections.Callable):
|
||||||
tzdata = tzinfos(res.tzname, res.tzoffset)
|
tzdata = tzinfos(res.tzname, res.tzoffset)
|
||||||
else:
|
else:
|
||||||
tzdata = tzinfos.get(res.tzname)
|
tzdata = tzinfos.get(res.tzname)
|
||||||
if isinstance(tzdata, datetime.tzinfo):
|
if isinstance(tzdata, datetime.tzinfo):
|
||||||
tzinfo = tzdata
|
tzinfo = tzdata
|
||||||
elif isinstance(tzdata, basestring):
|
elif isinstance(tzdata, text_type):
|
||||||
tzinfo = tz.tzstr(tzdata)
|
tzinfo = tz.tzstr(tzdata)
|
||||||
elif isinstance(tzdata, int):
|
elif isinstance(tzdata, integer_types):
|
||||||
tzinfo = tz.tzoffset(res.tzname, tzdata)
|
tzinfo = tz.tzoffset(res.tzname, tzdata)
|
||||||
else:
|
else:
|
||||||
raise ValueError, "offset must be tzinfo subclass, " \
|
raise ValueError("offset must be tzinfo subclass, " \
|
||||||
"tz string, or int offset"
|
"tz string, or int offset")
|
||||||
ret = ret.replace(tzinfo = tzinfo)
|
ret = ret.replace(tzinfo = tzinfo)
|
||||||
elif res.tzname and res.tzname in time.tzname:
|
elif res.tzname and res.tzname in time.tzname:
|
||||||
ret = ret.replace(tzinfo = tz.tzlocal())
|
ret = ret.replace(tzinfo = tz.tzlocal())
|
||||||
@@ -441,6 +446,17 @@ class parser(object):
|
|||||||
newidx = info.hms(l[i])
|
newidx = info.hms(l[i])
|
||||||
if newidx is not None:
|
if newidx is not None:
|
||||||
idx = newidx
|
idx = newidx
|
||||||
|
elif i == len_l and l[i - 2] == ' ' and info.hms(l[i - 3]) is not None:
|
||||||
|
# X h MM or X m SS
|
||||||
|
idx = info.hms(l[i - 3]) + 1
|
||||||
|
if idx == 1:
|
||||||
|
res.minute = int(value)
|
||||||
|
if value % 1:
|
||||||
|
res.second = int(60 * (value % 1))
|
||||||
|
elif idx == 2:
|
||||||
|
res.second, res.microsecond = \
|
||||||
|
_parsems(value_repr)
|
||||||
|
i += 1
|
||||||
elif i + 1 < len_l and l[i] == ':':
|
elif i + 1 < len_l and l[i] == ':':
|
||||||
# HH:MM[:SS[.ss]]
|
# HH:MM[:SS[.ss]]
|
||||||
res.hour = int(value)
|
res.hour = int(value)
|
||||||
@@ -691,6 +707,11 @@ class parser(object):
|
|||||||
|
|
||||||
DEFAULTPARSER = parser()
|
DEFAULTPARSER = parser()
|
||||||
def parse(timestr, parserinfo = None, **kwargs):
|
def parse(timestr, parserinfo = None, **kwargs):
|
||||||
|
# Python 2.x support: datetimes return their string presentation as
|
||||||
|
# bytes in 2.x and unicode in 3.x, so it's reasonable to expect that
|
||||||
|
# the parser will get both kinds. Internally we use unicode only.
|
||||||
|
if isinstance(timestr, binary_type):
|
||||||
|
timestr = timestr.decode()
|
||||||
if parserinfo:
|
if parserinfo:
|
||||||
return parser(parserinfo).parse(timestr, **kwargs)
|
return parser(parserinfo).parse(timestr, **kwargs)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
|
from six import integer_types
|
||||||
|
|
||||||
__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
|
__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
|
||||||
|
|
||||||
class weekday(object):
|
class weekday(object):
|
||||||
@@ -42,7 +43,7 @@ class weekday(object):
|
|||||||
|
|
||||||
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
|
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
|
||||||
|
|
||||||
class relativedelta:
|
class relativedelta(object):
|
||||||
"""
|
"""
|
||||||
The relativedelta type is based on the specification of the excelent
|
The relativedelta type is based on the specification of the excelent
|
||||||
work done by M.-A. Lemburg in his mx.DateTime extension. However,
|
work done by M.-A. Lemburg in his mx.DateTime extension. However,
|
||||||
@@ -113,10 +114,9 @@ Here is the behavior of operations with relativedelta:
|
|||||||
yearday=None, nlyearday=None,
|
yearday=None, nlyearday=None,
|
||||||
hour=None, minute=None, second=None, microsecond=None):
|
hour=None, minute=None, second=None, microsecond=None):
|
||||||
if dt1 and dt2:
|
if dt1 and dt2:
|
||||||
if not isinstance(dt1, datetime.date) or \
|
if (not isinstance(dt1, datetime.date)) or (not isinstance(dt2, datetime.date)):
|
||||||
not isinstance(dt2, datetime.date):
|
raise TypeError("relativedelta only diffs datetime/date")
|
||||||
raise TypeError, "relativedelta only diffs datetime/date"
|
if not type(dt1) == type(dt2): #isinstance(dt1, type(dt2)):
|
||||||
if type(dt1) is not type(dt2):
|
|
||||||
if not isinstance(dt1, datetime.datetime):
|
if not isinstance(dt1, datetime.datetime):
|
||||||
dt1 = datetime.datetime.fromordinal(dt1.toordinal())
|
dt1 = datetime.datetime.fromordinal(dt1.toordinal())
|
||||||
elif not isinstance(dt2, datetime.datetime):
|
elif not isinstance(dt2, datetime.datetime):
|
||||||
@@ -172,7 +172,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
self.second = second
|
self.second = second
|
||||||
self.microsecond = microsecond
|
self.microsecond = microsecond
|
||||||
|
|
||||||
if type(weekday) is int:
|
if isinstance(weekday, integer_types):
|
||||||
self.weekday = weekdays[weekday]
|
self.weekday = weekdays[weekday]
|
||||||
else:
|
else:
|
||||||
self.weekday = weekday
|
self.weekday = weekday
|
||||||
@@ -195,7 +195,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
self.day = yday-ydayidx[idx-1]
|
self.day = yday-ydayidx[idx-1]
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise ValueError, "invalid year day (%d)" % yday
|
raise ValueError("invalid year day (%d)" % yday)
|
||||||
|
|
||||||
self._fix()
|
self._fix()
|
||||||
|
|
||||||
@@ -242,9 +242,26 @@ Here is the behavior of operations with relativedelta:
|
|||||||
else:
|
else:
|
||||||
self.years = 0
|
self.years = 0
|
||||||
|
|
||||||
def __radd__(self, other):
|
def __add__(self, other):
|
||||||
|
if isinstance(other, relativedelta):
|
||||||
|
return relativedelta(years=other.years+self.years,
|
||||||
|
months=other.months+self.months,
|
||||||
|
days=other.days+self.days,
|
||||||
|
hours=other.hours+self.hours,
|
||||||
|
minutes=other.minutes+self.minutes,
|
||||||
|
seconds=other.seconds+self.seconds,
|
||||||
|
microseconds=other.microseconds+self.microseconds,
|
||||||
|
leapdays=other.leapdays or self.leapdays,
|
||||||
|
year=other.year or self.year,
|
||||||
|
month=other.month or self.month,
|
||||||
|
day=other.day or self.day,
|
||||||
|
weekday=other.weekday or self.weekday,
|
||||||
|
hour=other.hour or self.hour,
|
||||||
|
minute=other.minute or self.minute,
|
||||||
|
second=other.second or self.second,
|
||||||
|
microsecond=other.microsecond or self.microsecond)
|
||||||
if not isinstance(other, datetime.date):
|
if not isinstance(other, datetime.date):
|
||||||
raise TypeError, "unsupported type for add operation"
|
raise TypeError("unsupported type for add operation")
|
||||||
elif self._has_time and not isinstance(other, datetime.datetime):
|
elif self._has_time and not isinstance(other, datetime.datetime):
|
||||||
other = datetime.datetime.fromordinal(other.toordinal())
|
other = datetime.datetime.fromordinal(other.toordinal())
|
||||||
year = (self.year or other.year)+self.years
|
year = (self.year or other.year)+self.years
|
||||||
@@ -285,48 +302,31 @@ Here is the behavior of operations with relativedelta:
|
|||||||
ret += datetime.timedelta(days=jumpdays)
|
ret += datetime.timedelta(days=jumpdays)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
return self.__add__(other)
|
||||||
|
|
||||||
def __rsub__(self, other):
|
def __rsub__(self, other):
|
||||||
return self.__neg__().__radd__(other)
|
return self.__neg__().__radd__(other)
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
if not isinstance(other, relativedelta):
|
|
||||||
raise TypeError, "unsupported type for add operation"
|
|
||||||
return relativedelta(years=other.years+self.years,
|
|
||||||
months=other.months+self.months,
|
|
||||||
days=other.days+self.days,
|
|
||||||
hours=other.hours+self.hours,
|
|
||||||
minutes=other.minutes+self.minutes,
|
|
||||||
seconds=other.seconds+self.seconds,
|
|
||||||
microseconds=other.microseconds+self.microseconds,
|
|
||||||
leapdays=other.leapdays or self.leapdays,
|
|
||||||
year=other.year or self.year,
|
|
||||||
month=other.month or self.month,
|
|
||||||
day=other.day or self.day,
|
|
||||||
weekday=other.weekday or self.weekday,
|
|
||||||
hour=other.hour or self.hour,
|
|
||||||
minute=other.minute or self.minute,
|
|
||||||
second=other.second or self.second,
|
|
||||||
microsecond=other.second or self.microsecond)
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
if not isinstance(other, relativedelta):
|
if not isinstance(other, relativedelta):
|
||||||
raise TypeError, "unsupported type for sub operation"
|
raise TypeError("unsupported type for sub operation")
|
||||||
return relativedelta(years=other.years-self.years,
|
return relativedelta(years=self.years-other.years,
|
||||||
months=other.months-self.months,
|
months=self.months-other.months,
|
||||||
days=other.days-self.days,
|
days=self.days-other.days,
|
||||||
hours=other.hours-self.hours,
|
hours=self.hours-other.hours,
|
||||||
minutes=other.minutes-self.minutes,
|
minutes=self.minutes-other.minutes,
|
||||||
seconds=other.seconds-self.seconds,
|
seconds=self.seconds-other.seconds,
|
||||||
microseconds=other.microseconds-self.microseconds,
|
microseconds=self.microseconds-other.microseconds,
|
||||||
leapdays=other.leapdays or self.leapdays,
|
leapdays=self.leapdays or other.leapdays,
|
||||||
year=other.year or self.year,
|
year=self.year or other.year,
|
||||||
month=other.month or self.month,
|
month=self.month or other.month,
|
||||||
day=other.day or self.day,
|
day=self.day or other.day,
|
||||||
weekday=other.weekday or self.weekday,
|
weekday=self.weekday or other.weekday,
|
||||||
hour=other.hour or self.hour,
|
hour=self.hour or other.hour,
|
||||||
minute=other.minute or self.minute,
|
minute=self.minute or other.minute,
|
||||||
second=other.second or self.second,
|
second=self.second or other.second,
|
||||||
microsecond=other.second or self.microsecond)
|
microsecond=self.microsecond or other.microsecond)
|
||||||
|
|
||||||
def __neg__(self):
|
def __neg__(self):
|
||||||
return relativedelta(years=-self.years,
|
return relativedelta(years=-self.years,
|
||||||
@@ -346,7 +346,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
second=self.second,
|
second=self.second,
|
||||||
microsecond=self.microsecond)
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return not (not self.years and
|
return not (not self.years and
|
||||||
not self.months and
|
not self.months and
|
||||||
not self.days and
|
not self.days and
|
||||||
@@ -366,13 +366,13 @@ Here is the behavior of operations with relativedelta:
|
|||||||
|
|
||||||
def __mul__(self, other):
|
def __mul__(self, other):
|
||||||
f = float(other)
|
f = float(other)
|
||||||
return relativedelta(years=self.years*f,
|
return relativedelta(years=int(self.years*f),
|
||||||
months=self.months*f,
|
months=int(self.months*f),
|
||||||
days=self.days*f,
|
days=int(self.days*f),
|
||||||
hours=self.hours*f,
|
hours=int(self.hours*f),
|
||||||
minutes=self.minutes*f,
|
minutes=int(self.minutes*f),
|
||||||
seconds=self.seconds*f,
|
seconds=int(self.seconds*f),
|
||||||
microseconds=self.microseconds*f,
|
microseconds=int(self.microseconds*f),
|
||||||
leapdays=self.leapdays,
|
leapdays=self.leapdays,
|
||||||
year=self.year,
|
year=self.year,
|
||||||
month=self.month,
|
month=self.month,
|
||||||
@@ -383,6 +383,8 @@ Here is the behavior of operations with relativedelta:
|
|||||||
second=self.second,
|
second=self.second,
|
||||||
microsecond=self.microsecond)
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
|
__rmul__ = __mul__
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not isinstance(other, relativedelta):
|
if not isinstance(other, relativedelta):
|
||||||
return False
|
return False
|
||||||
@@ -415,6 +417,8 @@ Here is the behavior of operations with relativedelta:
|
|||||||
def __div__(self, other):
|
def __div__(self, other):
|
||||||
return self.__mul__(1/float(other))
|
return self.__mul__(1/float(other))
|
||||||
|
|
||||||
|
__truediv__ = __div__
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
l = []
|
l = []
|
||||||
for attr in ["years", "months", "days", "leapdays",
|
for attr in ["years", "months", "days", "leapdays",
|
||||||
@@ -426,7 +430,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
"hour", "minute", "second", "microsecond"]:
|
"hour", "minute", "second", "microsecond"]:
|
||||||
value = getattr(self, attr)
|
value = getattr(self, attr)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append("%s=%s" % (attr, `value`))
|
l.append("%s=%s" % (attr, repr(value)))
|
||||||
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
||||||
|
|
||||||
# vim:ts=4:sw=4:et
|
# vim:ts=4:sw=4:et
|
||||||
+68
-53
@@ -1,18 +1,22 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
import thread
|
try:
|
||||||
|
import _thread
|
||||||
|
except ImportError:
|
||||||
|
import thread as _thread
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from six import advance_iterator, integer_types
|
||||||
|
|
||||||
__all__ = ["rrule", "rruleset", "rrulestr",
|
__all__ = ["rrule", "rruleset", "rrulestr",
|
||||||
"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
|
"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
|
||||||
"HOURLY", "MINUTELY", "SECONDLY",
|
"HOURLY", "MINUTELY", "SECONDLY",
|
||||||
@@ -22,10 +26,10 @@ __all__ = ["rrule", "rruleset", "rrulestr",
|
|||||||
M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+
|
M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+
|
||||||
[7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7)
|
[7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7)
|
||||||
M365MASK = list(M366MASK)
|
M365MASK = list(M366MASK)
|
||||||
M29, M30, M31 = range(1,30), range(1,31), range(1,32)
|
M29, M30, M31 = list(range(1, 30)), list(range(1, 31)), list(range(1, 32))
|
||||||
MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
||||||
MDAY365MASK = list(MDAY366MASK)
|
MDAY365MASK = list(MDAY366MASK)
|
||||||
M29, M30, M31 = range(-29,0), range(-30,0), range(-31,0)
|
M29, M30, M31 = list(range(-29, 0)), list(range(-30, 0)), list(range(-31, 0))
|
||||||
NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
||||||
NMDAY365MASK = list(NMDAY366MASK)
|
NMDAY365MASK = list(NMDAY366MASK)
|
||||||
M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366)
|
M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366)
|
||||||
@@ -41,7 +45,7 @@ M365MASK = tuple(M365MASK)
|
|||||||
DAILY,
|
DAILY,
|
||||||
HOURLY,
|
HOURLY,
|
||||||
MINUTELY,
|
MINUTELY,
|
||||||
SECONDLY) = range(7)
|
SECONDLY) = list(range(7))
|
||||||
|
|
||||||
# Imported on demand.
|
# Imported on demand.
|
||||||
easter = None
|
easter = None
|
||||||
@@ -52,7 +56,7 @@ class weekday(object):
|
|||||||
|
|
||||||
def __init__(self, weekday, n=None):
|
def __init__(self, weekday, n=None):
|
||||||
if n == 0:
|
if n == 0:
|
||||||
raise ValueError, "Can't create weekday with n == 0"
|
raise ValueError("Can't create weekday with n == 0")
|
||||||
self.weekday = weekday
|
self.weekday = weekday
|
||||||
self.n = n
|
self.n = n
|
||||||
|
|
||||||
@@ -79,11 +83,11 @@ class weekday(object):
|
|||||||
|
|
||||||
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
|
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
|
||||||
|
|
||||||
class rrulebase:
|
class rrulebase(object):
|
||||||
def __init__(self, cache=False):
|
def __init__(self, cache=False):
|
||||||
if cache:
|
if cache:
|
||||||
self._cache = []
|
self._cache = []
|
||||||
self._cache_lock = thread.allocate_lock()
|
self._cache_lock = _thread.allocate_lock()
|
||||||
self._cache_gen = self._iter()
|
self._cache_gen = self._iter()
|
||||||
self._cache_complete = False
|
self._cache_complete = False
|
||||||
else:
|
else:
|
||||||
@@ -112,7 +116,7 @@ class rrulebase:
|
|||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
for j in range(10):
|
for j in range(10):
|
||||||
cache.append(gen.next())
|
cache.append(advance_iterator(gen))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self._cache_gen = gen = None
|
self._cache_gen = gen = None
|
||||||
self._cache_complete = True
|
self._cache_complete = True
|
||||||
@@ -133,13 +137,13 @@ class rrulebase:
|
|||||||
else:
|
else:
|
||||||
return list(itertools.islice(self,
|
return list(itertools.islice(self,
|
||||||
item.start or 0,
|
item.start or 0,
|
||||||
item.stop or sys.maxint,
|
item.stop or sys.maxsize,
|
||||||
item.step or 1))
|
item.step or 1))
|
||||||
elif item >= 0:
|
elif item >= 0:
|
||||||
gen = iter(self)
|
gen = iter(self)
|
||||||
try:
|
try:
|
||||||
for i in range(item+1):
|
for i in range(item+1):
|
||||||
res = gen.next()
|
res = advance_iterator(gen)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise IndexError
|
raise IndexError
|
||||||
return res
|
return res
|
||||||
@@ -232,7 +236,7 @@ class rrule(rrulebase):
|
|||||||
byweekno=None, byweekday=None,
|
byweekno=None, byweekday=None,
|
||||||
byhour=None, byminute=None, bysecond=None,
|
byhour=None, byminute=None, bysecond=None,
|
||||||
cache=False):
|
cache=False):
|
||||||
rrulebase.__init__(self, cache)
|
super(rrule, self).__init__(cache)
|
||||||
global easter
|
global easter
|
||||||
if not dtstart:
|
if not dtstart:
|
||||||
dtstart = datetime.datetime.now().replace(microsecond=0)
|
dtstart = datetime.datetime.now().replace(microsecond=0)
|
||||||
@@ -250,13 +254,13 @@ class rrule(rrulebase):
|
|||||||
self._until = until
|
self._until = until
|
||||||
if wkst is None:
|
if wkst is None:
|
||||||
self._wkst = calendar.firstweekday()
|
self._wkst = calendar.firstweekday()
|
||||||
elif type(wkst) is int:
|
elif isinstance(wkst, integer_types):
|
||||||
self._wkst = wkst
|
self._wkst = wkst
|
||||||
else:
|
else:
|
||||||
self._wkst = wkst.weekday
|
self._wkst = wkst.weekday
|
||||||
if bysetpos is None:
|
if bysetpos is None:
|
||||||
self._bysetpos = None
|
self._bysetpos = None
|
||||||
elif type(bysetpos) is int:
|
elif isinstance(bysetpos, integer_types):
|
||||||
if bysetpos == 0 or not (-366 <= bysetpos <= 366):
|
if bysetpos == 0 or not (-366 <= bysetpos <= 366):
|
||||||
raise ValueError("bysetpos must be between 1 and 366, "
|
raise ValueError("bysetpos must be between 1 and 366, "
|
||||||
"or between -366 and -1")
|
"or between -366 and -1")
|
||||||
@@ -280,14 +284,14 @@ class rrule(rrulebase):
|
|||||||
# bymonth
|
# bymonth
|
||||||
if not bymonth:
|
if not bymonth:
|
||||||
self._bymonth = None
|
self._bymonth = None
|
||||||
elif type(bymonth) is int:
|
elif isinstance(bymonth, integer_types):
|
||||||
self._bymonth = (bymonth,)
|
self._bymonth = (bymonth,)
|
||||||
else:
|
else:
|
||||||
self._bymonth = tuple(bymonth)
|
self._bymonth = tuple(bymonth)
|
||||||
# byyearday
|
# byyearday
|
||||||
if not byyearday:
|
if not byyearday:
|
||||||
self._byyearday = None
|
self._byyearday = None
|
||||||
elif type(byyearday) is int:
|
elif isinstance(byyearday, integer_types):
|
||||||
self._byyearday = (byyearday,)
|
self._byyearday = (byyearday,)
|
||||||
else:
|
else:
|
||||||
self._byyearday = tuple(byyearday)
|
self._byyearday = tuple(byyearday)
|
||||||
@@ -295,7 +299,7 @@ class rrule(rrulebase):
|
|||||||
if byeaster is not None:
|
if byeaster is not None:
|
||||||
if not easter:
|
if not easter:
|
||||||
from dateutil import easter
|
from dateutil import easter
|
||||||
if type(byeaster) is int:
|
if isinstance(byeaster, integer_types):
|
||||||
self._byeaster = (byeaster,)
|
self._byeaster = (byeaster,)
|
||||||
else:
|
else:
|
||||||
self._byeaster = tuple(byeaster)
|
self._byeaster = tuple(byeaster)
|
||||||
@@ -305,7 +309,7 @@ class rrule(rrulebase):
|
|||||||
if not bymonthday:
|
if not bymonthday:
|
||||||
self._bymonthday = ()
|
self._bymonthday = ()
|
||||||
self._bynmonthday = ()
|
self._bynmonthday = ()
|
||||||
elif type(bymonthday) is int:
|
elif isinstance(bymonthday, integer_types):
|
||||||
if bymonthday < 0:
|
if bymonthday < 0:
|
||||||
self._bynmonthday = (bymonthday,)
|
self._bynmonthday = (bymonthday,)
|
||||||
self._bymonthday = ()
|
self._bymonthday = ()
|
||||||
@@ -318,7 +322,7 @@ class rrule(rrulebase):
|
|||||||
# byweekno
|
# byweekno
|
||||||
if byweekno is None:
|
if byweekno is None:
|
||||||
self._byweekno = None
|
self._byweekno = None
|
||||||
elif type(byweekno) is int:
|
elif isinstance(byweekno, integer_types):
|
||||||
self._byweekno = (byweekno,)
|
self._byweekno = (byweekno,)
|
||||||
else:
|
else:
|
||||||
self._byweekno = tuple(byweekno)
|
self._byweekno = tuple(byweekno)
|
||||||
@@ -326,7 +330,7 @@ class rrule(rrulebase):
|
|||||||
if byweekday is None:
|
if byweekday is None:
|
||||||
self._byweekday = None
|
self._byweekday = None
|
||||||
self._bynweekday = None
|
self._bynweekday = None
|
||||||
elif type(byweekday) is int:
|
elif isinstance(byweekday, integer_types):
|
||||||
self._byweekday = (byweekday,)
|
self._byweekday = (byweekday,)
|
||||||
self._bynweekday = None
|
self._bynweekday = None
|
||||||
elif hasattr(byweekday, "n"):
|
elif hasattr(byweekday, "n"):
|
||||||
@@ -340,7 +344,7 @@ class rrule(rrulebase):
|
|||||||
self._byweekday = []
|
self._byweekday = []
|
||||||
self._bynweekday = []
|
self._bynweekday = []
|
||||||
for wday in byweekday:
|
for wday in byweekday:
|
||||||
if type(wday) is int:
|
if isinstance(wday, integer_types):
|
||||||
self._byweekday.append(wday)
|
self._byweekday.append(wday)
|
||||||
elif not wday.n or freq > MONTHLY:
|
elif not wday.n or freq > MONTHLY:
|
||||||
self._byweekday.append(wday.weekday)
|
self._byweekday.append(wday.weekday)
|
||||||
@@ -358,7 +362,7 @@ class rrule(rrulebase):
|
|||||||
self._byhour = (dtstart.hour,)
|
self._byhour = (dtstart.hour,)
|
||||||
else:
|
else:
|
||||||
self._byhour = None
|
self._byhour = None
|
||||||
elif type(byhour) is int:
|
elif isinstance(byhour, integer_types):
|
||||||
self._byhour = (byhour,)
|
self._byhour = (byhour,)
|
||||||
else:
|
else:
|
||||||
self._byhour = tuple(byhour)
|
self._byhour = tuple(byhour)
|
||||||
@@ -368,7 +372,7 @@ class rrule(rrulebase):
|
|||||||
self._byminute = (dtstart.minute,)
|
self._byminute = (dtstart.minute,)
|
||||||
else:
|
else:
|
||||||
self._byminute = None
|
self._byminute = None
|
||||||
elif type(byminute) is int:
|
elif isinstance(byminute, integer_types):
|
||||||
self._byminute = (byminute,)
|
self._byminute = (byminute,)
|
||||||
else:
|
else:
|
||||||
self._byminute = tuple(byminute)
|
self._byminute = tuple(byminute)
|
||||||
@@ -378,7 +382,7 @@ class rrule(rrulebase):
|
|||||||
self._bysecond = (dtstart.second,)
|
self._bysecond = (dtstart.second,)
|
||||||
else:
|
else:
|
||||||
self._bysecond = None
|
self._bysecond = None
|
||||||
elif type(bysecond) is int:
|
elif isinstance(bysecond, integer_types):
|
||||||
self._bysecond = (bysecond,)
|
self._bysecond = (bysecond,)
|
||||||
else:
|
else:
|
||||||
self._bysecond = tuple(bysecond)
|
self._bysecond = tuple(bysecond)
|
||||||
@@ -768,7 +772,7 @@ class _iterinfo(object):
|
|||||||
self.lastmonth = month
|
self.lastmonth = month
|
||||||
|
|
||||||
def ydayset(self, year, month, day):
|
def ydayset(self, year, month, day):
|
||||||
return range(self.yearlen), 0, self.yearlen
|
return list(range(self.yearlen)), 0, self.yearlen
|
||||||
|
|
||||||
def mdayset(self, year, month, day):
|
def mdayset(self, year, month, day):
|
||||||
set = [None]*self.yearlen
|
set = [None]*self.yearlen
|
||||||
@@ -823,27 +827,38 @@ class _iterinfo(object):
|
|||||||
|
|
||||||
class rruleset(rrulebase):
|
class rruleset(rrulebase):
|
||||||
|
|
||||||
class _genitem:
|
class _genitem(object):
|
||||||
def __init__(self, genlist, gen):
|
def __init__(self, genlist, gen):
|
||||||
try:
|
try:
|
||||||
self.dt = gen()
|
self.dt = advance_iterator(gen)
|
||||||
genlist.append(self)
|
genlist.append(self)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
pass
|
pass
|
||||||
self.genlist = genlist
|
self.genlist = genlist
|
||||||
self.gen = gen
|
self.gen = gen
|
||||||
|
|
||||||
def next(self):
|
def __next__(self):
|
||||||
try:
|
try:
|
||||||
self.dt = self.gen()
|
self.dt = advance_iterator(self.gen)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self.genlist.remove(self)
|
self.genlist.remove(self)
|
||||||
|
|
||||||
def __cmp__(self, other):
|
next = __next__
|
||||||
return cmp(self.dt, other.dt)
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.dt < other.dt
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.dt > other.dt
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.dt == other.dt
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return self.dt != other.dt
|
||||||
|
|
||||||
def __init__(self, cache=False):
|
def __init__(self, cache=False):
|
||||||
rrulebase.__init__(self, cache)
|
super(rruleset, self).__init__(cache)
|
||||||
self._rrule = []
|
self._rrule = []
|
||||||
self._rdate = []
|
self._rdate = []
|
||||||
self._exrule = []
|
self._exrule = []
|
||||||
@@ -864,14 +879,14 @@ class rruleset(rrulebase):
|
|||||||
def _iter(self):
|
def _iter(self):
|
||||||
rlist = []
|
rlist = []
|
||||||
self._rdate.sort()
|
self._rdate.sort()
|
||||||
self._genitem(rlist, iter(self._rdate).next)
|
self._genitem(rlist, iter(self._rdate))
|
||||||
for gen in [iter(x).next for x in self._rrule]:
|
for gen in [iter(x) for x in self._rrule]:
|
||||||
self._genitem(rlist, gen)
|
self._genitem(rlist, gen)
|
||||||
rlist.sort()
|
rlist.sort()
|
||||||
exlist = []
|
exlist = []
|
||||||
self._exdate.sort()
|
self._exdate.sort()
|
||||||
self._genitem(exlist, iter(self._exdate).next)
|
self._genitem(exlist, iter(self._exdate))
|
||||||
for gen in [iter(x).next for x in self._exrule]:
|
for gen in [iter(x) for x in self._exrule]:
|
||||||
self._genitem(exlist, gen)
|
self._genitem(exlist, gen)
|
||||||
exlist.sort()
|
exlist.sort()
|
||||||
lastdt = None
|
lastdt = None
|
||||||
@@ -880,17 +895,17 @@ class rruleset(rrulebase):
|
|||||||
ritem = rlist[0]
|
ritem = rlist[0]
|
||||||
if not lastdt or lastdt != ritem.dt:
|
if not lastdt or lastdt != ritem.dt:
|
||||||
while exlist and exlist[0] < ritem:
|
while exlist and exlist[0] < ritem:
|
||||||
exlist[0].next()
|
advance_iterator(exlist[0])
|
||||||
exlist.sort()
|
exlist.sort()
|
||||||
if not exlist or ritem != exlist[0]:
|
if not exlist or ritem != exlist[0]:
|
||||||
total += 1
|
total += 1
|
||||||
yield ritem.dt
|
yield ritem.dt
|
||||||
lastdt = ritem.dt
|
lastdt = ritem.dt
|
||||||
ritem.next()
|
advance_iterator(ritem)
|
||||||
rlist.sort()
|
rlist.sort()
|
||||||
self._len = total
|
self._len = total
|
||||||
|
|
||||||
class _rrulestr:
|
class _rrulestr(object):
|
||||||
|
|
||||||
_freq_map = {"YEARLY": YEARLY,
|
_freq_map = {"YEARLY": YEARLY,
|
||||||
"MONTHLY": MONTHLY,
|
"MONTHLY": MONTHLY,
|
||||||
@@ -932,7 +947,7 @@ class _rrulestr:
|
|||||||
ignoretz=kwargs.get("ignoretz"),
|
ignoretz=kwargs.get("ignoretz"),
|
||||||
tzinfos=kwargs.get("tzinfos"))
|
tzinfos=kwargs.get("tzinfos"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError, "invalid until date"
|
raise ValueError("invalid until date")
|
||||||
|
|
||||||
def _handle_WKST(self, rrkwargs, name, value, **kwargs):
|
def _handle_WKST(self, rrkwargs, name, value, **kwargs):
|
||||||
rrkwargs["wkst"] = self._weekday_map[value]
|
rrkwargs["wkst"] = self._weekday_map[value]
|
||||||
@@ -959,7 +974,7 @@ class _rrulestr:
|
|||||||
if line.find(':') != -1:
|
if line.find(':') != -1:
|
||||||
name, value = line.split(':')
|
name, value = line.split(':')
|
||||||
if name != "RRULE":
|
if name != "RRULE":
|
||||||
raise ValueError, "unknown parameter name"
|
raise ValueError("unknown parameter name")
|
||||||
else:
|
else:
|
||||||
value = line
|
value = line
|
||||||
rrkwargs = {}
|
rrkwargs = {}
|
||||||
@@ -972,9 +987,9 @@ class _rrulestr:
|
|||||||
ignoretz=ignoretz,
|
ignoretz=ignoretz,
|
||||||
tzinfos=tzinfos)
|
tzinfos=tzinfos)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError, "unknown parameter '%s'" % name
|
raise ValueError("unknown parameter '%s'" % name)
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
raise ValueError, "invalid '%s': %s" % (name, value)
|
raise ValueError("invalid '%s': %s" % (name, value))
|
||||||
return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
|
return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
|
||||||
|
|
||||||
def _parse_rfc(self, s,
|
def _parse_rfc(self, s,
|
||||||
@@ -991,7 +1006,7 @@ class _rrulestr:
|
|||||||
unfold = True
|
unfold = True
|
||||||
s = s.upper()
|
s = s.upper()
|
||||||
if not s.strip():
|
if not s.strip():
|
||||||
raise ValueError, "empty string"
|
raise ValueError("empty string")
|
||||||
if unfold:
|
if unfold:
|
||||||
lines = s.splitlines()
|
lines = s.splitlines()
|
||||||
i = 0
|
i = 0
|
||||||
@@ -1026,36 +1041,36 @@ class _rrulestr:
|
|||||||
name, value = line.split(':', 1)
|
name, value = line.split(':', 1)
|
||||||
parms = name.split(';')
|
parms = name.split(';')
|
||||||
if not parms:
|
if not parms:
|
||||||
raise ValueError, "empty property name"
|
raise ValueError("empty property name")
|
||||||
name = parms[0]
|
name = parms[0]
|
||||||
parms = parms[1:]
|
parms = parms[1:]
|
||||||
if name == "RRULE":
|
if name == "RRULE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
raise ValueError, "unsupported RRULE parm: "+parm
|
raise ValueError("unsupported RRULE parm: "+parm)
|
||||||
rrulevals.append(value)
|
rrulevals.append(value)
|
||||||
elif name == "RDATE":
|
elif name == "RDATE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
if parm != "VALUE=DATE-TIME":
|
if parm != "VALUE=DATE-TIME":
|
||||||
raise ValueError, "unsupported RDATE parm: "+parm
|
raise ValueError("unsupported RDATE parm: "+parm)
|
||||||
rdatevals.append(value)
|
rdatevals.append(value)
|
||||||
elif name == "EXRULE":
|
elif name == "EXRULE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
raise ValueError, "unsupported EXRULE parm: "+parm
|
raise ValueError("unsupported EXRULE parm: "+parm)
|
||||||
exrulevals.append(value)
|
exrulevals.append(value)
|
||||||
elif name == "EXDATE":
|
elif name == "EXDATE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
if parm != "VALUE=DATE-TIME":
|
if parm != "VALUE=DATE-TIME":
|
||||||
raise ValueError, "unsupported RDATE parm: "+parm
|
raise ValueError("unsupported RDATE parm: "+parm)
|
||||||
exdatevals.append(value)
|
exdatevals.append(value)
|
||||||
elif name == "DTSTART":
|
elif name == "DTSTART":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
raise ValueError, "unsupported DTSTART parm: "+parm
|
raise ValueError("unsupported DTSTART parm: "+parm)
|
||||||
if not parser:
|
if not parser:
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
dtstart = parser.parse(value, ignoretz=ignoretz,
|
dtstart = parser.parse(value, ignoretz=ignoretz,
|
||||||
tzinfos=tzinfos)
|
tzinfos=tzinfos)
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unsupported property: "+name
|
raise ValueError("unsupported property: "+name)
|
||||||
if (forceset or len(rrulevals) > 1 or
|
if (forceset or len(rrulevals) > 1 or
|
||||||
rdatevals or exrulevals or exdatevals):
|
rdatevals or exrulevals or exdatevals):
|
||||||
if not parser and (rdatevals or exdatevals):
|
if not parser and (rdatevals or exdatevals):
|
||||||
|
|||||||
+65
-56
@@ -1,11 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
from six import string_types, PY3
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import struct
|
import struct
|
||||||
@@ -25,6 +26,19 @@ try:
|
|||||||
except (ImportError, OSError):
|
except (ImportError, OSError):
|
||||||
tzwin, tzwinlocal = None, None
|
tzwin, tzwinlocal = None, None
|
||||||
|
|
||||||
|
def tzname_in_python2(myfunc):
|
||||||
|
"""Change unicode output into bytestrings in Python 2
|
||||||
|
|
||||||
|
tzname() API changed in Python 3. It used to return bytes, but was changed
|
||||||
|
to unicode strings
|
||||||
|
"""
|
||||||
|
def inner_func(*args, **kwargs):
|
||||||
|
if PY3:
|
||||||
|
return myfunc(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
return myfunc(*args, **kwargs).encode()
|
||||||
|
return inner_func
|
||||||
|
|
||||||
ZERO = datetime.timedelta(0)
|
ZERO = datetime.timedelta(0)
|
||||||
EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal()
|
EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal()
|
||||||
|
|
||||||
@@ -36,6 +50,7 @@ class tzutc(datetime.tzinfo):
|
|||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return "UTC"
|
return "UTC"
|
||||||
|
|
||||||
@@ -63,6 +78,7 @@ class tzoffset(datetime.tzinfo):
|
|||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@@ -75,7 +91,7 @@ class tzoffset(datetime.tzinfo):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s, %s)" % (self.__class__.__name__,
|
return "%s(%s, %s)" % (self.__class__.__name__,
|
||||||
`self._name`,
|
repr(self._name),
|
||||||
self._offset.days*86400+self._offset.seconds)
|
self._offset.days*86400+self._offset.seconds)
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
@@ -100,6 +116,7 @@ class tzlocal(datetime.tzinfo):
|
|||||||
else:
|
else:
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return time.tzname[self._isdst(dt)]
|
return time.tzname[self._isdst(dt)]
|
||||||
|
|
||||||
@@ -161,7 +178,7 @@ class _ttinfo(object):
|
|||||||
for attr in self.__slots__:
|
for attr in self.__slots__:
|
||||||
value = getattr(self, attr)
|
value = getattr(self, attr)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append("%s=%s" % (attr, `value`))
|
l.append("%s=%s" % (attr, repr(value)))
|
||||||
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@@ -191,16 +208,16 @@ class _ttinfo(object):
|
|||||||
class tzfile(datetime.tzinfo):
|
class tzfile(datetime.tzinfo):
|
||||||
|
|
||||||
# http://www.twinsun.com/tz/tz-link.htm
|
# http://www.twinsun.com/tz/tz-link.htm
|
||||||
# ftp://elsie.nci.nih.gov/pub/tz*.tar.gz
|
# ftp://ftp.iana.org/tz/tz*.tar.gz
|
||||||
|
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj):
|
||||||
if isinstance(fileobj, basestring):
|
if isinstance(fileobj, string_types):
|
||||||
self._filename = fileobj
|
self._filename = fileobj
|
||||||
fileobj = open(fileobj)
|
fileobj = open(fileobj, 'rb')
|
||||||
elif hasattr(fileobj, "name"):
|
elif hasattr(fileobj, "name"):
|
||||||
self._filename = fileobj.name
|
self._filename = fileobj.name
|
||||||
else:
|
else:
|
||||||
self._filename = `fileobj`
|
self._filename = repr(fileobj)
|
||||||
|
|
||||||
# From tzfile(5):
|
# From tzfile(5):
|
||||||
#
|
#
|
||||||
@@ -212,8 +229,8 @@ class tzfile(datetime.tzinfo):
|
|||||||
# ``standard'' byte order (the high-order byte
|
# ``standard'' byte order (the high-order byte
|
||||||
# of the value is written first).
|
# of the value is written first).
|
||||||
|
|
||||||
if fileobj.read(4) != "TZif":
|
if fileobj.read(4).decode() != "TZif":
|
||||||
raise ValueError, "magic not found"
|
raise ValueError("magic not found")
|
||||||
|
|
||||||
fileobj.read(16)
|
fileobj.read(16)
|
||||||
|
|
||||||
@@ -284,7 +301,7 @@ class tzfile(datetime.tzinfo):
|
|||||||
for i in range(typecnt):
|
for i in range(typecnt):
|
||||||
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
||||||
|
|
||||||
abbr = fileobj.read(charcnt)
|
abbr = fileobj.read(charcnt).decode()
|
||||||
|
|
||||||
# Then there are tzh_leapcnt pairs of four-byte
|
# Then there are tzh_leapcnt pairs of four-byte
|
||||||
# values, written in standard byte order; the
|
# values, written in standard byte order; the
|
||||||
@@ -448,6 +465,7 @@ class tzfile(datetime.tzinfo):
|
|||||||
# dst offset, so I belive that this wouldn't be the right
|
# dst offset, so I belive that this wouldn't be the right
|
||||||
# way to implement this.
|
# way to implement this.
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
if not self._ttinfo_std:
|
if not self._ttinfo_std:
|
||||||
return None
|
return None
|
||||||
@@ -465,11 +483,11 @@ class tzfile(datetime.tzinfo):
|
|||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, `self._filename`)
|
return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
if not os.path.isfile(self._filename):
|
if not os.path.isfile(self._filename):
|
||||||
raise ValueError, "Unpickable %s class" % self.__class__.__name__
|
raise ValueError("Unpickable %s class" % self.__class__.__name__)
|
||||||
return (self.__class__, (self._filename,))
|
return (self.__class__, (self._filename,))
|
||||||
|
|
||||||
class tzrange(datetime.tzinfo):
|
class tzrange(datetime.tzinfo):
|
||||||
@@ -515,6 +533,7 @@ class tzrange(datetime.tzinfo):
|
|||||||
else:
|
else:
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
if self._isdst(dt):
|
if self._isdst(dt):
|
||||||
return self._dst_abbr
|
return self._dst_abbr
|
||||||
@@ -561,7 +580,7 @@ class tzstr(tzrange):
|
|||||||
|
|
||||||
res = parser._parsetz(s)
|
res = parser._parsetz(s)
|
||||||
if res is None:
|
if res is None:
|
||||||
raise ValueError, "unknown string format"
|
raise ValueError("unknown string format")
|
||||||
|
|
||||||
# Here we break the compatibility with the TZ variable handling.
|
# Here we break the compatibility with the TZ variable handling.
|
||||||
# GMT-3 actually *means* the timezone -3.
|
# GMT-3 actually *means* the timezone -3.
|
||||||
@@ -624,9 +643,9 @@ class tzstr(tzrange):
|
|||||||
return relativedelta.relativedelta(**kwargs)
|
return relativedelta.relativedelta(**kwargs)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, `self._s`)
|
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
||||||
|
|
||||||
class _tzicalvtzcomp:
|
class _tzicalvtzcomp(object):
|
||||||
def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
|
def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
|
||||||
tzname=None, rrule=None):
|
tzname=None, rrule=None):
|
||||||
self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
|
self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
|
||||||
@@ -690,49 +709,50 @@ class _tzicalvtz(datetime.tzinfo):
|
|||||||
else:
|
else:
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return self._find_comp(dt).tzname
|
return self._find_comp(dt).tzname
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<tzicalvtz %s>" % `self._tzid`
|
return "<tzicalvtz %s>" % repr(self._tzid)
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
class tzical:
|
class tzical(object):
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj):
|
||||||
global rrule
|
global rrule
|
||||||
if not rrule:
|
if not rrule:
|
||||||
from dateutil import rrule
|
from dateutil import rrule
|
||||||
|
|
||||||
if isinstance(fileobj, basestring):
|
if isinstance(fileobj, string_types):
|
||||||
self._s = fileobj
|
self._s = fileobj
|
||||||
fileobj = open(fileobj)
|
fileobj = open(fileobj, 'r') # ical should be encoded in UTF-8 with CRLF
|
||||||
elif hasattr(fileobj, "name"):
|
elif hasattr(fileobj, "name"):
|
||||||
self._s = fileobj.name
|
self._s = fileobj.name
|
||||||
else:
|
else:
|
||||||
self._s = `fileobj`
|
self._s = repr(fileobj)
|
||||||
|
|
||||||
self._vtz = {}
|
self._vtz = {}
|
||||||
|
|
||||||
self._parse_rfc(fileobj.read())
|
self._parse_rfc(fileobj.read())
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self._vtz.keys()
|
return list(self._vtz.keys())
|
||||||
|
|
||||||
def get(self, tzid=None):
|
def get(self, tzid=None):
|
||||||
if tzid is None:
|
if tzid is None:
|
||||||
keys = self._vtz.keys()
|
keys = list(self._vtz.keys())
|
||||||
if len(keys) == 0:
|
if len(keys) == 0:
|
||||||
raise ValueError, "no timezones defined"
|
raise ValueError("no timezones defined")
|
||||||
elif len(keys) > 1:
|
elif len(keys) > 1:
|
||||||
raise ValueError, "more than one timezone available"
|
raise ValueError("more than one timezone available")
|
||||||
tzid = keys[0]
|
tzid = keys[0]
|
||||||
return self._vtz.get(tzid)
|
return self._vtz.get(tzid)
|
||||||
|
|
||||||
def _parse_offset(self, s):
|
def _parse_offset(self, s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
if not s:
|
if not s:
|
||||||
raise ValueError, "empty offset"
|
raise ValueError("empty offset")
|
||||||
if s[0] in ('+', '-'):
|
if s[0] in ('+', '-'):
|
||||||
signal = (-1, +1)[s[0]=='+']
|
signal = (-1, +1)[s[0]=='+']
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
@@ -743,12 +763,12 @@ class tzical:
|
|||||||
elif len(s) == 6:
|
elif len(s) == 6:
|
||||||
return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal
|
return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal
|
||||||
else:
|
else:
|
||||||
raise ValueError, "invalid offset: "+s
|
raise ValueError("invalid offset: "+s)
|
||||||
|
|
||||||
def _parse_rfc(self, s):
|
def _parse_rfc(self, s):
|
||||||
lines = s.splitlines()
|
lines = s.splitlines()
|
||||||
if not lines:
|
if not lines:
|
||||||
raise ValueError, "empty string"
|
raise ValueError("empty string")
|
||||||
|
|
||||||
# Unfold
|
# Unfold
|
||||||
i = 0
|
i = 0
|
||||||
@@ -772,7 +792,7 @@ class tzical:
|
|||||||
name, value = line.split(':', 1)
|
name, value = line.split(':', 1)
|
||||||
parms = name.split(';')
|
parms = name.split(';')
|
||||||
if not parms:
|
if not parms:
|
||||||
raise ValueError, "empty property name"
|
raise ValueError("empty property name")
|
||||||
name = parms[0].upper()
|
name = parms[0].upper()
|
||||||
parms = parms[1:]
|
parms = parms[1:]
|
||||||
if invtz:
|
if invtz:
|
||||||
@@ -781,7 +801,7 @@ class tzical:
|
|||||||
# Process component
|
# Process component
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unknown component: "+value
|
raise ValueError("unknown component: "+value)
|
||||||
comptype = value
|
comptype = value
|
||||||
founddtstart = False
|
founddtstart = False
|
||||||
tzoffsetfrom = None
|
tzoffsetfrom = None
|
||||||
@@ -791,27 +811,21 @@ class tzical:
|
|||||||
elif name == "END":
|
elif name == "END":
|
||||||
if value == "VTIMEZONE":
|
if value == "VTIMEZONE":
|
||||||
if comptype:
|
if comptype:
|
||||||
raise ValueError, \
|
raise ValueError("component not closed: "+comptype)
|
||||||
"component not closed: "+comptype
|
|
||||||
if not tzid:
|
if not tzid:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory TZID not found")
|
||||||
"mandatory TZID not found"
|
|
||||||
if not comps:
|
if not comps:
|
||||||
raise ValueError, \
|
raise ValueError("at least one component is needed")
|
||||||
"at least one component is needed"
|
|
||||||
# Process vtimezone
|
# Process vtimezone
|
||||||
self._vtz[tzid] = _tzicalvtz(tzid, comps)
|
self._vtz[tzid] = _tzicalvtz(tzid, comps)
|
||||||
invtz = False
|
invtz = False
|
||||||
elif value == comptype:
|
elif value == comptype:
|
||||||
if not founddtstart:
|
if not founddtstart:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory DTSTART not found")
|
||||||
"mandatory DTSTART not found"
|
|
||||||
if tzoffsetfrom is None:
|
if tzoffsetfrom is None:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory TZOFFSETFROM not found")
|
||||||
"mandatory TZOFFSETFROM not found"
|
|
||||||
if tzoffsetto is None:
|
if tzoffsetto is None:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory TZOFFSETFROM not found")
|
||||||
"mandatory TZOFFSETFROM not found"
|
|
||||||
# Process component
|
# Process component
|
||||||
rr = None
|
rr = None
|
||||||
if rrulelines:
|
if rrulelines:
|
||||||
@@ -825,8 +839,7 @@ class tzical:
|
|||||||
comps.append(comp)
|
comps.append(comp)
|
||||||
comptype = None
|
comptype = None
|
||||||
else:
|
else:
|
||||||
raise ValueError, \
|
raise ValueError("invalid component end: "+value)
|
||||||
"invalid component end: "+value
|
|
||||||
elif comptype:
|
elif comptype:
|
||||||
if name == "DTSTART":
|
if name == "DTSTART":
|
||||||
rrulelines.append(line)
|
rrulelines.append(line)
|
||||||
@@ -835,40 +848,36 @@ class tzical:
|
|||||||
rrulelines.append(line)
|
rrulelines.append(line)
|
||||||
elif name == "TZOFFSETFROM":
|
elif name == "TZOFFSETFROM":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError, \
|
raise ValueError("unsupported %s parm: %s "%(name, parms[0]))
|
||||||
"unsupported %s parm: %s "%(name, parms[0])
|
|
||||||
tzoffsetfrom = self._parse_offset(value)
|
tzoffsetfrom = self._parse_offset(value)
|
||||||
elif name == "TZOFFSETTO":
|
elif name == "TZOFFSETTO":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError, \
|
raise ValueError("unsupported TZOFFSETTO parm: "+parms[0])
|
||||||
"unsupported TZOFFSETTO parm: "+parms[0]
|
|
||||||
tzoffsetto = self._parse_offset(value)
|
tzoffsetto = self._parse_offset(value)
|
||||||
elif name == "TZNAME":
|
elif name == "TZNAME":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError, \
|
raise ValueError("unsupported TZNAME parm: "+parms[0])
|
||||||
"unsupported TZNAME parm: "+parms[0]
|
|
||||||
tzname = value
|
tzname = value
|
||||||
elif name == "COMMENT":
|
elif name == "COMMENT":
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unsupported property: "+name
|
raise ValueError("unsupported property: "+name)
|
||||||
else:
|
else:
|
||||||
if name == "TZID":
|
if name == "TZID":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError, \
|
raise ValueError("unsupported TZID parm: "+parms[0])
|
||||||
"unsupported TZID parm: "+parms[0]
|
|
||||||
tzid = value
|
tzid = value
|
||||||
elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
|
elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unsupported property: "+name
|
raise ValueError("unsupported property: "+name)
|
||||||
elif name == "BEGIN" and value == "VTIMEZONE":
|
elif name == "BEGIN" and value == "VTIMEZONE":
|
||||||
tzid = None
|
tzid = None
|
||||||
comps = []
|
comps = []
|
||||||
invtz = True
|
invtz = True
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, `self._s`)
|
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
||||||
|
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
TZFILES = ["/etc/localtime", "localtime"]
|
TZFILES = ["/etc/localtime", "localtime"]
|
||||||
|
|||||||
+15
-16
@@ -1,9 +1,8 @@
|
|||||||
# This code was originally contributed by Jeffrey Harris.
|
# This code was originally contributed by Jeffrey Harris.
|
||||||
import datetime
|
import datetime
|
||||||
import struct
|
import struct
|
||||||
import _winreg
|
import winreg
|
||||||
|
|
||||||
__author__ = "Jeffrey Harris & Gustavo Niemeyer <gustavo@niemeyer.net>"
|
|
||||||
|
|
||||||
__all__ = ["tzwin", "tzwinlocal"]
|
__all__ = ["tzwin", "tzwinlocal"]
|
||||||
|
|
||||||
@@ -15,9 +14,9 @@ TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
|
|||||||
|
|
||||||
def _settzkeyname():
|
def _settzkeyname():
|
||||||
global TZKEYNAME
|
global TZKEYNAME
|
||||||
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
try:
|
try:
|
||||||
_winreg.OpenKey(handle, TZKEYNAMENT).Close()
|
winreg.OpenKey(handle, TZKEYNAMENT).Close()
|
||||||
TZKEYNAME = TZKEYNAMENT
|
TZKEYNAME = TZKEYNAMENT
|
||||||
except WindowsError:
|
except WindowsError:
|
||||||
TZKEYNAME = TZKEYNAME9X
|
TZKEYNAME = TZKEYNAME9X
|
||||||
@@ -49,10 +48,10 @@ class tzwinbase(datetime.tzinfo):
|
|||||||
|
|
||||||
def list():
|
def list():
|
||||||
"""Return a list of all time zones known to the system."""
|
"""Return a list of all time zones known to the system."""
|
||||||
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
tzkey = _winreg.OpenKey(handle, TZKEYNAME)
|
tzkey = winreg.OpenKey(handle, TZKEYNAME)
|
||||||
result = [_winreg.EnumKey(tzkey, i)
|
result = [winreg.EnumKey(tzkey, i)
|
||||||
for i in range(_winreg.QueryInfoKey(tzkey)[0])]
|
for i in range(winreg.QueryInfoKey(tzkey)[0])]
|
||||||
tzkey.Close()
|
tzkey.Close()
|
||||||
handle.Close()
|
handle.Close()
|
||||||
return result
|
return result
|
||||||
@@ -79,8 +78,8 @@ class tzwin(tzwinbase):
|
|||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
|
|
||||||
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
tzkey = _winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name))
|
tzkey = winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name))
|
||||||
keydict = valuestodict(tzkey)
|
keydict = valuestodict(tzkey)
|
||||||
tzkey.Close()
|
tzkey.Close()
|
||||||
handle.Close()
|
handle.Close()
|
||||||
@@ -118,9 +117,9 @@ class tzwinlocal(tzwinbase):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
|
|
||||||
tzlocalkey = _winreg.OpenKey(handle, TZLOCALKEYNAME)
|
tzlocalkey = winreg.OpenKey(handle, TZLOCALKEYNAME)
|
||||||
keydict = valuestodict(tzlocalkey)
|
keydict = valuestodict(tzlocalkey)
|
||||||
tzlocalkey.Close()
|
tzlocalkey.Close()
|
||||||
|
|
||||||
@@ -128,7 +127,7 @@ class tzwinlocal(tzwinbase):
|
|||||||
self._dstname = keydict["DaylightName"].encode("iso-8859-1")
|
self._dstname = keydict["DaylightName"].encode("iso-8859-1")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tzkey = _winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname))
|
tzkey = winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname))
|
||||||
_keydict = valuestodict(tzkey)
|
_keydict = valuestodict(tzkey)
|
||||||
self._display = _keydict["Display"]
|
self._display = _keydict["Display"]
|
||||||
tzkey.Close()
|
tzkey.Close()
|
||||||
@@ -165,7 +164,7 @@ def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
|||||||
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
|
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
|
||||||
first = datetime.datetime(year, month, 1, hour, minute)
|
first = datetime.datetime(year, month, 1, hour, minute)
|
||||||
weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1))
|
weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1))
|
||||||
for n in xrange(whichweek):
|
for n in range(whichweek):
|
||||||
dt = weekdayone+(whichweek-n)*ONEWEEK
|
dt = weekdayone+(whichweek-n)*ONEWEEK
|
||||||
if dt.month == month:
|
if dt.month == month:
|
||||||
return dt
|
return dt
|
||||||
@@ -173,8 +172,8 @@ def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
|||||||
def valuestodict(key):
|
def valuestodict(key):
|
||||||
"""Convert a registry key's values to a dictionary."""
|
"""Convert a registry key's values to a dictionary."""
|
||||||
dict = {}
|
dict = {}
|
||||||
size = _winreg.QueryInfoKey(key)[1]
|
size = winreg.QueryInfoKey(key)[1]
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
data = _winreg.EnumValue(key, i)
|
data = winreg.EnumValue(key, i)
|
||||||
dict[data[0]] = data[1]
|
dict[data[0]] = data[1]
|
||||||
return dict
|
return dict
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
from dateutil.tz import tzfile
|
from dateutil.tz import tzfile
|
||||||
from tarfile import TarFile
|
from tarfile import TarFile
|
||||||
import os
|
import os
|
||||||
|
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__author__ = "Tomi Pieviläinen <tomi.pievilainen@iki.fi>"
|
||||||
__license__ = "PSF License"
|
__license__ = "Simplified BSD"
|
||||||
|
|
||||||
__all__ = ["setcachesize", "gettz", "rebuild"]
|
__all__ = ["setcachesize", "gettz", "rebuild"]
|
||||||
|
|
||||||
@@ -21,8 +22,7 @@ class tzfile(tzfile):
|
|||||||
return (gettz, (self._filename,))
|
return (gettz, (self._filename,))
|
||||||
|
|
||||||
def getzoneinfofile():
|
def getzoneinfofile():
|
||||||
filenames = os.listdir(os.path.join(os.path.dirname(__file__)))
|
filenames = sorted(os.listdir(os.path.join(os.path.dirname(__file__))))
|
||||||
filenames.sort()
|
|
||||||
filenames.reverse()
|
filenames.reverse()
|
||||||
for entry in filenames:
|
for entry in filenames:
|
||||||
if entry.startswith("zoneinfo") and ".tar." in entry:
|
if entry.startswith("zoneinfo") and ".tar." in entry:
|
||||||
@@ -66,7 +66,10 @@ def rebuild(filename, tag=None, format="gz"):
|
|||||||
targetname = "zoneinfo%s.tar.%s" % (tag, format)
|
targetname = "zoneinfo%s.tar.%s" % (tag, format)
|
||||||
try:
|
try:
|
||||||
tf = TarFile.open(filename)
|
tf = TarFile.open(filename)
|
||||||
for name in tf.getnames():
|
# The "backwards" zone file contains links to other files, so must be
|
||||||
|
# processed as last
|
||||||
|
for name in sorted(tf.getnames(),
|
||||||
|
key=lambda k: k != "backward" and k or "z"):
|
||||||
if not (name.endswith(".sh") or
|
if not (name.endswith(".sh") or
|
||||||
name.endswith(".tab") or
|
name.endswith(".tab") or
|
||||||
name == "leapseconds"):
|
name == "leapseconds"):
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+366
@@ -0,0 +1,366 @@
|
|||||||
|
"""Utilities for writing code that runs on Python 2 and 3"""
|
||||||
|
|
||||||
|
import operator
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
|
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||||
|
__version__ = "1.2.0"
|
||||||
|
|
||||||
|
|
||||||
|
# True if we are running on Python 3.
|
||||||
|
PY3 = sys.version_info[0] == 3
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
string_types = str,
|
||||||
|
integer_types = int,
|
||||||
|
class_types = type,
|
||||||
|
text_type = str
|
||||||
|
binary_type = bytes
|
||||||
|
|
||||||
|
MAXSIZE = sys.maxsize
|
||||||
|
else:
|
||||||
|
string_types = basestring,
|
||||||
|
integer_types = (int, long)
|
||||||
|
class_types = (type, types.ClassType)
|
||||||
|
text_type = unicode
|
||||||
|
binary_type = str
|
||||||
|
|
||||||
|
if sys.platform == "java":
|
||||||
|
# Jython always uses 32 bits.
|
||||||
|
MAXSIZE = int((1 << 31) - 1)
|
||||||
|
else:
|
||||||
|
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||||
|
class X(object):
|
||||||
|
def __len__(self):
|
||||||
|
return 1 << 31
|
||||||
|
try:
|
||||||
|
len(X())
|
||||||
|
except OverflowError:
|
||||||
|
# 32-bit
|
||||||
|
MAXSIZE = int((1 << 31) - 1)
|
||||||
|
else:
|
||||||
|
# 64-bit
|
||||||
|
MAXSIZE = int((1 << 63) - 1)
|
||||||
|
del X
|
||||||
|
|
||||||
|
|
||||||
|
def _add_doc(func, doc):
|
||||||
|
"""Add documentation to a function."""
|
||||||
|
func.__doc__ = doc
|
||||||
|
|
||||||
|
|
||||||
|
def _import_module(name):
|
||||||
|
"""Import module, returning the module after the last dot."""
|
||||||
|
__import__(name)
|
||||||
|
return sys.modules[name]
|
||||||
|
|
||||||
|
|
||||||
|
class _LazyDescr(object):
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __get__(self, obj, tp):
|
||||||
|
result = self._resolve()
|
||||||
|
setattr(obj, self.name, result)
|
||||||
|
# This is a bit ugly, but it avoids running this again.
|
||||||
|
delattr(tp, self.name)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class MovedModule(_LazyDescr):
|
||||||
|
|
||||||
|
def __init__(self, name, old, new=None):
|
||||||
|
super(MovedModule, self).__init__(name)
|
||||||
|
if PY3:
|
||||||
|
if new is None:
|
||||||
|
new = name
|
||||||
|
self.mod = new
|
||||||
|
else:
|
||||||
|
self.mod = old
|
||||||
|
|
||||||
|
def _resolve(self):
|
||||||
|
return _import_module(self.mod)
|
||||||
|
|
||||||
|
|
||||||
|
class MovedAttribute(_LazyDescr):
|
||||||
|
|
||||||
|
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
|
||||||
|
super(MovedAttribute, self).__init__(name)
|
||||||
|
if PY3:
|
||||||
|
if new_mod is None:
|
||||||
|
new_mod = name
|
||||||
|
self.mod = new_mod
|
||||||
|
if new_attr is None:
|
||||||
|
if old_attr is None:
|
||||||
|
new_attr = name
|
||||||
|
else:
|
||||||
|
new_attr = old_attr
|
||||||
|
self.attr = new_attr
|
||||||
|
else:
|
||||||
|
self.mod = old_mod
|
||||||
|
if old_attr is None:
|
||||||
|
old_attr = name
|
||||||
|
self.attr = old_attr
|
||||||
|
|
||||||
|
def _resolve(self):
|
||||||
|
module = _import_module(self.mod)
|
||||||
|
return getattr(module, self.attr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class _MovedItems(types.ModuleType):
|
||||||
|
"""Lazy loading of moved objects"""
|
||||||
|
|
||||||
|
|
||||||
|
_moved_attributes = [
|
||||||
|
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
||||||
|
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
||||||
|
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
||||||
|
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
||||||
|
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
|
||||||
|
MovedAttribute("reduce", "__builtin__", "functools"),
|
||||||
|
MovedAttribute("StringIO", "StringIO", "io"),
|
||||||
|
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
||||||
|
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
||||||
|
|
||||||
|
MovedModule("builtins", "__builtin__"),
|
||||||
|
MovedModule("configparser", "ConfigParser"),
|
||||||
|
MovedModule("copyreg", "copy_reg"),
|
||||||
|
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
||||||
|
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
||||||
|
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||||
|
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
||||||
|
MovedModule("http_client", "httplib", "http.client"),
|
||||||
|
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
||||||
|
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
|
||||||
|
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
|
||||||
|
MovedModule("cPickle", "cPickle", "pickle"),
|
||||||
|
MovedModule("queue", "Queue"),
|
||||||
|
MovedModule("reprlib", "repr"),
|
||||||
|
MovedModule("socketserver", "SocketServer"),
|
||||||
|
MovedModule("tkinter", "Tkinter"),
|
||||||
|
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
||||||
|
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
||||||
|
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||||
|
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||||
|
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
||||||
|
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
||||||
|
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
||||||
|
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
||||||
|
"tkinter.colorchooser"),
|
||||||
|
MovedModule("tkinter_commondialog", "tkCommonDialog",
|
||||||
|
"tkinter.commondialog"),
|
||||||
|
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
||||||
|
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
||||||
|
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
||||||
|
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
||||||
|
"tkinter.simpledialog"),
|
||||||
|
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
||||||
|
MovedModule("winreg", "_winreg"),
|
||||||
|
]
|
||||||
|
for attr in _moved_attributes:
|
||||||
|
setattr(_MovedItems, attr.name, attr)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
moves = sys.modules["six.moves"] = _MovedItems("moves")
|
||||||
|
|
||||||
|
|
||||||
|
def add_move(move):
|
||||||
|
"""Add an item to six.moves."""
|
||||||
|
setattr(_MovedItems, move.name, move)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_move(name):
|
||||||
|
"""Remove item from six.moves."""
|
||||||
|
try:
|
||||||
|
delattr(_MovedItems, name)
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
del moves.__dict__[name]
|
||||||
|
except KeyError:
|
||||||
|
raise AttributeError("no such move, %r" % (name,))
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
_meth_func = "__func__"
|
||||||
|
_meth_self = "__self__"
|
||||||
|
|
||||||
|
_func_code = "__code__"
|
||||||
|
_func_defaults = "__defaults__"
|
||||||
|
|
||||||
|
_iterkeys = "keys"
|
||||||
|
_itervalues = "values"
|
||||||
|
_iteritems = "items"
|
||||||
|
else:
|
||||||
|
_meth_func = "im_func"
|
||||||
|
_meth_self = "im_self"
|
||||||
|
|
||||||
|
_func_code = "func_code"
|
||||||
|
_func_defaults = "func_defaults"
|
||||||
|
|
||||||
|
_iterkeys = "iterkeys"
|
||||||
|
_itervalues = "itervalues"
|
||||||
|
_iteritems = "iteritems"
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
advance_iterator = next
|
||||||
|
except NameError:
|
||||||
|
def advance_iterator(it):
|
||||||
|
return it.next()
|
||||||
|
next = advance_iterator
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
def get_unbound_function(unbound):
|
||||||
|
return unbound
|
||||||
|
|
||||||
|
Iterator = object
|
||||||
|
|
||||||
|
def callable(obj):
|
||||||
|
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||||
|
else:
|
||||||
|
def get_unbound_function(unbound):
|
||||||
|
return unbound.im_func
|
||||||
|
|
||||||
|
class Iterator(object):
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return type(self).__next__(self)
|
||||||
|
|
||||||
|
callable = callable
|
||||||
|
_add_doc(get_unbound_function,
|
||||||
|
"""Get the function out of a possibly unbound function""")
|
||||||
|
|
||||||
|
|
||||||
|
get_method_function = operator.attrgetter(_meth_func)
|
||||||
|
get_method_self = operator.attrgetter(_meth_self)
|
||||||
|
get_function_code = operator.attrgetter(_func_code)
|
||||||
|
get_function_defaults = operator.attrgetter(_func_defaults)
|
||||||
|
|
||||||
|
|
||||||
|
def iterkeys(d):
|
||||||
|
"""Return an iterator over the keys of a dictionary."""
|
||||||
|
return iter(getattr(d, _iterkeys)())
|
||||||
|
|
||||||
|
def itervalues(d):
|
||||||
|
"""Return an iterator over the values of a dictionary."""
|
||||||
|
return iter(getattr(d, _itervalues)())
|
||||||
|
|
||||||
|
def iteritems(d):
|
||||||
|
"""Return an iterator over the (key, value) pairs of a dictionary."""
|
||||||
|
return iter(getattr(d, _iteritems)())
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
def b(s):
|
||||||
|
return s.encode("latin-1")
|
||||||
|
def u(s):
|
||||||
|
return s
|
||||||
|
if sys.version_info[1] <= 1:
|
||||||
|
def int2byte(i):
|
||||||
|
return bytes((i,))
|
||||||
|
else:
|
||||||
|
# This is about 2x faster than the implementation above on 3.2+
|
||||||
|
int2byte = operator.methodcaller("to_bytes", 1, "big")
|
||||||
|
import io
|
||||||
|
StringIO = io.StringIO
|
||||||
|
BytesIO = io.BytesIO
|
||||||
|
else:
|
||||||
|
def b(s):
|
||||||
|
return s
|
||||||
|
def u(s):
|
||||||
|
return unicode(s, "unicode_escape")
|
||||||
|
int2byte = chr
|
||||||
|
import StringIO
|
||||||
|
StringIO = BytesIO = StringIO.StringIO
|
||||||
|
_add_doc(b, """Byte literal""")
|
||||||
|
_add_doc(u, """Text literal""")
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
import builtins
|
||||||
|
exec_ = getattr(builtins, "exec")
|
||||||
|
|
||||||
|
|
||||||
|
def reraise(tp, value, tb=None):
|
||||||
|
if value.__traceback__ is not tb:
|
||||||
|
raise value.with_traceback(tb)
|
||||||
|
raise value
|
||||||
|
|
||||||
|
|
||||||
|
print_ = getattr(builtins, "print")
|
||||||
|
del builtins
|
||||||
|
|
||||||
|
else:
|
||||||
|
def exec_(code, globs=None, locs=None):
|
||||||
|
"""Execute code in a namespace."""
|
||||||
|
if globs is None:
|
||||||
|
frame = sys._getframe(1)
|
||||||
|
globs = frame.f_globals
|
||||||
|
if locs is None:
|
||||||
|
locs = frame.f_locals
|
||||||
|
del frame
|
||||||
|
elif locs is None:
|
||||||
|
locs = globs
|
||||||
|
exec("""exec code in globs, locs""")
|
||||||
|
|
||||||
|
|
||||||
|
exec_("""def reraise(tp, value, tb=None):
|
||||||
|
raise tp, value, tb
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def print_(*args, **kwargs):
|
||||||
|
"""The new-style print function."""
|
||||||
|
fp = kwargs.pop("file", sys.stdout)
|
||||||
|
if fp is None:
|
||||||
|
return
|
||||||
|
def write(data):
|
||||||
|
if not isinstance(data, basestring):
|
||||||
|
data = str(data)
|
||||||
|
fp.write(data)
|
||||||
|
want_unicode = False
|
||||||
|
sep = kwargs.pop("sep", None)
|
||||||
|
if sep is not None:
|
||||||
|
if isinstance(sep, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
elif not isinstance(sep, str):
|
||||||
|
raise TypeError("sep must be None or a string")
|
||||||
|
end = kwargs.pop("end", None)
|
||||||
|
if end is not None:
|
||||||
|
if isinstance(end, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
elif not isinstance(end, str):
|
||||||
|
raise TypeError("end must be None or a string")
|
||||||
|
if kwargs:
|
||||||
|
raise TypeError("invalid keyword arguments to print()")
|
||||||
|
if not want_unicode:
|
||||||
|
for arg in args:
|
||||||
|
if isinstance(arg, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
break
|
||||||
|
if want_unicode:
|
||||||
|
newline = unicode("\n")
|
||||||
|
space = unicode(" ")
|
||||||
|
else:
|
||||||
|
newline = "\n"
|
||||||
|
space = " "
|
||||||
|
if sep is None:
|
||||||
|
sep = space
|
||||||
|
if end is None:
|
||||||
|
end = newline
|
||||||
|
for i, arg in enumerate(args):
|
||||||
|
if i:
|
||||||
|
write(sep)
|
||||||
|
write(arg)
|
||||||
|
write(end)
|
||||||
|
|
||||||
|
_add_doc(reraise, """Reraise an exception.""")
|
||||||
|
|
||||||
|
|
||||||
|
def with_metaclass(meta, base=object):
|
||||||
|
"""Create a base class with a metaclass."""
|
||||||
|
return meta("NewBase", (base,), {})
|
||||||
Reference in new issue
Block a user