kopia lustrzana https://github.com/collective/icalendar
Merge pull request #575 from niccokunzmann/comparing
Compare test calendars to find components that do not equalpull/576/head
commit
9ce1fa8c8f
|
|
@ -29,6 +29,8 @@ Bug fixes:
|
|||
- Multivalue FREEBUSY property is now parsed properly
|
||||
Ref: #27
|
||||
[jacadzaca]
|
||||
- Compare equality and inequality of calendars more completely
|
||||
Ref: #570
|
||||
- Use non legacy timezone name.
|
||||
Ref: #567
|
||||
- Add some compare functions.
|
||||
|
|
@ -36,7 +38,7 @@ Bug fixes:
|
|||
- Change OSS Fuzz build script to point to harnesses in fuzzing directory
|
||||
Ref: #574
|
||||
|
||||
5.0.10 (unreleased)
|
||||
5.0.10 (2023-09-26)
|
||||
-------------------
|
||||
|
||||
Bug fixes:
|
||||
|
|
@ -92,7 +94,7 @@ Minor changes:
|
|||
|
||||
Minor changes:
|
||||
|
||||
- Added support for BYWEEKDAY in vRecur ref: #268
|
||||
- Added support for BYWEEKDAY in vRecur ref: #268
|
||||
|
||||
Bug fixes:
|
||||
|
||||
|
|
@ -104,7 +106,7 @@ Bug fixes:
|
|||
Minor changes:
|
||||
|
||||
- Improved documentation
|
||||
Ref: #503, #504
|
||||
Ref: #503, #504
|
||||
|
||||
Bug fixes:
|
||||
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ class Component(CaselessDict):
|
|||
return f"{self.name or type(self).__name__}({dict(self)}{', ' + subs if subs else ''})"
|
||||
|
||||
def __eq__(self, other):
|
||||
if not len(self.subcomponents) == len(other.subcomponents):
|
||||
if len(self.subcomponents) != len(other.subcomponents):
|
||||
return False
|
||||
|
||||
properties_equal = super().__eq__(other)
|
||||
|
|
@ -465,7 +465,6 @@ class Component(CaselessDict):
|
|||
|
||||
return True
|
||||
|
||||
|
||||
#######################################
|
||||
# components defined in RFC 5545
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ class CaselessDict(OrderedDict):
|
|||
def __eq__(self, other):
|
||||
return self is other or dict(self.items()) == dict(other.items())
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
# A list of keys that must appear first in sorted_keys and sorted_items;
|
||||
# must be uppercase.
|
||||
canonical_order = None
|
||||
|
|
|
|||
|
|
@ -145,6 +145,10 @@ class vBinary:
|
|||
except UnicodeError:
|
||||
raise ValueError('Not valid base 64 encoding.')
|
||||
|
||||
def __eq__(self, other):
|
||||
"""self == other"""
|
||||
return isinstance(other, vBinary) and self.obj == other.obj
|
||||
|
||||
|
||||
class vBoolean(int):
|
||||
"""Returns specific string according to state.
|
||||
|
|
@ -269,6 +273,7 @@ class vCategory:
|
|||
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])
|
||||
|
|
@ -279,8 +284,24 @@ class vCategory:
|
|||
out = unescape_char(ical).split(',')
|
||||
return out
|
||||
|
||||
def __eq__(self, other):
|
||||
"""self == other"""
|
||||
return isinstance(other, vCategory) and self.cats == other.cats
|
||||
|
||||
class vDDDTypes:
|
||||
class TimeBase:
|
||||
"""Make classes with a datetime/date comparable."""
|
||||
|
||||
def __eq__(self, other):
|
||||
"""self == other"""
|
||||
if isinstance(other, TimeBase):
|
||||
return self.params == other.params and self.dt == other.dt
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.dt)
|
||||
|
||||
|
||||
class vDDDTypes(TimeBase):
|
||||
"""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 +311,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 +341,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 +362,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(TimeBase):
|
||||
"""Render and generates iCalendar date format.
|
||||
"""
|
||||
|
||||
|
|
@ -377,7 +393,7 @@ class vDate:
|
|||
raise ValueError(f'Wrong date format {ical}')
|
||||
|
||||
|
||||
class vDatetime:
|
||||
class vDatetime(TimeBase):
|
||||
"""Render and generates icalendar datetime format.
|
||||
|
||||
vDatetime is timezone aware and uses the pytz library, an implementation of
|
||||
|
|
@ -438,7 +454,7 @@ class vDatetime:
|
|||
raise ValueError(f'Wrong datetime format: {ical}')
|
||||
|
||||
|
||||
class vDuration:
|
||||
class vDuration(TimeBase):
|
||||
"""Subclass of timedelta that renders itself in the iCalendar DURATION
|
||||
format.
|
||||
"""
|
||||
|
|
@ -495,8 +511,12 @@ class vDuration:
|
|||
|
||||
return value
|
||||
|
||||
@property
|
||||
def dt(self):
|
||||
"""The time delta for compatibility."""
|
||||
return self.td
|
||||
|
||||
class vPeriod:
|
||||
class vPeriod(TimeBase):
|
||||
"""A precise period of time.
|
||||
"""
|
||||
|
||||
|
|
@ -520,7 +540,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 +552,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 +583,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.
|
||||
|
|
@ -740,7 +753,7 @@ class vText(str):
|
|||
return cls(ical_unesc)
|
||||
|
||||
|
||||
class vTime:
|
||||
class vTime(TimeBase):
|
||||
"""Render and generates iCalendar time format.
|
||||
"""
|
||||
|
||||
|
|
@ -814,6 +827,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.
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@ SUMMARY:Example calendar with a ': ' in the summary
|
|||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
SUMMARY:Another event with a ': ' in the summary
|
||||
END:VEVENT
|
||||
END:VEVENT
|
||||
|
|
|
|||
|
|
@ -15,10 +15,16 @@ class DataSource:
|
|||
self._parser = parser
|
||||
self._data_source_folder = data_source_folder
|
||||
|
||||
def keys(self):
|
||||
"""Return all the files that could be used."""
|
||||
return [file[:-4] for file in os.listdir(self._data_source_folder) if file.lower().endswith(".ics")]
|
||||
|
||||
def __getattr__(self, attribute):
|
||||
"""Parse a file and return the result stored in the attribute."""
|
||||
source_file = attribute.replace('-', '_') + '.ics'
|
||||
source_path = os.path.join(self._data_source_folder, source_file)
|
||||
if not os.path.isfile(source_path):
|
||||
raise AttributeError(f"{source_path} does not exist.")
|
||||
with open(source_path, 'rb') as f:
|
||||
raw_ics = f.read()
|
||||
source = self._parser(raw_ics)
|
||||
|
|
@ -40,20 +46,23 @@ class DataSource:
|
|||
|
||||
HERE = os.path.dirname(__file__)
|
||||
CALENDARS_FOLDER = os.path.join(HERE, 'calendars')
|
||||
CALENDARS = DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical)
|
||||
TIMEZONES_FOLDER = os.path.join(HERE, 'timezones')
|
||||
TIMEZONES = DataSource(TIMEZONES_FOLDER, icalendar.Timezone.from_ical)
|
||||
EVENTS_FOLDER = os.path.join(HERE, 'events')
|
||||
EVENTS = DataSource(EVENTS_FOLDER, icalendar.Event.from_ical)
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture()
|
||||
def calendars():
|
||||
return DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical)
|
||||
return CALENDARS
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture()
|
||||
def timezones():
|
||||
return DataSource(TIMEZONES_FOLDER, icalendar.Timezone.from_ical)
|
||||
return TIMEZONES
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture()
|
||||
def events():
|
||||
return DataSource(EVENTS_FOLDER, icalendar.Event.from_ical)
|
||||
return EVENTS
|
||||
|
||||
@pytest.fixture(params=[
|
||||
pytz.utc,
|
||||
|
|
@ -71,3 +80,19 @@ def utc(request):
|
|||
])
|
||||
def in_timezone(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=[
|
||||
(data, key)
|
||||
for data in [CALENDARS, TIMEZONES, EVENTS]
|
||||
for key in data.keys() if key not in
|
||||
( # exclude broken calendars here
|
||||
"big_bad_calendar", "issue_104_broken_calendar", "small_bad_calendar",
|
||||
"multiple_calendar_components", "pr_480_summary_with_colon"
|
||||
)
|
||||
])
|
||||
def ics_file(request):
|
||||
"""An example ICS file."""
|
||||
data, key = request.param
|
||||
print(key)
|
||||
return data[key]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
"""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_if_parsed_again(ics_file):
|
||||
"""Ensure that a calendar equals the same calendar."""
|
||||
copy_of_calendar = ics_file.__class__.from_ical(ics_file.to_ical())
|
||||
assert copy_of_calendar == ics_file
|
||||
assert not copy_of_calendar != ics_file
|
||||
|
||||
|
||||
def test_parsed_calendars_are_equal_if_from_same_source(ics_file):
|
||||
"""Ensure that a calendar equals the same calendar."""
|
||||
cal1 = ics_file.__class__.from_ical(ics_file.raw_ics)
|
||||
cal2 = ics_file.__class__.from_ical(ics_file.raw_ics)
|
||||
assert cal1 == cal2
|
||||
assert not cal1 != cal2
|
||||
|
||||
|
||||
def test_copies_are_equal(ics_file):
|
||||
"""Ensure that copies are equal."""
|
||||
copy1 = ics_file.copy(); copy1.subcomponents = ics_file.subcomponents
|
||||
copy2 = ics_file.copy(); copy2.subcomponents = ics_file.subcomponents[:]
|
||||
assert copy1 == copy2
|
||||
assert copy1 == ics_file
|
||||
assert copy2 == ics_file
|
||||
assert not copy1 != copy2
|
||||
assert not copy1 != ics_file
|
||||
assert not copy2 != ics_file
|
||||
|
||||
|
||||
def test_copy_does_not_copy_subcomponents(calendars):
|
||||
"""If we copy the subcomponents, assumptions around copies will be broken."""
|
||||
assert calendars.timezoned.subcomponents
|
||||
assert not calendars.timezoned.copy().subcomponents
|
||||
|
||||
|
||||
def test_deep_copies_are_equal(ics_file):
|
||||
"""Ensure that deep copies are equal."""
|
||||
try:
|
||||
assert copy.deepcopy(ics_file) == copy.deepcopy(ics_file)
|
||||
assert copy.deepcopy(ics_file) == ics_file
|
||||
assert not copy.deepcopy(ics_file) != copy.deepcopy(ics_file)
|
||||
assert not copy.deepcopy(ics_file) != ics_file
|
||||
except pytz.UnknownTimeZoneError:
|
||||
# Ignore errors when a custom time zone is used.
|
||||
# This is still covered by the parsing test.
|
||||
pass
|
||||
|
||||
|
||||
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"])
|
||||
|
||||
|
||||
def test_vText():
|
||||
assert vText("HELLO") == vText("HELLO")
|
||||
assert not vText("HELLO") != vText("HELLO")
|
||||
assert vText("HELLO1") != vText("HELLO")
|
||||
assert not vText("HELLO1") == vText("HELLO")
|
||||
|
||||
|
||||
@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))),
|
||||
(vTime, time(10, 10, 10), time(10, 10, 11)),
|
||||
]
|
||||
)
|
||||
@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))
|
||||
assert not 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)))
|
||||
|
||||
|
||||
vDDDLists_examples = [
|
||||
vDDDLists([]),
|
||||
vDDDLists([datetime(2023, 11, 1, 10, 1)]),
|
||||
vDDDLists([datetime(2023, 11, 1, 10, 1), date(2023, 11, 1)]),
|
||||
]
|
||||
@pytest.mark.parametrize("l1", vDDDLists_examples)
|
||||
@pytest.mark.parametrize("l2", vDDDLists_examples)
|
||||
def test_vDDDLists(l1, l2):
|
||||
"""Check the equality functions of vDDDLists."""
|
||||
equal = l1 is l2
|
||||
l2 = copy.deepcopy(l2)
|
||||
assert equal == (l1 == l2)
|
||||
assert equal != (l1 != l2)
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
'''tests ensuring that *the* way of doing things works'''
|
||||
|
||||
import datetime
|
||||
|
||||
from icalendar import Calendar, Event
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_creating_calendar_with_unicode_fields(calendars, utc):
|
||||
''' create a calendar with events that contain unicode characters in their fields '''
|
||||
cal = Calendar()
|
||||
|
|
@ -38,4 +37,3 @@ def test_creating_calendar_with_unicode_fields(calendars, utc):
|
|||
cal.add_component(event2)
|
||||
|
||||
assert cal.to_ical() == calendars.created_calendar_with_unicode_fields.raw_ics
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class TestTime(unittest.TestCase):
|
|||
|
||||
def test_create_from_ical(self):
|
||||
directory = os.path.dirname(__file__)
|
||||
ics = open(os.path.join(directory, 'time.ics'), 'rb')
|
||||
ics = open(os.path.join(directory, 'calendars', 'time.ics'), 'rb')
|
||||
cal = icalendar.Calendar.from_ical(ics.read())
|
||||
ics.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ try:
|
|||
except:
|
||||
from backports import zoneinfo
|
||||
|
||||
HERE = os.path.dirname(__file__)
|
||||
CALENDARS_DIRECTORY = os.path.join(HERE, 'calendars')
|
||||
|
||||
class TestTimezoned(unittest.TestCase):
|
||||
|
||||
def test_create_from_ical_zoneinfo(self):
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'timezoned.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'timezoned.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
|
||||
|
|
@ -46,8 +48,7 @@ class TestTimezoned(unittest.TestCase):
|
|||
)
|
||||
|
||||
def test_create_from_ical_pytz(self):
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'timezoned.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'timezoned.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
|
||||
|
|
@ -269,9 +270,7 @@ class TestTimezoneCreation(unittest.TestCase):
|
|||
def test_create_america_new_york(self):
|
||||
"""testing America/New_York, the most complex example from the
|
||||
RFC"""
|
||||
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'america_new_york.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'america_new_york.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
|
||||
|
|
@ -307,8 +306,7 @@ class TestTimezoneCreation(unittest.TestCase):
|
|||
one RDATE property per subcomponent"""
|
||||
self.maxDiff = None
|
||||
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'pacific_fiji.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'pacific_fiji.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
|
||||
|
|
@ -442,8 +440,7 @@ class TestTimezoneCreation(unittest.TestCase):
|
|||
def test_same_start_date(self):
|
||||
"""testing if we can handle VTIMEZONEs whose different components
|
||||
have the same start DTIMEs."""
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'timezone_same_start.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'timezone_same_start.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
d = cal.subcomponents[1]['DTSTART'].dt
|
||||
|
|
@ -452,8 +449,7 @@ class TestTimezoneCreation(unittest.TestCase):
|
|||
def test_same_start_date_and_offset(self):
|
||||
"""testing if we can handle VTIMEZONEs whose different components
|
||||
have the same DTSTARTs, TZOFFSETFROM, and TZOFFSETTO."""
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'timezone_same_start_and_offset.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'timezone_same_start_and_offset.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
d = cal.subcomponents[1]['DTSTART'].dt
|
||||
|
|
@ -462,8 +458,7 @@ class TestTimezoneCreation(unittest.TestCase):
|
|||
def test_rdate(self):
|
||||
"""testing if we can handle VTIMEZONEs who only have an RDATE, not RRULE
|
||||
"""
|
||||
directory = os.path.dirname(__file__)
|
||||
with open(os.path.join(directory, 'timezone_rdate.ics'), 'rb') as fp:
|
||||
with open(os.path.join(CALENDARS_DIRECTORY, 'timezone_rdate.ics'), 'rb') as fp:
|
||||
data = fp.read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
vevent = cal.walk('VEVENT')[0]
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue