[CalendarServer-changes] [7162] CalendarServer/branches/users/cdaboo/pycalendar
source_changes at macosforge.org
source_changes at macosforge.org
Tue Mar 8 19:41:35 PST 2011
Revision: 7162
http://trac.macosforge.org/projects/calendarserver/changeset/7162
Author: cdaboo at apple.com
Date: 2011-03-08 19:41:33 -0800 (Tue, 08 Mar 2011)
Log Message:
-----------
Snapshot of pycalendar work - passes all unit tests and CDT (on branch).
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/purge.py
CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge.py
CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge_old_events.py
CalendarServer/branches/users/cdaboo/pycalendar/contrib/tools/dtraceanalyze.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/caldavxml.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/customxml.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/calendardata.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_calendardata.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_privateevents.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/dateops.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/freebusyurl.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/ical.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/instance.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/localization.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/mail.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/put_common.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/report_common.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarquery.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarqueryfilter.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/expression.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/sqlgenerator.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_calendarquery.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_queryfilter.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/icaldiff.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/implicit.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/itip.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/processing.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/scheduler.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_icaldiff.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_implicit.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_itip.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/sharing.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_icalendar.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_localization.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_mail.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_multiget.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_timezones.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_upgrade.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_validation.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezones.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezoneservice.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/sql.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/util.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/icalendarstore.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql.py
CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql_legacy.py
Added Paths:
-----------
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_caldavxml.py
CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_customxml.py
Modified: CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/purge.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/purge.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -19,11 +19,8 @@
import os
import sys
-from datetime import date, timedelta, datetime
from getopt import getopt, GetoptError
-from vobject.icalendar import utc
-
from twisted.application.service import Service
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue
@@ -44,6 +41,7 @@
from calendarserver.tap.util import getRootResource
from calendarserver.tools.principals import removeProxy
from calendarserver.tools.util import loadConfig
+from pycalendar.datetime import PyCalendarDateTime
log = Logger()
@@ -270,7 +268,10 @@
if dryrun:
verbose = True
- cutoff = (date.today()-timedelta(days=days)).strftime("%Y%m%dT000000Z")
+ cutoff = PyCalendarDateTime.getToday()
+ cutoff.setDateOnly(False)
+ cutoff.offsetDay(-days)
+ cutoff = cutoff.getText()
PurgeOldEventsService.cutoff = cutoff
PurgeOldEventsService.batchSize = batchSize
PurgeOldEventsService.dryrun = dryrun
@@ -531,7 +532,7 @@
@type event: L{twistedcaldav.ical.Component}
@param when: the cutoff date (anything after which is removed)
- @type when: datetime with tzinfo
+ @type when: PyCalendarDateTime
@param cua: Calendar User Address of principal being purged, to compare
to see if it's the organizer of the event or just an attendee
@@ -542,7 +543,8 @@
@return: one of the 4 constants above to indicate what action to take
"""
- whenDate = when.date()
+ whenDate = when.duplicate()
+ whenDate.setDateOnly(True)
master = event.masterComponent()
@@ -552,14 +554,9 @@
# Anything completely in the future is deleted
dtstart = master.getStartDateUTC()
- if isinstance(dtstart, datetime):
- isDateTime = True
- if dtstart > when:
- return CANCELEVENT_SHOULD_DELETE
- else:
- isDateTime = False
- if dtstart > whenDate:
- return CANCELEVENT_SHOULD_DELETE
+ isDateTime = not dtstart.isDateOnly()
+ if dtstart > when:
+ return CANCELEVENT_SHOULD_DELETE
organizer = master.getOrganizer()
@@ -579,19 +576,15 @@
# Set the UNTIL on RRULE to cease at the cutoff
if master.hasProperty("RRULE"):
for rrule in master.properties("RRULE"):
- tokens = {}
- tokens.update([valuePart.split("=") for valuePart in rrule.value().split(";")])
- if tokens.has_key("COUNT"):
- dirty = True
- del tokens["COUNT"]
+ rrule = rrule.value()
+ if rrule.getUseCount():
+ rrule.setUseCount(False)
+ rrule.setUseUntil(True)
if isDateTime:
- tokens["UNTIL"] = when.strftime("%Y%m%dT%H%M%SZ")
+ rrule.setUntil(when)
else:
- tokens["UNTIL"] = when.strftime("%Y%m%d")
-
- newValue = ";".join(["%s=%s" % (key, value,) for key, value in tokens.iteritems()])
- rrule.setValue(newValue)
+ rrule.setUntil(whenDate)
dirty = True
# Remove any EXDATEs and RDATEs beyond the cutoff
@@ -600,18 +593,14 @@
for exdate_rdate in master.properties(dateType):
newValues = []
for value in exdate_rdate.value():
- if isinstance(value, datetime):
- if value < when:
- newValues.append(value)
+ if value.getValue() < when:
+ newValues.append(value)
else:
- if value < whenDate:
- newValues.append(value)
+ exdate_rdate.value().remove(value)
+ dirty = True
if not newValues:
master.removeProperty(exdate_rdate)
dirty = True
- else:
- exdate_rdate.setValue(newValues)
- dirty = True
# Remove any overridden components beyond the cutoff
@@ -619,12 +608,8 @@
if component.name() == "VEVENT":
dtstart = component.getStartDateUTC()
remove = False
- if isinstance(dtstart, datetime):
- if dtstart > when:
- remove = True
- else:
- if dtstart > whenDate:
- remove = True
+ if dtstart > when:
+ remove = True
if remove:
event.removeComponent(component)
dirty = True
@@ -640,8 +625,7 @@
when=None):
if when is None:
- when = datetime.now(tz=utc)
- # when = datetime(2010, 12, 6, 12, 0, 0, 0, utc)
+ when = PyCalendarDateTime.getNowUTC()
# Does the record exist?
record = directory.recordWithGUID(guid)
@@ -671,7 +655,7 @@
calendarHome = yield principal.calendarHome(request)
# Anything in the past is left alone
- whenString = when.strftime("%Y%m%dT%H%M%SZ")
+ whenString = when.getText()
filter = caldavxml.Filter(
caldavxml.ComponentFilter(
caldavxml.ComponentFilter(
Modified: CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -15,20 +15,26 @@
##
-from twistedcaldav.ical import Component
from calendarserver.tools.purge import cancelEvent
from calendarserver.tools.purge import CANCELEVENT_MODIFIED, CANCELEVENT_SHOULD_DELETE
-from vobject.icalendar import utc
-from datetime import datetime, timedelta
+from twistedcaldav.ical import Component
from twistedcaldav.test.util import TestCase
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
-future = (datetime.utcnow() + timedelta(days=1)).strftime("%Y%m%dT%H%M%SZ")
-past = (datetime.utcnow() - timedelta(days=1)).strftime("%Y%m%dT%H%M%SZ")
+future = PyCalendarDateTime.getNowUTC()
+future.offsetDay(1)
+future = future.getText()
+
+past = PyCalendarDateTime.getNowUTC()
+past.offsetDay(-1)
+past = past.getText()
+
# For test_purgeExistingGUID
# No organizer/attendee
@@ -218,7 +224,7 @@
def test_cancelRepeating(self):
# A repeating event where purged CUA is organizer
event = Component.fromString(REPEATING_1_ICS_BEFORE)
- action = cancelEvent(event, datetime(2010, 12, 6, 12, 0, 0, 0, utc),
+ action = cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
"urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1")
self.assertEquals(action, CANCELEVENT_MODIFIED)
self.assertEquals(str(event), REPEATING_1_ICS_AFTER)
@@ -226,7 +232,7 @@
def test_cancelAllDayRepeating(self):
# A repeating All Day event where purged CUA is organizer
event = Component.fromString(REPEATING_2_ICS_BEFORE)
- action = cancelEvent(event, datetime(2010, 12, 6, 12, 0, 0, 0, utc),
+ action = cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
"urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1")
self.assertEquals(action, CANCELEVENT_MODIFIED)
self.assertEquals(str(event), REPEATING_2_ICS_AFTER)
@@ -234,21 +240,21 @@
def test_cancelFutureEvent(self):
# A future event
event = Component.fromString(FUTURE_EVENT_ICS)
- action = cancelEvent(event, datetime(2010, 12, 6, 12, 0, 0, 0, utc),
+ action = cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
"urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1")
self.assertEquals(action, CANCELEVENT_SHOULD_DELETE)
def test_cancelNonMeeting(self):
# A repeating non-meeting event
event = Component.fromString(REPEATING_NON_MEETING_ICS)
- action = cancelEvent(event, datetime(2010, 12, 6, 12, 0, 0, 0, utc),
+ action = cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
"urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1")
self.assertEquals(action, CANCELEVENT_SHOULD_DELETE)
def test_cancelAsAttendee(self):
# A repeating meeting event where purged CUA is an attendee
event = Component.fromString(REPEATING_ATTENDEE_MEETING_ICS)
- action = cancelEvent(event, datetime(2010, 12, 6, 12, 0, 0, 0, utc),
+ action = cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
"urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1")
self.assertEquals(action, CANCELEVENT_SHOULD_DELETE)
@@ -263,20 +269,20 @@
PRODID:-//Apple Inc.//iCal 4.0.4//EN
BEGIN:VTIMEZONE
TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:59E260E3-1644-4BDF-BBC6-6130B0C3A520
@@ -337,20 +343,20 @@
PRODID:-//Apple Inc.//iCal 4.0.4//EN
BEGIN:VTIMEZONE
TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:59E260E3-1644-4BDF-BBC6-6130B0C3A520
@@ -498,20 +504,20 @@
PRODID:-//Apple Inc.//iCal 4.0.4//EN
BEGIN:VTIMEZONE
TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:97B243D3-D252-4034-AA6D-9AE34E063991
@@ -532,20 +538,20 @@
PRODID:-//Apple Inc.//iCal 4.0.4//EN
BEGIN:VTIMEZONE
TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:4E4D0C8C-6546-4777-9BF5-AD629C05E7D5
@@ -567,20 +573,20 @@
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VTIMEZONE
TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:111A679F-EF8E-4CA5-9262-7C805E2C184D
Modified: CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge_old_events.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge_old_events.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/calendarserver/tools/test/test_purge_old_events.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -17,23 +17,23 @@
"""
Tests for calendarserver.tools.purge
"""
+from calendarserver.tap.util import getRootResource
+from calendarserver.tools.purge import purgeOldEvents, purgeGUID, purgeOrphanedAttachments
-from twisted.trial import unittest
-from twisted.internet.defer import inlineCallbacks, returnValue
from twext.web2.http_headers import MimeType
-from twistedcaldav.vcard import Component as VCardComponent
+from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.trial import unittest
+from twistedcaldav.config import config
+from twistedcaldav.memcacher import Memcacher
+from twistedcaldav.vcard import Component as VCardComponent
from txdav.common.datastore.test.util import buildStore, populateCalendarsFrom, CommonCommonTests
-from calendarserver.tap.util import getRootResource
-from calendarserver.tools.purge import purgeOldEvents, purgeGUID, purgeOrphanedAttachments
-from twistedcaldav.config import config
-from twistedcaldav.memcacher import Memcacher
-from vobject.icalendar import utc
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
-import datetime
import os
@@ -384,7 +384,7 @@
@inlineCallbacks
def test_eventsOlderThan(self):
- cutoff = datetime.datetime(2010, 4, 1)
+ cutoff = PyCalendarDateTime(2010, 4, 1, 0, 0, 0)
txn = self._sqlCalendarStore.newTransaction()
# Query for all old events
@@ -410,7 +410,7 @@
@inlineCallbacks
def test_removeOldEvents(self):
- cutoff = datetime.datetime(2010, 4, 1)
+ cutoff = PyCalendarDateTime(2010, 4, 1, 0, 0, 0)
txn = self._sqlCalendarStore.newTransaction()
# Remove oldest event
@@ -473,7 +473,7 @@
self.assertTrue(os.path.exists(attachmentPath))
# Delete all old events (including the event containing the attachment)
- cutoff = datetime.datetime(2010, 4, 1)
+ cutoff = PyCalendarDateTime(2010, 4, 1, 0, 0, 0)
count = (yield txn.removeOldEvents(cutoff))
# Just look for orphaned attachments but don't delete
@@ -499,18 +499,18 @@
# Dry run
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, datetime.datetime(2010, 4, 1), 2, dryrun=True,
+ self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, dryrun=True,
verbose=False))
self.assertEquals(total, 4)
# Actually remove
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, datetime.datetime(2010, 4, 1), 2, verbose=False))
+ self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, verbose=False))
self.assertEquals(total, 4)
# There should be no more left
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, datetime.datetime(2010, 4, 1), 2, verbose=False))
+ self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, verbose=False))
self.assertEquals(total, 0)
test_purgeOldEvents.todo = "New lazy indexing broke this"
@@ -537,7 +537,7 @@
# Purge home1
total, ignored = (yield purgeGUID("home1", self.directory,
self.rootResource, verbose=False, proxies=False,
- when=datetime.datetime(2010, 4, 1, 12, 0, 0, 0, utc)))
+ when=PyCalendarDateTime(2010, 4, 1, 12, 0, 0, 0, PyCalendarTimezone(utc=True))))
# 2 items deleted: 1 event and 1 vcard
self.assertEquals(total, 2)
@@ -555,7 +555,7 @@
# Remove old events first
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, datetime.datetime(2010, 4, 1), 2, verbose=False))
+ self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, verbose=False))
self.assertEquals(total, 4)
# Dry run
Modified: CalendarServer/branches/users/cdaboo/pycalendar/contrib/tools/dtraceanalyze.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/contrib/tools/dtraceanalyze.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/contrib/tools/dtraceanalyze.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -31,8 +31,10 @@
prefix_maps = {
"/usr/share/caldavd/lib/python/": "{caldavd}/",
+ "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.6": "{Python}",
"/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6": "{Python}",
"/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5": "{Python}",
+ "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python": "{Extras}",
"/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python": "{Extras}",
"/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python": "{Extras}",
}
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/caldavxml.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/caldavxml.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-from pycalendar.datetime import PyCalendarDateTime
"""
CalDAV XML Support.
@@ -26,10 +25,8 @@
See draft spec: http://ietf.webdav.org/caldav/draft-dusseault-caldav.txt
"""
-import datetime
+from pycalendar.datetime import PyCalendarDateTime
-from vobject.icalendar import utc, TimezoneComponent
-
from twext.web2.dav import davxml
from twext.python.log import Logger
@@ -103,16 +100,16 @@
@return: True if valid, False otherwise
"""
- if self.start is not None and not isinstance(self.start, datetime.datetime):
+ if self.start is not None and self.start.isDateOnly():
log.msg("start attribute in <time-range> is not a date-time: %s" % (self.start,))
return False
- if self.end is not None and not isinstance(self.end, datetime.datetime):
+ if self.end is not None and self.end.isDateOnly():
log.msg("end attribute in <time-range> is not a date-time: %s" % (self.end,))
return False
- if self.start is not None and self.start.tzinfo != utc:
+ if self.start is not None and not self.start.utc():
log.msg("start attribute in <time-range> is not UTC: %s" % (self.start,))
return False
- if self.end is not None and self.end.tzinfo != utc:
+ if self.end is not None and not self.end.utc():
log.msg("end attribute in <time-range> is not UTC: %s" % (self.end,))
return False
@@ -148,10 +145,7 @@
found = False
for subcomponent in calendar.subcomponents():
- if (
- subcomponent.name() == "VTIMEZONE" and
- isinstance(subcomponent._vobject, TimezoneComponent)
- ):
+ if (subcomponent.name() == "VTIMEZONE"):
if found:
return False
else:
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/customxml.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/customxml.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -31,11 +31,8 @@
from twistedcaldav import caldavxml, carddavxml
from twistedcaldav.ical import Component as iComponent
-from vobject.icalendar import utc
-from vobject.icalendar import dateTimeToString
+from pycalendar.datetime import PyCalendarDateTime
-import datetime
-
calendarserver_namespace = "http://calendarserver.org/ns/"
calendarserver_proxy_compliance = (
@@ -512,7 +509,7 @@
def __init__(self, *children):
super(DTStamp, self).__init__(children)
- self.children = (davxml.PCDATAElement(dateTimeToString(datetime.datetime.now(tz=utc))),)
+ self.children = (davxml.PCDATAElement(PyCalendarDateTime.getNowUTC().getText()),)
class Action (davxml.WebDAVElement):
"""
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/calendardata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/calendardata.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/calendardata.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -19,6 +19,7 @@
from twistedcaldav.datafilters.filter import CalendarFilter
from twistedcaldav.dateops import clipPeriod
from twistedcaldav.ical import Component
+from pycalendar.period import PyCalendarPeriod
__all__ = [
"CalendarDataFilter",
@@ -156,7 +157,7 @@
for property in component.properties("FREEBUSY"):
newvalue = []
for period in property.value():
- clipped = clipPeriod(period, (self.calendardata.freebusy_set.start, self.calendardata.freebusy_set.end))
+ clipped = clipPeriod(period.getValue(), PyCalendarPeriod(self.calendardata.freebusy_set.start, self.calendardata.freebusy_set.end))
if clipped:
newvalue.append(clipped)
if len(newvalue):
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_calendardata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_calendardata.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_calendardata.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -94,8 +94,6 @@
""".replace("\n", "\r\n")
result = """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//PYVOBJECT//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_privateevents.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_privateevents.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/datafilters/test/test_privateevents.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -66,6 +66,7 @@
data = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:PUBLIC
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
@@ -74,7 +75,6 @@
ATTENDEE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
END:VEVENT
-X-CALENDARSERVER-ACCESS:PUBLIC
END:VCALENDAR
""".replace("\n", "\r\n")
@@ -87,6 +87,7 @@
data = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:PRIVATE
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
@@ -95,7 +96,6 @@
ATTENDEE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
END:VEVENT
-X-CALENDARSERVER-ACCESS:PRIVATE
END:VCALENDAR
""".replace("\n", "\r\n")
@@ -109,6 +109,7 @@
data = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:CONFIDENTIAL
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
@@ -120,19 +121,18 @@
ORGANIZER;CN=User 01:mailto:user1 at example.com
SUMMARY:Confidential
END:VEVENT
-X-CALENDARSERVER-ACCESS:CONFIDENTIAL
END:VCALENDAR
""".replace("\n", "\r\n")
filtered = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:CONFIDENTIAL
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
END:VEVENT
-X-CALENDARSERVER-ACCESS:CONFIDENTIAL
END:VCALENDAR
""".replace("\n", "\r\n")
@@ -145,6 +145,7 @@
data = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:RESTRICTED
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
@@ -156,13 +157,13 @@
ORGANIZER;CN=User 01:mailto:user1 at example.com
SUMMARY:Confidential
END:VEVENT
-X-CALENDARSERVER-ACCESS:RESTRICTED
END:VCALENDAR
""".replace("\n", "\r\n")
filtered = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:RESTRICTED
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
@@ -170,7 +171,6 @@
LOCATION:My office
SUMMARY:Confidential
END:VEVENT
-X-CALENDARSERVER-ACCESS:RESTRICTED
END:VCALENDAR
""".replace("\n", "\r\n")
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/dateops.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/dateops.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/dateops.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -44,13 +44,13 @@
@return: the normalized PyCalendarDateTime
"""
if not isinstance(dt, PyCalendarDateTime):
- raise TypeError("%r is not a removeParameterValue instance" % (dt,))
+ raise TypeError("%r is not a PyCalendarDateTime instance" % (dt,))
dt = dt.duplicate()
if dt.isDateOnly():
dt.setDateOnly(False)
dt.setHHMMSS(0, 0, 0)
- dt.setTimezoneUTC(True)
+ dt.setTimezoneID(None) # Keep it floating
return dt
elif dt.floating():
return dt
@@ -123,10 +123,10 @@
def timeRangesOverlap(start1, end1, start2, end2, defaulttz = None):
# Can't compare date-time and date only, so normalize
# to date only if they are mixed.
- if not start1.isDateOnly() and (start2 is not None) and start2.isDateOnly(): start1 = start1.setDateOnly(True)
- if not start2.isDateOnly() and (start1 is not None) and start1.isDateOnly(): start2 = start2.setDateOnly(True)
- if not end1.isDateOnly() and (end2 is not None) and end2.isDateOnly(): end1 = end1.setDateOnly(True)
- if not end2.isDateOnly() and (end1 is not None) and end1.isDateOnly(): end2 = end2.setDateOnly(True)
+ if (start1 is not None) and not start1.isDateOnly() and (start2 is not None) and start2.isDateOnly(): start1 = start1.setDateOnly(True)
+ if (start2 is not None) and not start2.isDateOnly() and (start1 is not None) and start1.isDateOnly(): start2 = start2.setDateOnly(True)
+ if (end1 is not None) and not end1.isDateOnly() and (end2 is not None) and end2.isDateOnly(): end1 = end1.setDateOnly(True)
+ if (end2 is not None) and not end2.isDateOnly() and (end1 is not None) and end1.isDateOnly(): end2 = end2.setDateOnly(True)
# Note that start times are inclusive and end times are not.
if start1 is not None and start2 is not None:
@@ -149,15 +149,14 @@
"""
Normalize the list of periods by merging overlapping or consecutive ranges
and sorting the list by each periods start.
- @param list: a list of tuples of L{datetime.datetime} pairs. The list is changed in place.
+ @param list: a list of tuples of L{PyCalendarPeriod}. The list is changed in place.
"""
# First sort the list
def sortPeriods(p1, p2):
"""
Compare two periods. Sort by their start and then end times.
- A period is a tuple consisting of a pair of L{datetime.datetime}'s, or one
- L{datetime.datetime} and one L{datetime.timedelta}.
+ A period is a L{PyCalendarPeriod}.
@param p1: first period
@param p2: second period
@return: 1 if p1>p2, 0 if p1==p2, -1 if p1<p2
@@ -176,6 +175,8 @@
return compareDateTime(cmp1, cmp2)
+ for period in periods:
+ period.adjustToUTC()
periods.sort(cmp=sortPeriods)
# Now merge overlaps and consecutive periods
@@ -191,7 +192,7 @@
ie = periods[i].getEnd()
if (pe >= periods[i].getStart()):
if ie > pe:
- periods[index] = (periods[index].getStart(), ie)
+ periods[index] = PyCalendarPeriod(periods[index].getStart(), ie)
pe = ie
periods[i] = None
else:
@@ -227,6 +228,21 @@
result.setUseDuration(period.getUseDuration())
return result
+def pyCalendarTodatetime(pydt):
+
+ if pydt.isDateOnly():
+ return datetime.date(year=pydt.getYear(), month=pydt.getMonth(), day=pydt.getDay())
+ else:
+ return datetime.datetime(
+ year=pydt.getYear(),
+ month=pydt.getMonth(),
+ day=pydt.getDay(),
+ hour=pydt.getHours(),
+ minute=pydt.getMinutes(),
+ second=pydt.getSeconds(),
+ tzinfo=utc
+ )
+
def parseSQLTimestamp(ts):
# Handle case where fraction seconds may not be present
@@ -234,6 +250,18 @@
ts += ".0"
return datetime.datetime.strptime(ts, "%Y-%m-%d %H:%M:%S.%f")
+def parseSQLTimestampToPyCalendar(ts):
+ """
+ Parse an SQL formated timestamp into a PyCalendarDateTime
+ @param ts: the SQL timestamp
+ @type ts: C{str}
+
+ @return: L{PyCalendarDateTime} result
+ """
+
+ dt = datetime.datetime.strptime(ts[:19], "%Y-%m-%d %H:%M:%S")
+ return PyCalendarDateTime(year=dt.year, month=dt.month, day=dt.day, hours=dt.hour, minutes=dt.minute, seconds=dt.second)
+
def datetimeMktime(dt):
assert isinstance(dt, datetime.date)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/freebusyurl.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/freebusyurl.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/freebusyurl.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -22,10 +22,6 @@
"FreeBusyURLResource",
]
-import datetime
-
-from vobject.icalendar import utc
-
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twext.python.log import Logger
@@ -44,14 +40,15 @@
from twistedcaldav.config import config
from twistedcaldav.customxml import calendarserver_namespace
from twistedcaldav.ical import Property
-from twistedcaldav.ical import parse_datetime
-from twistedcaldav.ical import parse_duration
from twistedcaldav.resource import CalDAVResource, ReadOnlyNoCopyResourceMixIn
from twistedcaldav.schedule import deliverSchedulePrivilegeSet
from twistedcaldav.scheduling.caldav import ScheduleViaCalDAV
from twistedcaldav.scheduling.cuaddress import LocalCalendarUser
from twistedcaldav.scheduling.scheduler import Scheduler
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.duration import PyCalendarDuration
+
log = Logger()
@@ -179,15 +176,15 @@
# Start/end/duration must be valid iCalendar DATE-TIME UTC or DURATION values
try:
if self.start:
- self.start = parse_datetime(self.start)
- if self.start.tzinfo != utc:
+ self.start = PyCalendarDateTime.parseText(self.start)
+ if not self.start.utc():
raise ValueError()
if self.end:
- self.end = parse_datetime(self.end)
- if self.end.tzinfo != utc:
+ self.end = PyCalendarDateTime.parseText(self.end)
+ if not self.end.utc():
raise ValueError()
if self.duration:
- self.duration = parse_duration(self.duration)
+ self.duration = PyCalendarDuration.parseText(self.duration)
except ValueError:
raise HTTPError(ErrorResponse(
responsecode.BAD_REQUEST,
@@ -204,7 +201,7 @@
))
# Duration must be positive
- if self.duration and self.duration.days < 0:
+ if self.duration and self.duration.getTotalSeconds() < 0:
raise HTTPError(ErrorResponse(
responsecode.BAD_REQUEST,
(calendarserver_namespace, "valid-query-parameters")
@@ -212,12 +209,12 @@
# Now fill in the missing pieces
if self.start is None:
- now = datetime.datetime.now()
- self.start = now.replace(hour=0, minute=0, second=0, tzinfo=utc)
+ self.start = PyCalendarDateTime.getNowUTC()
+ self.start.setHHMMSS(0, 0, 0)
if self.duration:
self.end = self.start + self.duration
if self.end is None:
- self.end = self.start + datetime.timedelta(days=config.FreeBusyURL.TimePeriod)
+ self.end = self.start + PyCalendarDuration(days=config.FreeBusyURL.TimePeriod)
# End > start
if self.end <= self.start:
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/ical.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/ical.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/ical.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -14,15 +14,6 @@
# limitations under the License.
##
-from pycalendar import definitions
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.calendar import PyCalendar
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.property import PyCalendarProperty
-from pycalendar.timezone import PyCalendarTimezone
"""
iCalendar Utilities
@@ -38,6 +29,7 @@
]
import cStringIO as StringIO
+import codecs
import heapq
import itertools
@@ -49,6 +41,17 @@
from twistedcaldav.instance import InstanceList
from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
+from pycalendar import definitions
+from pycalendar.attribute import PyCalendarAttribute
+from pycalendar.calendar import PyCalendar
+from pycalendar.componentbase import PyCalendarComponentBase
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.duration import PyCalendarDuration
+from pycalendar.exceptions import PyCalendarInvalidData
+from pycalendar.period import PyCalendarPeriod
+from pycalendar.property import PyCalendarProperty
+from pycalendar.timezone import PyCalendarTimezone
+from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
log = Logger()
@@ -188,23 +191,23 @@
def name (self): return self._pycalendar.getName()
def value (self): return self._pycalendar.getValue().getValue()
+
+ def strvalue (self): return str(self._pycalendar.getValue())
+
def setValue(self, value):
self._pycalendar.setValue(value)
- def params(self):
+ def parameterNames(self):
"""
- Returns a mapping object containing parameters for this property.
-
- Keys are parameter names, values are sequences containing
- values for the named parameter.
+ Returns a set containing parameter names for this property.
"""
- result = {}
+ result = set()
for pyattrlist in self._pycalendar.getAttributes().values():
for pyattr in pyattrlist:
- result.setdefault(pyattr.getName(), []).extend(pyattr.getValues())
+ result.add(pyattr.getName())
return result
- def paramValue(self, name):
+ def parameterValue(self, name, default=None):
"""
Returns a single value for the given parameter. Raises
InvalidICalendarDataError if the parameter has more than one value.
@@ -212,14 +215,20 @@
try:
return self._pycalendar.getAttributeValue(name)
except KeyError:
- return None
+ return default
+ def hasParameter(self, paramname):
+ return self._pycalendar.hasAttribute(paramname)
+
def setParameter(self, paramname, paramvalue):
self._pycalendar.replaceAttribute(PyCalendarAttribute(paramname, paramvalue))
def removeParameter(self, paramname):
self._pycalendar.removeAttributes(paramname)
+ def removeAllParameters(self):
+ self._pycalendar.setAttributes({})
+
def removeParameterValue(self, paramname, paramvalue):
for attr in tuple(self._pycalendar.getAttributes()):
@@ -235,11 +244,9 @@
start/end period.
The only properties allowed for this query are: COMPLETED, CREATED, DTSTAMP and
LAST-MODIFIED (caldav -09).
- @param start: a L{datetime.datetime} or L{datetime.date} specifying the
- beginning of the given time span.
- @param end: a L{datetime.datetime} or L{datetime.date} specifying the
- end of the given time span. C{end} may be None, indicating that
- there is no end date.
+ @param start: a L{PyCalendarDateTime} specifying the beginning of the given time span.
+ @param end: a L{PyCalendarDateTime} specifying the end of the given time span.
+ C{end} may be None, indicating that there is no end date.
@param defaulttz: the default L{PyTimezone} to use in datetime comparisons.
@return: True if the property's date/date-time value is within the given time range,
False if not, or the property is not an appropriate date/date-time value.
@@ -251,7 +258,7 @@
return False
# get date/date-time value
- dt = self.getDateTimeValue().getValue()
+ dt = self._pycalendar.getValue().getValue()
assert isinstance(dt, PyCalendarDateTime), "Not a date/date-time value: %r" % (self,)
return timeRangesOverlap(dt, None, start, end, defaulttz)
@@ -296,6 +303,14 @@
"""
if type(string) is unicode:
string = string.encode("utf-8")
+ else:
+ # Valid utf-8 please
+ string.decode("utf-8")
+
+ # No BOMs please
+ if string[:3] == codecs.BOM_UTF8:
+ string = string[3:]
+
return clazz.fromStream(StringIO.StringIO(string))
@classmethod
@@ -307,7 +322,10 @@
C{stream}.
"""
cal = PyCalendar()
- result = cal.parse(stream)
+ try:
+ result = cal.parse(stream)
+ except PyCalendarInvalidData:
+ result = None
if not result:
stream.seek(0)
raise InvalidICalendarDataError("%s" % (stream.read(),))
@@ -364,8 +382,7 @@
self._parent = None
else:
# FIXME: figure out creating an arbitrary component
- raise NotImplementedError
- self._pycalendar = PyCalendar.makeComponent(name)
+ self._pycalendar = PyCalendar(False) if name == "VCALENDAR" else PyCalendar.makeComponent(name, None)
self._parent = None
def __str__ (self):
@@ -456,7 +473,7 @@
Return the overridden iCal component in this calendar matching the supplied RECURRENCE-ID property.
@param recurrence_id: The RECURRENCE-ID property value to match.
- @type recurrence_id: L{datetime.datetime} or L{datetime.date}
+ @type recurrence_id: L{PyCalendarDateTime}
@return: the L{Component} for the overridden component,
or C{None} if there isn't one.
"""
@@ -551,7 +568,7 @@
if name is None:
[properties.extend(i) for i in self._pycalendar.getProperties().values()]
elif self._pycalendar.countProperty(name) > 0:
- properties = self._pycalendar.getProperties()[name]
+ properties = self._pycalendar.getProperties(name)
return (
Property(None, None, None, pycalendar=p)
@@ -572,7 +589,7 @@
Return the start date or date-time for the specified component
converted to UTC.
@param component: the Component whose start should be returned.
- @return: the datetime.date or datetime.datetime for the start.
+ @return: the L{PyCalendarDateTime} for the start.
"""
dtstart = self.propertyValue("DTSTART")
return dtstart.duplicateAsUTC() if dtstart is not None else None
@@ -583,7 +600,7 @@
taking into account the presence or absence of DTEND/DURATION properties.
The returned date-time is converted to UTC.
@param component: the Component whose end should be returned.
- @return: the datetime.date or datetime.datetime for the end.
+ @return: the L{PyCalendarDateTime} for the end.
"""
dtend = self.propertyValue("DTEND")
if dtend is None:
@@ -599,7 +616,7 @@
Return the due date or date-time for the specified component
converted to UTC. Use DTSTART/DURATION if no DUE property.
@param component: the Component whose start should be returned.
- @return: the datetime.date or datetime.datetime for the start.
+ @return: the L{PyCalendarDateTime} for the start.
"""
due = self.propertyValue("DUE")
if due is None:
@@ -614,7 +631,7 @@
"""
Return the recurrence-id for the specified component.
@param component: the Component whose r-id should be returned.
- @return: the datetime.date or datetime.datetime for the r-id.
+ @return: the L{PyCalendarDateTime} for the r-id.
"""
rid = self.propertyValue("RECURRENCE-ID")
return rid.duplicateAsUTC() if rid is not None else None
@@ -627,7 +644,7 @@
"""
ridprop = self.getProperty("RECURRENCE-ID")
if ridprop is not None:
- range = ridprop.paramValue("RANGE")
+ range = ridprop.parameterValue("RANGE")
if range is not None:
return (range == "THISANDFUTURE")
@@ -638,7 +655,7 @@
Return the trigger information for the specified alarm component.
@param component: the Component whose start should be returned.
@return: ta tuple consisting of:
- trigger : the 'native' trigger value (either datetime.date or datetime.timedelta)
+ trigger : the 'native' trigger value
related : either True (for START) or False (for END)
repeat : an integer for the REPEAT count
duration: the repeat duration if present, otherwise None
@@ -651,7 +668,7 @@
raise InvalidICalendarDataError("VALARM has no TRIGGER property: %r" % (self,))
# The related parameter
- related = self.getProperty("TRIGGER").paramValue("RELATED")
+ related = self.getProperty("TRIGGER").parameterValue("RELATED")
if related is None:
related = True
else:
@@ -709,6 +726,7 @@
@param property: the L{Property} to add to this component.
"""
self._pycalendar.addProperty(property._pycalendar)
+ self._pycalendar.finalise()
def removeProperty(self, property):
"""
@@ -716,6 +734,7 @@
@param property: the L{Property} to remove from this component.
"""
self._pycalendar.removeProperty(property._pycalendar)
+ self._pycalendar.finalise()
def replaceProperty(self, property):
"""
@@ -736,7 +755,7 @@
result = set()
for property in self.properties():
- tzid = property.paramValue("TZID")
+ tzid = property.parameterValue("TZID")
if tzid is not None:
result.add(tzid)
break
@@ -818,13 +837,13 @@
Expand the components into a set of new components, one for each
instance in the specified range. Date-times are converted to UTC. A
new calendar object is returned.
- @param start: the L{datetime.datetime} for the start of the range.
- @param end: the L{datetime.datetime} for the end of the range.
+ @param start: the L{PyCalendarDateTime} for the start of the range.
+ @param end: the L{PyCalendarDateTime} for the end of the range.
@param timezone: the L{Component} the VTIMEZONE to use for floating/all-day.
@return: the L{Component} for the new calendar with expanded instances.
"""
- pytz = PyCalendarTimezone(timezone.getID()) if timezone else None
+ pytz = PyCalendarTimezone(tzid=timezone.propertyValue("TZID")) if timezone else None
# Create new calendar object with same properties as the original, but
# none of the originals sub-components
@@ -878,7 +897,6 @@
# Add RECURRENCE-ID if not first instance
if not first:
newcomp.addProperty(Property("RECURRENCE-ID", instance.rid))
- newcomp.transformAllToNative()
return newcomp
@@ -888,7 +906,7 @@
so we can return cached results in the future.
@param limit: the max datetime to cache up to.
- @type limit: L{datetime.datetime} or L{datetime.date}
+ @type limit: L{PyCalendarDateTime}
"""
# Checked for cached values first
@@ -908,7 +926,7 @@
contained within this VCALENDAR component. We will assume
that this component has already been validated as a CalDAV resource
(i.e. only one type of component, all with the same UID)
- @param limit: datetime.date value representing the end of the expansion.
+ @param limit: L{PyCalendarDateTime} value representing the end of the expansion.
@param ignoreInvalidInstances: C{bool} whether to ignore instance errors.
@return: a set of Instances for each recurrence in the set.
"""
@@ -922,7 +940,7 @@
What we do is first expand the master instance into the set of generate
instances. Then we merge the overridden instances, taking into account
THISANDFUTURE and THISANDPRIOR.
- @param limit: datetime.date value representing the end of the expansion.
+ @param limit: L{PyCalendarDateTime} value representing the end of the expansion.
@param componentSet: the set of components that are to make up the
recurrence set. These MUST all be components with the same UID
and type, forming a proper recurring set.
@@ -989,7 +1007,7 @@
is added as STATUS:CANCELLED and the EXDATE removed.
@param rid: recurrence-id value
- @type rid: L{datetime.datetime}
+ @type rid: L{PyCalendarDateTime}
@param allowCancelled: whether to allow a STATUS:CANCELLED override
@type allowCancelled: C{bool}
@@ -1006,8 +1024,7 @@
didCancel = False
for exdate in tuple(master.properties("EXDATE")):
for exdateValue in exdate.value():
- exdateValue = exdateValue.getValue()
- if exdateValue == rid:
+ if exdateValue.getValue() == rid:
if allowCancelled:
exdate.value().remove(exdateValue)
if len(exdate.value()) == 0:
@@ -1058,19 +1075,24 @@
oldduration = dtend.value() - dtstart.value()
newdtstartValue = rid.duplicate()
- if dtstart.value().local():
- newdtstartValue.adjustTimezone(dtstart.value().getTimezone())
+ if not dtstart.value().isDateOnly():
+ if dtstart.value().local():
+ newdtstartValue.adjustTimezone(dtstart.value().getTimezone())
+ else:
+ newdtstartValue.setDateOnly(True)
dtstart.setValue(newdtstartValue)
if newcomp.hasProperty("DTEND"):
dtend.setValue(newdtstartValue + oldduration)
- rid_params = {}
- newcomp.addProperty(Property("RECURRENCE-ID", dtstart.value(), params=rid_params))
+ newcomp.addProperty(Property("RECURRENCE-ID", dtstart.value(), params={}))
if didCancel:
newcomp.addProperty(Property("STATUS", "CANCELLED"))
+ # After creating/changing a component we need to do this to keep PyCalendar happy
+ newcomp._pycalendar.finalise()
+
return newcomp
def validInstances(self, rids):
@@ -1098,7 +1120,7 @@
Test whether the specified recurrence-id is a valid instance in this event.
@param rid: recurrence-id value
- @type rid: L{datetime.datetime}
+ @type rid: L{PyCalendarDateTime}
@return: C{bool}
"""
@@ -1304,7 +1326,9 @@
if fix:
log.debug("Fixing mismatch")
rrule.getUntil().setDateOnly(dtValue.isDateOnly())
- rrule.getUntil().setHHMMSS(dtutc.getHours(), dtutc.getMinutes(), dtutc.getSeconds())
+ if not dtValue.isDateOnly():
+ rrule.getUntil().setHHMMSS(dtutc.getHours(), dtutc.getMinutes(), dtutc.getSeconds())
+ rrule.getUntil().setTimezone(PyCalendarTimezone(utc=True))
rrules.changed()
else:
raise InvalidICalendarDataError(msg)
@@ -1370,6 +1394,23 @@
return foundOrganizer
+ def gettimezone(self):
+ """
+ Get the PyCalendarTimezone for a Timezone component.
+
+ @return: L{PyCalendarTimezone} if this is a VTIMEZONE, otherwise None.
+ """
+ if self.name() == "VTIMEZONE":
+ return PyCalendarTimezone(tzid=self._pycalendar.getID())
+ elif self.name() == "VCALENDAR":
+ for component in self.subcomponents():
+ if component.name() == "VTIMEZONE":
+ return component.gettimezone()
+ else:
+ return None
+ else:
+ return None
+
##
# iTIP stuff
##
@@ -1492,8 +1533,8 @@
is_server = False
organizerProp = self.getOrganizerProperty()
- if "SCHEDULE-AGENT" in organizerProp.params():
- if organizerProp.paramValue("SCHEDULE-AGENT") == "SERVER":
+ if organizerProp.hasParameter("SCHEDULE-AGENT"):
+ if organizerProp.parameterValue("SCHEDULE-AGENT") == "SERVER":
is_server = True
else:
is_server = True
@@ -1544,8 +1585,8 @@
for attendee in tuple(self.properties("ATTENDEE")):
if onlyScheduleAgentServer:
- if "SCHEDULE-AGENT" in attendee.params():
- if attendee.paramValue("SCHEDULE-AGENT") != "SERVER":
+ if attendee.hasParameter("SCHEDULE-AGENT"):
+ if attendee.parameterValue("SCHEDULE-AGENT") != "SERVER":
continue
cuaddr = attendee.value()
@@ -1833,8 +1874,8 @@
found_all_attendees = False
break
if onlyScheduleAgentServer:
- if "SCHEDULE-AGENT" in foundAttendee.params():
- if foundAttendee.paramValue("SCHEDULE-AGENT") != "SERVER":
+ if foundAttendee.hasParameter("SCHEDULE-AGENT"):
+ if foundAttendee.parameterValue("SCHEDULE-AGENT") != "SERVER":
found_all_attendees = False
break
if not found_all_attendees:
@@ -1946,7 +1987,7 @@
if xpname and p.name() not in keep_properties:
self.removeProperty(p)
elif not xpname and remove_x_parameters:
- for paramname in tuple(p.params()):
+ for paramname in p.parameterNames():
if paramname.startswith("X-"):
p.removeParameter(paramname)
@@ -1995,13 +2036,14 @@
default_params = {"VALUE": "TEXT"}
# Remove any default parameters
- for name, value in prop.params().items():
- if value == [default_params.get(name),]:
+ for name in prop.parameterNames():
+ value = prop.parameterValue(name)
+ if value == default_params.get(name):
prop.removeParameter(name)
# If there are no parameters, remove the property if it has the default value
- if len(prop.params()) == 0:
- if prop.value() == default_value:
+ if len(prop.parameterNames()) == 0:
+ if default_value is not None and prop.value() == default_value:
self.removeProperty(prop)
continue
@@ -2042,22 +2084,41 @@
duration = duration.value() if duration is not None else None,
)
- dtstart.setValue(timeRange.getStart().duplicateAsUTC())
+ # Have to fake the TZID value here when we convert date-times to UTC
+ # as we need to know what the original one was
+ if dtstart.hasParameter("TZID"):
+ dtstart.setParameter("_TZID", dtstart.parameterValue("TZID"))
+ dtstart.removeParameter("TZID")
+ dtstart.value().adjustToUTC()
if dtend is not None:
- dtend.setValue(timeRange.getEnd().duplicateAsUTC())
+ if dtend.hasParameter("TZID"):
+ dtend.setParameter("_TZID", dtend.parameterValue("TZID"))
+ dtend.removeParameter("TZID")
+ dtend.value().adjustToUTC()
elif duration is not None:
self.removeProperty(duration)
self.addProperty(Property("DTEND", timeRange.getEnd().duplicateAsUTC()))
+ rdates = self.properties("RDATE")
+ for rdate in rdates:
+ if rdate.hasParameter("TZID"):
+ rdate.setParameter("_TZID", rdate.parameterValue("TZID"))
+ rdate.removeParameter("TZID")
+ for value in rdate.value():
+ value.getValue().adjustToUTC()
+
exdates = self.properties("EXDATE")
for exdate in exdates:
- exdate.setValue([value.duplicateAsUTC() for value in exdate.value()])
- exdate.removeParameter("TZID")
+ if exdate.hasParameter("TZID"):
+ exdate.setParameter("_TZID", exdate.parameterValue("TZID"))
+ exdate.removeParameter("TZID")
+ for value in exdate.value():
+ value.getValue().adjustToUTC()
rid = self.getProperty("RECURRENCE-ID")
if rid is not None:
+ rid.removeParameter("TZID")
rid.setValue(rid.value().duplicateAsUTC())
- rid.removeProperty("TZID")
# Recurrence rules - we need to normalize the order of the value parts
# for rrule in self._pycalendar.getRecurrenceSet().getRules():
@@ -2082,7 +2143,7 @@
if type(prop.value()) is list and len(prop.value()) > 1:
self.removeProperty(prop)
for value in prop.value():
- self.addProperty(Property(propname, [value,]))
+ self.addProperty(Property(propname, [value.getValue(),]))
def normalizeAttachments(self):
"""
@@ -2099,7 +2160,7 @@
if dropboxPrefix is None:
return
for attachment in tuple(self.properties("ATTACH")):
- valueType = attachment.paramValue("VALUE")
+ valueType = attachment.parameterValue("VALUE")
if valueType in (None, "URI"):
dataValue = attachment.value()
if dataValue.find(dropboxPrefix) != -1:
@@ -2128,7 +2189,7 @@
continue
# Get any EMAIL parameter
- oldemail = prop.paramsValue("EMAIL")
+ oldemail = prop.parameterValue("EMAIL")
if oldemail:
oldemail = "mailto:%s" % (oldemail,)
@@ -2254,8 +2315,6 @@
@return: a C{list} of tuples of (C{datetime}, C{str})
"""
- start = datetime.datetime.fromordinal(start.toordinal())
- end = datetime.datetime.fromordinal(end.toordinal())
icalobj = Component.fromString(tzdata)
tzcomp = None
for comp in icalobj.subcomponents():
@@ -2265,52 +2324,23 @@
else:
raise InvalidICalendarDataError("No VTIMEZONE component in %s" % (tzdata,))
- tzinfo = tzcomp.gettzinfo()
+ tzexpanded = tzcomp._pycalendar.expandAll(start, end)
results = []
- # Get the start utc-offset - that is our first value
- results.append((dateTimeToString(start), deltaToOffset(tzinfo.utcoffset(start)),))
- last_dt = start
+ # Always need to ensure the start appears in the result
+ start.setDateOnly(False)
+ if tzexpanded:
+ if start != tzexpanded[0][0]:
+ results.append((str(start), PyCalendarUTCOffsetValue(tzexpanded[0][1]).getText(),))
+ else:
+ results.append((str(start), PyCalendarUTCOffsetValue(tzcomp._pycalendar.getTimezoneOffsetSeconds(start)).getText(),))
+ for tzstart, _ignore_tzoffsetfrom, tzoffsetto in tzexpanded:
+ results.append((
+ tzstart.getText(),
+ PyCalendarUTCOffsetValue(tzoffsetto).getText(),
+ ))
- while last_dt < end:
- # Get the transitions for the current year
- standard = getTransition("standard", last_dt.year, tzinfo)
- daylight = getTransition("daylight", last_dt.year, tzinfo)
-
- # Order the transitions
- if standard and daylight:
- if standard < daylight:
- first = standard
- second = daylight
- else:
- first = daylight
- second = standard
- elif standard:
- first = standard
- second = None
- else:
- first = daylight
- second = None
-
- for transition in (first, second):
- # Terminate if the next transition is outside the time range
- if transition and transition > end:
- break
-
- # If the next transition is after the last one, then add its info if
- # the utc-offset actually changed.
- if transition and transition > last_dt:
- utcoffset = deltaToOffset(tzinfo.utcoffset(transition + datetime.timedelta(days=1)))
- if utcoffset != results[-1][1]:
- results.append((dateTimeToString(transition), utcoffset,))
- last_dt = transition
-
- # Bump last transition up to the start of the next year
- last_dt = datetime.datetime(last_dt.year + 1, 1, 1, 0, 0, 0)
- if last_dt >= end:
- break
-
return results
##
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/instance.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/instance.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/instance.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -13,10 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.timezone import PyCalendarTimezone
"""
iCalendar Recurrence Expansion Utilities
@@ -24,6 +20,11 @@
from twistedcaldav.dateops import normalizeForIndex, differenceDateTime
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.duration import PyCalendarDuration
+from pycalendar.period import PyCalendarPeriod
+from pycalendar.timezone import PyCalendarTimezone
+
# The maximum number of instances we will expand out to.
# Raise a TooManyInstancesError exception if we exceed this.
max_allowed_instances = 1000
@@ -75,8 +76,10 @@
# Handle repeats
if repeat > 0:
- for i in xrange(1, repeat+1):
- triggers.add(start + (duration * i))
+ tstart = start.duplicate()
+ for _ignore in xrange(1, repeat+1):
+ tstart += duration
+ triggers.add(tstart)
return triggers
@@ -104,7 +107,7 @@
@param componentSet: the set of components that are to make up the
recurrence set. These MUST all be components with the same UID
and type, forming a proper recurring set.
- @param limit: datetime.date value representing the end of the expansion.
+ @param limit: L{PyCalendarDateTime} value representing the end of the expansion.
"""
# Look at each component type
@@ -167,11 +170,12 @@
Add the specified master VEVENT Component to the instance list, expanding it
within the supplied time range.
@param component: the Component to expand
- @param limit: the end datetime.datetime for expansion
+ @param limit: the end L{PyCalendarDateTime} for expansion
"""
start = component.getStartDateUTC()
if start is None:
return
+ rulestart = component.propertyValue("DTSTART")
end = component.getEndDateUTC()
duration = None
@@ -186,7 +190,7 @@
else:
duration = differenceDateTime(start, end)
- self._addMasterComponent(component, limit, start, end, duration)
+ self._addMasterComponent(component, limit, rulestart, start, end, duration)
def _addOverrideEventComponent(self, component, limit, got_master):
"""
@@ -220,7 +224,7 @@
Add the specified master VTODO Component to the instance list, expanding it
within the supplied time range.
@param component: the Component to expand
- @param limit: the end datetime.datetime for expansion
+ @param limit: the end L{PyCalendarDateTime} for expansion
"""
start = component.getStartDateUTC()
due = component.getDueDateUTC()
@@ -228,13 +232,15 @@
if start is None and due is None:
return
+ rulestart = component.propertyValue("DTSTART")
if start is None:
start = due
+ rulestart = component.propertyValue("DUE")
elif due is None:
due = start
duration = differenceDateTime(start, due)
- self._addMasterComponent(component, limit, start, due, duration)
+ self._addMasterComponent(component, limit, rulestart, start, due, duration)
def _addOverrideToDoComponent(self, component, limit, got_master):
"""
@@ -259,13 +265,13 @@
self._addOverrideComponent(component, limit, start, due, got_master)
- def _addMasterComponent(self, component, limit, start, end, duration):
+ def _addMasterComponent(self, component, limit, rulestart, start, end, duration):
rrules = component.getRecurrenceSet()
if rrules is not None:
# Do recurrence set expansion
expanded = []
- limited = rrules.expand(start, PyCalendarPeriod(start, limit), expanded)
+ limited = rrules.expand(rulestart, PyCalendarPeriod(start, limit), expanded)
for startDate in expanded:
startDate = normalizeForIndex(startDate)
endDate = startDate + duration
@@ -343,7 +349,7 @@
Add the specified master VFREEBUSY Component to the instance list, expanding it
within the supplied time range.
@param component: the Component to expand
- @param limit: the end datetime.datetime for expansion
+ @param limit: the end L{PyCalendarDateTime} for expansion
"""
start = component.getStartDateUTC()
@@ -361,6 +367,7 @@
assert isinstance(fb.value(), list), "FREEBUSY property does not contain a list of values: %r" % (fb,)
for period in fb.value():
# Ignore if period starts after limit
+ period = period.getValue()
if period.getStart() >= limit:
continue
start = normalizeForIndex(period.getStart())
@@ -375,7 +382,7 @@
depending on the presence of the properties. If unbounded at one or both ends, we will
set the time to 1/1/1900 in the past and 1/1/3000 in the future.
@param component: the Component to expand
- @param limit: the end datetime.datetime for expansion
+ @param limit: the end L{PyCalendarDateTime} for expansion
"""
start = component.getStartDateUTC()
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/localization.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/localization.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/localization.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -24,6 +24,7 @@
from locale import normalize
from twext.python.log import Logger
+from pycalendar.duration import PyCalendarDuration
try:
from Foundation import (
@@ -90,12 +91,12 @@
helper methods for date formatting:
with translationTo('en') as trans:
- print trans.dtDate(datetime.today())
+ print trans.dtDate(PyCalendarDateTime.getToday())
... Thursday, October 23, 2008
with translationTo('fr') as trans:
- print trans.dtDate(datetime.today())
+ print trans.dtDate(PyCalendarDateTime.getToday())
... Jeudi, Octobre 23, 2008
@@ -151,7 +152,7 @@
return self.translation.ugettext(monthsAbbrev[monthNumber])
def date(self, component):
- dtStart = component.propertyNativeValue("DTSTART")
+ dtStart = component.propertyValue("DTSTART")
return self.dtDate(dtStart)
def time(self, component):
@@ -173,32 +174,29 @@
_ = self.translation.ugettext
tzStart = tzEnd = None
- dtStart = component.propertyNativeValue("DTSTART")
- if isinstance(dtStart, datetime.datetime):
- tzStart = dtStart.tzname()
+ dtStart = component.propertyValue("DTSTART")
+ if dtStart.isDateOnly():
+ return ("", _("All day"))
else:
- return ("", _("All day"))
+ tzStart = dtStart.timeZoneDescriptor()
- # tzStart = component.getProperty("DTSTART").params().get("TZID", "UTC")
-
- dtEnd = component.propertyNativeValue("DTEND")
+ dtEnd = component.propertyValue("DTEND")
if dtEnd:
- if isinstance(dtEnd, datetime.datetime):
- tzEnd = dtEnd.tzname()
- # tzEnd = component.getProperty("DTEND").params().get("TZID", "UTC")
+ if not dtEnd.isDateOnly():
+ tzEnd = dtEnd.timeZoneDescriptor()
duration = dtEnd - dtStart
else:
tzEnd = tzStart
- duration = component.propertyNativeValue("DURATION")
+ duration = component.propertyValue("DURATION")
if duration:
dtEnd = dtStart + duration
else:
- if isinstance(dtStart, datetime.date):
+ if dtStart.isDateOnly():
dtEnd = None
- duration = datetime.timedelta(days=1)
+ duration = PyCalendarDuration(days=1)
else:
- dtEnd = dtStart + datetime.timedelta(days=1)
- dtEnd.hour = dtEnd.minute = dtEnd.second = 0
+ dtEnd = dtStart + PyCalendarDuration(days=1)
+ dtEnd.setHHMMSS(0, 0, 0)
duration = dtEnd - dtStart
if dtStart == dtEnd:
@@ -222,37 +220,37 @@
return (
_("%(dayName)s, %(monthName)s %(dayNumber)d, %(yearNumber)d")
% {
- 'dayName' : _(daysFull[val.weekday()]),
- 'monthName' : _(monthsFull[val.month]),
- 'dayNumber' : val.day,
- 'yearNumber' : val.year,
+ 'dayName' : _(daysFull[(val.getDayOfWeek() + 6) % 7]),
+ 'monthName' : _(monthsFull[val.getMonth()]),
+ 'dayNumber' : val.getDay(),
+ 'yearNumber' : val.getYear(),
}
)
def dtTime(self, val, includeTimezone=True):
- if not isinstance(val, (datetime.datetime, datetime.time)):
+ if val.isDateOnly():
return ""
# Bind to '_' so pygettext.py will pick this up for translation
_ = self.translation.ugettext
- ampm = _("AM") if val.hour < 12 else _("PM")
- hour12 = val.hour % 12
+ ampm = _("AM") if val.getHours() < 12 else _("PM")
+ hour12 = val.getHours() % 12
if hour12 == 0:
hour12 = 12
result = (
_("%(hour12Number)d:%(minuteNumber)02d %(ampm)s")
% {
- 'hour24Number' : val.hour, # 0-23
+ 'hour24Number' : val.getHours(), # 0-23
'hour12Number' : hour12, # 1-12
- 'minuteNumber' : val.minute, # 0-59
+ 'minuteNumber' : val.getMinutes(), # 0-59
'ampm' : _(ampm),
}
)
- if includeTimezone and val.tzname():
- result += " %s" % (val.tzname())
+ if includeTimezone and val.local():
+ result += " %s" % (val.timeZoneDescriptor(),)
return result
@@ -263,15 +261,17 @@
parts = []
- if val.days == 1:
+ total = val.getTotalSeconds()
+ days = total / (24 * 60 * 60)
+ if days == 1:
parts.append(_("1 day"))
- elif val.days > 1:
+ elif days > 1:
parts.append(_("%(dayCount)d days" %
- { 'dayCount' : val.days }))
+ { 'dayCount' : days }))
- hours = val.seconds / 3600
- minutes = divmod(val.seconds / 60, 60)[1]
- seconds = divmod(val.seconds, 60)[1]
+ hours = divmod(total / 3600, 24)[1]
+ minutes = divmod(total / 60, 60)[1]
+ seconds = divmod(total, 60)[1]
if hours == 1:
parts.append(_("1 hour"))
@@ -320,7 +320,7 @@
]
monthsFull = [
- "datetime.month is 1-based",
+ "month is 1-based",
_("January"),
_("February"),
_("March"),
@@ -336,7 +336,7 @@
]
monthsAbbrev = [
- "datetime.month is 1-based",
+ "month is 1-based",
_("JAN"),
_("FEB"),
_("MAR"),
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/mail.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/mail.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -781,7 +781,7 @@
# The organizer will then see that the reply was not successful.
attendeeProp = Property("ATTENDEE", attendee,
params = {
- "SCHEDULE-STATUS": [iTIPRequestStatus.SERVICE_UNAVAILABLE],
+ "SCHEDULE-STATUS": iTIPRequestStatus.SERVICE_UNAVAILABLE,
}
)
event.addProperty(attendeeProp)
@@ -833,17 +833,16 @@
# readable email message (not modifying the calendar body)
attendees = []
for attendeeProp in calendar.getAllAttendeeProperties():
- params = attendeeProp.params()
- cutype = params.get('CUTYPE', (None,))[0]
+ cutype = attendeeProp.parameterValue('CUTYPE', None)
if cutype == "INDIVIDUAL":
- cn = params.get("CN", (None,))[0]
+ cn = attendeeProp.parameterValue("CN", None)
cuaddr = normalizeCUAddr(attendeeProp.value())
if cuaddr.startswith("mailto:"):
mailto = cuaddr[7:]
if not cn:
cn = mailto
else:
- emailAddress = params.get("EMAIL", (None,))[0]
+ emailAddress = attendeeProp.parameterValue("EMAIL", None)
if emailAddress:
mailto = emailAddress
else:
@@ -898,7 +897,7 @@
else:
fromAddr = serverAddress
orgEmail = None
- cn = calendar.getOrganizerProperty().params().get('CN', (None,))[0]
+ cn = calendar.getOrganizerProperty().parameterValue('CN', None)
if cn is None:
cn = 'Calendar Server'
orgCN = orgEmail
@@ -920,19 +919,18 @@
raise ValueError("ORGANIZER address '%s' must be mailto: for REPLY." % (organizerMailto,))
orgEmail = organizerMailto[7:]
- orgCN = calendar.getOrganizerProperty().params().get('CN', (None,))[0]
+ orgCN = calendar.getOrganizerProperty().parameterValue('CN', None)
addressWithToken = formattedFrom
# Now prevent any "internal" CUAs from being exposed by converting
# to mailto: if we have one
for attendeeProp in calendar.getAllAttendeeProperties():
- params = attendeeProp.params()
- cutype = params.get('CUTYPE', (None,))[0]
+ cutype = attendeeProp.parameterValue('CUTYPE', None)
if cutype == "INDIVIDUAL":
cuaddr = normalizeCUAddr(attendeeProp.value())
if not cuaddr.startswith("mailto:"):
- emailAddress = params.get("EMAIL", (None,))[0]
+ emailAddress = attendeeProp.parameterValue("EMAIL", None)
if emailAddress:
attendeeProp.setValue("mailto:%s" % (emailAddress,))
@@ -1221,9 +1219,9 @@
results = { }
- dtStart = component.propertyNativeValue("DTSTART")
- results['month'] = dtStart.month
- results['day'] = dtStart.day
+ dtStart = component.propertyValue("DTSTART")
+ results['month'] = dtStart.getMonth()
+ results['day'] = dtStart.getDay()
summary = component.propertyValue("SUMMARY")
if summary is None:
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/put_common.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/put_common.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -620,7 +620,7 @@
)
attachments = [
attachment for attachment in attachments
- if attachment.params().get("VALUE", ("TEXT",))[0] == "URI" and attachment.value().startswith("http")
+ if attachment.paramsValue("VALUE", "TEXT") == "URI" and attachment.value().startswith("http")
]
if len(xdropboxes) or len(attachments):
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/report_common.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/method/report_common.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -29,7 +29,6 @@
"buildFreeBusyResult",
]
-import datetime
import time
try:
@@ -37,8 +36,6 @@
except ImportError:
from md5 import new as md5
-from vobject.icalendar import utc, dateTimeToString
-
from twisted.internet.defer import inlineCallbacks, returnValue, maybeDeferred
from twisted.python.failure import Failure
from twext.web2 import responsecode
@@ -62,7 +59,7 @@
from twistedcaldav.datafilters.privateevents import PrivateEventFilter
from twistedcaldav.datafilters.addressdata import AddressDataFilter
from twistedcaldav.dateops import clipPeriod, normalizePeriodList, timeRangesOverlap,\
- compareDateTime, normalizeToUTC
+ compareDateTime, normalizeToUTC, parseSQLTimestampToPyCalendar
from twistedcaldav.ical import Component, Property, iCalendarProductID
from twistedcaldav.instance import InstanceList
from twistedcaldav.memcacher import Memcacher
@@ -71,6 +68,11 @@
from txdav.common.icommondatastore import IndexedSearchException
+from pycalendar.duration import PyCalendarDuration
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
+from pycalendar.period import PyCalendarPeriod
+
log = Logger()
COLLECTION_TYPE_REGULAR = "collection"
@@ -403,8 +405,8 @@
if entry:
# Offset one day at either end to account for floating
- cached_start = entry.timerange.start + datetime.timedelta(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
- cached_end = entry.timerange.end - datetime.timedelta(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
+ cached_start = entry.timerange.start + PyCalendarDuration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
+ cached_end = entry.timerange.end - PyCalendarDuration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
# Verify that the requested timerange lies within the cache timerange
if compareDateTime(timerange.end, cached_end) <= 0 and compareDateTime(timerange.start, cached_start) >= 0:
@@ -481,12 +483,12 @@
request.extendedLogItems["fb-uncached"] = request.extendedLogItems.get("fb-uncached", 0) + 1
# We want to cache a large range of time based on the current date
- cache_start = normalizeToUTC(datetime.date.today() - datetime.timedelta(days=config.FreeBusyCacheDaysBack))
- cache_end = normalizeToUTC(datetime.date.today() + datetime.timedelta(days=config.FreeBusyCacheDaysForward))
+ cache_start = normalizeToUTC(PyCalendarDateTime.getToday() + PyCalendarDuration(days=-config.FreeBusyCacheDaysBack))
+ cache_end = normalizeToUTC(PyCalendarDateTime.getToday() + PyCalendarDuration(days=config.FreeBusyCacheDaysForward))
# If the requested timerange would fit in our allowed cache range, trigger the cache creation
if compareDateTime(timerange.start, cache_start) >= 0 and compareDateTime(timerange.end, cache_end) <= 0:
- cache_timerange = TimeRange(start=dateTimeToString(cache_start), end=dateTimeToString(cache_end))
+ cache_timerange = TimeRange(start=cache_start.getText(), end=cache_end.getText())
caching = True
#
@@ -568,19 +570,19 @@
continue
# Apply a timezone to any floating times
- fbstart = datetime.datetime.strptime(start[:19], "%Y-%m-%d %H:%M:%S")
+ fbstart = parseSQLTimestampToPyCalendar(start)
if float == 'Y':
- fbstart = fbstart.replace(tzinfo=tzinfo)
+ fbstart.setTimezone(tzinfo)
else:
- fbstart = fbstart.replace(tzinfo=utc)
- fbend =datetime.datetime.strptime(end[:19], "%Y-%m-%d %H:%M:%S")
+ fbstart.setTimezone(PyCalendarTimezone(utc=True))
+ fbend = parseSQLTimestampToPyCalendar(end)
if float == 'Y':
- fbend = fbend.replace(tzinfo=tzinfo)
+ fbend.setTimezone(tzinfo)
else:
- fbend = fbend.replace(tzinfo=utc)
+ fbend.setTimezone(PyCalendarTimezone(utc=True))
- # Click instance to time range
- clipped = clipPeriod((fbstart, fbend - fbstart), (timerange.start, timerange.end))
+ # Clip instance to time range
+ clipped = clipPeriod(PyCalendarPeriod(fbstart, duration=fbend-fbstart), PyCalendarPeriod(timerange.start, timerange.end))
# Double check for overlap
if clipped:
@@ -642,7 +644,7 @@
@param calendar: the L{Component} that is the VCALENDAR containing the VEVENT's.
@param fbinfo: the tuple used to store the three types of fb data.
@param timerange: the time range to restrict free busy data to.
- @param tzinfo: the L{datetime.tzinfo} for the timezone to use for floating/all-day events.
+ @param tzinfo: the L{PyCalendarTimezone} for the timezone to use for floating/all-day events.
"""
# Expand out the set of instances for the event with in the required range
@@ -651,7 +653,7 @@
# Can only do timed events
for key in instances:
instance = instances[key]
- if not isinstance(instance.start, datetime.datetime):
+ if instance.start.isDateOnly():
return
break
else:
@@ -662,11 +664,11 @@
# Apply a timezone to any floating times
fbstart = instance.start
- if fbstart.tzinfo is None:
- fbstart = fbstart.replace(tzinfo=tzinfo)
+ if fbstart.floating():
+ fbstart.setTimezone(tzinfo)
fbend = instance.end
- if fbend.tzinfo is None:
- fbend = fbend.replace(tzinfo=tzinfo)
+ if fbend.floating():
+ fbend.setTimezone(tzinfo)
# Check TRANSP property of underlying component
if instance.component.hasProperty("TRANSP"):
@@ -687,10 +689,10 @@
# Clip period for this instance - use duration for period end if that
# is what original component used
if instance.component.hasProperty("DURATION"):
- period = (fbstart, fbend - fbstart)
+ period = PyCalendarPeriod(fbstart, duration=fbend-fbstart)
else:
- period = (fbstart, fbend)
- clipped = clipPeriod(period, (timerange.start, timerange.end))
+ period = PyCalendarPeriod(fbstart, fbend)
+ clipped = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
# Double check for overlap
if clipped:
@@ -706,7 +708,7 @@
@param fbinfo: the tuple used to store the three types of fb data.
@param timerange: the time range to restrict free busy data to.
"""
-
+
for vfb in [x for x in calendar.subcomponents() if x.name() == "VFREEBUSY"]:
# First check any start/end in the actual component
start = vfb.getStartDateUTC()
@@ -718,10 +720,7 @@
# Now look at each FREEBUSY property
for fb in vfb.properties("FREEBUSY"):
# Check the type
- if "FBTYPE" in fb.params():
- fbtype = fb.params()["FBTYPE"][0]
- else:
- fbtype = "BUSY"
+ fbtype = fb.parameterValue("FBTYPE", default="BUSY")
if fbtype == "FREE":
continue
@@ -729,7 +728,7 @@
assert isinstance(fb.value(), list), "FREEBUSY property does not contain a list of values: %r" % (fb,)
for period in fb.value():
# Clip period for this instance
- clipped = clipPeriod(period, (timerange.start, timerange.end))
+ clipped = clipPeriod(period.getValue(), PyCalendarPeriod(timerange.start, timerange.end))
if clipped:
fbinfo[fbtype_mapper.get(fbtype, 0)].append(clipped)
@@ -746,12 +745,12 @@
# Get overall start/end
start = vav.getStartDateUTC()
if start is None:
- start = datetime.datetime(1900, 1, 1, 0, 0, 0, tzinfo=utc)
+ start = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
end = vav.getEndDateUTC()
if end is None:
- end = datetime.datetime(3000, 1, 1, 0, 0, 0, tzinfo=utc)
- period = (start, end)
- overall = clipPeriod(period, (timerange.start, timerange.end))
+ end = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+ period = PyCalendarPeriod(start, end)
+ overall = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
if overall is None:
continue
@@ -762,11 +761,11 @@
busyperiods = []
last_end = timerange.start
for period in periods:
- if last_end < period[0]:
- busyperiods.append((last_end, period[0]))
- last_end = period[1]
+ if last_end < period.getStart():
+ busyperiods.append(PyCalendarPeriod(last_end, period.getStart()))
+ last_end = period.getEnd()
if last_end < timerange.end:
- busyperiods.append((last_end, timerange.end))
+ busyperiods.append(PyCalendarPeriod(last_end, timerange.end))
# Add to actual results mapped by busy type
fbtype = vav.propertyValue("BUSYTYPE")
@@ -803,19 +802,19 @@
# Ignore any with floating times (which should not happen as the spec requires UTC or local
# but we will try and be safe here).
start = instance.start
- if start.tzinfo is None:
+ if start.floating():
continue
end = instance.end
- if end.tzinfo is None:
+ if end.floating():
continue
# Clip period for this instance - use duration for period end if that
# is what original component used
if instance.component.hasProperty("DURATION"):
- period = (start, end - start)
+ period = PyCalendarPeriod(start, duration=end-start)
else:
- period = (start, end)
- clipped = clipPeriod(period, (timerange.start, timerange.end))
+ period = PyCalendarPeriod(start, end)
+ clipped = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
if clipped:
periods.append(clipped)
@@ -842,6 +841,7 @@
# Now build a new calendar object with the free busy info we have
fbcalendar = Component("VCALENDAR")
+ fbcalendar.addProperty(Property("VERSION", "2.0"))
fbcalendar.addProperty(Property("PRODID", iCalendarProductID))
if method:
fbcalendar.addProperty(Property("METHOD", method))
@@ -853,13 +853,13 @@
fb.addProperty(attendee)
fb.addProperty(Property("DTSTART", timerange.start))
fb.addProperty(Property("DTEND", timerange.end))
- fb.addProperty(Property("DTSTAMP", datetime.datetime.now(tz=utc)))
+ fb.addProperty(Property("DTSTAMP", PyCalendarDateTime.getNowUTC()))
if len(fbinfo[0]) != 0:
- fb.addProperty(Property("FREEBUSY", fbinfo[0], {"FBTYPE": ["BUSY"]}))
+ fb.addProperty(Property("FREEBUSY", fbinfo[0], {"FBTYPE": "BUSY"}))
if len(fbinfo[1]) != 0:
- fb.addProperty(Property("FREEBUSY", fbinfo[1], {"FBTYPE": ["BUSY-TENTATIVE"]}))
+ fb.addProperty(Property("FREEBUSY", fbinfo[1], {"FBTYPE": "BUSY-TENTATIVE"}))
if len(fbinfo[2]) != 0:
- fb.addProperty(Property("FREEBUSY", fbinfo[2], {"FBTYPE": ["BUSY-UNAVAILABLE"]}))
+ fb.addProperty(Property("FREEBUSY", fbinfo[2], {"FBTYPE": "BUSY-UNAVAILABLE"}))
if uid is not None:
fb.addProperty(Property("UID", uid))
else:
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarquery.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarquery.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarquery.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -26,7 +26,7 @@
"sqlcalendarquery",
]
-from twistedcaldav.dateops import floatoffset
+from twistedcaldav.dateops import floatoffset, pyCalendarTodatetime
from twistedcaldav.query import expression, sqlgenerator, calendarqueryfilter
# SQL Index column (field) names
@@ -197,10 +197,10 @@
endfloat = floatoffset(end, tzinfo) if end else None
return (
- str(start) if start else None,
- str(end) if end else None,
- str(startfloat) if startfloat else None,
- str(endfloat) if endfloat else None,
+ str(pyCalendarTodatetime(start)) if start else None,
+ str(pyCalendarTodatetime(end)) if end else None,
+ str(pyCalendarTodatetime(startfloat)) if startfloat else None,
+ str(pyCalendarTodatetime(endfloat)) if endfloat else None,
)
def sqlcalendarquery(filter, calendarid=None, userid=None, generator=sqlgenerator.sqlgenerator):
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarqueryfilter.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarqueryfilter.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/calendarqueryfilter.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-from pycalendar.datetime import PyCalendarDateTime
"""
Object model of CALDAV:filter element used in a calendar-query.
@@ -28,9 +27,10 @@
from twistedcaldav.caldavxml import caldav_namespace, CalDAVTimeZoneElement
from twistedcaldav.dateops import timeRangesOverlap
from twistedcaldav.ical import Component, Property
-from vobject.icalendar import utc
-import datetime
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
+
log = Logger()
class FilterBase(object):
@@ -83,7 +83,7 @@
instances = None
else:
# Expand the instances up to infinity
- instances = component.expandTimeRanges(datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc), ignoreInvalidInstances=True)
+ instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), ignoreInvalidInstances=True)
else:
instances = component.expandTimeRanges(maxend, ignoreInvalidInstances=True)
else:
@@ -109,7 +109,7 @@
Set the default timezone to use with this query.
@param calendar: a L{Component} for the VCALENDAR containing the one
VTIMEZONE that we want
- @return: the L{datetime.tzinfo} derived from the VTIMEZONE or utc.
+ @return: the L{PyCalendarTimezone} derived from the VTIMEZONE or utc.
"""
assert tzelement is None or isinstance(tzelement, CalDAVTimeZoneElement)
@@ -119,11 +119,12 @@
for subcomponent in calendar.subcomponents():
if subcomponent.name() == "VTIMEZONE":
# <filter> contains exactly one <comp-filter>
- tzinfo = subcomponent.gettzinfo()
- self.child.settzinfo(tzinfo)
- return tzinfo
+ tz = subcomponent.gettimezone()
+ self.child.settzinfo(tz)
+ return tz
# Default to using utc tzinfo
+ utc = PyCalendarTimezone(utc=True)
self.child.settzinfo(utc)
return utc
@@ -320,7 +321,7 @@
def settzinfo(self, tzinfo):
"""
Set the default timezone to use with this query.
- @param tzinfo: a L{datetime.tzinfo} to use.
+ @param tzinfo: a L{PyCalendarTimezone} to use.
"""
# Give tzinfo to any TimeRange we have
@@ -336,7 +337,7 @@
Get the date furthest into the future in any time-range elements
@param currentMaximum: current future value to compare with
- @type currentMaximum: L{datetime.datetime}
+ @type currentMaximum: L{PyCalendarDateTime}
"""
# Give tzinfo to any TimeRange we have
@@ -406,7 +407,7 @@
def settzinfo(self, tzinfo):
"""
Set the default timezone to use with this query.
- @param tzinfo: a L{datetime.tzinfo} to use.
+ @param tzinfo: a L{PyCalendarTimezone} to use.
"""
# Give tzinfo to any TimeRange we have
@@ -418,7 +419,7 @@
Get the date furthest into the future in any time-range elements
@param currentMaximum: current future value to compare with
- @type currentMaximum: L{datetime.datetime}
+ @type currentMaximum: L{PyCalendarDateTime}
"""
# Give tzinfo to any TimeRange we have
@@ -439,24 +440,13 @@
def _match(self, property, access):
- # We have to deal with the problem that the 'Native' form of a property
- # will be missing the TZID parameter due to the conversion performed. Converting
- # to non-native for the entire calendar object causes problems elsewhere, so its
- # best to do it here for this one special case.
- if self.filter_name == "TZID":
- transformed = property.transformAllFromNative()
- else:
- transformed = False
-
- # At least one property must match (or is-not-defined is set)
+ # At least one parameter must match (or is-not-defined is set)
result = not self.defined
- for parameterName in property.params().keys():
- if parameterName == self.filter_name and self.match(property.params()[parameterName], access):
+ for parameterName in property.parameterNames():
+ if parameterName == self.filter_name and self.match([property.parameterValue(parameterName)], access):
result = self.defined
break
- if transformed:
- property.transformAllToNative()
return result
class IsNotDefined (FilterBase):
@@ -508,7 +498,7 @@
if item is None: return False
if isinstance(item, Property):
- values = [item.value()]
+ values = [item.strvalue()]
else:
values = item
@@ -527,7 +517,7 @@
for value in values:
# NB Its possible that we have a text list value which appears as a Python list,
- # so we need to check for that an iterate over the list.
+ # so we need to check for that and iterate over the list.
if isinstance(value, list):
for subvalue in value:
matched, result = _textCompare(subvalue)
@@ -560,7 +550,7 @@
def settzinfo(self, tzinfo):
"""
Set the default timezone to use with this query.
- @param tzinfo: a L{datetime.tzinfo} to use.
+ @param tzinfo: a L{PyCalendarTimezone} to use.
"""
# Give tzinfo to any TimeRange we have
@@ -573,16 +563,16 @@
@return: True if valid, False otherwise
"""
- if self.start is not None and not isinstance(self.start, datetime.datetime):
+ if self.start is not None and self.start.isDateOnly():
log.msg("start attribute in <time-range> is not a date-time: %s" % (self.start,))
return False
- if self.end is not None and not isinstance(self.end, datetime.datetime):
+ if self.end is not None and self.end.isDateOnly():
log.msg("end attribute in <time-range> is not a date-time: %s" % (self.end,))
return False
- if self.start is not None and self.start.tzinfo != utc:
+ if self.start is not None and not self.start.utc():
log.msg("start attribute in <time-range> is not UTC: %s" % (self.start,))
return False
- if self.end is not None and self.end.tzinfo != utc:
+ if self.end is not None and not self.end.utc():
log.msg("end attribute in <time-range> is not UTC: %s" % (self.end,))
return False
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/expression.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/expression.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/expression.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -75,7 +75,7 @@
def __str__(self):
"""
- Generate a suitable text descriptor of this epxression.
+ Generate a suitable text descriptor of this expression.
@return: a C{str} of the text for this expression.
"""
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/sqlgenerator.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/sqlgenerator.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/sqlgenerator.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -266,13 +266,13 @@
e3 = expression.notcontainsExpression("SUMMARY", "help", True)
e5 = expression.andExpression([e1, e2, e3])
print e5
- sql = sqlgenerator(e5)
+ sql = sqlgenerator(e5, None, None)
print sql.generate()
e6 = expression.inExpression("TYPE", ("VEVENT", "VTODO",), False)
print e6
- sql = sqlgenerator(e6)
+ sql = sqlgenerator(e6, None, None)
print sql.generate()
e7 = expression.notinExpression("TYPE", ("VEVENT", "VTODO",), False)
print e7
- sql = sqlgenerator(e7)
+ sql = sqlgenerator(e7, None, None)
print sql.generate()
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_calendarquery.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_calendarquery.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_calendarquery.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -16,8 +16,8 @@
from twistedcaldav import caldavxml
from twistedcaldav.query import calendarqueryfilter
-import datetime
import twistedcaldav.test.util
+from pycalendar.timezone import PyCalendarTimezone
class Tests(twistedcaldav.test.util.TestCase):
@@ -33,64 +33,5 @@
)
)
filter = calendarqueryfilter.Filter(filter)
-
- # A complete implementation of current DST rules for major US time zones.
-
- def first_sunday_on_or_after(dt):
- days_to_go = 6 - dt.weekday()
- if days_to_go:
- dt += datetime.timedelta(days_to_go)
- return dt
-
- # In the US, DST starts at 2am (standard time) on the first Sunday in April.
- DSTSTART = datetime.datetime(1, 4, 1, 2)
- # and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct.
- # which is the first Sunday on or after Oct 25.
- DSTEND = datetime.datetime(1, 10, 25, 1)
-
- ZERO = datetime.timedelta(0)
- HOUR = datetime.timedelta(hours=1)
-
- class USTimeZone(datetime.tzinfo):
-
- def __init__(self, hours, reprname, stdname, dstname):
- self.stdoffset = datetime.timedelta(hours=hours)
- self.reprname = reprname
- self.stdname = stdname
- self.dstname = dstname
-
- def __repr__(self):
- return self.reprname
-
- def tzname(self, dt):
- if self.dst(dt):
- return self.dstname
- else:
- return self.stdname
-
- def utcoffset(self, dt):
- return self.stdoffset + self.dst(dt)
-
- def dst(self, dt):
- if dt is None or dt.tzinfo is None:
- # An exception may be sensible here, in one or both cases.
- # It depends on how you want to treat them. The default
- # fromutc() implementation (called by the default astimezone()
- # implementation) passes a datetime with dt.tzinfo is self.
- return ZERO
- assert dt.tzinfo is self
-
- # Find first Sunday in April & the last in October.
- start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
- end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
-
- # Can't compare naive to aware objects, so strip the timezone from
- # dt first.
- if start <= dt.replace(tzinfo=None) < end:
- return HOUR
- else:
- return ZERO
-
- Eastern = USTimeZone(-5, "Eastern", "EST", "EDT")
- filter.child.settzinfo(Eastern)
+ filter.child.settzinfo(PyCalendarTimezone(tzid="America/New_York"))
\ No newline at end of file
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_queryfilter.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_queryfilter.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/query/test/test_queryfilter.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -17,6 +17,8 @@
from twistedcaldav import caldavxml
from twistedcaldav.query import calendarqueryfilter
import twistedcaldav.test.util
+from twistedcaldav.caldavxml import TimeZone
+from pycalendar.timezone import PyCalendarTimezone
class Tests(twistedcaldav.test.util.TestCase):
@@ -74,4 +76,151 @@
)
calendarqueryfilter.Filter(xml_element)
-
\ No newline at end of file
+
+ def test_queryWithTimezone(self):
+
+ xml_element = caldavxml.Filter(
+ caldavxml.ComponentFilter(
+ caldavxml.ComponentFilter(
+ caldavxml.TimeRange(**{"start":"20060605T160000Z", "end":"20060605T170000Z"}),
+ **{"name":"VEVENT"}
+ ),
+ **{"name":"VCALENDAR"}
+ )
+ )
+
+ filter = calendarqueryfilter.Filter(xml_element)
+ tz = filter.settimezone(TimeZone.fromString("""BEGIN:VCALENDAR
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19180331T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU;UNTIL=19200328T070000Z
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19181027T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=19201031T060000Z
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19210424T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1SU;UNTIL=19410427T070000Z
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19210925T020000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU;UNTIL=19410928T060000Z
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19460428T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1SU;UNTIL=19730429T070000Z
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19460929T020000
+RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU;UNTIL=19540926T060000Z
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19551030T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;UNTIL=20061029T060000Z
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=-1SU;UNTIL=19860427T070000Z
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU;UNTIL=20060402T070000Z
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:-045602
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:18831118T120358
+RDATE:18831118T120358
+END:STANDARD
+BEGIN:STANDARD
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19200101T000000
+RDATE:19200101T000000
+RDATE:19420101T000000
+RDATE:19460101T000000
+RDATE:19670101T000000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EWT
+DTSTART:19420209T020000
+RDATE:19420209T020000
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0400
+TZNAME:EPT
+DTSTART:19450814T190000
+RDATE:19450814T190000
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19450930T020000
+RDATE:19450930T020000
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19740106T020000
+RDATE:19740106T020000
+RDATE:19750223T020000
+END:DAYLIGHT
+END:VTIMEZONE
+END:VCALENDAR
+"""))
+
+ self.assertTrue(isinstance(tz, PyCalendarTimezone))
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/icaldiff.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/icaldiff.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -24,6 +24,8 @@
from twistedcaldav import accounting
from difflib import unified_diff
+from pycalendar.period import PyCalendarPeriod
+from pycalendar.datetime import PyCalendarDateTime
"""
Class that handles diff'ing two calendar objects.
@@ -209,7 +211,7 @@
# Whenever SCHEDULE-FORCE-SEND is explicitly set by the Organizer we assume the Organizer
# is deliberately overwriting PARTSTAT
- if new_attendee.params().get("SCHEDULE-FORCE-SEND", ["",])[0] == "REQUEST":
+ if new_attendee.parameterValue("SCHEDULE-FORCE-SEND", "") == "REQUEST":
continue
# Transfer parameters from any old Attendees found
@@ -221,14 +223,14 @@
self._transferParameter(old_attendee, new_attendee, "SCHEDULE-STATUS")
def _transferParameter(self, old_property, new_property, parameter):
- paramvalue = old_property.params().get(parameter)
+ paramvalue = old_property.parameterValue(parameter)
if paramvalue is None:
try:
- del new_property.params()[parameter]
+ new_property.removeParameter(parameter)
except KeyError:
pass
else:
- new_property.params()[parameter] = paramvalue
+ new_property.setParameter(parameter, paramvalue)
def attendeeMerge(self, attendee):
"""
@@ -282,7 +284,7 @@
# Get all EXDATEs in UTC
exdates = set()
for exdate in master.properties("EXDATE"):
- exdates.update([asUTC(value) for value in exdate.value()])
+ exdates.update([value.getValue().adjustToUTC() for value in exdate.value()])
return exdates, map, master
@@ -331,7 +333,7 @@
# Mark Attendee as DECLINED in the server instance
if self._attendeeDecline(self.newCalendar.overriddenComponent(rid)):
changeCausesReply = True
- changedRids.append(iCalendarString(rid) if rid else "")
+ changedRids.append(rid.getText() if rid else "")
else:
# We used to generate a 403 here - but instead we now ignore this error and let the server data
# override the client
@@ -407,7 +409,7 @@
#return False, False, (), None
changeCausesReply |= reply
if reply:
- changedRids.append(iCalendarString(rid) if rid else "")
+ changedRids.append(rid.getText() if rid else "")
# We need to derive instances for any declined using an EXDATE
for decline in sorted(declines):
@@ -418,7 +420,7 @@
self.newCalendar.addComponent(overridden)
if self._attendeeDecline(overridden):
changeCausesReply = True
- changedRids.append(iCalendarString(decline) if decline else "")
+ changedRids.append(decline.getText() if decline else "")
else:
self._logDiffError("attendeeMerge: Unable to override an instance to mark as DECLINED: %s" % (decline,))
return False, False, (), None
@@ -456,17 +458,17 @@
# ATTENDEE/PARTSTAT/RSVP
serverAttendee = serverComponent.getAttendeeProperty((self.attendee,))
clientAttendee = clientComponent.getAttendeeProperty((self.attendee,))
- if serverAttendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0] != clientAttendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0]:
- serverAttendee.params()["PARTSTAT"] = clientAttendee.params().get("PARTSTAT", "NEEDS-ACTION")
+ if serverAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION") != clientAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION"):
+ serverAttendee.setParameter("PARTSTAT", clientAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION"))
replyNeeded = True
- if serverAttendee.params().get("RSVP", ("FALSE",))[0] != clientAttendee.params().get("RSVP", ("FALSE",))[0]:
- if clientAttendee.params().get("RSVP", ("FALSE",))[0] == "FALSE":
+ if serverAttendee.parameterValue("RSVP", "FALSE") != clientAttendee.parameterValue("RSVP", "FALSE"):
+ if clientAttendee.parameterValue("RSVP", "FALSE") == "FALSE":
try:
- del serverAttendee.params()["RSVP"]
+ serverAttendee.removeParameter("RSVP")
except KeyError:
pass
else:
- serverAttendee.params()["RSVP"] = ["TRUE",]
+ serverAttendee.setParameter("RSVP", "TRUE")
# Transfer these properties from the client data
replyNeeded |= self._transferProperty("X-CALENDARSERVER-PRIVATE-COMMENT", serverComponent, clientComponent)
@@ -506,7 +508,7 @@
# Remove existing ATTACH's from server
for attachment in tuple(serverComponent.properties("ATTACH")):
- valueType = attachment.paramValue("VALUE")
+ valueType = attachment.parameterValue("VALUE")
if valueType in (None, "URI"):
dataValue = attachment.value()
if dataValue.find(serverDropbox) != -1:
@@ -514,7 +516,7 @@
# Copy new ATTACH's to server
for attachment in tuple(clientComponent.properties("ATTACH")):
- valueType = attachment.paramValue("VALUE")
+ valueType = attachment.parameterValue("VALUE")
if valueType in (None, "URI"):
dataValue = attachment.value()
if dataValue.find(serverDropbox) != -1:
@@ -540,7 +542,7 @@
# Bad if EXDATEs have been removed
missing = serverProps[-1] - clientProps[-1]
if missing:
- log.debug("EXDATEs missing: %s" % (", ".join([iCalendarString(exdate) for exdate in missing]),))
+ log.debug("EXDATEs missing: %s" % (", ".join([exdate.getText() for exdate in missing]),))
return False
declines.extend(clientProps[-1] - serverProps[-1])
return True
@@ -555,7 +557,7 @@
dtend = component.getProperty("DTEND")
duration = component.getProperty("DURATION")
- timeRange = timerange(
+ timeRange = PyCalendarPeriod(
start = dtstart.value() if dtstart is not None else None,
end = dtend.value() if dtend is not None else None,
duration = duration.value() if duration is not None else None,
@@ -567,23 +569,23 @@
duration = component.getProperty("DURATION")
if dtstart or duration:
- timeRange = timerange(
+ timeRange = PyCalendarPeriod(
start = dtstart.value() if dtstart is not None else None,
duration = duration.value() if duration is not None else None,
)
else:
- timeRange = timerange()
+ timeRange = PyCalendarPeriod()
newdue = component.getProperty("DUE")
if newdue is not None:
- newdue = asUTC(newdue.value())
+ newdue.value().adjustToUTC()
# Recurrence rules - we need to normalize the order of the value parts
newrrules = set()
rrules = component.properties("RRULE")
for rrule in rrules:
indexedTokens = {}
- indexedTokens.update([valuePart.split("=") for valuePart in rrule.value().split(";")])
+ indexedTokens.update([valuePart.split("=") for valuePart in rrule.value().getText().split(";")])
sortedValue = ";".join(["%s=%s" % (key, value,) for key, value in sorted(indexedTokens.iteritems(), key=lambda x:x[0])])
newrrules.add(sortedValue)
@@ -591,15 +593,18 @@
newrdates = set()
rdates = component.properties("RDATE")
for rdate in rdates:
- newrdates.update([asUTC(value) for value in rdate.value()])
+ for value in rdate.value():
+ if isinstance(PyCalendarDateTime()):
+ value.adjustToUTC()
+ newrdates.add(value)
# EXDATEs
newexdates = set()
exdates = component.properties("EXDATE")
for exdate in exdates:
- newexdates.update([asUTC(value) for value in exdate.value()])
+ newexdates.update([value.getValue().adjustToUTC() for value in exdate.value()])
- return timeRange.start(), timeRange.end(), newdue, newrrules, newrdates, newexdates
+ return timeRange.getStart(), timeRange.getEnd(), newdue, newrrules, newrdates, newexdates
def _transferProperty(self, propName, serverComponent, clientComponent):
@@ -625,8 +630,8 @@
@return: C{bool} indicating whether the PARTSTAT value was in fact changed
"""
attendee = component.getAttendeeProperty((self.attendee,))
- partstatChanged = attendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0] != "DECLINED"
- attendee.params()["PARTSTAT"] = ["DECLINED",]
+ partstatChanged = attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") != "DECLINED"
+ attendee.setParameter("PARTSTAT", "DECLINED")
prop = component.getProperty("X-APPLE-NEEDS-REPLY")
if prop:
component.removeProperty(prop)
@@ -705,11 +710,7 @@
comp2 = self._componentDuplicateAndNormalize(comp2)
# Diff all the properties
- comp1.transformAllFromNative()
- comp2.transformAllFromNative()
propdiff = set(comp1.properties()) ^ set(comp2.properties())
- comp1.transformAllToNative()
- comp2.transformAllToNative()
addedChanges = False
propsChanged = {}
@@ -728,17 +729,17 @@
prop1s = tuple(comp1.properties(prop.name()))
prop2s = tuple(comp2.properties(prop.name()))
if len(prop1s) == 1 and len(prop2s) == 1:
- param1s = set(["%s=%s" % (name, value) for name, value in prop1s[0].params().iteritems()])
- param2s = set(["%s=%s" % (name, value) for name, value in prop2s[0].params().iteritems()])
+ param1s = set(["%s=%s" % (name, prop1s[0].parameterValue(name)) for name in prop1s[0].parameterNames()])
+ param2s = set(["%s=%s" % (name, prop2s[0].parameterValue(name)) for name in prop2s[0].parameterNames()])
paramDiffs = param1s ^ param2s
propsChanged[prop.name()].update([param.split("=")[0] for param in paramDiffs])
- if "ORIGINAL-TZID" in propsChanged[prop.name()]:
- propsChanged[prop.name()].remove("ORIGINAL-TZID")
+ if "_TZID" in propsChanged[prop.name()]:
+ propsChanged[prop.name()].remove("_TZID")
propsChanged[prop.name()].add("TZID")
if addedChanges:
rid = comp1.getRecurrenceIDUTC()
- rids[iCalendarString(rid) if rid is not None else ""] = propsChanged
+ rids[rid.getText() if rid is not None else ""] = propsChanged
def _logDiffError(self, title):
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/implicit.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/implicit.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -276,7 +276,7 @@
self.request.suppressRefresh = False
for attendee in self.calendar.getAllAttendeeProperties():
- if attendee.params().get("PARTSTAT", ["NEEDS-ACTION"])[0] == "NEEDS-ACTION":
+ if attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") == "NEEDS-ACTION":
self.request.suppressRefresh = True
if hasattr(self.request, "doing_attendee_refresh"):
@@ -485,7 +485,7 @@
comp = self.calendar.overriddenComponent(rid)
for attendee in comp.getAllAttendeeProperties():
- if attendee.params().has_key("PARTSTAT"):
+ if attendee.hasParameter("PARTSTAT"):
cuaddr = attendee.value()
if cuaddr in self.organizerPrincipal.calendarUserAddresses():
@@ -494,7 +494,7 @@
# The organizer is automatically ACCEPTED to the event.
continue
- attendee.params()["PARTSTAT"] = ["NEEDS-ACTION",]
+ attendee.setParameter("PARTSTAT", "NEEDS-ACTION")
# Check for removed attendees
if not recurrence_reschedule:
@@ -505,15 +505,15 @@
# Always set RSVP=TRUE for any NEEDS-ACTION
for attendee in self.calendar.getAllAttendeeProperties():
- if attendee.params().get("PARTSTAT", ["NEEDS-ACTION"])[0] == "NEEDS-ACTION":
- attendee.params()["RSVP"] = ["TRUE",]
+ if attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") == "NEEDS-ACTION":
+ attendee.setParameter("RSVP", "TRUE")
yield self.scheduleWithAttendees()
# Always clear SCHEDULE-FORCE-SEND from all attendees after scheduling
for attendee in self.calendar.getAllAttendeeProperties():
try:
- del attendee.params()["SCHEDULE-FORCE-SEND"]
+ attendee.removeParameter("SCHEDULE-FORCE-SEND")
except KeyError:
pass
@@ -564,7 +564,7 @@
reinvites = set()
for attendee in self.calendar.getAllAttendeeProperties():
try:
- if attendee.params()["SCHEDULE-FORCE-SEND"][0] == "REQUEST":
+ if attendee.parameterValue("SCHEDULE-FORCE-SEND") == "REQUEST":
reinvites.add(attendee.value())
except KeyError:
pass
@@ -602,10 +602,10 @@
# Also look for new EXDATEs
oldexdates = set()
for property in self.oldcalendar.masterComponent().properties("EXDATE"):
- oldexdates.update(property.value())
+ oldexdates.update([value.getValue() for value in property.value()])
newexdates = set()
for property in self.calendar.masterComponent().properties("EXDATE"):
- newexdates.update(property.value())
+ newexdates.update([value.getValue() for value in property.value()])
addedexdates = newexdates - oldexdates
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/itip.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/itip.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -30,17 +30,13 @@
# know how to deal with overridden instances.
#
-import datetime
-
-from vobject.icalendar import utc
-from vobject.icalendar import dateTimeToString
-
from twext.python.log import Logger
-#from twext.python.datetime import asUTC, iCalendarString
from twistedcaldav.config import config
from twistedcaldav.ical import Property, iCalendarProductID, Component
+from pycalendar.datetime import PyCalendarDateTime
+
log = Logger()
__version__ = "0.0"
@@ -101,7 +97,7 @@
private_comments = current_master.properties("X-CALENDARSERVER-PRIVATE-COMMENT")
transps = current_master.properties("TRANSP")
organizer = current_master.getProperty("ORGANIZER")
- organizer_schedule_status = organizer.params().get("SCHEDULE-STATUS", None) if organizer else None
+ organizer_schedule_status = organizer.parameterValue("SCHEDULE-STATUS", None) if organizer else None
else:
master_valarms = ()
private_comments = ()
@@ -124,7 +120,7 @@
if organizer_schedule_status:
organizer = master_component.getProperty("ORGANIZER")
if organizer:
- organizer.params()["SCHEDULE-STATUS"] = organizer_schedule_status
+ organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
# Now try to match recurrences
for component in new_calendar.subcomponents():
@@ -321,7 +317,7 @@
if attendee:
attendees.add(attendee)
if rids is not None and (partstat or private_comment):
- rids.add((iCalendarString(rid), partstat, private_comment,))
+ rids.add((rid.getText(), partstat, private_comment,))
# Check for an invalid instance by itself
len_attendees = len(attendees)
@@ -363,20 +359,20 @@
return None, False, False
attendee = attendees[0]
- partstat = attendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0]
+ partstat = attendee.parameterValue("PARTSTAT", "NEEDS-ACTION")
# Now find matching ATTENDEE in to_component
existing_attendee = to_component.getAttendeeProperty((attendee.value(),))
if existing_attendee:
- oldpartstat = existing_attendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0]
- existing_attendee.params()["PARTSTAT"] = [partstat]
- existing_attendee.params()["SCHEDULE-STATUS"] = [reqstatus]
+ oldpartstat = existing_attendee.parameterValue("PARTSTAT", "NEEDS-ACTION")
+ existing_attendee.setParameter("PARTSTAT", partstat)
+ existing_attendee.setParameter("SCHEDULE-STATUS", reqstatus)
partstat_changed = (oldpartstat != partstat)
# Always delete RSVP on PARTSTAT change
if partstat_changed:
try:
- del existing_attendee.params()["RSVP"]
+ existing_attendee.removeParameter("RSVP")
except KeyError:
pass
@@ -389,12 +385,8 @@
# Look for matching X-CALENDARSERVER-ATTENDEE-COMMENT property in existing data (State 2 in spec)
private_comments = tuple(to_component.properties("X-CALENDARSERVER-ATTENDEE-COMMENT"))
for comment in private_comments:
- params = comment.params()["X-CALENDARSERVER-ATTENDEE-REF"]
- if len(params) != 1:
- log.error("Must be one and only one X-CALENDARSERVER-ATTENDEE-REF parameter in X-CALENDARSERVER-ATTENDEE-COMMENT")
- params = (None,)
- param = params[0]
- if param == attendee.value():
+ attendeeref = comment.parameterValue("X-CALENDARSERVER-ATTENDEE-REF")
+ if attendeeref == attendee.value():
private_comment = comment
break
else:
@@ -410,11 +402,11 @@
elif attendee_comment is None and private_comment is not None:
# Remove all property parameters
- private_comment.params().clear()
+ private_comment.removeAllParameters()
# Add default parameters
- private_comment.params()["X-CALENDARSERVER-ATTENDEE-REF"] = [attendee.value()]
- private_comment.params()["X-CALENDARSERVER-DTSTAMP"] = [dateTimeToString(datetime.datetime.now(tz=utc))]
+ private_comment.setParameter("X-CALENDARSERVER-ATTENDEE-REF", attendee.value())
+ private_comment.setParameter("X-CALENDARSERVER-DTSTAMP", PyCalendarDateTime.getNowUTC().getText())
# Set value empty
private_comment.setValue("")
@@ -428,8 +420,8 @@
"X-CALENDARSERVER-ATTENDEE-COMMENT",
attendee_comment.value(),
params = {
- "X-CALENDARSERVER-ATTENDEE-REF": [attendee.value()],
- "X-CALENDARSERVER-DTSTAMP": [dateTimeToString(datetime.datetime.now(tz=utc))],
+ "X-CALENDARSERVER-ATTENDEE-REF": attendee.value(),
+ "X-CALENDARSERVER-DTSTAMP": PyCalendarDateTime.getNowUTC().getText(),
}
)
to_component.addProperty(private_comment)
@@ -440,11 +432,11 @@
# Only change if different
if private_comment.value() != attendee_comment.value():
# Remove all property parameters
- private_comment.params().clear()
+ private_comment.removeAllParameters()
# Add default parameters
- private_comment.params()["X-CALENDARSERVER-ATTENDEE-REF"] = [attendee.value()]
- private_comment.params()["X-CALENDARSERVER-DTSTAMP"] = [dateTimeToString(datetime.datetime.now(tz=utc))]
+ private_comment.setParameter("X-CALENDARSERVER-ATTENDEE-REF", attendee.value())
+ private_comment.setParameter("X-CALENDARSERVER-DTSTAMP", PyCalendarDateTime.getNowUTC().getText())
# Set new value
private_comment.setValue(attendee_comment.value())
@@ -467,11 +459,11 @@
[to_component.replaceProperty(prop) for prop in matched.properties("TRANSP")]
organizer = matched.getProperty("ORGANIZER")
- organizer_schedule_status = organizer.params().get("SCHEDULE-STATUS", None) if organizer else None
+ organizer_schedule_status = organizer.parameterValue("SCHEDULE-STATUS", None) if organizer else None
if organizer_schedule_status:
organizer = to_component.getProperty("ORGANIZER")
if organizer:
- organizer.params()["SCHEDULE-STATUS"] = organizer_schedule_status
+ organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
# Remove the old one
if remove_matched:
@@ -486,7 +478,7 @@
if organizer_schedule_status:
organizer = to_component.getProperty("ORGANIZER")
if organizer:
- organizer.params()["SCHEDULE-STATUS"] = organizer_schedule_status
+ organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
@staticmethod
def fixForiCal3(components, recipient, compatibilityMode):
@@ -498,7 +490,7 @@
continue
attendee = component.getAttendeeProperty((recipient,))
if attendee:
- partstat = attendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0]
+ partstat = attendee.parameterValue("PARTSTAT", "NEEDS-ACTION")
if partstat == "NEEDS-ACTION":
if compatibilityMode:
component.addProperty(Property("X-APPLE-NEEDS-REPLY", "TRUE"))
@@ -523,7 +515,6 @@
# Create a new component matching the type of the original
comp = Component(original.mainType())
- itip.addComponent(comp)
# Use the master component when the instance is None
if not instance_rid:
@@ -535,14 +526,14 @@
assert instance is not None, "Need a master component"
# Add some required properties extracted from the original
- comp.addProperty(Property("DTSTAMP", datetime.datetime.now(tz=utc)))
+ comp.addProperty(Property("DTSTAMP", PyCalendarDateTime.getNowUTC()))
comp.addProperty(Property("UID", instance.propertyValue("UID")))
seq = instance.propertyValue("SEQUENCE")
- seq = str(int(seq) + 1) if seq else "1"
+ seq = int(seq) + 1 if seq else 1
comp.addProperty(Property("SEQUENCE", seq))
comp.addProperty(instance.getOrganizerProperty())
if instance_rid:
- comp.addProperty(Property("RECURRENCE-ID", asUTC(instance_rid)))
+ comp.addProperty(Property("RECURRENCE-ID", instance_rid.duplicate().adjustToUTC()))
def addProperties(propname):
for property in instance.properties(propname):
@@ -567,6 +558,8 @@
comp.addProperty(attendeeProp)
tzids.update(comp.timezoneIDs())
+
+ itip.addComponent(comp)
# Now include any referenced tzids
for comp in original.subcomponents():
@@ -589,7 +582,7 @@
itip.addProperty(Property("METHOD", "REQUEST"))
# Force update to DTSTAMP everywhere
- itip.replacePropertyInAllComponents(Property("DTSTAMP", datetime.datetime.now(tz=utc)))
+ itip.replacePropertyInAllComponents(Property("DTSTAMP", PyCalendarDateTime.getNowUTC()))
# Now filter out components that do not contain every attendee
itip.attendeesView(attendees, onlyScheduleAgentServer=True)
@@ -617,7 +610,7 @@
itip.filterComponents(changedRids)
# Force update to DTSTAMP everywhere
- itip.replacePropertyInAllComponents(Property("DTSTAMP", datetime.datetime.now(tz=utc)))
+ itip.replacePropertyInAllComponents(Property("DTSTAMP", PyCalendarDateTime.getNowUTC()))
# Remove all attendees except the one we want
itip.removeAllButOneAttendee(attendee)
@@ -651,11 +644,11 @@
attendeeProps = itip.getAttendeeProperties((attendee,))
assert attendeeProps, "Must have some matching ATTENDEEs"
for attendeeProp in attendeeProps:
- attendeeProp.params().setdefault("PARTSTAT", ["DECLINED",])[0] = "DECLINED"
+ attendeeProp.setParameter("PARTSTAT", "DECLINED")
# Add REQUEST-STATUS to each top-level component
itip.addPropertyToAllComponents(Property("REQUEST-STATUS", ["2.0", "Success",]))
-
+
# Strip out unwanted bits
iTipGenerator.prepareSchedulingMessage(itip, reply=True)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/processing.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/processing.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -14,12 +14,9 @@
# limitations under the License.
##
-import datetime
import time
from hashlib import md5
-from vobject.icalendar import dateTimeToString, utc
-
from twisted.python.log import err as log_traceback
from twext.python.log import Logger
@@ -37,6 +34,9 @@
from twistedcaldav.scheduling.itip import iTipProcessing, iTIPRequestStatus
from twistedcaldav.scheduling.utils import getCalendarObjectForPrincipals
from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
+from pycalendar.duration import PyCalendarDuration
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
__all__ = [
"ImplicitProcessor",
@@ -480,8 +480,8 @@
log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - checking for auto-reply" % (self.recipient.cuaddr, self.uid))
# First expand current one to get instances (only go 1 year into the future)
- default_future_expansion_duration = datetime.timedelta(days=356*1)
- expand_max = datetime.date.today() + default_future_expansion_duration
+ default_future_expansion_duration = PyCalendarDuration(days=356*1)
+ expand_max = PyCalendarDateTime.getToday() + default_future_expansion_duration
instances = calendar.expandTimeRanges(expand_max, ignoreInvalidInstances=True)
instance_states = dict([(instance, True) for instance in instances.instances.itervalues()])
@@ -501,9 +501,9 @@
has_prop = (yield testcal.hasProperty((caldav_namespace, "calendar-timezone"), self.request))
if has_prop:
tz = (yield testcal.readProperty((caldav_namespace, "calendar-timezone"), self.request))
- tzinfo = tz.calendar().gettzinfo()
+ tzinfo = tz.calendar().gettimezone()
else:
- tzinfo = utc
+ tzinfo = PyCalendarTimezone(utc=True)
# Now do search for overlapping time-range
for instance in instances.instances.itervalues():
@@ -513,15 +513,18 @@
fbinfo = ([], [], [])
def makeTimedUTC(dt):
- if isinstance(dt, datetime.date) and not isinstance(dt, datetime.datetime):
- dt = datetime.datetime.fromordinal(dt.toordinal())
- if dt.tzinfo is None:
- dt = dt.replace(tzinfo=tzinfo).astimezone(utc)
+ dt = dt.duplicate()
+ if dt.isDateOnly():
+ dt.setDateOnly(False)
+ dt.setHHMMSS(0, 0, 0)
+ if dt.floating():
+ dt.setTimezone(tzinfo)
+ dt.adjustToUTC()
return dt
tr = caldavxml.TimeRange(
- start=dateTimeToString(makeTimedUTC(instance.start)),
- end=dateTimeToString(makeTimedUTC(instance.end)),
+ start=str(makeTimedUTC(instance.start)),
+ end=str(makeTimedUTC(instance.end)),
)
yield report_common.generateFreeBusyInfo(self.request, testcal, fbinfo, tr, 0, uid, servertoserver=True)
@@ -692,14 +695,14 @@
madeChanges = False
for attendee in attendees:
- if attendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0] != partstat:
- attendee.params()["PARTSTAT"] = [partstat]
+ if attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") != partstat:
+ attendee.setParameter("PARTSTAT", partstat)
madeChanges = True
# Always remove RSVP - this is only an attendee change so madeChanges
# does not need to be changed
try:
- del attendee.params()["RSVP"]
+ attendee.removeParameter("RSVP")
except KeyError:
pass
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/scheduler.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/scheduler.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -374,7 +374,7 @@
))
# Some clients send floating instead of UTC - coerce to UTC
- if dtstart.tzinfo is None or dtend.tzinfo is None:
+ if not dtstart.utc() or not dtend.utc():
log.err("VFREEBUSY start or end not UTC: %s" % (self.calendar,))
raise HTTPError(ErrorResponse(
responsecode.FORBIDDEN,
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_icaldiff.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_icaldiff.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_icaldiff.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -855,6 +855,13 @@
BEGIN:VTIMEZONE
TZID:US-Eastern
LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:19900404T010000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19901026T060000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
@@ -862,13 +869,6 @@
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19900404T010000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:12345-67890
@@ -952,6 +952,13 @@
BEGIN:VTIMEZONE
TZID:US-Eastern
LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:19900404T010000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19901026T060000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
@@ -959,13 +966,6 @@
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19900404T010000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:12345-67890
@@ -1049,6 +1049,13 @@
BEGIN:VTIMEZONE
TZID:US-Eastern
LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:19900404T010000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19901026T060000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
@@ -1056,13 +1063,6 @@
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19900404T010000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:12345-67890
@@ -1146,6 +1146,13 @@
BEGIN:VTIMEZONE
TZID:US-Eastern
LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:19900404T010000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19901026T060000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
@@ -1153,13 +1160,6 @@
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19900404T010000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:12345-67890
@@ -1245,7 +1245,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1325,7 +1325,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:Test for Attendee
@@ -1392,7 +1392,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1471,7 +1471,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1559,7 +1559,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1647,7 +1647,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1728,7 +1728,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1784,7 +1784,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1858,7 +1858,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -1924,7 +1924,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -2079,7 +2079,7 @@
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
BEGIN:VEVENT
UID:12345-67890
@@ -2147,7 +2147,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
EXDATE:20080604T120000Z
ORGANIZER;CN=User 01:mailto:user1 at example.com
-RRULE:COUNT=400;FREQ=DAILY
+RRULE:FREQ=DAILY;COUNT=400
END:VEVENT
END:VCALENDAR
""")
@@ -2431,8 +2431,8 @@
UID:12345-67890
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
-ATTACH;VALUE=URI:http://localhost/calendars/users/dropbox/6073432E-644B-49
- 65-B6F7-C3F08E70BBF9.dropbox/caldavd.plist
+ATTACH:http://localhost/calendars/users/dropbox/6073432E-644B-4965-B6F7-C3
+ F08E70BBF9.dropbox/caldavd.plist
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
@@ -2533,8 +2533,8 @@
UID:12345-67890
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
-ATTACH;VALUE=URI:http://localhost/calendars/users/dropbox/6073432E-644B-49
- 65-B6F7-C3F08E70BBF9.dropbox/caldavd.plist
+ATTACH:http://localhost/calendars/users/dropbox/6073432E-644B-4965-B6F7-C3
+ F08E70BBF9.dropbox/caldavd.plist
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
@@ -2641,10 +2641,10 @@
UID:12345-67890
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
-ATTACH;VALUE=URI:http://localhost/calendars/users/dropbox/6073432E-644B-49
- 65-B6F7-C3F08E70BBF9.dropbox/caldavd.plist
-ATTACH;VALUE=URI:http://localhost/calendars/users/dropbox/6073432E-644B-49
- 65-B6F7-C3F08E70BBF9.dropbox/caldavd-2.plist
+ATTACH:http://localhost/calendars/users/dropbox/6073432E-644B-4965-B6F7-C3
+ F08E70BBF9.dropbox/caldavd.plist
+ATTACH:http://localhost/calendars/users/dropbox/6073432E-644B-4965-B6F7-C3
+ F08E70BBF9.dropbox/caldavd-2.plist
ATTENDEE:mailto:user1 at example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
ORGANIZER;CN=User 01:mailto:user1 at example.com
@@ -3595,6 +3595,44 @@
""",
{"":{"ATTENDEE":set(),}},
),
+ (
+ "#2.8 Simple recurring component, property order change",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080602T120000Z
+EXDATE:20080603T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080603T120000Z
+EXDATE:20080602T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ {},
+ ),
)
data3 = (
@@ -3843,7 +3881,7 @@
END:VEVENT
END:VCALENDAR
""",
- {"":{"SUMMARY":set()}, "20080602T120000Z":{"DESCRIPTION":set()}},
+ {"":{"SUMMARY":set()}, "20080602T120000Z":{"Description":set()}},
),
(
"#3.6 Simple component, instance added no change",
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_implicit.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_implicit.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -17,8 +17,8 @@
from twistedcaldav.ical import Component
import twistedcaldav.test.util
from twistedcaldav.scheduling.implicit import ImplicitScheduler
-from dateutil.tz import tzutc
-import datetime
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
class Implicit (twistedcaldav.test.util.TestCase):
"""
@@ -28,134 +28,134 @@
def test_removed_attendees(self):
data = (
+# (
+# "#1.1 Simple component, no change",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#ATTENDEE:mailto:user2 at example.com
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#ATTENDEE:mailto:user2 at example.com
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# (),
+# ),
+# (
+# "#1.2 Simple component, one removal",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#ATTENDEE:mailto:user2 at example.com
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# (("mailto:user2 at example.com", None),),
+# ),
+# (
+# "#1.3 Simple component, two removals",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#ATTENDEE:mailto:user2 at example.com
+#ATTENDEE:mailto:user3 at example.com
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# (
+# ("mailto:user2 at example.com", None),
+# ("mailto:user3 at example.com", None),
+# ),
+# ),
+# (
+# "#2.1 Simple recurring component, two removals",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#ATTENDEE:mailto:user2 at example.com
+#ATTENDEE:mailto:user3 at example.com
+#RRULE:FREQ=MONTHLY
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# """BEGIN:VCALENDAR
+#VERSION:2.0
+#PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+#BEGIN:VEVENT
+#UID:12345-67890
+#DTSTART:20080601T120000Z
+#DTEND:20080601T130000Z
+#ORGANIZER;CN="User 01":mailto:user1 at example.com
+#ATTENDEE:mailto:user1 at example.com
+#RRULE:FREQ=MONTHLY
+#END:VEVENT
+#END:VCALENDAR
+#""",
+# (
+# ("mailto:user2 at example.com", None),
+# ("mailto:user3 at example.com", None),
+# ),
+# ),
(
- "#1.1 Simple component, no change",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-ATTENDEE:mailto:user2 at example.com
-END:VEVENT
-END:VCALENDAR
-""",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-ATTENDEE:mailto:user2 at example.com
-END:VEVENT
-END:VCALENDAR
-""",
- (),
- ),
- (
- "#1.2 Simple component, one removal",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-ATTENDEE:mailto:user2 at example.com
-END:VEVENT
-END:VCALENDAR
-""",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-END:VEVENT
-END:VCALENDAR
-""",
- (("mailto:user2 at example.com", None),),
- ),
- (
- "#1.3 Simple component, two removals",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-ATTENDEE:mailto:user2 at example.com
-ATTENDEE:mailto:user3 at example.com
-END:VEVENT
-END:VCALENDAR
-""",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-END:VEVENT
-END:VCALENDAR
-""",
- (
- ("mailto:user2 at example.com", None),
- ("mailto:user3 at example.com", None),
- ),
- ),
- (
- "#2.1 Simple recurring component, two removals",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-ATTENDEE:mailto:user2 at example.com
-ATTENDEE:mailto:user3 at example.com
-RRULE:FREQ=MONTHLY
-END:VEVENT
-END:VCALENDAR
-""",
- """BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:12345-67890
-DTSTART:20080601T120000Z
-DTEND:20080601T130000Z
-ORGANIZER;CN="User 01":mailto:user1 at example.com
-ATTENDEE:mailto:user1 at example.com
-RRULE:FREQ=MONTHLY
-END:VEVENT
-END:VCALENDAR
-""",
- (
- ("mailto:user2 at example.com", None),
- ("mailto:user3 at example.com", None),
- ),
- ),
- (
"#2.2 Simple recurring component, add exdate",
"""BEGIN:VCALENDAR
VERSION:2.0
@@ -189,9 +189,9 @@
END:VCALENDAR
""",
(
- ("mailto:user1 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -228,12 +228,12 @@
END:VCALENDAR
""",
(
- ("mailto:user1 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user1 at example.com", datetime.datetime(2008, 9, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 9, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 9, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -271,15 +271,15 @@
END:VCALENDAR
""",
(
- ("mailto:user1 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user1 at example.com", datetime.datetime(2008, 9, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 9, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 9, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user1 at example.com", datetime.datetime(2008, 12, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 12, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 12, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 12, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 12, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 12, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -388,7 +388,7 @@
""",
(
("mailto:user3 at example.com", None),
- ("mailto:user3 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -443,7 +443,7 @@
END:VCALENDAR
""",
(
- ("mailto:user3 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -589,9 +589,9 @@
END:VCALENDAR
""",
(
- ("mailto:user1 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user3 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user3 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -646,7 +646,7 @@
""",
(
("mailto:user3 at example.com", None),
- ("mailto:user4 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user4 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -692,7 +692,7 @@
END:VCALENDAR
""",
(
- ("mailto:user4 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user4 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
(
@@ -739,9 +739,9 @@
END:VCALENDAR
""",
(
- ("mailto:user1 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user2 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
- ("mailto:user4 at example.com", datetime.datetime(2008, 8, 1, 12, 0, 0, tzinfo=tzutc())),
+ ("mailto:user1 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user2 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
+ ("mailto:user4 at example.com", PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
),
),
)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_itip.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/scheduling/test/test_itip.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -14,10 +14,10 @@
# limitations under the License.
##
-from dateutil.tz import tzutc
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
from twistedcaldav.ical import Component
from twistedcaldav.scheduling.itip import iTipProcessing, iTipGenerator
-import datetime
import os
import twistedcaldav.test.util
@@ -1269,7 +1269,7 @@
END:VCALENDAR
""",
("mailto:user2 at example.com",),
- (datetime.datetime(2008, 11, 14, 0, 0, tzinfo=tzutc()), ),
+ (PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), ),
),
# Recurring component with one instance, each with one attendee - cancel instance
@@ -1308,7 +1308,7 @@
END:VCALENDAR
""",
("mailto:user2 at example.com",),
- (datetime.datetime(2008, 11, 14, 0, 0, tzinfo=tzutc()), ),
+ (PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), ),
),
# Recurring component with one instance, each with one attendee - cancel master
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/sharing.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/sharing.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -41,10 +41,9 @@
from twistedcaldav.linkresource import LinkFollowerMixIn
from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
-from vobject.icalendar import dateTimeToString, utc
+from pycalendar.datetime import PyCalendarDateTime
from uuid import uuid4
-import datetime
import os
import types
@@ -564,7 +563,7 @@
typeAttr = {'shared-type':self.sharedResourceType()}
xmltype = customxml.InviteNotification(**typeAttr)
xmldata = customxml.Notification(
- customxml.DTStamp.fromString(dateTimeToString(datetime.datetime.now(tz=utc))),
+ customxml.DTStamp.fromString(PyCalendarDateTime.getNowUTC().getText()),
customxml.InviteNotification(
customxml.UID.fromString(record.inviteuid),
davxml.HRef.fromString(record.userid),
@@ -1125,7 +1124,7 @@
notificationUID = "%s-reply" % (replytoUID,)
xmltype = customxml.InviteReply()
xmldata = customxml.Notification(
- customxml.DTStamp.fromString(dateTimeToString(datetime.datetime.now(tz=utc))),
+ customxml.DTStamp.fromString(PyCalendarDateTime.getNowUTC().getText()),
customxml.InviteReply(
*(
(
Added: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_caldavxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_caldavxml.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_caldavxml.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twistedcaldav import caldavxml
+import twistedcaldav.test.util
+
+class CustomXML (twistedcaldav.test.util.TestCase):
+
+
+ def test_TimeRange(self):
+
+ self.assertRaises(ValueError, caldavxml.CalDAVTimeRangeElement)
+
+ tr = caldavxml.CalDAVTimeRangeElement(start="20110201T120000Z")
+ self.assertTrue(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(start="20110201T120000")
+ self.assertFalse(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(start="20110201")
+ self.assertFalse(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(end="20110201T120000Z")
+ self.assertTrue(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(end="20110201T120000")
+ self.assertFalse(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(end="20110201")
+ self.assertFalse(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(start="20110201T120000Z", end="20110202T120000Z")
+ self.assertTrue(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(start="20110201T120000Z", end="20110202T120000")
+ self.assertFalse(tr.valid())
+
+ tr = caldavxml.CalDAVTimeRangeElement(start="20110201T120000Z", end="20110202")
+ self.assertFalse(tr.valid())
Added: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_customxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_customxml.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_customxml.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -0,0 +1,29 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twistedcaldav import customxml
+import time
+import twistedcaldav.test.util
+
+class CustomXML (twistedcaldav.test.util.TestCase):
+
+
+ def test_DTStamp(self):
+
+ dtstamp = customxml.DTStamp()
+ now = time.time()
+ now_tm = time.gmtime( now )
+ self.assertEqual(str(dtstamp)[:4], "%s" % (now_tm.tm_year,))
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_icalendar.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_icalendar.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -51,17 +51,183 @@
SkipTest("test unimplemented")
def test_component_equality(self):
- for filename in (
- os.path.join(self.data_dir, "Holidays", "C318A4BA-1ED0-11D9-A5E0-000A958A3252.ics"),
- os.path.join(self.data_dir, "Holidays.ics"),
- ):
- data = file(filename).read()
+# for filename in (
+# os.path.join(self.data_dir, "Holidays", "C318A4BA-1ED0-11D9-A5E0-000A958A3252.ics"),
+# os.path.join(self.data_dir, "Holidays.ics"),
+# ):
+# data = file(filename).read()
+#
+# calendar1 = Component.fromString(data)
+# calendar2 = Component.fromString(data)
+#
+# self.assertEqual(calendar1, calendar2)
+
+ data1 = (
+ (
+ "1.1 Switch property order",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080602T120000Z
+EXDATE:20080603T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080603T120000Z
+EXDATE:20080602T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ ),
+ (
+ "1.2 Switch component order",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080602T120000Z
+EXDATE:20080603T120000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080603T120000Z
+EXDATE:20080602T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ ),
+ (
+ "1.3 Switch VALARM order",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080602T120000Z
+EXDATE:20080603T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-2
+TRIGGER;RELATED=START:-PT5M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Test
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:COUNT=400;FREQ=DAILY
+EXDATE:20080603T120000Z
+EXDATE:20080602T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-2
+TRIGGER;RELATED=START:-PT5M
+END:VALARM
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ ),
+ )
+
+ for description, item1, item2, result in data1:
+ if "1.3" not in description:
+ continue
+ calendar1 = Component.fromString(item1)
+ calendar2 = Component.fromString(item2)
+ (self.assertEqual if result else self.assertNotEqual)(
+ calendar1, calendar2, "%s" % (description,)
+ )
- calendar1 = Component.fromString(data)
- calendar2 = Component.fromString(data)
-
- self.assertEqual(calendar1, calendar2)
-
def test_component_validate(self):
"""
CalDAV resource validation.
@@ -789,14 +955,14 @@
for original, result in data:
component = Component.fromString(original)
- component.addPropertyToAllComponents(Property("REQUEST-STATUS", "2.0;Success"))
+ component.addPropertyToAllComponents(Property("REQUEST-STATUS", ["2.0", "Success"]))
self.assertEqual(result, str(component).replace("\r", ""))
def test_attendees_views(self):
data = (
- # Simple component, no Attendees - no filtering
(
+ "1.1 Simple component, no Attendees - no filtering",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -819,8 +985,8 @@
()
),
- # Simple component, no Attendees - filtering
(
+ "1.2 Simple component, no Attendees - filtering",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -839,8 +1005,8 @@
("mailto:user01 at example.com",)
),
- # Simple component, with one attendee - filtering match
(
+ "1.3 Simple component, with one attendee - filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -867,8 +1033,8 @@
("mailto:user2 at example.com",)
),
- # Simple component, with one attendee - no filtering match
(
+ "1.4 Simple component, with one attendee - no filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -889,8 +1055,8 @@
("mailto:user3 at example.com",)
),
- # Recurring component with one instance, each with one attendee - filtering match
(
+ "2.1 Recurring component with one instance, each with one attendee - filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -933,8 +1099,8 @@
("mailto:user2 at example.com",)
),
- # Recurring component with one instance, each with one attendee - no filtering match
(
+ "2.2 Recurring component with one instance, each with one attendee - no filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -963,8 +1129,8 @@
("mailto:user3 at example.com",)
),
- # Recurring component with one instance, master with one attendee, instance without attendee - filtering match
(
+ "2.3 Recurring component with one instance, master with one attendee, instance without attendee - filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1000,8 +1166,8 @@
("mailto:user2 at example.com",)
),
- # Recurring component with one instance, master with one attendee, instance without attendee - no filtering match
(
+ "2.4 Recurring component with one instance, master with one attendee, instance without attendee - no filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1029,8 +1195,8 @@
("mailto:user3 at example.com",)
),
- # Recurring component with one instance, master without attendee, instance with attendee - filtering match
(
+ "2.5 Recurring component with one instance, master without attendee, instance with attendee - filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1065,8 +1231,8 @@
("mailto:user2 at example.com",)
),
- # Recurring component with one instance, master without attendee, instance with attendee - no filtering match
(
+ "2.6 Recurring component with one instance, master without attendee, instance with attendee - no filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1094,8 +1260,8 @@
("mailto:user3 at example.com",)
),
- # Simple component, no Attendees - no filtering
(
+ "3.1 Simple component, no Attendees - no filtering",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1118,8 +1284,8 @@
()
),
- # Simple component, no Attendees - filtering
(
+ "3.2 Simple component, no Attendees - filtering",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1138,8 +1304,8 @@
("mailto:user01 at example.com",)
),
- # Simple component, with one attendee - filtering match
(
+ "3.3 Simple component, with one attendee - filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1166,8 +1332,8 @@
("mailto:user2 at example.com",)
),
- # Simple component, with one attendee - filtering match
(
+ "3.4 Simple component, with one attendee - filtering match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1194,8 +1360,8 @@
("mailto:user2 at example.com",)
),
- # Simple component, with one attendee - filtering match - no schedule-agent match
(
+ "3.5 Simple component, with one attendee - filtering match - no schedule-agent match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1216,8 +1382,8 @@
("mailto:user2 at example.com",)
),
- # Simple component, with one attendee - filtering match - no schedule-agent match
(
+ "3.6 Simple component, with one attendee - filtering match - no schedule-agent match",
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -1240,10 +1406,10 @@
)
- for original, checkScheduleAgent, filtered, attendees in data:
+ for description, original, checkScheduleAgent, filtered, attendees in data:
component = Component.fromString(original)
component.attendeesView(attendees, onlyScheduleAgentServer=checkScheduleAgent)
- self.assertEqual(filtered, str(component).replace("\r", ""))
+ self.assertEqual(filtered, str(component).replace("\r", ""), "Failed: %s" % (description,))
def test_all_but_one_attendee(self):
@@ -1737,7 +1903,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1752,7 +1918,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=2
END:VEVENT
END:VCALENDAR
@@ -1771,7 +1937,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=2
RDATE:20071116T010000Z
END:VEVENT
@@ -1792,7 +1958,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=3
EXDATE:20071115T000000Z
END:VEVENT
@@ -1812,7 +1978,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=3
EXDATE:20071114T000000Z
END:VEVENT
@@ -1832,14 +1998,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=2
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1857,14 +2023,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=2
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T010000Z
DTSTART:20071115T000000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1879,14 +2045,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=2
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T010000Z
DTSTART:20071115T000000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1919,7 +2085,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1934,7 +2100,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1949,14 +2115,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1971,14 +2137,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -1993,14 +2159,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -2015,14 +2181,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -2037,14 +2203,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -2059,14 +2225,14 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
END:VEVENT
BEGIN:VEVENT
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
END:VEVENT
END:VCALENDAR
""",
@@ -2090,7 +2256,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:True
END:VEVENT
END:VCALENDAR
@@ -2101,7 +2267,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM2:True
END:VEVENT
END:VCALENDAR
@@ -2112,7 +2278,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:True
X-ITEM2:True
END:VEVENT
@@ -2128,7 +2294,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:True
END:VEVENT
END:VCALENDAR
@@ -2139,7 +2305,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM2:True
X-ITEM3:True
END:VEVENT
@@ -2151,7 +2317,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:True
X-ITEM2:True
X-ITEM3:True
@@ -2168,7 +2334,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:True
END:VEVENT
END:VCALENDAR
@@ -2179,7 +2345,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM2:True
X-ITEM1:False
END:VEVENT
@@ -2191,7 +2357,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:True
X-ITEM2:True
X-ITEM1:False
@@ -2208,7 +2374,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
X-ITEM1:True
END:VEVENT
@@ -2216,7 +2382,7 @@
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:False
END:VEVENT
END:VCALENDAR
@@ -2227,7 +2393,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
X-ITEM2:True
END:VEVENT
@@ -2235,7 +2401,7 @@
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM2:False
END:VEVENT
END:VCALENDAR
@@ -2246,7 +2412,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
X-ITEM1:True
X-ITEM2:True
@@ -2255,7 +2421,7 @@
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:False
X-ITEM2:False
END:VEVENT
@@ -2271,7 +2437,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
X-ITEM1:True
END:VEVENT
@@ -2279,7 +2445,7 @@
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:False
END:VEVENT
END:VCALENDAR
@@ -2290,7 +2456,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
X-ITEM2:True
END:VEVENT
@@ -2302,7 +2468,7 @@
BEGIN:VEVENT
UID:12345-67890-1
DTSTART:20071114T000000Z
-DURATION:P1H
+DURATION:PT1H
RRULE:FREQ=DAILY
X-ITEM1:True
X-ITEM2:True
@@ -2311,7 +2477,7 @@
UID:12345-67890-1
RECURRENCE-ID:20071115T000000Z
DTSTART:20071115T010000Z
-DURATION:P1H
+DURATION:PT1H
X-ITEM1:False
X-ITEM2:True
END:VEVENT
@@ -2419,6 +2585,74 @@
END:VCALENDAR
""",
),
+ (
+ "1.4",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART;TZID=US/Pacific:20071114T000000
+RRULE:FREQ=WEEKLY;WKST=SU;INTERVAL=1;BYDAY=MO,WE,FR
+TRANSP:OPAQUE
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user03 at example.com
+ATTENDEE;RSVP=FALSE:mailto:user04 at example.com
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART;_TZID=US/Pacific:20071114T080000Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;RSVP=TRUE:mailto:user02 at example.com
+ATTENDEE:mailto:user03 at example.com
+ATTENDEE:mailto:user04 at example.com
+RRULE:BYDAY=MO,WE,FR;FREQ=WEEKLY;INTERVAL=1;WKST=SU
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+""",
+ ),
)
for title, original, result in data:
@@ -2852,8 +3086,6 @@
)
for title, calendar, rid, result in data:
- if not title.startswith("3"):
- continue
ical = Component.fromString(calendar)
derived = ical.deriveInstance(rid)
derived = str(derived).replace("\r", "") if derived else None
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_localization.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_localization.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_localization.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -19,7 +19,8 @@
from twistedcaldav.localization import translationTo
from twistedcaldav.ical import Component
from twistedcaldav.test.util import TestCase
-from datetime import time
+from pycalendar.datetime import PyCalendarDateTime
+
import os
def getComp(str):
@@ -64,21 +65,21 @@
with translationTo('English', localeDir=localeDir) as t:
- self.assertEquals(t.dtTime(time(0,0)), "12:00 AM")
- self.assertEquals(t.dtTime(time(12,0)), "12:00 PM")
- self.assertEquals(t.dtTime(time(23,59)), "11:59 PM")
- self.assertEquals(t.dtTime(time(6,5)), "6:05 AM")
- self.assertEquals(t.dtTime(time(16,5)), "4:05 PM")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 0, 0, 0)), "12:00 AM")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 12, 0, 0)), "12:00 PM")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 23, 59, 0)), "11:59 PM")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 6, 5, 0)), "6:05 AM")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 16, 5, 0)), "4:05 PM")
def test_TimeFormatting24Hour(self):
with translationTo('pig', localeDir=localeDir) as t:
- self.assertEquals(t.dtTime(time(0,0)), "00:00")
- self.assertEquals(t.dtTime(time(12,0)), "12:00")
- self.assertEquals(t.dtTime(time(23,59)), "23:59")
- self.assertEquals(t.dtTime(time(6,5)), "06:05")
- self.assertEquals(t.dtTime(time(16,5)), "16:05")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 0, 0, 0)), "00:00")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 12, 0, 0)), "12:00")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 23, 59, 0)), "23:59")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 6, 5, 0)), "06:05")
+ self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 16, 5, 0)), "16:05")
def test_CalendarFormatting(self):
@@ -87,15 +88,15 @@
comp = data[0][1]
self.assertEquals(t.date(comp), "Saturday, October 25, 2008")
self.assertEquals(t.time(comp),
- (u'9:15 AM to 10:15 AM PDT', u'1 hour 1 second'))
+ (u'9:15 AM to 10:15 AM (PDT)', u'1 hour 1 second'))
comp = data[1][1]
self.assertEquals(t.time(comp),
- (u'1:15 PM to 3:15 PM PDT', u'2 hours 2 seconds'))
+ (u'1:15 PM to 3:15 PM (PDT)', u'2 hours 2 seconds'))
comp = data[2][1]
self.assertEquals(t.time(comp),
- (u'11:05 AM to 2:15 PM PDT', u'3 hours 10 minutes'))
+ (u'11:05 AM to 2:15 PM (PDT)', u'3 hours 10 minutes'))
comp = data[3][1]
self.assertEquals(t.time(comp),
@@ -103,11 +104,11 @@
comp = data[4][1]
self.assertEquals(t.time(comp),
- (u'1:15 PM PDT', ""))
+ (u'1:15 PM (PDT)', ""))
comp = data[5][1]
self.assertEquals(t.time(comp),
- (u'11:05 AM PDT to 6:15 PM EDT', u'4 hours 10 minutes'))
+ (u'11:05 AM (PDT) to 6:15 PM (EDT)', u'4 hours 10 minutes'))
self.assertEquals(t.monthAbbreviation(1), "JAN")
@@ -116,15 +117,15 @@
comp = data[0][1]
self.assertEquals(t.date(comp), 'Aturdaysay, Octoberway 25, 2008')
self.assertEquals(t.time(comp),
- (u'09:15 otay 10:15 PDT', u'1 ourhay 1 econdsay'))
+ (u'09:15 otay 10:15 (PDT)', u'1 ourhay 1 econdsay'))
comp = data[1][1]
self.assertEquals(t.time(comp),
- (u'13:15 otay 15:15 PDT', u'2 ourshay 2 econdsay'))
+ (u'13:15 otay 15:15 (PDT)', u'2 ourshay 2 econdsay'))
comp = data[2][1]
self.assertEquals(t.time(comp),
- (u'11:05 otay 14:15 PDT', u'3 ourshay 10 inutesmay'))
+ (u'11:05 otay 14:15 (PDT)', u'3 ourshay 10 inutesmay'))
comp = data[3][1]
self.assertEquals(t.time(comp),
@@ -132,10 +133,10 @@
comp = data[4][1]
self.assertEquals(t.time(comp),
- (u'13:15 PDT', ""))
+ (u'13:15 (PDT)', ""))
comp = data[5][1]
self.assertEquals(t.time(comp),
- (u'11:05 PDT otay 18:15 EDT', u'4 ourshay 10 inutesmay'))
+ (u'11:05 (PDT) otay 18:15 (EDT)', u'4 ourshay 10 inutesmay'))
self.assertEquals(t.monthAbbreviation(1), "ANJAY")
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_mail.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_mail.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_mail.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -65,7 +65,45 @@
def test_processDSN(self):
- template = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nMETHOD:REQUEST\nPRODID:-//example Inc.//iCal 3.0//EN\nBEGIN:VTIMEZONE\nTZID:US/Pacific\nBEGIN:STANDARD\nDTSTART:20071104T020000\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\nTZNAME:PST\nTZOFFSETFROM:-0700\nTZOFFSETTO:-0800\nEND:STANDARD\nBEGIN:DAYLIGHT\nDTSTART:20070311T020000\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\nTZNAME:PDT\nTZOFFSETFROM:-0800\nTZOFFSETTO:-0700\nEND:DAYLIGHT\nEND:VTIMEZONE\nBEGIN:VEVENT\nUID:1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C\nDTSTART;TZID=US/Pacific:20080812T094500\nDTEND;TZID=US/Pacific:20080812T104500\nATTENDEE;CUTYPE=INDIVIDUAL;CN=User 01;PARTSTAT=ACCEPTED:mailto:user01 at exam\n ple.com\nATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-A\n CTION;CN=nonexistant at example.com:mailto:nonexistant at example.com\nCREATED:20080812T191857Z\nDTSTAMP:20080812T191932Z\nORGANIZER;CN=User 01:mailto:xyzzy+%s at example.com\nSEQUENCE:2\nSUMMARY:New Event\nTRANSP:OPAQUE\nEND:VEVENT\nEND:VCALENDAR\n'
+ template = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+PRODID:-//example Inc.//iCal 3.0//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C
+DTSTART;TZID=US/Pacific:20080812T094500
+DTEND;TZID=US/Pacific:20080812T104500
+ATTENDEE;CUTYPE=INDIVIDUAL;CN=User 01;PARTSTAT=ACCEPTED:mailto:user01 at exam
+ ple.com
+ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-A
+ CTION;CN=nonexistant at example.com:mailto:nonexistant at example.com
+CREATED:20080812T191857Z
+DTSTAMP:20080812T191932Z
+ORGANIZER;CN=User 01:mailto:xyzzy+%s at example.com
+SEQUENCE:2
+SUMMARY:New Event
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+"""
# Make sure an unknown token is not processed
calBody = template % "bogus_token"
@@ -80,7 +118,42 @@
"xyzzy", echo)
self.assertEquals(organizer, 'mailto:user01 at example.com')
self.assertEquals(attendee, 'mailto:user02 at example.com')
- self.assertEquals(str(calendar), 'BEGIN:VCALENDAR\r\nVERSION:2.0\r\nCALSCALE:GREGORIAN\r\nMETHOD:REQUEST\r\nPRODID:-//example Inc.//iCal 3.0//EN\r\nBEGIN:VTIMEZONE\r\nTZID:US/Pacific\r\nBEGIN:STANDARD\r\nDTSTART:20071104T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\nTZNAME:PST\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0800\r\nEND:STANDARD\r\nBEGIN:DAYLIGHT\r\nDTSTART:20070311T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\nTZNAME:PDT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nEND:DAYLIGHT\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C\r\nDTSTART;TZID=US/Pacific:20080812T094500\r\nDTEND;TZID=US/Pacific:20080812T104500\r\nCREATED:20080812T191857Z\r\nDTSTAMP:20080812T191932Z\r\nORGANIZER;CN=User 01:mailto:user01 at example.com\r\nREQUEST-STATUS:5.1;Service unavailable\r\nSEQUENCE:2\r\nSUMMARY:New Event\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n')
+ self.assertEquals(str(calendar), """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+PRODID:-//example Inc.//iCal 3.0//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C
+DTSTART;TZID=US/Pacific:20080812T094500
+DTEND;TZID=US/Pacific:20080812T104500
+CREATED:20080812T191857Z
+DTSTAMP:20080812T191932Z
+ORGANIZER;CN=User 01:mailto:user01 at example.com
+REQUEST-STATUS:5.1;Service unavailable
+SEQUENCE:2
+SUMMARY:New Event
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"))
self.assertEquals(msgId, 'xyzzy')
@@ -129,8 +202,7 @@
# have added an attendee back in with a "5.1;Service unavailable"
# schedule-status
attendeeProp = calendar.mainComponent().getAttendeeProperty([attendee])
- self.assertEquals(attendeeProp.paramValue("SCHEDULE-STATUS"),
- iTIPRequestStatus.SERVICE_UNAVAILABLE)
+ self.assertEquals(attendeeProp.parameterValue("SCHEDULE-STATUS"), iTIPRequestStatus.SERVICE_UNAVAILABLE)
@inlineCallbacks
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_multiget.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_multiget.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_multiget.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -214,7 +214,7 @@
self.fail("Got calendar for unexpected UID %r" % (uid,))
if data:
- original_calendar = ical.Component.fromStream(data[uid])
+ original_calendar = ical.Component.fromString(data[uid])
else:
original_filename = file(os.path.join(self.holidays_dir, uid + ".ics"))
original_calendar = ical.Component.fromStream(original_filename)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_timezones.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_timezones.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_timezones.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -16,11 +16,11 @@
import twistedcaldav.test.util
from twistedcaldav.ical import Component
-from vobject.icalendar import utc, getTzid
-from vobject.icalendar import registerTzid
from twistedcaldav.timezones import TimezoneCache, TimezoneException
from twistedcaldav.timezones import readTZ, listTZs
-import datetime
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.timezone import PyCalendarTimezone
+
import os
class TimezoneProblemTest (twistedcaldav.test.util.TestCase):
@@ -30,6 +30,10 @@
data_dir = os.path.join(os.path.dirname(__file__), "data")
+ def tearDown(self):
+ TimezoneCache.clear()
+ TimezoneCache.create()
+
def doTest(self, filename, dtstart, dtend, testEqual=True):
if testEqual:
@@ -40,7 +44,7 @@
calendar = Component.fromStream(file(os.path.join(self.data_dir, filename)))
if calendar.name() != "VCALENDAR": self.fail("Calendar is not a VCALENDAR")
- instances = calendar.expandTimeRanges(datetime.date(2100, 1, 1))
+ instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
for key in instances:
instance = instances[key]
start = instance.start
@@ -54,83 +58,83 @@
Properties in components
"""
- oldtzid = getTzid("America/New_York")
- try:
- registerTzid("America/New_York", None)
- self.doTest("TruncatedApr01.ics", datetime.datetime(2007, 04, 01, 16, 0, 0, tzinfo=utc), datetime.datetime(2007, 04, 01, 17, 0, 0, tzinfo=utc))
- finally:
- registerTzid("America/New_York", oldtzid)
+ TimezoneCache.create("")
+ TimezoneCache.clear()
+ self.doTest(
+ "TruncatedApr01.ics",
+ PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True))
+ )
+
def test_truncatedDec(self):
"""
Properties in components
"""
- oldtzid = getTzid("America/New_York")
- try:
- registerTzid("America/New_York", None)
- self.doTest("TruncatedDec10.ics", datetime.datetime(2007, 12, 10, 17, 0, 0, tzinfo=utc), datetime.datetime(2007, 12, 10, 18, 0, 0, tzinfo=utc))
- finally:
- registerTzid("America/New_York", oldtzid)
+ TimezoneCache.create("")
+ TimezoneCache.clear()
+ self.doTest(
+ "TruncatedDec10.ics",
+ PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True))
+ )
+
def test_truncatedAprThenDecFail(self):
"""
Properties in components
"""
- if TimezoneCache.activeCache:
- TimezoneCache.activeCache.unregister()
- oldtzid = getTzid("America/New_York")
- try:
- registerTzid("America/New_York", None)
- self.doTest(
- "TruncatedApr01.ics",
- datetime.datetime(2007, 04, 01, 16, 0, 0, tzinfo=utc),
- datetime.datetime(2007, 04, 01, 17, 0, 0, tzinfo=utc),
- )
- self.doTest(
- "TruncatedDec10.ics",
- datetime.datetime(2007, 12, 10, 17, 0, 0, tzinfo=utc),
- datetime.datetime(2007, 12, 10, 18, 0, 0, tzinfo=utc),
- testEqual=False
- )
- finally:
- registerTzid("America/New_York", oldtzid)
+ TimezoneCache.create("")
+ TimezoneCache.clear()
+ self.doTest(
+ "TruncatedApr01.ics",
+ PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True)),
+ )
+ self.doTest(
+ "TruncatedDec10.ics",
+ PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True)),
+ testEqual=False
+ )
+
def test_truncatedAprThenDecOK(self):
"""
Properties in components
"""
- oldtzid = getTzid("America/New_York")
- try:
- registerTzid("America/New_York", None)
- tzcache = TimezoneCache()
- tzcache.register()
- self.doTest(
- "TruncatedApr01.ics",
- datetime.datetime(2007, 04, 01, 16, 0, 0, tzinfo=utc),
- datetime.datetime(2007, 04, 01, 17, 0, 0, tzinfo=utc),
- )
- self.doTest(
- "TruncatedDec10.ics",
- datetime.datetime(2007, 12, 10, 17, 0, 0, tzinfo=utc),
- datetime.datetime(2007, 12, 10, 18, 0, 0, tzinfo=utc),
- )
- tzcache.unregister()
- finally:
- registerTzid("America/New_York", oldtzid)
+ TimezoneCache.create()
+ self.doTest(
+ "TruncatedApr01.ics",
+ PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True)),
+ )
+ self.doTest(
+ "TruncatedDec10.ics",
+ PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True)),
+ )
+
def test_truncatedDecThenApr(self):
"""
Properties in components
"""
- oldtzid = getTzid("America/New_York")
- try:
- registerTzid("America/New_York", None)
- self.doTest("TruncatedDec10.ics", datetime.datetime(2007, 12, 10, 17, 0, 0, tzinfo=utc), datetime.datetime(2007, 12, 10, 18, 0, 0, tzinfo=utc))
- self.doTest("TruncatedApr01.ics", datetime.datetime(2007, 04, 01, 16, 0, 0, tzinfo=utc), datetime.datetime(2007, 04, 01, 17, 0, 0, tzinfo=utc))
- finally:
- registerTzid("America/New_York", oldtzid)
+ TimezoneCache.create("")
+ TimezoneCache.clear()
+ self.doTest(
+ "TruncatedDec10.ics",
+ PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True))
+ )
+ self.doTest(
+ "TruncatedApr01.ics",
+ PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True))
+ )
+
class TimezoneCacheTest (twistedcaldav.test.util.TestCase):
"""
Timezone support tests
@@ -140,19 +144,13 @@
def test_basic(self):
- registerTzid("America/New_York", None)
- registerTzid("US/Eastern", None)
+ TimezoneCache.create()
+ self.assertTrue(readTZ("America/New_York"))
+ self.assertTrue(readTZ("US/Eastern"))
- tzcache = TimezoneCache()
- tzcache.register()
- self.assertTrue(tzcache.loadTimezone("America/New_York"))
- self.assertTrue(tzcache.loadTimezone("US/Eastern"))
- tzcache.unregister()
-
def test_not_in_cache(self):
- tzcache = TimezoneCache()
- tzcache.register()
+ TimezoneCache.create()
data = """BEGIN:VCALENDAR
VERSION:2.0
@@ -186,21 +184,24 @@
calendar = Component.fromString(data)
if calendar.name() != "VCALENDAR": self.fail("Calendar is not a VCALENDAR")
- instances = calendar.expandTimeRanges(datetime.date(2100, 1, 1))
+ instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
for key in instances:
instance = instances[key]
start = instance.start
end = instance.end
- self.assertEqual(start, datetime.datetime(2007, 12, 25, 05, 0, 0, tzinfo=utc))
- self.assertEqual(end, datetime.datetime(2007, 12, 25, 06, 0, 0, tzinfo=utc))
+ self.assertEqual(start, PyCalendarDateTime(2007, 12, 25, 05, 0, 0, PyCalendarTimezone(utc=True)))
+ self.assertEqual(end, PyCalendarDateTime(2007, 12, 25, 06, 0, 0, PyCalendarTimezone(utc=True)))
break;
- tzcache.unregister()
class TimezonePackageTest (twistedcaldav.test.util.TestCase):
"""
Timezone support tests
"""
+ def setUp(self):
+ TimezoneCache.clear()
+ TimezoneCache.create()
+
def test_ReadTZ(self):
self.assertTrue(readTZ("America/New_York").find("TZID:America/New_York") != -1)
@@ -223,7 +224,6 @@
def test_ListTZsCached(self):
results = listTZs()
- results = listTZs()
self.assertTrue("America/New_York" in results)
self.assertTrue("Europe/London" in results)
self.assertTrue("GB" in results)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_upgrade.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_upgrade.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -1304,20 +1304,20 @@
PRODID:-//Apple Inc.//iCal 3.0//EN
BEGIN:VTIMEZONE
TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:1E238CA1-3C95-4468-B8CD-C8A399F78C71
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_validation.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_validation.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/test/test_validation.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -44,8 +44,9 @@
self.destination.name = lambda : '1'
self.destinationParent = CalDAVResource()
self.destinationParent.name = lambda : '2'
- self.sampleCalendar = Component.fromString("""
-BEGIN:VCALENDAR
+
+ def _getSampleCalendar(self):
+ return Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:12345-67890
@@ -56,6 +57,9 @@
END:VEVENT
END:VCALENDAR
""")
+
+ def _getStorer(self, calendar):
+ self.sampleCalendar = calendar
req = SimpleRequest(None, "COPY", "http://example.com/foo/bar")
self.storer = StoreCalendarObjectResource(
req,
@@ -64,8 +68,8 @@
destination_uri="http://example.com/foo/baz",
calendar=self.sampleCalendar
)
-
-
+ return self.storer
+
@inlineCallbacks
def test_simpleValidRequest(self):
"""
@@ -73,7 +77,7 @@
L{StoreCalendarObjectResource.fullValidation} results in a L{Deferred}
which fires with C{None} (and raises no exception).
"""
- self.assertEquals((yield self.storer.fullValidation()), None)
+ self.assertEquals((yield self._getStorer(self._getSampleCalendar()).fullValidation()), None)
@inlineCallbacks
@@ -87,13 +91,14 @@
"""
# Get the event, and add too many attendees to it.
+ self.sampleCalendar = self._getSampleCalendar()
eventComponent = list(self.sampleCalendar.subcomponents())[0]
for x in xrange(config.MaxAttendeesPerInstance):
eventComponent.addProperty(
- Property(u"ATTENDEE", u"mailto:user%d at example.com" % (x+3,)))
+ Property("ATTENDEE", "mailto:user%d at example.com" % (x+3,)))
try:
- yield self.storer.fullValidation()
+ yield self._getStorer(self.sampleCalendar).fullValidation()
except HTTPError, err:
element = XML(err.response.stream.mem)[0]
self.assertEquals(
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezones.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezones.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezones.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -16,13 +16,9 @@
import os
-import vobject
-from vobject.icalendar import getTzid
-from vobject.icalendar import registerTzid
-
from twext.python.log import Logger
-from twistedcaldav.ical import Component
+from pycalendar.timezonedb import PyCalendarTimezoneDatabase
log = Logger()
@@ -51,114 +47,55 @@
class TimezoneCache(object):
- activeCache = None
+ dirName = None
@staticmethod
- def create():
- if TimezoneCache.activeCache is None:
- TimezoneCache.activeCache = TimezoneCache()
- TimezoneCache.activeCache.register()
+ def _getDBPath():
+ if TimezoneCache.dirName is None:
+ try:
+ import pkg_resources
+ except ImportError:
+ TimezoneCache.dirName = os.path.join(os.path.dirname(__file__), "zoneinfo")
+ else:
+ TimezoneCache.dirName = pkg_resources.resource_filename("twistedcaldav", "zoneinfo")
- def __init__(self):
- self._caching = False
+ return TimezoneCache.dirName
- def register(self):
- self.vobjectRegisterTzid = registerTzid
- vobject.icalendar.registerTzid = self.registerTzidFromCache
+ @staticmethod
+ def create(dbpath=None):
+ PyCalendarTimezoneDatabase.createTimezoneDatabase(TimezoneCache._getDBPath() if dbpath is None else dbpath)
- def unregister(self):
- vobject.icalendar.registerTzid = self.vobjectRegisterTzid
+ @staticmethod
+ def clear():
+ PyCalendarTimezoneDatabase.clearTimezoneDatabase()
- def loadTimezone(self, tzid):
- # Make sure it is not already loaded
- if getTzid(tzid) != None:
- return False
+# zoneinfo never changes in a running instance so cache all this data as we use it
+cachedTZs = {}
+cachedTZIDs = []
- tzData = readTZ(tzid)
- calendar = Component.fromString(tzData)
+def readTZ(tzid):
- if calendar.name() != "VCALENDAR":
- raise TimezoneException("%s does not contain valid iCalendar data." % (tzid,))
-
- # Check that we now have it cached
- if getTzid(tzid) == None:
- raise TimezoneException("Could not read timezone %s from timezone cache." % (tzid,))
+ if tzid not in cachedTZs:
- return True
-
- def registerTzidFromCache(self, tzid, tzinfo):
- if not self._caching:
- self._caching = True
- try:
- self.loadTimezone(tzid)
- except TimezoneException:
- # Fallback to vobject processing the actual tzdata
- log.err("Cannot load timezone data for %s from timezone cache" % (tzid,))
- self.vobjectRegisterTzid(tzid, tzinfo)
- self._caching = False
+ tzcal = PyCalendarTimezoneDatabase.getTimezoneInCalendar(tzid)
+ if tzcal:
+ cachedTZs[tzid] = str(tzcal)
else:
- self.vobjectRegisterTzid(tzid, tzinfo)
-
-try:
- # zoneinfo never changes in a running instance so cache all this data as we use it
- cachedTZs = {}
- cachedTZIDs = []
-
- import pkg_resources
-except ImportError:
- #
- # We don't have pkg_resources, so assume file paths work, since that's all we have
- #
-
- dirname = os.path.join(os.path.dirname(__file__), "zoneinfo")
- def readTZ(tzid):
-
- if tzid not in cachedTZs:
- tzpath = os.path.join(*tzid.split("/")) # Don't assume "/" from tzid is a path separator
- tzpath = os.path.join(dirname, tzpath + ".ics")
- try:
- cachedTZs[tzid] = file(tzpath).read()
- except IOError:
- raise TimezoneException("Unknown time zone: %s" % (tzid,))
-
- return cachedTZs[tzid]
+ raise TimezoneException("Unknown time zone: %s" % (tzid,))
- def listTZs(path=""):
- if not path and cachedTZIDs:
- return cachedTZIDs
+ return cachedTZs[tzid]
- result = []
- for item in os.listdir(os.path.join(dirname, path)):
- if item.find('.') == -1:
- result.extend(listTZs(os.path.join(path, item)))
- elif item.endswith(".ics"):
- result.append(os.path.join(path, item[:-4]))
-
- if not path:
- cachedTZIDs.extend(result)
- return result
-else:
- def readTZ(tzid):
- if tzid not in cachedTZs:
- # Here, "/" is always the path separator
- try:
- cachedTZs[tzid] = pkg_resources.resource_stream("twistedcaldav", "zoneinfo/%s.ics" % (tzid,)).read()
- except IOError:
- raise TimezoneException("Unknown time zone: %s" % (tzid,))
-
- return cachedTZs[tzid]
+def listTZs(path=""):
+ if not path and cachedTZIDs:
+ return cachedTZIDs
- def listTZs(path=""):
- if not path and cachedTZIDs:
- return cachedTZIDs
-
- result = []
- for item in pkg_resources.resource_listdir("twistedcaldav", os.path.join("zoneinfo", path)):
- if item.find('.') == -1:
- result.extend(listTZs(os.path.join(path, item)))
- elif item.endswith(".ics"):
- result.append(os.path.join(path, item[:-4]))
-
- if not path:
- cachedTZIDs.extend(result)
- return result
+ result = []
+ for item in os.listdir(os.path.join(TimezoneCache._getDBPath(), path)):
+ if item.find('.') == -1:
+ result.extend(listTZs(os.path.join(path, item)))
+ elif item.endswith(".ics"):
+ result.append(os.path.join(path, item[:-4]))
+
+ if not path:
+ cachedTZIDs.extend(result)
+ return result
Modified: CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezoneservice.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezoneservice.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/twistedcaldav/timezoneservice.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -40,13 +40,14 @@
from twistedcaldav.customxml import calendarserver_namespace
from twistedcaldav.extensions import DAVResource,\
DAVResourceWithoutChildrenMixin
-from twistedcaldav.ical import parse_date_or_datetime
from twistedcaldav.ical import tzexpand
from twistedcaldav.resource import ReadOnlyNoCopyResourceMixIn
from twistedcaldav.timezones import TimezoneException
from twistedcaldav.timezones import listTZs
from twistedcaldav.timezones import readTZ
+from pycalendar.datetime import PyCalendarDateTime
+
class TimezoneServiceResource (ReadOnlyNoCopyResourceMixIn, DAVResourceWithoutChildrenMixin, DAVResource):
"""
Timezone Service resource.
@@ -228,7 +229,7 @@
start = request.args.get("start", ())
if len(start) != 1:
raise ValueError()
- start = parse_date_or_datetime(start[0])
+ start = PyCalendarDateTime.parseText(start[0])
except ValueError:
raise HTTPError(ErrorResponse(
responsecode.BAD_REQUEST,
@@ -239,7 +240,7 @@
end = request.args.get("end", ())
if len(end) != 1:
raise ValueError()
- end = parse_date_or_datetime(end[0])
+ end = PyCalendarDateTime.parseText(end[0])
if end <= start:
raise ValueError()
except ValueError:
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -39,8 +39,6 @@
except ImportError:
from pysqlite2 import dbapi2 as sqlite
-from vobject.icalendar import utc
-
from twisted.internet.defer import maybeDeferred, succeed
from twext.python.log import Logger, LoggingMixIn
@@ -48,6 +46,7 @@
from txdav.common.icommondatastore import SyncTokenValidException,\
ReservationError, IndexedSearchException
+from twistedcaldav.dateops import pyCalendarTodatetime
from twistedcaldav.ical import Component
from twistedcaldav.query import calendarquery, calendarqueryfilter
from twistedcaldav.sql import AbstractSQLDatabase
@@ -56,6 +55,10 @@
from twistedcaldav.config import config
from twistedcaldav.memcachepool import CachePoolUserMixIn
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.duration import PyCalendarDuration
+from pycalendar.timezone import PyCalendarTimezone
+
log = Logger()
db_basename = db_prefix + "sqlite"
@@ -311,9 +314,9 @@
# will have been indexed with an "infinite" value always included.
maxDate, isStartDate = filter.getmaxtimerange()
if maxDate:
- maxDate = maxDate.date()
+ maxDate.setDateOnly(True)
if isStartDate:
- maxDate += datetime.timedelta(days=365)
+ maxDate += PyCalendarDuration(days=365)
self.testAndUpdateIndex(maxDate)
else:
# We cannot handle this filter in an indexed search
@@ -605,7 +608,7 @@
Gives all resources which have not been expanded beyond a given date
in the index
"""
- return self._db_values_for_sql("select NAME from RESOURCE where RECURRANCE_MAX < :1", minDate)
+ return self._db_values_for_sql("select NAME from RESOURCE where RECURRANCE_MAX < :1", pyCalendarTodatetime(minDate))
def reExpandResource(self, name, expand_until):
"""
@@ -639,7 +642,7 @@
# When there is no master we have a set of overridden components - index them all.
# When there is one instance - index it.
# When bounded - index all.
- expand = datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc)
+ expand = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
doInstanceIndexing = True
else:
# If migrating or re-creating or config option for delayed indexing is off, always index
@@ -650,8 +653,8 @@
# by default. This is a caching parameter which affects the size of the index;
# it does not affect search results beyond this period, but it may affect
# performance of such a search.
- expand = (datetime.date.today() +
- datetime.timedelta(days=config.FreeBusyIndexExpandAheadDays))
+ expand = (PyCalendarDateTime.getToday() +
+ PyCalendarDuration(days=config.FreeBusyIndexExpandAheadDays))
if expand_until and expand_until > expand:
expand = expand_until
@@ -668,8 +671,8 @@
# occurrences into some obscenely far-in-the-future date, so we cap the caching
# period. Searches beyond this period will always be relatively expensive for
# resources with occurrences beyond this period.
- if expand > (datetime.date.today() +
- datetime.timedelta(days=config.FreeBusyIndexExpandMaxDays)):
+ if expand > (PyCalendarDateTime.getToday() +
+ PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)):
raise IndexedSearchException()
# Always do recurrence expansion even if we do not intend to index - we need this to double-check the
@@ -684,7 +687,7 @@
# Now coerce indexing to off if needed
if not doInstanceIndexing:
instances = None
- recurrenceLimit = datetime.datetime(1900, 1, 1, 0, 0, 0, tzinfo=utc)
+ recurrenceLimit = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
self._delete_from_db(name, uid, False)
@@ -693,7 +696,7 @@
"""
insert into RESOURCE (NAME, UID, TYPE, RECURRANCE_MAX, ORGANIZER)
values (:1, :2, :3, :4, :5)
- """, name, uid, calendar.resourceType(), recurrenceLimit, organizer
+ """, name, uid, calendar.resourceType(), pyCalendarTodatetime(recurrenceLimit) if recurrenceLimit else None, organizer
)
resourceid = self.lastrowid
@@ -720,9 +723,9 @@
if doInstanceIndexing:
for key in instances:
instance = instances[key]
- start = instance.start.replace(tzinfo=utc)
- end = instance.end.replace(tzinfo=utc)
- float = 'Y' if instance.start.tzinfo is None else 'N'
+ start = instance.start
+ end = instance.end
+ float = 'Y' if instance.start.floating() else 'N'
transp = 'T' if instance.component.propertyValue("TRANSP") == "TRANSPARENT" else 'F'
self._db_execute(
"""
@@ -731,8 +734,8 @@
""",
resourceid,
float,
- start,
- end,
+ pyCalendarTodatetime(start),
+ pyCalendarTodatetime(end),
icalfbtype_to_indexfbtype.get(instance.component.getFBType(), 'F'),
transp
)
@@ -751,14 +754,14 @@
# Special - for unbounded recurrence we insert a value for "infinity"
# that will allow an open-ended time-range to always match it.
if calendar.isRecurringUnbounded():
- start = datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc)
- end = datetime.datetime(2100, 1, 1, 1, 0, 0, tzinfo=utc)
+ start = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+ end = PyCalendarDateTime(2100, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
float = 'N'
self._db_execute(
"""
insert into TIMESPAN (RESOURCEID, FLOAT, START, END, FBTYPE, TRANSPARENT)
values (:1, :2, :3, :4, :5, :6)
- """, resourceid, float, start, end, '?', '?'
+ """, resourceid, float, pyCalendarTodatetime(start), pyCalendarTodatetime(end), '?', '?'
)
instanceid = self.lastrowid
peruserdata = calendar.perUserTransparency(None)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/sql.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/sql.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -39,7 +39,7 @@
from twistedcaldav.caldavxml import ScheduleCalendarTransp, Opaque
from twistedcaldav.config import config
from twistedcaldav.dateops import normalizeForIndex, datetimeMktime,\
- parseSQLTimestamp
+ parseSQLTimestamp, pyCalendarTodatetime
from twistedcaldav.ical import Component
from twistedcaldav.instance import InvalidOverriddenInstanceError
from twistedcaldav.memcacher import Memcacher
@@ -69,10 +69,10 @@
from twext.enterprise.dal.syntax import Len
from txdav.common.icommondatastore import IndexedSearchException
-from vobject.icalendar import utc
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.duration import PyCalendarDuration
+from pycalendar.timezone import PyCalendarTimezone
-import datetime
-
from zope.interface.declarations import implements
class CalendarHome(CommonHome):
@@ -421,12 +421,12 @@
doInstanceIndexing = False
master = component.masterComponent()
if ( master is None or not component.isRecurring()
- and not component.isRecurringUnbounded() ):
+ or not component.isRecurringUnbounded() ):
# When there is no master we have a set of overridden components -
# index them all.
# When there is one instance - index it.
# When bounded - index all.
- expand = datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc)
+ expand = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
doInstanceIndexing = True
else:
@@ -438,8 +438,8 @@
# by default. This is a caching parameter which affects the size of the index;
# it does not affect search results beyond this period, but it may affect
# performance of such a search.
- expand = (datetime.date.today() +
- datetime.timedelta(days=config.FreeBusyIndexExpandAheadDays))
+ expand = (PyCalendarDateTime.getToday() +
+ PyCalendarDuration(days=config.FreeBusyIndexExpandAheadDays))
if expand_until and expand_until > expand:
expand = expand_until
@@ -456,8 +456,8 @@
# occurrences into some obscenely far-in-the-future date, so we cap the caching
# period. Searches beyond this period will always be relatively expensive for
# resources with occurrences beyond this period.
- if expand > (datetime.date.today() +
- datetime.timedelta(days=config.FreeBusyIndexExpandMaxDays)):
+ if expand > (PyCalendarDateTime.getToday() +
+ PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)):
raise IndexedSearchException
# Always do recurrence expansion even if we do not intend to index - we need this to double-check the
@@ -479,7 +479,7 @@
# Now coerce indexing to off if needed
if not doInstanceIndexing:
instances = None
- recurrenceLimit = datetime.datetime(1900, 1, 1, 0, 0, 0, tzinfo=utc)
+ recurrenceLimit = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
co = schema.CALENDAR_OBJECT
tr = schema.TIME_RANGE
@@ -524,7 +524,7 @@
co.DROPBOX_ID : self._dropboxID,
co.ORGANIZER : organizer,
co.RECURRANCE_MAX :
- normalizeForIndex(recurrenceLimit) if recurrenceLimit else None,
+ pyCalendarTodatetime(normalizeForIndex(recurrenceLimit)) if recurrenceLimit else None,
co.ACCESS : self._access,
co.SCHEDULE_OBJECT : self._schedule_object,
co.SCHEDULE_TAG : self._schedule_tag,
@@ -556,7 +556,7 @@
else:
values = {
co.RECURRANCE_MAX :
- normalizeForIndex(recurrenceLimit) if recurrenceLimit else None,
+ pyCalendarTodatetime(normalizeForIndex(recurrenceLimit)) if recurrenceLimit else None,
}
yield Update(
@@ -574,16 +574,18 @@
# TIME_RANGE table update
for key in instances:
instance = instances[key]
- start = instance.start.replace(tzinfo=utc)
- end = instance.end.replace(tzinfo=utc)
- float = instance.start.tzinfo is None
+ start = instance.start
+ end = instance.end
+ float = instance.start.floating()
+ start.setTimezoneUTC(True)
+ end.setTimezoneUTC(True)
transp = instance.component.propertyValue("TRANSP") == "TRANSPARENT"
instanceid = (yield Insert({
tr.CALENDAR_RESOURCE_ID : self._calendar._resourceID,
tr.CALENDAR_OBJECT_RESOURCE_ID : self._resourceID,
tr.FLOATING : float,
- tr.START_DATE : start,
- tr.END_DATE : end,
+ tr.START_DATE : pyCalendarTodatetime(start),
+ tr.END_DATE : pyCalendarTodatetime(end),
tr.FBTYPE :
icalfbtype_to_indexfbtype.get(
instance.component.getFBType(),
@@ -601,16 +603,16 @@
# Special - for unbounded recurrence we insert a value for "infinity"
# that will allow an open-ended time-range to always match it.
if component.isRecurringUnbounded():
- start = datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc)
- end = datetime.datetime(2100, 1, 1, 1, 0, 0, tzinfo=utc)
+ start = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+ end = PyCalendarDateTime(2100, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
float = False
transp = True
instanceid = (yield Insert({
tr.CALENDAR_RESOURCE_ID : self._calendar._resourceID,
tr.CALENDAR_OBJECT_RESOURCE_ID : self._resourceID,
tr.FLOATING : float,
- tr.START_DATE : start,
- tr.END_DATE : end,
+ tr.START_DATE : pyCalendarTodatetime(start),
+ tr.END_DATE : pyCalendarTodatetime(end),
tr.FBTYPE :
icalfbtype_to_indexfbtype["UNKNOWN"],
tr.TRANSPARENT : transp,
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -15,6 +15,7 @@
##
from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
from twisted.internet.task import deferLater
from txdav.caldav.datastore.index_file import Index, MemcachedUIDReserver
@@ -29,11 +30,10 @@
from twistedcaldav.test.util import InMemoryMemcacheProtocol
import twistedcaldav.test.util
-import datetime
+from pycalendar.datetime import PyCalendarDateTime
+
import os
-from twisted.internet.defer import inlineCallbacks
-
class MinimalCalendarObjectReplacement(object):
"""
Provide the minimal set of attributes and methods from CalDAVFile required
@@ -301,7 +301,7 @@
else:
self.assertFalse(self.db.resourceExists(name), msg=description)
- self.db.testAndUpdateIndex(datetime.date(2020, 1, 1))
+ self.db.testAndUpdateIndex(PyCalendarDateTime(2020, 1, 1))
for description, name, calendar_txt, reCreate, ok in data:
if ok:
self.assertTrue(self.db.resourceExists(name), msg=description)
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/util.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/util.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -89,16 +89,15 @@
# Now look at each ATTACH property and see if it might be a dropbox item
# and if so extract the id from that
- attachments = (yield calendarObject.component()
- ).getAllPropertiesInAnyComponent(
+ attachments = (yield calendarObject.component()).getAllPropertiesInAnyComponent(
"ATTACH",
depth=1,
)
for attachment in attachments:
# Make sure the value type is URI and http(s) and it is in a dropbox
- valueType = attachment.params().get("VALUE", ("TEXT",))
- if valueType[0] == "URI" and attachment.value().startswith("http"):
+ valueType = attachment.parameterValue("VALUE", "URI")
+ if valueType == "URI" and attachment.value().startswith("http"):
segments = attachment.value().split("/")
try:
if segments[-3] == "dropbox":
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/icalendarstore.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/icalendarstore.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -35,16 +35,6 @@
]
-# The following imports are used by the L{} links below, but shouldn't actually
-# be imported.as they're not really needed.
-
-# from datetime import datetime, date, tzinfo
-
-# from twext.python.vcomponent import VComponent
-
-# from txdav.idav import IPropertyStore
-# from txdav.idav import ITransaction
-
class ICalendarTransaction(ICommonTransaction):
"""
Transaction functionality required to be implemented by calendar stores.
@@ -288,9 +278,9 @@
instances that occur within the time range that begins at
C{start} and ends at C{end}.
- @param start: a L{datetime} or L{date}.
- @param end: a L{datetime} or L{date}.
- @param timeZone: a L{tzinfo}.
+ @param start: a L{PyCalendarDateTime}.
+ @param end: a L{PyCalendarDateTime}.
+ @param timeZone: a L{PyCalendarTimezone}.
@return: an iterable of L{ICalendarObject}s.
"""
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -75,7 +75,8 @@
from txdav.base.propertystore.sql import PropertyStore
from twistedcaldav.customxml import NotificationType
-from twistedcaldav.dateops import datetimeMktime, parseSQLTimestamp
+from twistedcaldav.dateops import datetimeMktime, parseSQLTimestamp,\
+ pyCalendarTodatetime
v1_schema = getModule(__name__).filePath.sibling("sql_schema_v1.sql").getContent()
@@ -303,12 +304,12 @@
def eventsOlderThan(self, cutoff, batchSize=None):
"""
Return up to the oldest batchSize events which exist completely earlier
- than "cutoff" (datetime)
+ than "cutoff" (PyCalendarDateTime)
Returns a deferred to a list of (uid, calendarName, eventName, maxDate)
tuples.
"""
- kwds = { "CutOff" : cutoff }
+ kwds = { "CutOff" : pyCalendarTodatetime(cutoff) }
if batchSize is not None:
kwds["batchSize"] = batchSize
query = self._oldEventsLimited
Modified: CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql_legacy.py 2011-03-09 03:29:17 UTC (rev 7161)
+++ CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql_legacy.py 2011-03-09 03:41:33 UTC (rev 7162)
@@ -20,7 +20,6 @@
PostgreSQL data store.
"""
-import datetime
import StringIO
from twistedcaldav.sharing import SharedCollectionRecord
@@ -32,7 +31,7 @@
from twistedcaldav import carddavxml
from twistedcaldav.config import config
-from twistedcaldav.dateops import normalizeForIndex
+from twistedcaldav.dateops import normalizeForIndex, pyCalendarTodatetime
from twistedcaldav.memcachepool import CachePoolUserMixIn
from twistedcaldav.notifications import NotificationRecord
from twistedcaldav.query import calendarqueryfilter, calendarquery, \
@@ -48,6 +47,8 @@
CALENDAR_BIND_TABLE, CALENDAR_HOME_TABLE, ADDRESSBOOK_HOME_TABLE, \
ADDRESSBOOK_BIND_TABLE
+from pycalendar.duration import PyCalendarDuration
+
log = Logger()
indexfbtype_to_icalfbtype = {
@@ -948,7 +949,7 @@
returnValue([row[0] for row in (yield self._txn.execSQL(
"select RESOURCE_NAME from CALENDAR_OBJECT "
"where RECURRANCE_MAX < %s and CALENDAR_RESOURCE_ID = %s",
- [normalizeForIndex(minDate), self.calendar._resourceID]
+ [pyCalendarTodatetime(normalizeForIndex(minDate)), self.calendar._resourceID]
))])
@@ -1002,9 +1003,9 @@
# "infinite" value always included.
maxDate, isStartDate = filter.getmaxtimerange()
if maxDate:
- maxDate = maxDate.date()
+ maxDate.setDateOnly(True)
if isStartDate:
- maxDate += datetime.timedelta(days=365)
+ maxDate += PyCalendarDuration(days=365)
yield self.testAndUpdateIndex(maxDate)
else:
# We cannot handler this filter in an indexed search
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110308/6a52be3e/attachment-0001.html>
More information about the calendarserver-changes
mailing list