kopia lustrzana https://github.com/collective/icalendar
equality of vDDDTypes, vBinary and vCategory
rodzic
0eae8ceb04
commit
6274d88809
|
@ -124,7 +124,20 @@ class LocalTimezone(tzinfo):
|
|||
return tt.tm_isdst > 0
|
||||
|
||||
|
||||
class vBinary:
|
||||
class EqualityMixin:
|
||||
"""A class to share equality functions of properties."""
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Check the equality between this property and the other.
|
||||
|
||||
You can override this to make comparing faster.
|
||||
"""
|
||||
return isinstance(other, EqualityMixin) and \
|
||||
self.params == other.params and \
|
||||
self.to_ical() == other.to_ical()
|
||||
|
||||
|
||||
class vBinary(EqualityMixin):
|
||||
"""Binary property values are base 64 encoded.
|
||||
"""
|
||||
|
||||
|
@ -263,12 +276,13 @@ class vDDDLists:
|
|||
return self.dts == other.dts
|
||||
|
||||
|
||||
class vCategory:
|
||||
class vCategory(EqualityMixin):
|
||||
|
||||
def __init__(self, c_list):
|
||||
if not hasattr(c_list, '__iter__') or isinstance(c_list, str):
|
||||
c_list = [c_list]
|
||||
self.cats = [vText(c) for c in c_list]
|
||||
self.params = Parameters()
|
||||
|
||||
def to_ical(self):
|
||||
return b",".join([c.to_ical() for c in self.cats])
|
||||
|
@ -280,7 +294,19 @@ class vCategory:
|
|||
return out
|
||||
|
||||
|
||||
class vDDDTypes:
|
||||
class DtEqualityMixin:
|
||||
"""Make classes with a datetime/date comparable."""
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, DtEqualityMixin):
|
||||
return self.params == other.params and self.dt == other.dt
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.dt)
|
||||
|
||||
|
||||
class vDDDTypes(DtEqualityMixin):
|
||||
"""A combined Datetime, Date or Duration parser/generator. Their format
|
||||
cannot be confused, and often values can be of either types.
|
||||
So this is practical.
|
||||
|
@ -290,7 +316,7 @@ class vDDDTypes:
|
|||
if not isinstance(dt, (datetime, date, timedelta, time, tuple)):
|
||||
raise ValueError('You must use datetime, date, timedelta, '
|
||||
'time or tuple (for periods)')
|
||||
if isinstance(dt, datetime):
|
||||
if isinstance(dt, (datetime, timedelta)):
|
||||
self.params = Parameters()
|
||||
elif isinstance(dt, date):
|
||||
self.params = Parameters({'value': 'DATE'})
|
||||
|
@ -320,14 +346,6 @@ class vDDDTypes:
|
|||
else:
|
||||
raise ValueError(f'Unknown date type: {type(dt)}')
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, vDDDTypes):
|
||||
return self.params == other.params and self.dt == other.dt
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.dt)
|
||||
|
||||
@classmethod
|
||||
def from_ical(cls, ical, timezone=None):
|
||||
if isinstance(ical, cls):
|
||||
|
@ -349,8 +367,11 @@ class vDDDTypes:
|
|||
f"Expected datetime, date, or time, got: '{ical}'"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
"""repr(self)"""
|
||||
return f"{self.__class__.__name__}({self.dt}, {self.params})"
|
||||
|
||||
class vDate:
|
||||
class vDate(DtEqualityMixin):
|
||||
"""Render and generates iCalendar date format.
|
||||
"""
|
||||
|
||||
|
@ -377,7 +398,7 @@ class vDate:
|
|||
raise ValueError(f'Wrong date format {ical}')
|
||||
|
||||
|
||||
class vDatetime:
|
||||
class vDatetime(DtEqualityMixin):
|
||||
"""Render and generates icalendar datetime format.
|
||||
|
||||
vDatetime is timezone aware and uses the pytz library, an implementation of
|
||||
|
@ -438,7 +459,7 @@ class vDatetime:
|
|||
raise ValueError(f'Wrong datetime format: {ical}')
|
||||
|
||||
|
||||
class vDuration:
|
||||
class vDuration(DtEqualityMixin):
|
||||
"""Subclass of timedelta that renders itself in the iCalendar DURATION
|
||||
format.
|
||||
"""
|
||||
|
@ -495,8 +516,12 @@ class vDuration:
|
|||
|
||||
return value
|
||||
|
||||
@property
|
||||
def dt(self):
|
||||
"""The time delta for compatibility."""
|
||||
return self.td
|
||||
|
||||
class vPeriod:
|
||||
class vPeriod(DtEqualityMixin):
|
||||
"""A precise period of time.
|
||||
"""
|
||||
|
||||
|
@ -520,7 +545,7 @@ class vPeriod:
|
|||
if start > end:
|
||||
raise ValueError("Start time is greater than end time")
|
||||
|
||||
self.params = Parameters()
|
||||
self.params = Parameters({'value': 'PERIOD'})
|
||||
# set the timezone identifier
|
||||
# does not support different timezones for start and end
|
||||
tzid = tzid_from_dt(start)
|
||||
|
@ -532,17 +557,6 @@ class vPeriod:
|
|||
self.by_duration = by_duration
|
||||
self.duration = duration
|
||||
|
||||
def __cmp__(self, other):
|
||||
if not isinstance(other, vPeriod):
|
||||
raise NotImplementedError(
|
||||
f'Cannot compare vPeriod with {other!r}')
|
||||
return cmp((self.start, self.end), (other.start, other.end))
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, vPeriod):
|
||||
return False
|
||||
return (self.start, self.end) == (other.start, other.end)
|
||||
|
||||
def overlaps(self, other):
|
||||
if self.start > other.start:
|
||||
return other.overlaps(self)
|
||||
|
@ -574,6 +588,10 @@ class vPeriod:
|
|||
p = (self.start, self.end)
|
||||
return f'vPeriod({p!r})'
|
||||
|
||||
@property
|
||||
def dt(self):
|
||||
"""Make this cooperate with the other vDDDTypes."""
|
||||
return (self.start, (self.duration if self.by_duration else self.end))
|
||||
|
||||
class vWeekday(str):
|
||||
"""This returns an unquoted weekday abbrevation.
|
||||
|
@ -814,6 +832,8 @@ class vGeo:
|
|||
except Exception:
|
||||
raise ValueError(f"Expected 'float;float' , got: {ical}")
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.to_ical() == other.to_ical()
|
||||
|
||||
class vUTCOffset:
|
||||
"""Renders itself as a utc offset.
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
"""Test the equality and inequality of components."""
|
||||
import copy
|
||||
import pytz
|
||||
from icalendar.prop import *
|
||||
from datetime import datetime, date, timedelta
|
||||
import pytest
|
||||
|
||||
|
||||
def test_parsed_calendars_are_equal(ics_file):
|
||||
|
@ -41,3 +44,55 @@ def test_a_components_copy_also_copies_subcomponents(calendars):
|
|||
assert copy.subcomponents
|
||||
assert copy.subcomponents is not cal.subcomponents
|
||||
assert copy.subcomponents == cal.subcomponents
|
||||
|
||||
|
||||
def test_vGeo():
|
||||
"""Check the equality of vGeo."""
|
||||
assert vGeo(("100", "12.33")) == vGeo(("100.00", "12.330"))
|
||||
assert vGeo(("100", "12.331")) != vGeo(("100.00", "12.330"))
|
||||
assert vGeo(("10", "12.33")) != vGeo(("100.00", "12.330"))
|
||||
|
||||
|
||||
def test_vBinary():
|
||||
assert vBinary('asd') == vBinary('asd')
|
||||
assert vBinary('asdf') != vBinary('asd')
|
||||
|
||||
def test_vBoolean():
|
||||
assert vBoolean.from_ical('TRUE') == vBoolean.from_ical('TRUE')
|
||||
assert vBoolean.from_ical('FALSE') == vBoolean.from_ical('FALSE')
|
||||
assert vBoolean.from_ical('TRUE') != vBoolean.from_ical('FALSE')
|
||||
|
||||
def test_vCategory():
|
||||
assert vCategory("HELLO") == vCategory("HELLO")
|
||||
assert vCategory(["a","b"]) == vCategory(["a","b"])
|
||||
assert vCategory(["a","b"]) != vCategory(["a","b", "c"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vType,v1,v2",
|
||||
[
|
||||
(vDatetime, datetime(2023, 11, 1, 10, 11), datetime(2023, 11, 1, 10, 10)),
|
||||
(vDate, date(2023, 11, 1), date(2023, 10, 31)),
|
||||
(vDuration, timedelta(3, 11, 1), timedelta(23, 10, 31)),
|
||||
(vPeriod, (datetime(2023, 11, 1, 10, 11), timedelta(3, 11, 1)), (datetime(2023, 11, 1, 10, 11), timedelta(23, 10, 31))),
|
||||
(vPeriod, (datetime(2023, 11, 1, 10, 1), timedelta(3, 11, 1)), (datetime(2023, 11, 1, 10, 11), timedelta(3, 11, 1))),
|
||||
(vPeriod, (datetime(2023, 11, 1, 10, 1), datetime(2023, 11, 1, 10, 3)), (datetime(2023, 11, 1, 10, 1), datetime(2023, 11, 1, 10, 2))),
|
||||
]
|
||||
)
|
||||
@pytest.mark.parametrize("eq", ["==", "!="])
|
||||
@pytest.mark.parametrize("cls1", [0, 1])
|
||||
@pytest.mark.parametrize("cls2", [0, 1])
|
||||
@pytest.mark.parametrize("hash", [lambda x:x, hash])
|
||||
def test_vDDDTypes_and_others(vType, v1, v2, cls1, cls2, eq, hash):
|
||||
"""Check equality and inequality."""
|
||||
t1 = (vType, vDDDTypes)[cls1]
|
||||
t2 = (vType, vDDDTypes)[cls2]
|
||||
if eq == "==":
|
||||
assert hash(v1) == hash(v1)
|
||||
assert hash(t1(v1)) == hash(t2(v1))
|
||||
else:
|
||||
assert hash(v1) != hash(v2)
|
||||
assert hash(t1(v1)) != hash(t2(v2))
|
||||
|
||||
def test_repr_vDDDTypes():
|
||||
assert "vDDDTypes" in repr(vDDDTypes(timedelta(3, 11, 1)))
|
||||
|
|
Ładowanie…
Reference in New Issue