[Vobject] copy.deepcopy on a calendar
Cyrus Daboo
cyrus+lists.vobject at daboo.name
Wed Feb 22 13:53:34 CST 2006
Hi,
I am trying to duplicate a calendar using copy.deepcopy, but have run into
a problem. Basically, whenever a DATE-TIME value in the iCal component
contains a named timezone, the deepcopy fails with:
copy.Error: un(deep)copyable object of type <type 'thread.lock'>
Setting the date-time value to UTC or floating results in deepcopy working.
Also, doing a 'transformFromNative' on the calendar Component and all its
children also fixes the problem. i.e. the problem seems to be related to
use of an explicit timezone object in a datetime.datetime value in a
property.
Attached is some code that illustrates the problem.
I believe the issue is caused by the self._cache_lock in class rrulebase in
rrule.py in dateutil. However, I'm not sure if it can be resolved there.
Some possible workarounds:
1) Do 'transformFromNative', then do deepcopy, then transform back each
time a duplicate component is needed.
2) Fix dateutil.
3) Add a 'duplicate' method in vobject that does not use deepcopy.
I ended up doing the later and that works well. However I'm not sure
whether others would want this. Attached is a patch to base.py that does
this - please comment.
--
Cyrus Daboo
-------------- next part --------------
import base, behavior, icalendar, vcard
import copy
icaltest1=r"""BEGIN:VCALENDAR
CALSCALE:GREGORIAN
X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
METHOD:PUBLISH
PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
X-WR-CALNAME;VALUE=TEXT:Example
VERSION:2.0
BEGIN:VEVENT
SEQUENCE:5
DTSTART;TZID=US/Pacific:20021028T140000
DTSTAMP:20021028T011706Z
SUMMARY:Coffee with Jason
UID:EC9439B1-FF65-11D6-9973-003065F99D04
DTEND;TZID=US/Pacific:20021028T150000
END:VEVENT
BEGIN:VTIMEZONE
X-LIC-LOCATION:Random location
TZID:US/Pacific
LAST-MODIFIED:19870101T000000Z
BEGIN:STANDARD
DTSTART:19671029T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19870405T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR"""
icaltest2=r"""BEGIN:VCALENDAR
CALSCALE:GREGORIAN
X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
METHOD:PUBLISH
PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
X-WR-CALNAME;VALUE=TEXT:Example
VERSION:2.0
BEGIN:VEVENT
SEQUENCE:5
DTSTART:20021028T140000Z
DTSTAMP:20021028T011706Z
SUMMARY:Coffee with Jason
UID:EC9439B1-FF65-11D6-9973-003065F99D04
DTEND:20021028T150000Z
END:VEVENT
END:VCALENDAR"""
def doCopy(name, calname):
try:
cal = base.readOne(calname)
copy.deepcopy(cal)
except copy.Error, txt:
print "deepcopy failed for file %s with error %s" % (name, txt)
else:
print "deepcopy worked for file %s" % (name,)
if __name__ == '__main__':
doCopy("icaltest1", icaltest1)
doCopy("icaltest2", icaltest2)
-------------- next part --------------
Index: src/vobject/base.py
===================================================================
--- src/vobject/base.py (revision 131)
+++ src/vobject/base.py (working copy)
@@ -1,5 +1,6 @@
"""vobject module for reading vCard and vCalendar files."""
+import copy
import re
import sys
import logging
@@ -56,6 +57,12 @@
self.parentBehavior = None
self.isNative = False
+ def copy(self, copyit):
+ self.group = copyit.group
+ self.behavior = copyit.behavior
+ self.parentBehavior = copyit.parentBehavior
+ self.isNative = copyit.isNative
+
def validate(self, *args, **kwds):
"""Call the behavior's validate method, or return True."""
if self.behavior:
@@ -245,6 +252,21 @@
if qp:
self.value = str(self.value).decode('quoted-printable')
+ @classmethod
+ def duplicate(clz, copyit):
+ newcopy = clz('', {}, '')
+ newcopy.copy(copyit)
+ return newcopy
+
+ def copy(self, copyit):
+ super(ContentLine, self).copy(copyit)
+ self.name = copyit.name
+ self.value = copy.copy(copyit.value)
+ self.encoded = self.encoded
+ self.params = copy.copy(copyit.params)
+ self.singletonparams = copy.copy(copyit.singletonparams)
+ self.lineNumber = copyit.lineNumber
+
def __eq__(self, other):
try:
return (self.name == other.name) and (self.params == other.params) and (self.value == other.value)
@@ -348,6 +370,27 @@
self.autoBehavior()
+ @classmethod
+ def duplicate(clz, copyit):
+ newcopy = clz()
+ newcopy.copy(copyit)
+ return newcopy
+
+ def copy(self, copyit):
+ super(Component, self).copy(copyit)
+
+ # deep copy of contents
+ self.contents = {}
+ for key, lvalue in copyit.contents.items():
+ newvalue = []
+ for value in lvalue:
+ newitem = value.duplicate(value)
+ newvalue.append(newitem)
+ self.contents[key] = newvalue
+
+ self.name = copyit.name
+ self.useBegin = copyit.useBegin
+
def setProfile(self, name):
"""Assign a PROFILE to this unnamed component.
More information about the VObject
mailing list