mirror of
https://github.com/kennethreitz/maya.git
synced 2026-06-05 23:00:18 +00:00
add compatibility for Python3
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
maya.compat
|
||||
~~~~~~~~~~~~~~~
|
||||
This module handles import compatibility issues between Python 2 and
|
||||
Python 3.
|
||||
"""
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
_PY3 = False
|
||||
else:
|
||||
_PY3 = True
|
||||
|
||||
try:
|
||||
cmp = cmp
|
||||
except NameError:
|
||||
def cmp(a, b):
|
||||
"""
|
||||
Compare two objects.
|
||||
Returns a negative number if C{a < b}, zero if they are equal, and a
|
||||
positive number if C{a > b}.
|
||||
"""
|
||||
if a < b:
|
||||
return -1
|
||||
elif a == b:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
def comparable(klass):
|
||||
"""
|
||||
Class decorator that ensures support for the special C{__cmp__} method.
|
||||
On Python 2 this does nothing.
|
||||
On Python 3, C{__eq__}, C{__lt__}, etc. methods are added to the class,
|
||||
relying on C{__cmp__} to implement their comparisons.
|
||||
"""
|
||||
# On Python 2, __cmp__ will just work, so no need to add extra methods:
|
||||
if not _PY3:
|
||||
return klass
|
||||
|
||||
def __eq__(self, other):
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c
|
||||
return c == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c
|
||||
return c != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c
|
||||
return c < 0
|
||||
|
||||
def __le__(self, other):
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c
|
||||
return c <= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c
|
||||
return c > 0
|
||||
|
||||
def __ge__(self, other):
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c
|
||||
return c >= 0
|
||||
|
||||
klass.__lt__ = __lt__
|
||||
klass.__gt__ = __gt__
|
||||
klass.__le__ = __le__
|
||||
klass.__ge__ = __ge__
|
||||
klass.__eq__ = __eq__
|
||||
klass.__ne__ = __ne__
|
||||
return klass
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# ___ __ ___ _ _ ___
|
||||
# || \/ | ||=|| \\// ||=||
|
||||
# || | || || // || ||
|
||||
@@ -6,8 +5,8 @@
|
||||
# Ignore warnings for yaml usage.
|
||||
import warnings
|
||||
import ruamel.yaml
|
||||
warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning)
|
||||
|
||||
warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning)
|
||||
|
||||
import email.utils
|
||||
import time
|
||||
@@ -19,6 +18,7 @@ import dateparser
|
||||
import pendulum
|
||||
from tzlocal import get_localzone
|
||||
|
||||
from compat import cmp, comparable
|
||||
|
||||
_EPOCH_START = (1970, 1, 1)
|
||||
|
||||
@@ -276,15 +276,17 @@ def to_iso8601(dt):
|
||||
|
||||
|
||||
def end_of_day_midnight(dt):
|
||||
return dt if dt.time() == time.min else\
|
||||
return dt if dt.time() == time.min else \
|
||||
(dt.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1))
|
||||
|
||||
|
||||
@comparable
|
||||
class MayaInterval(object):
|
||||
"""
|
||||
A MayaInterval represents a range between two datetimes, inclusive of the start
|
||||
and exclusive of the end.
|
||||
"""
|
||||
|
||||
def __init__(self, start=None, end=None, duration=None):
|
||||
try:
|
||||
# Ensure that proper arguments were passed.
|
||||
@@ -337,7 +339,6 @@ class MayaInterval(object):
|
||||
# # Duration and end, such as "P1Y2M10DT2H30M/2008-05-11T15:30:00Z"
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def __and__(self, i):
|
||||
return self.intersection(i)
|
||||
|
||||
@@ -536,7 +537,8 @@ def when(string, timezone='UTC'):
|
||||
timezone -- timezone referenced from (default: 'UTC')
|
||||
|
||||
"""
|
||||
dt = dateparser.parse(string, settings={'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True, 'TO_TIMEZONE': 'UTC'})
|
||||
dt = dateparser.parse(string,
|
||||
settings={'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True, 'TO_TIMEZONE': 'UTC'})
|
||||
|
||||
if dt is None:
|
||||
raise ValueError('invalid datetime input specified.')
|
||||
@@ -558,7 +560,6 @@ def parse(string, day_first=False):
|
||||
|
||||
|
||||
def seconds_or_timedelta(s):
|
||||
|
||||
# Convert seconds into timedelta.
|
||||
if isinstance(s, int):
|
||||
s = timedelta(seconds=s)
|
||||
|
||||
+82
-82
@@ -5,7 +5,7 @@ import pytest
|
||||
import pytz
|
||||
|
||||
import maya
|
||||
|
||||
from compat import cmp
|
||||
|
||||
Los_Angeles = pytz.timezone('America/Los_Angeles')
|
||||
New_York = pytz.timezone('America/New_York')
|
||||
@@ -65,32 +65,32 @@ def test_interval_init_end_duration():
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start_doy1,end_doy1,start_doy2,end_doy2,intersection_doys', (
|
||||
(0, 2, 1, 3, (1, 2)),
|
||||
(0, 2, 3, 4, None),
|
||||
(0, 2, 2, 3, None),
|
||||
(0, 1, 0, 1, (0, 1)),
|
||||
(1, 1, 1, 3, (1, 1)),
|
||||
(1, 1, 1, 1, (1, 1)),
|
||||
(1, 1, 2, 3, None),
|
||||
(2, 2, 1, 3, (2, 2)),
|
||||
(1, 3, 1, 1, (1, 1)),
|
||||
(2, 3, 1, 1, None),
|
||||
(1, 3, 2, 2, (2, 2)),
|
||||
(0, 2, 1, 3, (1, 2)),
|
||||
(0, 2, 3, 4, None),
|
||||
(0, 2, 2, 3, None),
|
||||
(0, 1, 0, 1, (0, 1)),
|
||||
(1, 1, 1, 3, (1, 1)),
|
||||
(1, 1, 1, 1, (1, 1)),
|
||||
(1, 1, 2, 3, None),
|
||||
(2, 2, 1, 3, (2, 2)),
|
||||
(1, 3, 1, 1, (1, 1)),
|
||||
(2, 3, 1, 1, None),
|
||||
(1, 3, 2, 2, (2, 2)),
|
||||
), ids=(
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'adjacent',
|
||||
'equal',
|
||||
'instant overlapping start only',
|
||||
'instant equal',
|
||||
'instant disjoint',
|
||||
'instant overlapping',
|
||||
'instant overlapping start only (left)',
|
||||
'instant disjoint (left)',
|
||||
'instant overlapping (left)'
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'adjacent',
|
||||
'equal',
|
||||
'instant overlapping start only',
|
||||
'instant equal',
|
||||
'instant disjoint',
|
||||
'instant overlapping',
|
||||
'instant overlapping start only (left)',
|
||||
'instant disjoint (left)',
|
||||
'instant overlapping (left)'
|
||||
))
|
||||
def test_interval_intersection(
|
||||
start_doy1, end_doy1, start_doy2, end_doy2, intersection_doys
|
||||
start_doy1, end_doy1, start_doy2, end_doy2, intersection_doys
|
||||
):
|
||||
base = maya.MayaDT.from_datetime(datetime(2016, 1, 1))
|
||||
interval1 = maya.MayaInterval(
|
||||
@@ -161,20 +161,20 @@ def test_interval_duration():
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start_doy1,end_doy1,start_doy2,end_doy2,expected', (
|
||||
(0, 2, 1, 3, False),
|
||||
(0, 2, 3, 4, False),
|
||||
(0, 2, 2, 3, False),
|
||||
(0, 1, 0, 1, True),
|
||||
(0, 3, 1, 2, True),
|
||||
(0, 2, 1, 3, False),
|
||||
(0, 2, 3, 4, False),
|
||||
(0, 2, 2, 3, False),
|
||||
(0, 1, 0, 1, True),
|
||||
(0, 3, 1, 2, True),
|
||||
), ids=(
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'adjacent',
|
||||
'equal',
|
||||
'subset',
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'adjacent',
|
||||
'equal',
|
||||
'subset',
|
||||
))
|
||||
def test_interval_contains(
|
||||
start_doy1, end_doy1, start_doy2, end_doy2, expected
|
||||
start_doy1, end_doy1, start_doy2, end_doy2, expected
|
||||
):
|
||||
base = maya.MayaDT.from_datetime(datetime(2016, 1, 1))
|
||||
interval1 = maya.MayaInterval(
|
||||
@@ -191,20 +191,20 @@ def test_interval_contains(
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start_doy,end_doy,dt_doy,expected', (
|
||||
(2, 4, 1, False),
|
||||
(2, 4, 2, True),
|
||||
(2, 4, 3, True),
|
||||
(2, 4, 4, False),
|
||||
(2, 4, 5, False),
|
||||
(2, 4, 1, False),
|
||||
(2, 4, 2, True),
|
||||
(2, 4, 3, True),
|
||||
(2, 4, 4, False),
|
||||
(2, 4, 5, False),
|
||||
), ids=(
|
||||
'before-start',
|
||||
'on-start',
|
||||
'during',
|
||||
'on-end',
|
||||
'after-end',
|
||||
'before-start',
|
||||
'on-start',
|
||||
'during',
|
||||
'on-end',
|
||||
'after-end',
|
||||
))
|
||||
def test_interval_in_operator_maya_dt(
|
||||
start_doy, end_doy, dt_doy, expected
|
||||
start_doy, end_doy, dt_doy, expected
|
||||
):
|
||||
base = maya.MayaDT.from_datetime(datetime(2016, 1, 1))
|
||||
interval = maya.MayaInterval(
|
||||
@@ -239,10 +239,10 @@ def test_interval_iter():
|
||||
(2, 4, 1, 3, 1),
|
||||
(1, 2, 1, 3, -1),
|
||||
], ids=(
|
||||
'equal',
|
||||
'less-than',
|
||||
'greater-than',
|
||||
'use-end-time-if-start-time-identical',
|
||||
'equal',
|
||||
'less-than',
|
||||
'greater-than',
|
||||
'use-end-time-if-start-time-identical',
|
||||
))
|
||||
def test_interval_cmp(start1, end1, start2, end2, expected):
|
||||
base = maya.now()
|
||||
@@ -263,10 +263,10 @@ def test_interval_cmp(start1, end1, start2, end2, expected):
|
||||
(1, 2, 3, 4, [(1, 2), (3, 4)]),
|
||||
(1, 5, 2, 3, [(1, 5)]),
|
||||
], ids=(
|
||||
'adjacent',
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'contains',
|
||||
'adjacent',
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'contains',
|
||||
))
|
||||
def test_interval_combine(start1, end1, start2, end2, expected):
|
||||
base = maya.now()
|
||||
@@ -297,14 +297,14 @@ def test_interval_combine(start1, end1, start2, end2, expected):
|
||||
(1, 4, 1, 2, [(2, 4)]),
|
||||
(1, 4, 3, 4, [(1, 3)]),
|
||||
], ids=(
|
||||
'non-overlapping',
|
||||
'adjacent',
|
||||
'contains',
|
||||
'splits',
|
||||
'overlaps-left',
|
||||
'overlaps-right',
|
||||
'overlaps-left-identical-start',
|
||||
'overlaps-right-identical-end',
|
||||
'non-overlapping',
|
||||
'adjacent',
|
||||
'contains',
|
||||
'splits',
|
||||
'overlaps-left',
|
||||
'overlaps-right',
|
||||
'overlaps-left-identical-start',
|
||||
'overlaps-right-identical-end',
|
||||
))
|
||||
def test_interval_subtract(start1, end1, start2, end2, expected):
|
||||
base = maya.now()
|
||||
@@ -330,10 +330,10 @@ def test_interval_subtract(start1, end1, start2, end2, expected):
|
||||
(1, 3, 2, 3, False),
|
||||
(2, 3, 4, 5, False),
|
||||
], ids=(
|
||||
'adjacent-right',
|
||||
'adjacent-left',
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
'adjacent-right',
|
||||
'adjacent-left',
|
||||
'overlapping',
|
||||
'non-overlapping',
|
||||
))
|
||||
def test_interval_is_adjacent(start1, end1, start2, end2, expected):
|
||||
base = maya.now()
|
||||
@@ -356,12 +356,12 @@ def test_interval_is_adjacent(start1, end1, start2, end2, expected):
|
||||
(0, 2, 5, False, []),
|
||||
(0, 2, 5, True, [(0, 2)]),
|
||||
], ids=(
|
||||
'even-split',
|
||||
'even-split-include-partial',
|
||||
'uneven-split-do-not-include-partial',
|
||||
'uneven-split-include-partial',
|
||||
'delta-larger-than-timepsan-do-not-include-partial',
|
||||
'delta-larger-than-timepsan-include-partial',
|
||||
'even-split',
|
||||
'even-split-include-partial',
|
||||
'uneven-split-do-not-include-partial',
|
||||
'uneven-split-include-partial',
|
||||
'delta-larger-than-timepsan-do-not-include-partial',
|
||||
'delta-larger-than-timepsan-include-partial',
|
||||
))
|
||||
def test_interval_split(start, end, delta, include_remainder, expected):
|
||||
base = maya.now()
|
||||
@@ -406,16 +406,16 @@ def test_interval_split_non_positive_delta():
|
||||
((6, 20), (6, 50), 60, 'America/Chicago', False, (6, 0), (6, 0)),
|
||||
((6, 20), (6, 50), 60, 'America/Chicago', True, (6, 0), (7, 0)),
|
||||
], ids=(
|
||||
'normal',
|
||||
'normal-snap_out',
|
||||
'already-quantized',
|
||||
'already-quantized-snap_out',
|
||||
'with-timezone',
|
||||
'with-timezone-snap_out',
|
||||
'too-small',
|
||||
'too-small-snap_out',
|
||||
'too-small-with-timezone',
|
||||
'too-small-with-timezone-snap_out',
|
||||
'normal',
|
||||
'normal-snap_out',
|
||||
'already-quantized',
|
||||
'already-quantized-snap_out',
|
||||
'with-timezone',
|
||||
'with-timezone-snap_out',
|
||||
'too-small',
|
||||
'too-small-snap_out',
|
||||
'too-small-with-timezone',
|
||||
'too-small-with-timezone-snap_out',
|
||||
))
|
||||
def test_quantize(start, end, minutes, timezone, snap_out, expected_start, expected_end):
|
||||
base = maya.MayaDT.from_datetime(datetime(2017, 1, 1))
|
||||
|
||||
Reference in New Issue
Block a user