summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomi Pieviläinen <tomi.pievilainen+launchpad@iki.fi>2012-02-18 22:45:14 +0200
committerTomi Pieviläinen <tomi.pievilainen+launchpad@iki.fi>2012-02-18 22:45:14 +0200
commit628cb9e642dc7b188c7f1a21879a29429b2cb9c2 (patch)
tree1dc6529531e988d7039dcd9893f936b12932c8e1
parent52093c973d3c91661ab1a64197b8694b25ca531c (diff)
parentfe750f2af0f1e04137f46f398506f6500fa6b054 (diff)
downloaddateutil-628cb9e642dc7b188c7f1a21879a29429b2cb9c2.tar.gz
Merge new style classes branch, works now on 2.6-3.2
-rw-r--r--dateutil/parser.py14
-rw-r--r--dateutil/relativedelta.py6
-rw-r--r--dateutil/rrule.py44
-rw-r--r--dateutil/tz.py24
-rw-r--r--sandbox/rrulewrapper.py2
-rw-r--r--sandbox/scheduler.py8
-rwxr-xr-xtest.py23
-rw-r--r--tox.ini6
8 files changed, 93 insertions, 34 deletions
diff --git a/dateutil/parser.py b/dateutil/parser.py
index 279970b..aa3eae0 100644
--- a/dateutil/parser.py
+++ b/dateutil/parser.py
@@ -5,9 +5,11 @@ Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
This module offers extensions to the standard python 2.3+
datetime module.
"""
+from __future__ import unicode_literals
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
__license__ = "Simplified BSD"
+
import datetime
import string
import time
@@ -20,6 +22,8 @@ try:
except ImportError:
from io import StringIO
+from six import text_type, binary_type
+
from . import relativedelta
from . import tz
@@ -40,7 +44,7 @@ __all__ = ["parse", "parserinfo"]
class _timelex(object):
def __init__(self, instream):
- if isinstance(instream, str):
+ if isinstance(instream, text_type):
instream = StringIO(instream)
self.instream = instream
self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
@@ -140,6 +144,9 @@ class _timelex(object):
raise StopIteration
return token
+ def next(self):
+ return self.__next__() # Python 2.x support
+
def split(cls, s):
return list(cls(s))
split = classmethod(split)
@@ -692,6 +699,11 @@ class parser(object):
DEFAULTPARSER = parser()
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:
return parser(parserinfo).parse(timestr, **kwargs)
else:
diff --git a/dateutil/relativedelta.py b/dateutil/relativedelta.py
index 1f07d82..d0b599a 100644
--- a/dateutil/relativedelta.py
+++ b/dateutil/relativedelta.py
@@ -42,7 +42,7 @@ class weekday(object):
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
work done by M.-A. Lemburg in his mx.DateTime extension. However,
@@ -305,7 +305,7 @@ Here is the behavior of operations with relativedelta:
hour=other.hour or self.hour,
minute=other.minute or self.minute,
second=other.second or self.second,
- microsecond=other.second or self.microsecond)
+ microsecond=other.microsecond or self.microsecond)
def __sub__(self, other):
if not isinstance(other, relativedelta):
@@ -325,7 +325,7 @@ Here is the behavior of operations with relativedelta:
hour=other.hour or self.hour,
minute=other.minute or self.minute,
second=other.second or self.second,
- microsecond=other.second or self.microsecond)
+ microsecond=other.microsecond or self.microsecond)
def __neg__(self):
return relativedelta(years=-self.years,
diff --git a/dateutil/rrule.py b/dateutil/rrule.py
index 13e6509..48013f8 100644
--- a/dateutil/rrule.py
+++ b/dateutil/rrule.py
@@ -10,9 +10,14 @@ __license__ = "Simplified BSD"
import itertools
import datetime
import calendar
-import _thread
+try:
+ import _thread
+except ImportError:
+ import thread as _thread
import sys
+from six import advance_iterator
+
__all__ = ["rrule", "rruleset", "rrulestr",
"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
"HOURLY", "MINUTELY", "SECONDLY",
@@ -79,7 +84,7 @@ class weekday(object):
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):
if cache:
self._cache = []
@@ -112,7 +117,7 @@ class rrulebase:
break
try:
for j in range(10):
- cache.append(next(gen))
+ cache.append(advance_iterator(gen))
except StopIteration:
self._cache_gen = gen = None
self._cache_complete = True
@@ -139,7 +144,7 @@ class rrulebase:
gen = iter(self)
try:
for i in range(item+1):
- res = next(gen)
+ res = advance_iterator(gen)
except StopIteration:
raise IndexError
return res
@@ -232,7 +237,7 @@ class rrule(rrulebase):
byweekno=None, byweekday=None,
byhour=None, byminute=None, bysecond=None,
cache=False):
- rrulebase.__init__(self, cache)
+ super(rrule, self).__init__(cache)
global easter
if not dtstart:
dtstart = datetime.datetime.now().replace(microsecond=0)
@@ -823,10 +828,10 @@ class _iterinfo(object):
class rruleset(rrulebase):
- class _genitem:
+ class _genitem(object):
def __init__(self, genlist, gen):
try:
- self.dt = gen()
+ self.dt = advance_iterator(gen)
genlist.append(self)
except StopIteration:
pass
@@ -835,10 +840,12 @@ class rruleset(rrulebase):
def __next__(self):
try:
- self.dt = self.gen()
+ self.dt = advance_iterator(self.gen)
except StopIteration:
self.genlist.remove(self)
+ next = __next__
+
def __lt__(self, other):
return self.dt < other.dt
@@ -848,8 +855,11 @@ class rruleset(rrulebase):
def __eq__(self, other):
return self.dt == other.dt
+ def __ne__(self, other):
+ return self.dt != other.dt
+
def __init__(self, cache=False):
- rrulebase.__init__(self, cache)
+ super(rruleset, self).__init__(cache)
self._rrule = []
self._rdate = []
self._exrule = []
@@ -857,7 +867,7 @@ class rruleset(rrulebase):
def rrule(self, rrule):
self._rrule.append(rrule)
-
+
def rdate(self, rdate):
self._rdate.append(rdate)
@@ -870,14 +880,14 @@ class rruleset(rrulebase):
def _iter(self):
rlist = []
self._rdate.sort()
- self._genitem(rlist, iter(self._rdate).__next__)
- for gen in [iter(x).__next__ for x in self._rrule]:
+ self._genitem(rlist, iter(self._rdate))
+ for gen in [iter(x) for x in self._rrule]:
self._genitem(rlist, gen)
rlist.sort()
exlist = []
self._exdate.sort()
- self._genitem(exlist, iter(self._exdate).__next__)
- for gen in [iter(x).__next__ for x in self._exrule]:
+ self._genitem(exlist, iter(self._exdate))
+ for gen in [iter(x) for x in self._exrule]:
self._genitem(exlist, gen)
exlist.sort()
lastdt = None
@@ -886,17 +896,17 @@ class rruleset(rrulebase):
ritem = rlist[0]
if not lastdt or lastdt != ritem.dt:
while exlist and exlist[0] < ritem:
- next(exlist[0])
+ advance_iterator(exlist[0])
exlist.sort()
if not exlist or ritem != exlist[0]:
total += 1
yield ritem.dt
lastdt = ritem.dt
- next(ritem)
+ advance_iterator(ritem)
rlist.sort()
self._len = total
-class _rrulestr:
+class _rrulestr(object):
_freq_map = {"YEARLY": YEARLY,
"MONTHLY": MONTHLY,
diff --git a/dateutil/tz.py b/dateutil/tz.py
index 41003df..3dca4a9 100644
--- a/dateutil/tz.py
+++ b/dateutil/tz.py
@@ -25,6 +25,20 @@ try:
except (ImportError, OSError):
tzwin, tzwinlocal = None, None
+def tzname_in_python2(myfunc):
+ import six
+ """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 six.PY3:
+ return myfunc(*args, **kwargs)
+ else:
+ return myfunc(*args, **kwargs).encode()
+ return inner_func
+
ZERO = datetime.timedelta(0)
EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal()
@@ -36,6 +50,7 @@ class tzutc(datetime.tzinfo):
def dst(self, dt):
return ZERO
+ @tzname_in_python2
def tzname(self, dt):
return "UTC"
@@ -63,6 +78,7 @@ class tzoffset(datetime.tzinfo):
def dst(self, dt):
return ZERO
+ @tzname_in_python2
def tzname(self, dt):
return self._name
@@ -100,6 +116,7 @@ class tzlocal(datetime.tzinfo):
else:
return ZERO
+ @tzname_in_python2
def tzname(self, dt):
return time.tzname[self._isdst(dt)]
@@ -448,6 +465,7 @@ class tzfile(datetime.tzinfo):
# dst offset, so I belive that this wouldn't be the right
# way to implement this.
+ @tzname_in_python2
def tzname(self, dt):
if not self._ttinfo_std:
return None
@@ -515,6 +533,7 @@ class tzrange(datetime.tzinfo):
else:
return ZERO
+ @tzname_in_python2
def tzname(self, dt):
if self._isdst(dt):
return self._dst_abbr
@@ -626,7 +645,7 @@ class tzstr(tzrange):
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
-class _tzicalvtzcomp:
+class _tzicalvtzcomp(object):
def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
tzname=None, rrule=None):
self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
@@ -690,6 +709,7 @@ class _tzicalvtz(datetime.tzinfo):
else:
return ZERO
+ @tzname_in_python2
def tzname(self, dt):
return self._find_comp(dt).tzname
@@ -698,7 +718,7 @@ class _tzicalvtz(datetime.tzinfo):
__reduce__ = object.__reduce__
-class tzical:
+class tzical(object):
def __init__(self, fileobj):
global rrule
if not rrule:
diff --git a/sandbox/rrulewrapper.py b/sandbox/rrulewrapper.py
index 3be7c85..da4fa85 100644
--- a/sandbox/rrulewrapper.py
+++ b/sandbox/rrulewrapper.py
@@ -1,6 +1,6 @@
from rrule import *
-class rrulewrapper:
+class rrulewrapper(object):
def __init__(self, freq, **kwargs):
self._construct = kwargs.copy()
self._construct["freq"] = freq
diff --git a/sandbox/scheduler.py b/sandbox/scheduler.py
index 6216fe6..39740eb 100644
--- a/sandbox/scheduler.py
+++ b/sandbox/scheduler.py
@@ -12,7 +12,7 @@ import _thread
import signal
import time
-class sched:
+class sched(object):
def __init__(self, rrule,
tolerance=None, last=None,
@@ -49,7 +49,7 @@ class sched:
return item
-class schedset:
+class schedset(object):
def __init__(self):
self._scheds = []
@@ -76,7 +76,7 @@ class schedset:
return res
-class schedthread:
+class schedthread(object):
def __init__(self, sched, lock=None):
self._sched = sched
@@ -109,7 +109,7 @@ class schedthread:
time.sleep(seconds)
-class schedalarm:
+class schedalarm(object):
def __init__(self, sched, lock=None):
self._sched = sched
diff --git a/test.py b/test.py
index 3763fbc..3fa865d 100755
--- a/test.py
+++ b/test.py
@@ -1,6 +1,8 @@
-#!/usr/bin/python3
+#!/usr/bin/python
# -*- encoding: utf-8 -*-
-from io import StringIO,BytesIO
+from __future__ import unicode_literals
+
+from six import StringIO, BytesIO
import unittest
import calendar
import time
@@ -146,6 +148,15 @@ class RelativeDeltaTest(unittest.TestCase):
self.assertEqual(self.today+relativedelta(yearday=261),
date(2003, 9, 18))
+ def test884317(self):
+ # See https://bugs.launchpad.net/dateutil/+bug/884317
+ a = relativedelta(second = 2, microsecond = 20)
+ b = relativedelta(second = 1, microsecond = 10)
+ c = a-b
+ self.assertEqual(c.microsecond, b.microsecond)
+ c = a+b
+ self.assertEqual(c.microsecond, b.microsecond)
+
class RRuleTest(unittest.TestCase):
def testYearly(self):
@@ -3874,12 +3885,12 @@ END:VTIMEZONE
tzrange("EST", -18000, "EDT"))
def testFileStart1(self):
- tz = tzfile(BytesIO(base64.decodebytes(self.TZFILE_EST5EDT)))
+ tz = tzfile(BytesIO(base64.decodestring(self.TZFILE_EST5EDT)))
self.assertEqual(datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname(), "EST")
self.assertEqual(datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname(), "EDT")
def testFileEnd1(self):
- tz = tzfile(BytesIO(base64.decodebytes(self.TZFILE_EST5EDT)))
+ tz = tzfile(BytesIO(base64.decodestring(self.TZFILE_EST5EDT)))
self.assertEqual(datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname(), "EDT")
self.assertEqual(datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname(), "EST")
@@ -3915,14 +3926,14 @@ END:VTIMEZONE
def testRoundNonFullMinutes(self):
# This timezone has an offset of 5992 seconds in 1900-01-01.
- tz = tzfile(BytesIO(base64.decodebytes(self.EUROPE_HELSINKI)))
+ tz = tzfile(BytesIO(base64.decodestring(self.EUROPE_HELSINKI)))
self.assertEqual(str(datetime(1900, 1, 1, 0, 0, tzinfo=tz)),
"1900-01-01 00:00:00+01:40")
def testLeapCountDecodesProperly(self):
# This timezone has leapcnt, and failed to decode until
# Eugene Oden notified about the issue.
- tz = tzfile(BytesIO(base64.decodebytes(self.NEW_YORK)))
+ tz = tzfile(BytesIO(base64.decodestring(self.NEW_YORK)))
self.assertEqual(datetime(2007, 3, 31, 20, 12).tzname(), None)
def testBrokenIsDstHandling(self):
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..51c5d99
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,6 @@
+[tox]
+envlist = py26, py27, py32
+
+[testenv]
+commands = python test.py
+deps = six