<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[11914] PyCalendar/trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/11914">11914</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2013-11-08 12:35:58 -0800 (Fri, 08 Nov 2013)</dd>
</dl>
<h3>Log Message</h3>
<pre>Major refactor to support JSON encoded iCalendar data. Module was re-organized and various naming issues cleaned up. This change is
NOT backwards compatible. Most code using PyCalendar will need to be updated.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#PyCalendartrunkpydevproject">PyCalendar/trunk/.pydevproject</a></li>
<li><a href="#PyCalendartrunksetuppy">PyCalendar/trunk/setup.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendar__init__py">PyCalendar/trunk/src/pycalendar/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarbinaryvaluepy">PyCalendar/trunk/src/pycalendar/binaryvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcaladdressvaluepy">PyCalendar/trunk/src/pycalendar/caladdressvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentbasepy">PyCalendar/trunk/src/pycalendar/componentbase.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardatetimepy">PyCalendar/trunk/src/pycalendar/datetime.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardatetimevaluepy">PyCalendar/trunk/src/pycalendar/datetimevalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardurationpy">PyCalendar/trunk/src/pycalendar/duration.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardurationvaluepy">PyCalendar/trunk/src/pycalendar/durationvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarexceptionspy">PyCalendar/trunk/src/pycalendar/exceptions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendar__init__py">PyCalendar/trunk/src/pycalendar/icalendar/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendartests__init__py">PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_validationpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvalidationpy">PyCalendar/trunk/src/pycalendar/icalendar/validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarintegervaluepy">PyCalendar/trunk/src/pycalendar/integervalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarlocalepy">PyCalendar/trunk/src/pycalendar/locale.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarmanagerpy">PyCalendar/trunk/src/pycalendar/manager.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarmultivaluepy">PyCalendar/trunk/src/pycalendar/multivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaroutputfilterpy">PyCalendar/trunk/src/pycalendar/outputfilter.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarperiodpy">PyCalendar/trunk/src/pycalendar/period.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarperiodvaluepy">PyCalendar/trunk/src/pycalendar/periodvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarplaintextvaluepy">PyCalendar/trunk/src/pycalendar/plaintextvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarpropertypy">PyCalendar/trunk/src/pycalendar/property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarstringutilspy">PyCalendar/trunk/src/pycalendar/stringutils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartests__init__py">PyCalendar/trunk/src/pycalendar/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_datetimepy">PyCalendar/trunk/src/pycalendar/tests/test_datetime.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_durationpy">PyCalendar/trunk/src/pycalendar/tests/test_duration.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_multivaluepy">PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_urivaluepy">PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_utilspy">PyCalendar/trunk/src/pycalendar/tests/test_utils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_validationpy">PyCalendar/trunk/src/pycalendar/tests/test_validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartextvaluepy">PyCalendar/trunk/src/pycalendar/textvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartimezonepy">PyCalendar/trunk/src/pycalendar/timezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartimezonedbpy">PyCalendar/trunk/src/pycalendar/timezonedb.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarunknownvaluepy">PyCalendar/trunk/src/pycalendar/unknownvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarurivaluepy">PyCalendar/trunk/src/pycalendar/urivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarutcoffsetvaluepy">PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarutilspy">PyCalendar/trunk/src/pycalendar/utils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalidationpy">PyCalendar/trunk/src/pycalendar/validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalidatorpy">PyCalendar/trunk/src/pycalendar/validator.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvaluepy">PyCalendar/trunk/src/pycalendar/value.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalueutilspy">PyCalendar/trunk/src/pycalendar/valueutils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcard__init__py">PyCalendar/trunk/src/pycalendar/vcard/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardcardpy">PyCalendar/trunk/src/pycalendar/vcard/card.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcarddefinitionspy">PyCalendar/trunk/src/pycalendar/vcard/definitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardpropertypy">PyCalendar/trunk/src/pycalendar/vcard/property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardtests__init__py">PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_cardpy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_propertypy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_validationpy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardvalidationpy">PyCalendar/trunk/src/pycalendar/vcard/validation.py</a></li>
<li><a href="#PyCalendartrunksrczonal__init__py">PyCalendar/trunk/src/zonal/__init__.py</a></li>
<li><a href="#PyCalendartrunksrczonalrulepy">PyCalendar/trunk/src/zonal/rule.py</a></li>
<li><a href="#PyCalendartrunksrczonaltests__init__py">PyCalendar/trunk/src/zonal/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrczonalteststest_rulepy">PyCalendar/trunk/src/zonal/tests/test_rule.py</a></li>
<li><a href="#PyCalendartrunksrczonalteststest_zonepy">PyCalendar/trunk/src/zonal/tests/test_zone.py</a></li>
<li><a href="#PyCalendartrunksrczonaltzconvertpy">PyCalendar/trunk/src/zonal/tzconvert.py</a></li>
<li><a href="#PyCalendartrunksrczonaltzdumppy">PyCalendar/trunk/src/zonal/tzdump.py</a></li>
<li><a href="#PyCalendartrunksrczonaltzverifypy">PyCalendar/trunk/src/zonal/tzverify.py</a></li>
<li><a href="#PyCalendartrunksrczonalutilspy">PyCalendar/trunk/src/zonal/utils.py</a></li>
<li><a href="#PyCalendartrunksrczonalzonepy">PyCalendar/trunk/src/zonal/zone.py</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#PyCalendartrunksrcpycalendarcontainerbasepy">PyCalendar/trunk/src/pycalendar/containerbase.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarfloatvaluepy">PyCalendar/trunk/src/pycalendar/floatvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendargeovaluepy">PyCalendar/trunk/src/pycalendar/geovalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendaravailablepy">PyCalendar/trunk/src/pycalendar/icalendar/available.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcalendarpy">PyCalendar/trunk/src/pycalendar/icalendar/calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcomponentpy">PyCalendar/trunk/src/pycalendar/icalendar/component.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcomponentexpandedpy">PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcomponentrecurpy">PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendardefinitionspy">PyCalendar/trunk/src/pycalendar/icalendar/definitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarfreebusypy">PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendaritipdefinitionspy">PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarpropertypy">PyCalendar/trunk/src/pycalendar/icalendar/property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrecurrencepy">PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrecurrencesetpy">PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrecurrencevaluepy">PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrequeststatusvaluepy">PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_calendarpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_componentrecurpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_i18npy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_jsonpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_propertypy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_recurrencepy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_requeststatuspy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_timezonepy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_vpollpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_xmlpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvalarmpy">PyCalendar/trunk/src/pycalendar/icalendar/valarm.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvavailabilitypy">PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarveventpy">PyCalendar/trunk/src/pycalendar/icalendar/vevent.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvfreebusypy">PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvjournalpy">PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvpollpy">PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezonepy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezonedaylightpy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezoneelementpy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezonestandardpy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtodopy">PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvunknownpy">PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarxmldefinitionspy">PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarparameterpy">PyCalendar/trunk/src/pycalendar/parameter.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardadrpy">PyCalendar/trunk/src/pycalendar/vcard/adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardadrvaluepy">PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardnpy">PyCalendar/trunk/src/pycalendar/vcard/n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardnvaluepy">PyCalendar/trunk/src/pycalendar/vcard/nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardorgvaluepy">PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_adrpy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_adrvaluepy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_npy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_nvaluepy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_orgvaluepy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardxmldefinitionspy">PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarxmldefinitionspy">PyCalendar/trunk/src/pycalendar/xmldefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarxmlutilspy">PyCalendar/trunk/src/pycalendar/xmlutils.py</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#PyCalendartrunksrcpycalendaradrpy">PyCalendar/trunk/src/pycalendar/adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaradrvaluepy">PyCalendar/trunk/src/pycalendar/adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarattributepy">PyCalendar/trunk/src/pycalendar/attribute.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaravailablepy">PyCalendar/trunk/src/pycalendar/available.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcalendarpy">PyCalendar/trunk/src/pycalendar/calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentpy">PyCalendar/trunk/src/pycalendar/component.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentexpandedpy">PyCalendar/trunk/src/pycalendar/componentexpanded.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentrecurpy">PyCalendar/trunk/src/pycalendar/componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardefinitionspy">PyCalendar/trunk/src/pycalendar/definitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarfreebusypy">PyCalendar/trunk/src/pycalendar/freebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaritipdefinitionspy">PyCalendar/trunk/src/pycalendar/itipdefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarnpy">PyCalendar/trunk/src/pycalendar/n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarnvaluepy">PyCalendar/trunk/src/pycalendar/nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarorgvaluepy">PyCalendar/trunk/src/pycalendar/orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrecurrencepy">PyCalendar/trunk/src/pycalendar/recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrecurrencesetpy">PyCalendar/trunk/src/pycalendar/recurrenceset.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrecurrencevaluepy">PyCalendar/trunk/src/pycalendar/recurrencevalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrequeststatusvaluepy">PyCalendar/trunk/src/pycalendar/requeststatusvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_adrpy">PyCalendar/trunk/src/pycalendar/tests/test_adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_adrvaluepy">PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_calendarpy">PyCalendar/trunk/src/pycalendar/tests/test_calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_componentrecurpy">PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_i18npy">PyCalendar/trunk/src/pycalendar/tests/test_i18n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_npy">PyCalendar/trunk/src/pycalendar/tests/test_n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_nvaluepy">PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_orgvaluepy">PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_propertypy">PyCalendar/trunk/src/pycalendar/tests/test_property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_recurrencepy">PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_requeststatuspy">PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_timezonepy">PyCalendar/trunk/src/pycalendar/tests/test_timezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_xmlpy">PyCalendar/trunk/src/pycalendar/tests/test_xml.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalarmpy">PyCalendar/trunk/src/pycalendar/valarm.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvavailabilitypy">PyCalendar/trunk/src/pycalendar/vavailability.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarveventpy">PyCalendar/trunk/src/pycalendar/vevent.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvfreebusypy">PyCalendar/trunk/src/pycalendar/vfreebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvjournalpy">PyCalendar/trunk/src/pycalendar/vjournal.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezonepy">PyCalendar/trunk/src/pycalendar/vtimezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezonedaylightpy">PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezoneelementpy">PyCalendar/trunk/src/pycalendar/vtimezoneelement.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezonestandardpy">PyCalendar/trunk/src/pycalendar/vtimezonestandard.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtodopy">PyCalendar/trunk/src/pycalendar/vtodo.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvunknownpy">PyCalendar/trunk/src/pycalendar/vunknown.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarxmldefspy">PyCalendar/trunk/src/pycalendar/xmldefs.py</a></li>
</ul>
<h3>Property Changed</h3>
<ul>
<li><a href="#PyCalendartrunk">PyCalendar/trunk/</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="PyCalendartrunk"></a>
<div class="propset"><h4>Property changes: PyCalendar/trunk</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/PyCalendar/branches/revised-api-126:10457-10463
</span><span class="cx">/PyCalendar/branches/server:10466-10553
</span><span class="cx"> + /PyCalendar/branches/duplicate-items:10464-10465
</span><span class="cx">/PyCalendar/branches/json-2:11324-11912
</span><span class="cx">/PyCalendar/branches/revised-api-126:10457-10463
</span><span class="cx">/PyCalendar/branches/server:10466-10553
</span><a id="PyCalendartrunkpydevproject"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/.pydevproject (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/.pydevproject        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/.pydevproject        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,8 +1,6 @@
</span><span class="cx"> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
</span><del>-<?eclipse-pydev version="1.0"?>
-
-<pydev_project>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.5</pydev_property>
</del><ins>+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
</ins><span class="cx"> <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
</span><span class="cx"> <path>/PyCalendar/src</path>
</span><span class="cx"> </pydev_pathproperty>
</span></span></pre></div>
<a id="PyCalendartrunksetuppy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/setup.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/setup.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/setup.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,12 +1,12 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2011 Cyrus Daboo. All rights reserved.
-#
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
+#
</ins><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="cx"> # You may obtain a copy of the License at
</span><del>-#
</del><ins>+#
</ins><span class="cx"> # http://www.apache.org/licenses/LICENSE-2.0
</span><del>-#
</del><ins>+#
</ins><span class="cx"> # Unless required by applicable law or agreed to in writing, software
</span><span class="cx"> # distributed under the License is distributed on an "AS IS" BASIS,
</span><span class="cx"> # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
</span><span class="lines">@@ -17,13 +17,13 @@
</span><span class="cx"> from distutils.core import setup, Extension
</span><span class="cx">
</span><span class="cx"> setup (
</span><del>- name = "pycalendar",
- version = "2.0",
- description = "iCalendar/vCard Library",
- license = "Apache 2.0",
- platforms = ["any"],
</del><ins>+ name="pycalendar",
+ version="2.1",
+ description="iCalendar/vCard Library",
+ license="Apache 2.0",
+ platforms=["any"],
</ins><span class="cx"> package_dir={'': 'src'},
</span><del>- packages = [
</del><ins>+ packages=[
</ins><span class="cx"> 'pycalendar',
</span><span class="cx"> 'pycalendar.icalendar',
</span><span class="cx"> 'pycalendar.vcard',
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendar__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,62 +14,38 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-__all__ = [
- "attribute",
- "available",
- "binaryvalue",
- "caladdressvalue",
- "calendar",
- "datetime",
- "datetimevalue",
- "definitions",
- "duration",
- "durationvalue",
- "exceptions",
- "freebusy",
- "integervalue",
- "locale",
- "manager",
- "multivalue",
- "period",
- "periodvalue",
- "plaintextvalue",
- "property",
- "recurrence",
- "recurrencevalue",
- "requeststatusvalue",
- "textvalue",
- "timezone",
- "timezonedb",
- "unknownvalue",
- "urivalue",
- "utcoffsetvalue",
- "valarm",
- "value",
- "vevent",
- "vfreebusy",
- "vjournal",
- "vtimezone",
- "vtimezonedaylight",
- "vtimezonestandard",
- "vtodo",
- "vunknown",
-]
-
</del><span class="cx"> # Import these to register the values
</span><ins>+
</ins><span class="cx"> import binaryvalue
</span><span class="cx"> import caladdressvalue
</span><span class="cx"> import datetimevalue
</span><span class="cx"> import durationvalue
</span><ins>+import floatvalue
+import geovalue
+import icalendar.recurrencevalue
+import icalendar.requeststatusvalue
</ins><span class="cx"> import integervalue
</span><span class="cx"> import multivalue
</span><span class="cx"> import periodvalue
</span><del>-import recurrencevalue
-import requeststatusvalue
</del><span class="cx"> import textvalue
</span><span class="cx"> import unknownvalue
</span><span class="cx"> import urivalue
</span><span class="cx"> import utcoffsetvalue
</span><ins>+import vcard.adrvalue
+import vcard.nvalue
+import vcard.orgvalue
</ins><span class="cx">
</span><del>-# Import these to force static initialisation
-import property
</del><ins>+# Import these to register the components
+
+import icalendar.available
+import icalendar.valarm
+import icalendar.vavailability
+import icalendar.vevent
+import icalendar.vfreebusy
+import icalendar.vjournal
+import icalendar.vpoll
+import icalendar.vtimezone
+import icalendar.vtimezonedaylight
+import icalendar.vtimezonestandard
+import icalendar.vtodo
+import icalendar.vunknown
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaradrpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/adr.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/adr.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,127 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# vCard ADR value
-
-from pycalendar import utils
-from pycalendar.valueutils import ValueMixin
-
-class Adr(ValueMixin):
- """
- mValue is a tuple of seven str or tuples of str
- """
-
- (
- POBOX,
- EXTENDED,
- STREET,
- LOCALITY,
- REGION,
- POSTALCODE,
- COUNTRY,
- MAXITEMS
- ) = range(8)
-
- def __init__(self, pobox="", extended="", street="", locality="", region="", postalcode="", country=""):
- self.mValue = (pobox, extended, street, locality, region, postalcode, country)
-
-
- def duplicate(self):
- return Adr(*self.mValue)
-
-
- def __hash__(self):
- return hash(self.mValue)
-
-
- def __repr__(self):
- return "ADR %s" % (self.getText(),)
-
-
- def __eq__(self, comp):
- return self.mValue == comp.mValue
-
-
- def getPobox(self):
- return self.mValue[Adr.POBOX]
-
-
- def setPobox(self, value):
- self.mValue[Adr.POBOX] = value
-
-
- def getExtended(self):
- return self.mValue[Adr.EXTENDED]
-
-
- def setExtended(self, value):
- self.mValue[Adr.EXTENDED] = value
-
-
- def getStreet(self):
- return self.mValue[Adr.STREET]
-
-
- def setStreet(self, value):
- self.mValue[Adr.STREET] = value
-
-
- def getLocality(self):
- return self.mValue[Adr.LOCALITY]
-
-
- def setLocality(self, value):
- self.mValue[Adr.LOCALITY] = value
-
-
- def getRegion(self):
- return self.mValue[Adr.REGION]
-
-
- def setRegion(self, value):
- self.mValue[Adr.REGION] = value
-
-
- def getPostalCode(self):
- return self.mValue[Adr.POSTALCODE]
-
-
- def setPostalCode(self, value):
- self.mValue[Adr.POSTALCODE] = value
-
-
- def getCountry(self):
- return self.mValue[Adr.COUNTRY]
-
-
- def setCountry(self, value):
- self.mValue[Adr.COUNTRY] = value
-
-
- def parse(self, data):
- self.mValue = utils.parseDoubleNestedList(data, Adr.MAXITEMS)
-
-
- def generate(self, os):
- utils.generateDoubleNestedList(os, self.mValue)
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendaradrvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/adrvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/adrvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,51 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# vCard ADR value
-
-from pycalendar.adr import Adr
-from pycalendar.value import PyCalendarValue
-
-class AdrValue(PyCalendarValue):
-
- def __init__(self, value=None):
- self.mValue = value if value is not None else Adr()
-
-
- def duplicate(self):
- return AdrValue(self.mValue.duplicate())
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_ADR
-
-
- def parse(self, data):
- self.mValue.parse(data)
-
-
- def generate(self, os):
- self.mValue.generate(os)
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_ADR, AdrValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarattributepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/attribute.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/attribute.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/attribute.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,128 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-"""
-ICalendar attribute.
-
-The attribute can consist of one or more values, all string.
-"""
-
-from pycalendar import xmldefs
-from pycalendar.utils import encodeParameterValue
-import xml.etree.cElementTree as XML
-
-class PyCalendarAttribute(object):
-
- def __init__(self, name, value=None):
- self.mName = name
- if value is None:
- self.mValues = []
- elif isinstance(value, basestring):
- self.mValues = [value]
- else:
- self.mValues = value
-
-
- def duplicate(self):
- other = PyCalendarAttribute(self.mName)
- other.mValues = self.mValues[:]
- return other
-
-
- def __hash__(self):
- return hash((self.mName.upper(), tuple(self.mValues)))
-
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
-
- def __eq__(self, other):
- if not isinstance(other, PyCalendarAttribute):
- return False
- return self.mName.upper() == other.mName.upper() and self.mValues == other.mValues
-
-
- def getName(self):
- return self.mName
-
-
- def setName(self, name):
- self.mName = name
-
-
- def getFirstValue(self):
- return self.mValues[0]
-
-
- def getValues(self):
- return self.mValues
-
-
- def setValues(self, values):
- self.mValues = values
-
-
- def addValue(self, value):
- self.mValues.append(value)
-
-
- def removeValue(self, value):
- self.mValues.remove(value)
- return len(self.mValues)
-
-
- def generate(self, os):
- try:
- os.write(self.mName)
-
- # To support vCard 2.1 syntax we allow parameters without values
- if self.mValues:
- os.write("=")
-
- first = True
- for s in self.mValues:
- if first:
- first = False
- else:
- os.write(",")
-
- # Write with quotation if required
- self.generateValue(os, s)
-
- except:
- # We ignore errors
- pass
-
-
- def generateValue(self, os, str):
-
- # ^-escaping
- str = encodeParameterValue(str)
-
- # Look for quoting
- if str.find(":") != -1 or str.find(";") != -1 or str.find(",") != -1:
- os.write("\"%s\"" % (str,))
- else:
- os.write(str)
-
-
- def writeXML(self, node, namespace):
- param = XML.SubElement(node, xmldefs.makeTag(namespace, self.getName()))
- for value in self.getValues():
- # TODO: need to figure out proper value types
- text = XML.SubElement(param, xmldefs.makeTag(namespace, xmldefs.value_text))
- text.text = value
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendaravailablepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/available.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/available.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/available.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,90 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarAvailable(PyCalendarComponentRecur):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTAMP,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_UID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_CREATED,
- definitions.cICalProperty_DESCRIPTION,
- definitions.cICalProperty_GEO,
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_LOCATION,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_RRULE,
- definitions.cICalProperty_SEQUENCE,
- definitions.cICalProperty_SUMMARY,
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_DURATION,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
- super(PyCalendarAvailable, self).__init__(parent=parent)
-
-
- def duplicate(self, parent=None):
- return super(PyCalendarAvailable, self).duplicate(parent=parent)
-
-
- def getType(self):
- return definitions.cICalComponent_AVAILABLE
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems, else raise. If
- loggedProblems is not None it must be a C{list} and problem descriptions are appended
- to that.
- """
-
- fixed, unfixed = super(PyCalendarAvailable, self).validate(doFix)
-
- # Extra constraint: only one of DTEND or DURATION
- if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
- # Fix by removing the DTEND
- logProblem = "[%s] Properties must not both be present: %s, %s" % (
- self.getType(),
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_DURATION,
- )
- if doFix:
- self.removeProperties(definitions.cICalProperty_DTEND)
- fixed.append(logProblem)
- else:
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_DTEND,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarbinaryvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/binaryvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/binaryvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/binaryvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,13 +16,13 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar Binary value
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarBinaryValue(PyCalendarPlainTextValue):
</del><ins>+class BinaryValue(PlainTextValue):
</ins><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarValue.VALUETYPE_BINARY
</del><ins>+ return Value.VALUETYPE_BINARY
</ins><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_BINARY, PyCalendarBinaryValue, xmldefs.value_binary)
</del><ins>+Value.registerType(Value.VALUETYPE_BINARY, BinaryValue, xmldefinitions.value_binary)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcaladdressvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/caladdressvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/caladdressvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/caladdressvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,13 +16,13 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarCalAddressValue(PyCalendarPlainTextValue):
</del><ins>+class CalAddressValue(PlainTextValue):
</ins><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarValue.VALUETYPE_CALADDRESS
</del><ins>+ return Value.VALUETYPE_CALADDRESS
</ins><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_CALADDRESS, PyCalendarCalAddressValue, xmldefs.value_cal_address)
</del><ins>+Value.registerType(Value.VALUETYPE_CALADDRESS, CalAddressValue, xmldefinitions.value_cal_address)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcalendarpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/calendar.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/calendar.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,754 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 cStringIO import StringIO
-from pycalendar import definitions, xmldefs
-from pycalendar.available import PyCalendarAvailable
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.componentexpanded import PyCalendarComponentExpanded
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.exceptions import PyCalendarInvalidData, \
- PyCalendarValidationError
-from pycalendar.freebusy import PyCalendarFreeBusy
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.parser import ParserContext
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.property import PyCalendarProperty
-from pycalendar.utils import readFoldedLine
-from pycalendar.valarm import PyCalendarVAlarm
-from pycalendar.vavailability import PyCalendarVAvailability
-from pycalendar.vevent import PyCalendarVEvent
-from pycalendar.vfreebusy import PyCalendarVFreeBusy
-from pycalendar.vjournal import PyCalendarVJournal
-from pycalendar.vtimezone import PyCalendarVTimezone
-from pycalendar.vtimezonedaylight import PyCalendarVTimezoneDaylight
-from pycalendar.vtimezonestandard import PyCalendarVTimezoneStandard
-from pycalendar.vtodo import PyCalendarVToDo
-from pycalendar.vunknown import PyCalendarUnknownComponent
-import collections
-import xml.etree.cElementTree as XML
-
-class PyCalendar(PyCalendarComponentBase):
-
- REMOVE_ALL = 0
- REMOVE_ONLY_THIS = 1
- REMOVE_THIS_AND_FUTURE = 2
-
- FIND_EXACT = 0
- FIND_MASTER = 1
-
- sProdID = "-//mulberrymail.com//Mulberry v4.0//EN"
- sDomain = "mulberrymail.com"
-
- @staticmethod
- def setPRODID(prodid):
- PyCalendar.sProdID = prodid
-
-
- @staticmethod
- def setDomain(domain):
- PyCalendar.sDomain = domain
-
- propertyCardinality_1 = (
- definitions.cICalProperty_PRODID,
- definitions.cICalProperty_VERSION,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_CALSCALE,
- definitions.cICalProperty_METHOD,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None, add_defaults=True):
- super(PyCalendar, self).__init__(None)
-
- self.mName = ""
- self.mDescription = ""
- self.mMasterComponentsByTypeAndUID = collections.defaultdict(lambda: collections.defaultdict(list))
- self.mOverriddenComponentsByUID = collections.defaultdict(list)
-
- if add_defaults:
- self.addDefaultProperties()
-
-
- def duplicate(self):
- other = super(PyCalendar, self).duplicate()
- other.mName = self.mName
- other.mDescription = self.mDescription
- return other
-
-
- def getType(self):
- return definitions.cICalComponent_VCALENDAR
-
-
- def getName(self):
- return self.mName
-
-
- def setName(self, name):
- self.mName = name
-
-
- def editName(self, name):
- if self.mName != name:
- # Updated cached value
- self.mName = name
-
- # Remove existing items
- self.removeProperties(definitions.cICalProperty_XWRCALNAME)
-
- # Now create properties
- if len(name):
- self.ddProperty(PyCalendarProperty(definitions.cICalProperty_XWRCALNAME, name))
-
-
- def getDescription(self):
- return self.mDescription
-
-
- def setDescription(self, description):
- self.mDescription = description
-
-
- def editDescription(self, description):
- if self.mDescription != description:
- # Updated cached value
- self.mDescription = description
-
- # Remove existing items
- self.removeProperties(definitions.cICalProperty_XWRCALDESC)
-
- # Now create properties
- if len(description):
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_XWRCALDESC, description))
-
-
- def getMethod(self):
- result = ""
- if self.hasProperty(definitions.cICalProperty_METHOD):
- result = self.loadValueString(definitions.cICalProperty_METHOD)
- return result
-
-
- def changeUID(self, oldUID, newUID):
- """
- Change the UID of all components with a matching UID to a new value. We need to
- do this at the calendar level because this object maintains mappings based on UID
- which need to be updated whenever the UID changes.
-
- @param oldUID: the old value to match
- @type oldUID: C{str}
- @param newUID: the new value to match
- @type newUID: C{str}
- """
-
- # Each component
- for component in self.mComponents:
- if component.getUID() == oldUID:
- component.setUID(newUID)
-
- # Maps
- if oldUID in self.mOverriddenComponentsByUID:
- self.mOverriddenComponentsByUID[newUID] = self.mOverriddenComponentsByUID[oldUID]
- del self.mOverriddenComponentsByUID[oldUID]
- for ctype in self.mMasterComponentsByTypeAndUID:
- if oldUID in self.mMasterComponentsByTypeAndUID[ctype]:
- self.mMasterComponentsByTypeAndUID[ctype][newUID] = self.mMasterComponentsByTypeAndUID[ctype][oldUID]
- del self.mMasterComponentsByTypeAndUID[ctype][oldUID]
-
-
- def finalise(self):
- # Get calendar name if present
-
- # Get X-WR-CALNAME
- temps = self.loadValueString(definitions.cICalProperty_XWRCALNAME)
- if temps is not None:
- self.mName = temps
-
- # Get X-WR-CALDESC
- temps = self.loadValueString(definitions.cICalProperty_XWRCALDESC)
- if temps is not None:
- self.mDescription = temps
-
-
- def validate(self, doFix=False, doRaise=False):
- """
- Validate the data in this component and optionally fix any problems. Return
- a tuple containing two lists: the first describes problems that were fixed, the
- second problems that were not fixed. Caller can then decide what to do with unfixed
- issues.
- """
-
- # Optional raise behavior
- fixed, unfixed = super(PyCalendar, self).validate(doFix)
- if doRaise and unfixed:
- raise PyCalendarValidationError(";".join(unfixed))
- return fixed, unfixed
-
-
- def sortedComponentNames(self):
- return (
- definitions.cICalComponent_VTIMEZONE,
- definitions.cICalComponent_VEVENT,
- definitions.cICalComponent_VTODO,
- definitions.cICalComponent_VJOURNAL,
- definitions.cICalComponent_VFREEBUSY,
- definitions.cICalComponent_VAVAILABILITY,
- )
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_VERSION,
- definitions.cICalProperty_CALSCALE,
- definitions.cICalProperty_METHOD,
- definitions.cICalProperty_PRODID,
- )
-
-
- @staticmethod
- def parseText(data):
-
- cal = PyCalendar(add_defaults=False)
- if cal.parse(StringIO(data)):
- return cal
- else:
- return None
-
-
- def parse(self, ins):
-
- result = False
-
- self.setProperties({})
-
- LOOK_FOR_VCALENDAR = 0
- GET_PROPERTY_OR_COMPONENT = 1
-
- state = LOOK_FOR_VCALENDAR
-
- # Get lines looking for start of calendar
- lines = [None, None]
- comp = self
- compend = None
- componentstack = []
-
- while readFoldedLine(ins, lines):
-
- line = lines[0]
-
- if state == LOOK_FOR_VCALENDAR:
-
- # Look for start
- if line == self.getBeginDelimiter():
- # Next state
- state = GET_PROPERTY_OR_COMPONENT
-
- # Indicate success at this point
- result = True
-
- # Handle blank line
- elif len(line) == 0:
- # Raise if requested, otherwise just ignore
- if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
- raise PyCalendarInvalidData("iCalendar data has blank lines")
-
- # Unrecognized data
- else:
- raise PyCalendarInvalidData("iCalendar data not recognized", line)
-
- elif state == GET_PROPERTY_OR_COMPONENT:
-
- # Parse property or look for start of component
- if line.startswith("BEGIN:"):
-
- # Push previous details to stack
- componentstack.append((comp, compend,))
-
- # Start a new component
- comp = PyCalendar.makeComponent(line[6:], comp)
- compend = comp.getEndDelimiter()
-
- # Look for end of object
- elif line == self.getEndDelimiter():
-
- # Finalise the current calendar
- self.finalise()
-
- # Change state
- state = LOOK_FOR_VCALENDAR
-
- # Look for end of current component
- elif line == compend:
-
- # Finalise the component (this caches data from the properties)
- comp.finalise()
-
- # Embed component in parent and reset to use parent
- componentstack[-1][0].addComponent(comp)
- comp, compend = componentstack.pop()
-
- # Blank line
- elif len(line) == 0:
- # Raise if requested, otherwise just ignore
- if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
- raise PyCalendarInvalidData("iCalendar data has blank lines")
-
- # Must be a property
- else:
-
- # Parse attribute/value for top-level calendar item
- prop = PyCalendarProperty()
- if prop.parse(line):
-
- # Check for valid property
- if comp is self:
- if not comp.validProperty(prop):
- raise PyCalendarInvalidData("Invalid property", str(prop))
- elif not comp.ignoreProperty(prop):
- comp.addProperty(prop)
- else:
- comp.addProperty(prop)
-
- # Check for truncated data
- if state != LOOK_FOR_VCALENDAR:
- raise PyCalendarInvalidData("iCalendar data not complete")
-
- # We need to store all timezones in the static object so they can be accessed by any date object
- from timezonedb import PyCalendarTimezoneDatabase
- PyCalendarTimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
-
- # Validate some things
- if result and not self.hasProperty("VERSION"):
- raise PyCalendarInvalidData("iCalendar missing VERSION")
-
- return result
-
-
- def parseComponent(self, ins):
-
- result = None
-
- LOOK_FOR_VCALENDAR = 0
- GET_PROPERTY_OR_COMPONENT = 1
- GOT_VCALENDAR = 4
-
- state = LOOK_FOR_VCALENDAR
-
- # Get lines looking for start of calendar
- lines = [None, None]
- comp = self
- compend = None
- componentstack = []
- got_timezone = False
-
- while readFoldedLine(ins, lines):
-
- if state == LOOK_FOR_VCALENDAR:
-
- # Look for start
- if lines[0] == self.getBeginDelimiter():
- # Next state
- state = GET_PROPERTY_OR_COMPONENT
-
- # Handle blank line
- elif len(lines[0]) == 0:
- # Raise if requested, otherwise just ignore
- if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
- raise PyCalendarInvalidData("iCalendar data has blank lines")
-
- # Unrecognized data
- else:
- raise PyCalendarInvalidData("iCalendar data not recognized", lines[0])
-
- elif state == GET_PROPERTY_OR_COMPONENT:
-
- # Parse property or look for start of component
- if lines[0].startswith("BEGIN:"):
-
- # Push previous details to stack
- componentstack.append((comp, compend,))
-
- # Start a new component
- comp = PyCalendar.makeComponent(lines[0][6:], comp)
- compend = comp.getEndDelimiter()
-
- # Cache as result - but only the first one, we ignore the rest
- if result is None:
- result = comp
-
- # Look for timezone component to trigger timezone merge only if one is present
- if comp.getType() == definitions.cICalComponent_VTIMEZONE:
- got_timezone = True
-
- elif lines[0] == self.getEndDelimiter():
-
- # Change state
- state = GOT_VCALENDAR
-
- # Look for end of current component
- elif lines[0] == compend:
-
- # Finalise the component (this caches data from the properties)
- comp.finalise()
-
- # Embed component in parent and reset to use parent
- componentstack[-1][0].addComponent(comp)
- comp, compend = componentstack.pop()
-
- # Blank line
- elif len(lines[0]) == 0:
- # Raise if requested, otherwise just ignore
- if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
- raise PyCalendarInvalidData("iCalendar data has blank lines")
-
- # Ignore top-level items
- elif comp is self:
- pass
-
- # Must be a property
- else:
-
- # Parse attribute/value for top-level calendar item
- prop = PyCalendarProperty()
- if prop.parse(lines[0]):
-
- # Check for valid property
- if comp is not self:
- comp.addProperty(prop)
-
- # Exit if we have one - ignore all the rest
- if state == GOT_VCALENDAR:
- break
-
- # We need to store all timezones in the static object so they can be accessed by any date object
- # Only do this if we read in a timezone
- if got_timezone:
- from timezonedb import PyCalendarTimezoneDatabase
- PyCalendarTimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
-
- return result
-
-
- def addComponent(self, component):
- """
- Override to track components by UID.
- """
- super(PyCalendar, self).addComponent(component)
-
- if isinstance(component, PyCalendarComponentRecur):
- uid = component.getUID()
- rid = component.getRecurrenceID()
- if rid:
- self.mOverriddenComponentsByUID[uid].append(component)
- else:
- self.mMasterComponentsByTypeAndUID[component.getType()][uid] = component
-
-
- def removeComponent(self, component):
- """
- Override to track components by UID.
- """
- super(PyCalendar, self).removeComponent(component)
-
- if isinstance(component, PyCalendarComponentRecur):
- uid = component.getUID()
- rid = component.getRecurrenceID()
- if rid:
- self.mOverriddenComponentsByUID[uid].remove(component)
- else:
- del self.mMasterComponentsByTypeAndUID[component.getType()][uid]
-
-
- def getText(self, includeTimezones=False):
- s = StringIO()
- self.generate(s, includeTimezones=includeTimezones)
- return s.getvalue()
-
-
- def generate(self, os, includeTimezones=False):
- # Make sure all required timezones are in this object
- if includeTimezones:
- self.includeTimezones()
- super(PyCalendar, self).generate(os)
-
-
- def getTextXML(self, includeTimezones=False):
- node = self.writeXML(includeTimezones)
- return xmldefs.toString(node)
-
-
- def writeXML(self, includeTimezones=False):
- # Make sure all required timezones are in this object
- if includeTimezones:
- self.includeTimezones()
-
- # Root node structure
- root = XML.Element(xmldefs.makeTag(xmldefs.iCalendar20_namespace, xmldefs.icalendar))
- super(PyCalendar, self).writeXML(root, xmldefs.iCalendar20_namespace)
- return root
-
-
- # Get expanded components
- def getVEvents(self, period, list, all_day_at_top=True):
- # Look at each VEvent
- for vevent in self.getComponents(definitions.cICalComponent_VEVENT):
- vevent.expandPeriod(period, list)
-
- if (all_day_at_top):
- list.sort(PyCalendarComponentExpanded.sort_by_dtstart_allday)
- else:
- list.sort(PyCalendarComponentExpanded.sort_by_dtstart)
-
-
- def getVToDos(self, only_due, all_dates, upto_due_date, list):
- # Get current date-time less one day to test for completed events during the last day
- minusoneday = PyCalendarDateTime()
- minusoneday.setNowUTC()
- minusoneday.offsetDay(-1)
-
- today = PyCalendarDateTime()
- today.setToday()
-
- # Look at each VToDo
- for vtodo in self.getComponents(definitions.cICalComponent_VTODO):
-
- # Filter out done (that were complted more than a day ago) or cancelled to dos if required
- if only_due:
- if vtodo.getStatus() == definitions.eStatus_VToDo_Cancelled:
- continue
- elif ((vtodo.getStatus() == definitions.eStatus_VToDo_Completed) and
- (not vtodo.hasCompleted() or (vtodo.getCompleted() < minusoneday))):
- continue
-
- # Filter out those with end after chosen date if required
- if not all_dates:
- if vtodo.hasEnd() and (vtodo.getEnd() > upto_due_date):
- continue
- elif not vtodo.hasEnd() and (today > upto_due_date):
- continue
-
- # TODO: fix this
- #list.append(PyCalendarComponentExpandedShared(PyCalendarComponentExpanded(vtodo, None)))
-
-
- def getRecurrenceInstancesItems(self, type, uid, items):
- # Get instances from list
- items.extend(self.mOverriddenComponentsByUID.get(uid, ()))
-
-
- def getRecurrenceInstancesIds(self, type, uid, ids):
- # Get instances from list
- ids.extend([comp.getRecurrenceID() for comp in self.mOverriddenComponentsByUID.get(uid, ())])
-
-
- # Freebusy generation
- def getVFreeBusyList(self, period, list):
- # Look at each VFreeBusy
- for vfreebusy in self.getComponents(definitions.cICalComponent_VFREEBUSY):
- vfreebusy.expandPeriod(period, list)
-
-
- def getVFreeBusyFB(self, period, fb):
- # First create expanded set
- # TODO: fix this
- #list = PyCalendarExpandedComponents()
- self.getVEvents(period, list)
- if len(list) == 0:
- return
-
- # Get start/end list for each non-all-day expanded components
- dtstart = []
- dtend = []
- for dt in list:
-
- # Ignore if all-day
- if dt.getInstanceStart().isDateOnly():
- continue
-
- # Ignore if transparent to free-busy
- transp = ""
- if dt.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
- continue
-
- # Add start/end to list
- dtstart.append(dt.getInstanceStart())
- dtend.append(dt.getInstanceEnd())
-
- # No longer need the expanded items
- list.clear()
-
- # Create non-overlapping periods as properties in the freebusy component
- temp = PyCalendarPeriod(dtstart.front(), dtend.front())
- dtstart_iter = dtstart.iter()
- dtstart_iter.next()
- dtend_iter = dtend.iter()
- dtend_iter.next()
- for i in i:
-
- # Check for non-overlap
- if dtstart_iter > temp.getEnd():
-
- # Current period is complete
- fb.addProperty(PyCalendarProperty(definitions.cICalProperty_FREEBUSY, temp))
-
- # Reset period to new range
- temp = PyCalendarPeriod(dtstart_iter, dtend_iter)
-
- # They overlap - check for extended end
- if dtend_iter > temp.getEnd():
-
- # Extend the end
- temp = PyCalendarPeriod(temp.getStart(), dtend_iter)
-
- # Add remaining period as property
- fb.addProperty(PyCalendarProperty(definitions.cICalProperty_FREEBUSY, temp))
-
-
- def getFreeBusy(self, period, fb):
- # First create expanded set
-
- list = []
- self.getVEvents(period, list)
-
- # Get start/end list for each non-all-day expanded components
- for comp in list:
-
- # Ignore if all-day
- if comp.getInstanceStart().isDateOnly():
- continue
-
- # Ignore if transparent to free-busy
- transp = ""
- if comp.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
- continue
-
- # Add free busy item to list
- status = comp.getMaster().getStatus()
- if status in (definitions.eStatus_VEvent_None, definitions.eStatus_VEvent_Confirmed):
- fb.append(PyCalendarFreeBusy(PyCalendarFreeBusy.BUSY, PyCalendarPeriod(comp.getInstanceStart(), comp.getInstanceEnd())))
- elif status == definitions.eStatus_VEvent_Tentative:
- fb.append(PyCalendarFreeBusy(PyCalendarFreeBusy.BUSYTENTATIVE, PyCalendarPeriod(comp.getInstanceStart(), comp.getInstanceEnd())))
- break
- elif status == definitions.eStatus_VEvent_Cancelled:
- # Cancelled => does not contribute to busy time
- pass
-
- # Now get the VFREEBUSY info
- list2 = []
- self.getVFreeBusy(period, list2)
-
- # Get start/end list for each free-busy
- for comp in list2:
-
- # Expand component and add free busy info to list
- comp.expandPeriod(period, fb)
-
- # Add remaining period as property
- PyCalendarFreeBusy.resolveOverlaps(fb)
-
-
- def getTimezoneOffsetSeconds(self, tzid, dt):
- # Find timezone that matches the name (which is the same as the map key)
- timezone = self.getTimezone(tzid)
- return timezone.getTimezoneOffsetSeconds(dt) if timezone else 0
-
-
- def getTimezoneDescriptor(self, tzid, dt):
- # Find timezone that matches the name (which is the same as the map key)
- timezone = self.getTimezone(tzid)
- return timezone.getTimezoneDescriptor(dt) if timezone else ""
-
-
- def getTimezone(self, tzid):
- # Find timezone that matches the name (which is the same as the map key)
- for timezone in self.getComponents(definitions.cICalComponent_VTIMEZONE):
- if timezone.getID() == tzid:
- return timezone
- else:
- return None
-
-
- def addDefaultProperties(self):
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_PRODID, PyCalendar.sProdID))
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_VERSION, "2.0"))
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_CALSCALE, "GREGORIAN"))
-
-
- def validProperty(self, prop):
- if prop.getName() == definitions.cICalProperty_VERSION:
-
- tvalue = prop.getTextValue()
- if ((tvalue is None) or (tvalue.getValue() != "2.0")):
- return False
-
- elif prop.getName() == definitions.cICalProperty_CALSCALE:
-
- tvalue = prop.getTextValue()
- if ((tvalue is None) or (tvalue.getValue() != "GREGORIAN")):
- return False
-
- return True
-
-
- def ignoreProperty(self, prop):
- return False #prop.getName() in (definitions.cICalProperty_VERSION, definitions.cICalProperty_CALSCALE, definitions.cICalProperty_PRODID)
-
-
- def includeTimezones(self):
- # Get timezone names from each component
- tzids = set()
- for component in self.mComponents:
- if component.getType() != definitions.cICalComponent_VTIMEZONE:
- component.getTimezones(tzids)
-
- # Make sure each timezone is in current calendar
- from timezonedb import PyCalendarTimezoneDatabase
- for tzid in tzids:
- tz = self.getTimezone(tzid)
- if tz is None:
- # Find it in the static object
- tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
- if tz is not None:
- dup = tz.duplicate()
- self.addComponent(dup)
-
-
- @staticmethod
- def makeComponent(compname, parent):
-
- mapper = {
- definitions.cICalComponent_VEVENT: PyCalendarVEvent,
- definitions.cICalComponent_VTODO: PyCalendarVToDo,
- definitions.cICalComponent_VJOURNAL: PyCalendarVJournal,
- definitions.cICalComponent_VFREEBUSY: PyCalendarVFreeBusy,
- definitions.cICalComponent_VTIMEZONE: PyCalendarVTimezone,
- definitions.cICalComponent_VAVAILABILITY: PyCalendarVAvailability,
- definitions.cICalComponent_VALARM: PyCalendarVAlarm,
- definitions.cICalComponent_AVAILABLE: PyCalendarAvailable,
- definitions.cICalComponent_STANDARD: PyCalendarVTimezoneStandard,
- definitions.cICalComponent_DAYLIGHT: PyCalendarVTimezoneDaylight,
- }
-
- try:
- cls = mapper[compname]
- return cls(parent=parent)
- except KeyError:
- return PyCalendarUnknownComponent(parent=parent, comptype=compname)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/component.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/component.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/component.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,192 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import stringutils
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.property import PyCalendarProperty
-import os
-import time
-import uuid
-
-class PyCalendarComponent(PyCalendarComponentBase):
-
- uid_ctr = 1
-
- def __init__(self, parent=None):
-
- super(PyCalendarComponent, self).__init__(parent)
- self.mUID = ""
- self.mSeq = 0
- self.mOriginalSeq = 0
- self.mChanged = False
-
-
- def duplicate(self, parent=None, **args):
-
- other = super(PyCalendarComponent, self).duplicate(parent=parent, **args)
- other.mUID = self.mUID
- other.mSeq = self.mSeq
- other.mOriginalSeq = self.mOriginalSeq
-
- other.mChanged = self.mChanged
-
- return other
-
-
- def __repr__(self):
- return "%s: UID: %s" % (self.getType(), self.getMapKey(),)
-
-
- def getMimeComponentName(self):
- raise NotImplementedError
-
-
- def getMapKey(self):
- if hasattr(self, "mMapKey"):
- return self.mMapKey
- elif self.mUID:
- return self.mUID
- else:
- self.mMapKey = str(uuid.uuid4())
- return self.mMapKey
-
-
- def getSortKey(self):
- return self.getMapKey()
-
-
- def getMasterKey(self):
- return self.mUID
-
-
- def getUID(self):
- return self.mUID
-
-
- def setUID(self, uid):
- if uid:
- self.mUID = uid
- else:
- # Get left-side of UID (first 24 chars of MD5 digest of time, pid
- # and ctr)
- lhs_txt = ""
- lhs_txt += str(time.time())
- lhs_txt += "."
- lhs_txt += str(os.getpid())
- lhs_txt += "."
- lhs_txt += str(PyCalendarComponent.uid_ctr)
- PyCalendarComponent.uid_ctr += 1
- lhs = stringutils.md5digest(lhs_txt)
-
- # Get right side (domain) of message-id
- rhs = None
-
- # Use app name
- from pycalendar.calendar import PyCalendar
- domain = PyCalendar.sDomain
- domain += str(PyCalendarComponent.uid_ctr)
-
- # Use first 24 chars of MD5 digest of the domain as the
- # right-side of message-id
- rhs = stringutils.md5digest(domain)
-
- # Generate the UID string
- new_uid = lhs
- new_uid += "@"
- new_uid += rhs
-
- self.mUID = new_uid
-
- self.removeProperties(definitions.cICalProperty_UID)
-
- prop = PyCalendarProperty(definitions.cICalProperty_UID, self.mUID)
- self.addProperty(prop)
-
-
- def getSeq(self):
- return self.mSeq
-
-
- def setSeq(self, seq):
- self.mSeq = seq
-
- self.removeProperties(definitions.cICalProperty_SEQUENCE)
-
- prop = PyCalendarProperty(definitions.cICalProperty_SEQUENCE, self.mSeq)
- self.addProperty(prop)
-
-
- def getOriginalSeq(self):
- return self.mOriginalSeq
-
-
- def getChanged(self):
- return self.mChanged
-
-
- def setChanged(self, changed):
- self.mChanged = changed
-
-
- def initDTSTAMP(self):
- self.removeProperties(definitions.cICalProperty_DTSTAMP)
-
- prop = PyCalendarProperty(definitions.cICalProperty_DTSTAMP,
- PyCalendarDateTime.getNowUTC())
- self.addProperty(prop)
-
-
- def updateLastModified(self):
- self.removeProperties(definitions.cICalProperty_LAST_MODIFIED)
-
- prop = PyCalendarProperty(definitions.cICalProperty_LAST_MODIFIED,
- PyCalendarDateTime.getNowUTC())
- self.addProperty(prop)
-
-
- def finalise(self):
- # Get UID
- temps = self.loadValueString(definitions.cICalProperty_UID)
- if temps is not None:
- self.mUID = temps
-
- # Get SEQ
- temp = self.loadValueInteger(definitions.cICalProperty_SEQUENCE)
- if temp is not None:
- self.mSeq = temp
-
- # Cache the original sequence when the component is read in.
- # This will be used to synchronise changes between two instances of the
- # same calendar
- self.mOriginalSeq = self.mSeq
-
-
- def canGenerateInstance(self):
- return True
-
-
- def getTimezones(self, tzids):
- # Look for all date-time properties
- for props in self.mProperties.itervalues():
- for prop in props:
- # Try to get a date-time value from the property
- dtv = prop.getDateTimeValue()
- if dtv is not None:
- # Add timezone id if appropriate
- if dtv.getValue().getTimezoneID():
- tzids.add(dtv.getValue().getTimezoneID())
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentbasepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/componentbase.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/componentbase.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/componentbase.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,14 +15,14 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar import xmldefs
-from pycalendar.datetimevalue import PyCalendarDateTimeValue
-from pycalendar.periodvalue import PyCalendarPeriodValue
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions, xmlutils
+from pycalendar.datetimevalue import DateTimeValue
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.value import Value
</ins><span class="cx"> import xml.etree.cElementTree as XML
</span><ins>+from pycalendar.exceptions import InvalidComponent, ErrorBase
</ins><span class="cx">
</span><del>-class PyCalendarComponentBase(object):
</del><ins>+class ComponentBase(object):
</ins><span class="cx">
</span><span class="cx"> # These are class attributes for sets of properties for testing cardinality constraints. The sets
</span><span class="cx"> # must contain property names.
</span><span class="lines">@@ -35,6 +35,9 @@
</span><span class="cx">
</span><span class="cx"> sortSubComponents = True
</span><span class="cx">
</span><ins>+ sComponentType = None
+ sPropertyType = None
+
</ins><span class="cx"> def __init__(self, parent=None):
</span><span class="cx"> self.mParentComponent = parent
</span><span class="cx"> self.mComponents = []
</span><span class="lines">@@ -70,7 +73,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __eq__(self, other):
</span><del>- if not isinstance(other, PyCalendarComponentBase):
</del><ins>+ if not isinstance(other, ComponentBase):
</ins><span class="cx"> return False
</span><span class="cx"> return self.getType() == other.getType() and self.compareProperties(other) and self.compareComponents(other)
</span><span class="cx">
</span><span class="lines">@@ -276,7 +279,7 @@
</span><span class="cx"> elif self.countProperty(propname) == 0: # Possibly fix by adding empty property
</span><span class="cx"> logProblem = "[%s] Missing required property: %s" % (self.getType(), propname)
</span><span class="cx"> if doFix:
</span><del>- self.addProperty(PyCalendarProperty(propname, ""))
</del><ins>+ self.addProperty(self.sPropertyType(propname, ""))
</ins><span class="cx"> fixed.append(logProblem)
</span><span class="cx"> else:
</span><span class="cx"> unfixed.append(logProblem)
</span><span class="lines">@@ -337,7 +340,7 @@
</span><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx">
</span><span class="cx"> # Component element
</span><del>- comp = XML.SubElement(node, xmldefs.makeTag(namespace, self.getType()))
</del><ins>+ comp = XML.SubElement(node, xmlutils.makeTag(namespace, self.getType()))
</ins><span class="cx">
</span><span class="cx"> # Each property
</span><span class="cx"> self.writePropertiesXML(comp, namespace)
</span><span class="lines">@@ -348,7 +351,7 @@
</span><span class="cx">
</span><span class="cx"> def writeXMLFiltered(self, node, namespace, filter):
</span><span class="cx"> # Component element
</span><del>- comp = XML.SubElement(node, xmldefs.makeTag(namespace, self.getType()))
</del><ins>+ comp = XML.SubElement(node, xmlutils.makeTag(namespace, self.getType()))
</ins><span class="cx">
</span><span class="cx"> # Each property
</span><span class="cx"> self.writePropertiesFilteredXML(comp, namespace, filter)
</span><span class="lines">@@ -357,6 +360,60 @@
</span><span class="cx"> self.writeComponentsFilteredXML(comp, namespace, filter)
</span><span class="cx">
</span><span class="cx">
</span><ins>+ @classmethod
+ def parseJSON(cls, jobject, parent, comp=None):
+ """
+ Parse the JSON object which has the form:
+
+ [name, properties, subcomponents]
+
+ @param jobject: a JSON array
+ @type jobject: C{list}
+ """
+ # [name, properties, subcomponents]
+
+ try:
+ if comp is None:
+ comp = cls.sComponentType.makeComponent(jobject[0].upper(), parent)
+ for prop in jobject[1]:
+ comp.addProperty(cls.sPropertyType.parseJSON(prop))
+ for subcomp in jobject[2]:
+ comp.addComponent(cls.sComponentType.parseJSON(subcomp, comp))
+ comp.finalise()
+ return comp
+ except ErrorBase:
+ raise
+ except Exception:
+ raise InvalidComponent("Invalid component", jobject)
+
+
+ def writeJSON(self, jobject):
+
+ # Component element
+ comp = [self.getType().lower(), [], []]
+
+ # Each property
+ self.writePropertiesJSON(comp[1])
+
+ # Each component
+ self.writeComponentsJSON(comp[2])
+
+ jobject.append(comp)
+
+
+ def writeJSONFiltered(self, jobject, filter):
+ # Component element
+ comp = [self.getType().lower(), [], []]
+
+ # Each property
+ self.writePropertiesFilteredJSON(comp[1], filter)
+
+ # Each component
+ self.writeComponentsFilteredJSON(comp[2], filter)
+
+ jobject.append(comp)
+
+
</ins><span class="cx"> def sortedComponents(self):
</span><span class="cx">
</span><span class="cx"> components = self.mComponents[:]
</span><span class="lines">@@ -407,7 +464,7 @@
</span><span class="cx"> def writeComponentsXML(self, node, namespace):
</span><span class="cx">
</span><span class="cx"> if self.mComponents:
</span><del>- comps = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.components))
</del><ins>+ comps = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.components))
</ins><span class="cx">
</span><span class="cx"> # Write out the remainder
</span><span class="cx"> for component in self.sortedComponents():
</span><span class="lines">@@ -417,7 +474,7 @@
</span><span class="cx"> def writeComponentsFilteredXML(self, node, namespace, filter):
</span><span class="cx">
</span><span class="cx"> if self.mComponents:
</span><del>- comps = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.components))
</del><ins>+ comps = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.components))
</ins><span class="cx">
</span><span class="cx"> # Shortcut for all sub-components
</span><span class="cx"> if filter.isAllSubComponents():
</span><span class="lines">@@ -426,9 +483,30 @@
</span><span class="cx"> for subcomp in self.sortedcomponents():
</span><span class="cx"> subfilter = filter.getSubComponentFilter(subcomp.getType())
</span><span class="cx"> if subfilter is not None:
</span><del>- subcomp.writeFilteredXML(comps, namespace, subfilter)
</del><ins>+ subcomp.writeXMLFiltered(comps, namespace, subfilter)
</ins><span class="cx">
</span><span class="cx">
</span><ins>+ def writeComponentsJSON(self, jobject):
+
+ if self.mComponents:
+ # Write out the remainder
+ for component in self.sortedComponents():
+ component.writeJSON(jobject)
+
+
+ def writeComponentsFilteredJSON(self, jobject, filter):
+
+ if self.mComponents:
+ # Shortcut for all sub-components
+ if filter.isAllSubComponents():
+ self.writeJSON(jobject)
+ elif filter.hasSubComponentFilters():
+ for subcomp in self.sortedcomponents():
+ subfilter = filter.getSubComponentFilter(subcomp.getType())
+ if subfilter is not None:
+ subcomp.writeJSONFiltered(jobject, subfilter)
+
+
</ins><span class="cx"> def loadValue(self, value_name):
</span><span class="cx"> if self.hasProperty(value_name):
</span><span class="cx"> return self.findFirstProperty(value_name)
</span><span class="lines">@@ -439,18 +517,18 @@
</span><span class="cx"> def loadValueInteger(self, value_name, type=None):
</span><span class="cx"> if type:
</span><span class="cx"> if self.hasProperty(value_name):
</span><del>- if type == PyCalendarValue.VALUETYPE_INTEGER:
</del><ins>+ if type == Value.VALUETYPE_INTEGER:
</ins><span class="cx"> ivalue = self.findFirstProperty(value_name).getIntegerValue()
</span><span class="cx"> if ivalue is not None:
</span><span class="cx"> return ivalue.getValue()
</span><del>- elif type == PyCalendarValue.VALUETYPE_UTC_OFFSET:
</del><ins>+ elif type == Value.VALUETYPE_UTC_OFFSET:
</ins><span class="cx"> uvalue = self.findFirstProperty(value_name).getUTCOffsetValue()
</span><span class="cx"> if (uvalue is not None):
</span><span class="cx"> return uvalue.getValue()
</span><span class="cx">
</span><span class="cx"> return None
</span><span class="cx"> else:
</span><del>- return self.loadValueInteger(value_name, PyCalendarValue.VALUETYPE_INTEGER)
</del><ins>+ return self.loadValueInteger(value_name, Value.VALUETYPE_INTEGER)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def loadValueString(self, value_name):
</span><span class="lines">@@ -513,12 +591,12 @@
</span><span class="cx"> if (mvalue is not None):
</span><span class="cx"> for obj in mvalue.getValues():
</span><span class="cx"> # cast to date-time
</span><del>- if isinstance(obj, PyCalendarDateTimeValue):
</del><ins>+ if isinstance(obj, DateTimeValue):
</ins><span class="cx"> if add:
</span><span class="cx"> value.addDT(obj.getValue())
</span><span class="cx"> else:
</span><span class="cx"> value.subtractDT(obj.getValue())
</span><del>- elif isinstance(obj, PyCalendarPeriodValue):
</del><ins>+ elif isinstance(obj, PeriodValue):
</ins><span class="cx"> if add:
</span><span class="cx"> value.addPeriod(obj.getValue().getStart())
</span><span class="cx"> else:
</span><span class="lines">@@ -573,7 +651,7 @@
</span><span class="cx">
</span><span class="cx"> def writePropertiesXML(self, node, namespace):
</span><span class="cx">
</span><del>- properties = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.properties))
</del><ins>+ properties = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.properties))
</ins><span class="cx">
</span><span class="cx"> # Sort properties by name
</span><span class="cx"> keys = self.sortedPropertyKeys()
</span><span class="lines">@@ -585,7 +663,7 @@
</span><span class="cx">
</span><span class="cx"> def writePropertiesFilteredXML(self, node, namespace, filter):
</span><span class="cx">
</span><del>- props = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.properties))
</del><ins>+ props = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.properties))
</ins><span class="cx">
</span><span class="cx"> # Sort properties by name
</span><span class="cx"> keys = self.sortedPropertyKeys()
</span><span class="lines">@@ -598,9 +676,35 @@
</span><span class="cx"> elif filter.hasPropertyFilters():
</span><span class="cx"> for key in keys:
</span><span class="cx"> for prop in self.getProperties(key):
</span><del>- prop.writeFilteredXML(props, namespace, filter)
</del><ins>+ prop.writeXMLFiltered(props, namespace, filter)
</ins><span class="cx">
</span><span class="cx">
</span><ins>+ def writePropertiesJSON(self, jobject):
+
+ # Sort properties by name
+ keys = self.sortedPropertyKeys()
+ for key in keys:
+ props = self.mProperties[key]
+ for prop in props:
+ prop.writeJSON(jobject)
+
+
+ def writePropertiesFilteredJSON(self, jobject, filter):
+
+ # Sort properties by name
+ keys = self.sortedPropertyKeys()
+
+ # Shortcut for all properties
+ if filter.isAllProperties():
+ for key in keys:
+ for prop in self.getProperties(key):
+ prop.writeJSON(jobject)
+ elif filter.hasPropertyFilters():
+ for key in keys:
+ for prop in self.getProperties(key):
+ prop.writeJSONFiltered(jobject, filter)
+
+
</ins><span class="cx"> def loadPrivateValue(self, value_name):
</span><span class="cx"> # Read it in from properties list and then delete the property from the
</span><span class="cx"> # main list
</span><span class="lines">@@ -611,7 +715,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def writePrivateProperty(self, os, key, value):
</span><del>- prop = PyCalendarProperty(name=key, value=value)
</del><ins>+ prop = self.sPropertyType(name=key, value=value)
</ins><span class="cx"> prop.generate(os)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -622,4 +726,4 @@
</span><span class="cx">
</span><span class="cx"> # Now create properties
</span><span class="cx"> if propvalue:
</span><del>- self.addProperty(PyCalendarProperty(name=propname, value=propvalue))
</del><ins>+ self.addProperty(self.sPropertyType(name=propname, value=propvalue))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentexpandedpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/componentexpanded.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/componentexpanded.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/componentexpanded.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,158 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.datetime import PyCalendarDateTime
-
-class PyCalendarComponentExpanded(object):
-
- @staticmethod
- def sort_by_dtstart_allday(e1, e2):
-
- if e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly():
- return e1.mInstanceStart < e2.mInstanceStart
- elif e1.mInstanceStart.isDateOnly():
- return True
- elif e2.mInstanceStart.isDateOnly():
- return False
- elif e1.mInstanceStart == e2.mInstanceStart:
- if e1.mInstanceEnd == e2.mInstanceEnd:
- # Put ones created earlier in earlier columns in day view
- return e1.getOwner().getStamp() < e2.getOwner().getStamp()
- else:
- # Put ones that end later in earlier columns in day view
- return e1.mInstanceEnd > e2.mInstanceEnd
- else:
- return e1.mInstanceStart < e2.mInstanceStart
-
-
- @staticmethod
- def sort_by_dtstart(e1, e2):
- if e1.mInstanceStart == e2.mInstanceStart:
- if (e1.mInstanceStart.isDateOnly() and not e2.mInstanceStart.isDateOnly() or
- not e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly()):
- return e1.mInstanceStart.isDateOnly()
- else:
- return False
- else:
- return e1.mInstanceStart < e2.mInstanceStart
-
-
- def __init__(self, owner, rid):
-
- self.mOwner = owner
- self.initFromOwner(rid)
-
-
- def duplicate(self):
- other = PyCalendarComponentExpanded(self.mOwner, None)
- other.mInstanceStart = self.mInstanceStart.duplicate()
- other.mInstanceEnd = self.mInstanceEnd.duplicate()
- other.mRecurring = self.mRecurring
- return other
-
-
- def close(self):
- # Clean-up
- self.mOwner = None
-
-
- def getOwner(self):
- return self.mOwner
-
-
- def getMaster(self):
- return self.mOwner
-
-
- def getTrueMaster(self):
- return self.mOwner.getMaster()
-
-
- def getInstanceStart(self):
- return self.mInstanceStart
-
-
- def getInstanceEnd(self):
- return self.mInstanceEnd
-
-
- def recurring(self):
- return self.mRecurring
-
-
- def isNow(self):
- # Check instance start/end against current date-time
- now = PyCalendarDateTime.getNowUTC()
- return self.mInstanceStart <= now and self.mInstanceEnd > now
-
-
- def initFromOwner(self, rid):
- # There are four possibilities here:
- #
- # 1: this instance is the instance for the master component
- #
- # 2: this instance is an expanded instance derived directly from the
- # master component
- #
- # 3: This instance is the instance for a slave (overridden recurrence
- # instance)
- #
- # 4: This instance is the expanded instance for a slave with a RANGE
- # parameter
- #
-
- # rid is not set if the owner is the master (case 1)
- if rid is None:
- # Just get start/end from owner
- self.mInstanceStart = self.mOwner.getStart()
- self.mInstanceEnd = self.mOwner.getEnd()
- self.mRecurring = False
-
- # If the owner is not a recurrence instance then it is case 2
- elif not self.mOwner.isRecurrenceInstance():
- # Derive start/end from rid and duration of master
-
- # Start of the recurrence instance is the recurrence id
- self.mInstanceStart = rid
-
- # End is based on original events settings
- if self.mOwner.hasEnd():
- self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
- else:
- self.mInstanceEnd = self.mInstanceStart.duplicate()
-
- self.mRecurring = True
-
- # If the owner is a recurrence item and the passed in rid is the same
- # as the component rid we have case 3
- elif rid == self.mOwner.getRecurrenceID():
- # Derive start/end directly from the owner
- self.mInstanceStart = self.mOwner.getStart()
- self.mInstanceEnd = self.mOwner.getEnd()
-
- self.mRecurring = True
-
- # case 4 - the complicated one!
- else:
- # We need to use the rid as the starting point, but adjust it by
- # the offset between the slave's
- # rid and its start
- self.mInstanceStart = rid + (self.mOwner.getStart() - self.mOwner.getRecurrenceID())
-
- # End is based on duration of owner
- self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
-
- self.mRecurring = True
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentrecurpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/componentrecur.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/componentrecur.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,714 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.componentexpanded import PyCalendarComponentExpanded
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.property import PyCalendarProperty
-from pycalendar.recurrenceset import PyCalendarRecurrenceSet
-from pycalendar.timezone import PyCalendarTimezone
-from pycalendar.utils import set_difference
-import uuid
-
-class PyCalendarComponentRecur(PyCalendarComponent):
-
- propertyCardinality_STATUS_Fix = (
- definitions.cICalProperty_STATUS,
- )
-
- @staticmethod
- def mapKey(uid, rid=None):
- if uid:
- result = "u:" + uid
- if rid is not None:
- result += rid
- return result
- else:
- return None
-
-
- @staticmethod
- def sort_by_dtstart_allday(e1, e2):
-
- if e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly():
- return e1.self.mStart < e2.self.mStart
- elif e1.self.mStart.isDateOnly():
- return True
- elif (e2.self.mStart.isDateOnly()):
- return False
- elif e1.self.mStart == e2.self.mStart:
- if e1.self.mEnd == e2.self.mEnd:
- # Put ones created earlier in earlier columns in day view
- return e1.self.mStamp < e2.self.mStamp
- else:
- # Put ones that end later in earlier columns in day view
- return e1.self.mEnd > e2.self.mEnd
- else:
- return e1.self.mStart < e2.self.mStart
-
-
- @staticmethod
- def sort_by_dtstart(e1, e2):
- if e1.self.mStart == e2.self.mStart:
- if (e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly() or
- not e1.self.mStart.isDateOnly() and not e2.self.mStart.isDateOnly()):
- return False
- else:
- return e1.self.mStart.isDateOnly()
- else:
- return e1.self.mStart < e2.self.mStart
-
-
- def __init__(self, parent=None):
- super(PyCalendarComponentRecur, self).__init__(parent=parent)
- self.mMaster = self
- self.mMapKey = None
- self.mSummary = None
- self.mStamp = PyCalendarDateTime()
- self.mHasStamp = False
- self.mStart = PyCalendarDateTime()
- self.mHasStart = False
- self.mEnd = PyCalendarDateTime()
- self.mHasEnd = False
- self.mDuration = False
- self.mHasRecurrenceID = False
- self.mAdjustFuture = False
- self.mAdjustPrior = False
- self.mRecurrenceID = None
- self.mRecurrences = None
-
- # This is a special check we do only for STATUS due to a calendarserver bug
- self.cardinalityChecks += (
- self.check_cardinality_STATUS_Fix,
- )
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarComponentRecur, self).duplicate(parent=parent)
-
- # Special determination of master
- other.mMaster = self.mMaster if self.recurring() else self
-
- other.mMapKey = self.mMapKey
-
- other.mSummary = self.mSummary
-
- if (self.mStamp is not None):
- other.mStamp = self.mStamp.duplicate()
- other.mHasStamp = self.mHasStamp
-
- other.mStart = self.mStart.duplicate()
- other.mHasStart = self.mHasStart
- other.mEnd = self.mEnd.duplicate()
- other.mHasEnd = self.mHasEnd
- other.mDuration = self.mDuration
-
- other.mHasRecurrenceID = self.mHasRecurrenceID
- other.mAdjustFuture = self.mAdjustFuture
- other.mAdjustPrior = self.mAdjustPrior
- if self.mRecurrenceID is not None:
- other.mRecurrenceID = self.mRecurrenceID.duplicate()
-
- other._resetRecurrenceSet()
-
- return other
-
-
- def canGenerateInstance(self):
- return not self.mHasRecurrenceID
-
-
- def recurring(self):
- return (self.mMaster is not None) and (self.mMaster is not self)
-
-
- def setMaster(self, master):
- self.mMaster = master
- self.initFromMaster()
-
-
- def getMaster(self):
- return self.mMaster
-
-
- def getMapKey(self):
-
- if self.mMapKey is None:
- self.mMapKey = str(uuid.uuid4())
- return self.mMapKey
-
-
- def getMasterKey(self):
- return PyCalendarComponentRecur.mapKey(self.mUID)
-
-
- def initDTSTAMP(self):
- # Save new one
- super(PyCalendarComponentRecur, self).initDTSTAMP()
-
- # Get the new one
- temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
- self.mHasStamp = temp is not None
- if self.mHasStamp:
- self.mStamp = temp
-
-
- def getStamp(self):
- return self.mStamp
-
-
- def hasStamp(self):
- return self.mHasStamp
-
-
- def getStart(self):
- return self.mStart
-
-
- def hasStart(self):
- return self.mHasStart
-
-
- def getEnd(self):
- return self.mEnd
-
-
- def hasEnd(self):
- return self.mHasEnd
-
-
- def useDuration(self):
- return self.mDuration
-
-
- def isRecurrenceInstance(self):
- return self.mHasRecurrenceID
-
-
- def isAdjustFuture(self):
- return self.mAdjustFuture
-
-
- def isAdjustPrior(self):
- return self.mAdjustPrior
-
-
- def getRecurrenceID(self):
- return self.mRecurrenceID
-
-
- def isRecurring(self):
- return (self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
-
-
- def getRecurrenceSet(self):
- return self.mRecurrences
-
-
- def setUID(self, uid):
- super(PyCalendarComponentRecur, self).setUID(uid)
-
- # Update the map key
- if self.mHasRecurrenceID:
- self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
- else:
- self.mMapKey = self.mapKey(self.mUID)
-
-
- def getSummary(self):
- return self.mSummary
-
-
- def setSummary(self, summary):
- self.mSummary = summary
-
-
- def getDescription(self):
- # Get DESCRIPTION
- txt = self.loadValueString(definitions.cICalProperty_DESCRIPTION)
- if txt is not None:
- return txt
- else:
- return ""
-
-
- def getLocation(self):
- # Get LOCATION
- txt = self.loadValueString(definitions.cICalProperty_LOCATION)
- if txt is not None:
- return txt
- else:
- return ""
-
-
- def finalise(self):
- super(PyCalendarComponentRecur, self).finalise()
-
- # Get DTSTAMP
- temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
- self.mHasStamp = temp is not None
- if self.mHasStamp:
- self.mStamp = temp
-
- # Get DTSTART
- temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
- self.mHasStart = temp is not None
- if self.mHasStart:
- self.mStart = temp
-
- # Get DTEND
- temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
- if temp is None:
- # Try DURATION instead
- temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
- if temp is not None:
- self.mHasEnd = False
- self.mEnd = self.mStart + temp
- self.mDuration = True
- else:
- # If no end or duration then use the start
- self.mHasEnd = False
- self.mEnd = self.mStart.duplicate()
- self.mDuration = False
- else:
- self.mHasEnd = True
- self.mEnd = temp
- self.mDuration = False
-
- # Get SUMMARY
- temp = self.loadValueString(definitions.cICalProperty_SUMMARY)
- if temp is not None:
- self.mSummary = temp
-
- # Get RECURRENCE-ID
- self.mHasRecurrenceID = (self.countProperty(definitions.cICalProperty_RECURRENCE_ID) != 0)
- if self.mHasRecurrenceID:
- self.mRecurrenceID = self.loadValueDateTime(definitions.cICalProperty_RECURRENCE_ID)
-
- # Update the map key
- if self.mHasRecurrenceID:
- self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
-
- # Also get the RANGE attribute
- attrs = self.findFirstProperty(definitions.cICalProperty_RECURRENCE_ID).getAttributes()
- if definitions.cICalAttribute_RANGE in attrs:
- self.mAdjustFuture = (attrs[definitions.cICalAttribute_RANGE][0].getFirstValue() == definitions.cICalAttribute_RANGE_THISANDFUTURE)
- self.mAdjustPrior = (attrs[definitions.cICalAttribute_RANGE][0].getFirstValue() == definitions.cICalAttribute_RANGE_THISANDPRIOR)
- else:
- self.mAdjustFuture = False
- self.mAdjustPrior = False
- else:
- self.mMapKey = self.mapKey(self.mUID)
-
- self._resetRecurrenceSet()
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems. Return
- a tuple containing two lists: the first describes problems that were fixed, the
- second problems that were not fixed. Caller can then decide what to do with unfixed
- issues.
- """
-
- # Do normal checks
- fixed, unfixed = super(PyCalendarComponentRecur, self).validate(doFix)
-
- # Check that any UNTIL value matches that for DTSTART
- if self.mHasStart and self.mRecurrences:
- dtutc = self.mStart.duplicateAsUTC()
- for rrule in self.mRecurrences.getRules():
- if rrule.getUseUntil():
- if rrule.getUntil().isDateOnly() ^ self.mStart.isDateOnly():
- logProblem = "[%s] Value types must match: %s, %s" % (
- self.getType(),
- definitions.cICalProperty_DTSTART,
- definitions.cICalValue_RECUR_UNTIL,
- )
- if doFix:
- rrule.getUntil().setDateOnly(self.mStart.isDateOnly())
- if not self.mStart.isDateOnly():
- rrule.getUntil().setHHMMSS(dtutc.getHours(), dtutc.getMinutes(), dtutc.getSeconds())
- rrule.getUntil().setTimezone(PyCalendarTimezone(utc=True))
- self.mRecurrences.changed()
- fixed.append(logProblem)
- else:
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- def check_cardinality_STATUS_Fix(self, fixed, unfixed, doFix):
- """
- Special for bug with STATUS where STATUS:CANCELLED is added alongside
- another STATUS. In this case we want STATUS:CANCELLED to win.
- """
- for propname in self.propertyCardinality_STATUS_Fix:
- if self.countProperty(propname) > 1:
- logProblem = "[%s] Too many properties: %s" % (self.getType(), propname)
- if doFix:
- # Check that one of them is STATUS:CANCELLED
- for prop in self.getProperties(propname):
- if prop.getTextValue().getValue().upper() == definitions.cICalProperty_STATUS_CANCELLED:
- self.removeProperties(propname)
- self.addProperty(PyCalendarProperty(propname, definitions.cICalProperty_STATUS_CANCELLED))
- fixed.append(logProblem)
- break
- else:
- unfixed.append(logProblem)
- else:
- unfixed.append(logProblem)
-
-
- def _resetRecurrenceSet(self):
- # May need to create items
- self.mRecurrences = None
- if ((self.countProperty(definitions.cICalProperty_RRULE) != 0) or
- (self.countProperty(definitions.cICalProperty_RDATE) != 0) or
- (self.countProperty(definitions.cICalProperty_EXRULE) != 0) or
- (self.countProperty(definitions.cICalProperty_EXDATE) != 0)):
-
- self.mRecurrences = PyCalendarRecurrenceSet()
-
- # Get RRULEs
- self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
-
- # Get RDATEs
- self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
-
- # Get EXRULEs
- self.loadValueRRULE(definitions.cICalProperty_EXRULE, self.mRecurrences, False)
-
- # Get EXDATEs
- self.loadValueRDATE(definitions.cICalProperty_EXDATE, self.mRecurrences, False)
-
-
- def FixStartEnd(self):
- # End is always greater than start if start exists
- if self.mHasStart and self.mEnd <= self.mStart:
- # Use the start
- self.mEnd = self.mStart.duplicate()
- self.mDuration = False
-
- # Adjust to approriate non-inclusive end point
- if self.mStart.isDateOnly():
- self.mEnd.offsetDay(1)
-
- # For all day events it makes sense to use duration
- self.mDuration = True
- else:
- # Use end of current day
- self.mEnd.offsetDay(1)
- self.mEnd.setHHMMSS(0, 0, 0)
-
-
- def expandPeriod(self, period, results):
- # Check for recurrence and True master
- if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
- and not self.isRecurrenceInstance()):
- # Expand recurrences within the range
- items = []
- self.mRecurrences.expand(self.mStart, period, items)
-
- # Look for overridden recurrence items
- cal = self.mParentComponent
- if cal is not None:
- # Remove recurrence instances from the list of items
- recurs = []
- cal.getRecurrenceInstancesIds(definitions.cICalComponent_VEVENT, self.getUID(), recurs)
- recurs.sort()
- if len(recurs) != 0:
- temp = []
- temp = set_difference(items, recurs)
- items = temp
-
- # Now get actual instances
- instances = []
- cal.getRecurrenceInstancesItems(definitions.cICalComponent_VEVENT, self.getUID(), instances)
-
- # Get list of each ones with RANGE
- prior = []
- future = []
- for iter in instances:
- if iter.isAdjustPrior():
- prior.append(iter)
- if iter.isAdjustFuture():
- future.append(iter)
-
- # Check for special behaviour
- if len(prior) + len(future) == 0:
- # Add each expanded item
- for iter in items:
- results.append(self.createExpanded(self, iter))
- else:
- # Sort each list first
- prior.sort(self.sort_by_dtstart)
- future.sort(self.sort_by_dtstart)
-
- # Add each expanded item
- for iter1 in items:
-
- # Now step through each using the slave item
- # instead of the master as appropriate
- slave = None
-
- # Find most appropriate THISANDPRIOR item
- for i in range(len(prior) - 1, 0, -1):
- riter2 = prior[i]
- if riter2.getStart() > iter1:
- slave = riter2
- break
-
- # Find most appropriate THISANDFUTURE item
- for i in range(len(future) - 1, 0, -1):
- riter2 = future.elementAt(i)
- if riter2.getStart() < iter1:
- slave = riter2
- break
-
- if slave is None:
- slave = self
- results.append(self.createExpanded(slave, iter1))
- else:
- # Add each expanded item
- for iter in items:
- results.append(self.createExpanded(self, iter))
-
- elif self.withinPeriod(period):
- if self.isRecurrenceInstance():
- rid = self.mRecurrenceID
- else:
- rid = None
- results.append(PyCalendarComponentExpanded(self, rid))
-
-
- def withinPeriod(self, period):
- # Check for recurrence
- if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()):
- items = []
- self.mRecurrences.expand(self.mStart, period, items)
- return len(items) != 0
- else:
- # Does event span the period (assume self.mEnd > self.mStart)
- # Check start (inclusive) and end (exclusive)
- if self.mEnd <= period.getStart() or self.mStart >= period.getEnd():
- return False
- else:
- return True
-
-
- def changedRecurrence(self):
- # Clear cached values
- if self.mRecurrences is not None:
- self.mRecurrences.changed()
-
-
- # Editing
- def editSummary(self, summary):
- # Updated cached value
- self.mSummary = summary
-
- # Remove existing items
- self.editProperty(definitions.cICalProperty_SUMMARY, summary)
-
-
- def editDetails(self, description, location):
-
- # Edit existing items
- self.editProperty(definitions.cICalProperty_DESCRIPTION, description)
- self.editProperty(definitions.cICalProperty_LOCATION, location)
-
-
- def editTiming(self):
- # Updated cached values
- self.mHasStart = False
- self.mHasEnd = False
- self.mDuration = False
- self.mStart.setToday()
- self.mEnd.setToday()
-
- # Remove existing DTSTART & DTEND & DURATION & DUE items
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
- self.removeProperties(definitions.cICalProperty_DUE)
-
-
- def editTimingDue(self, due):
- # Updated cached values
- self.mHasStart = False
- self.mHasEnd = True
- self.mDuration = False
- self.mStart = due
- self.mEnd = due
-
- # Remove existing DUE & DTSTART & DTEND & DURATION items
- self.removeProperties(definitions.cICalProperty_DUE)
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
-
- # Now create properties
- prop = PyCalendarProperty(definitions.cICalProperty_DUE, due)
- self.addProperty(prop)
-
-
- def editTimingStartEnd(self, start, end):
- # Updated cached values
- self.mHasStart = self.mHasEnd = True
- self.mStart = start
- self.mEnd = end
- self.mDuration = False
- self.FixStartEnd()
- # Remove existing DTSTART & DTEND & DURATION & DUE items
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
- self.removeProperties(definitions.cICalProperty_DUE)
-
- # Now create properties
- prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
- self.addProperty(prop)
-
- # If its an all day event and the end one day after the start, ignore it
- temp = start.duplicate()
- temp.offsetDay(1)
- if not start.isDateOnly() or end != temp:
- prop = PyCalendarProperty(definitions.cICalProperty_DTEND, end)
- self.addProperty(prop)
-
-
- def editTimingStartDuration(self, start, duration):
- # Updated cached values
- self.mHasStart = True
- self.mHasEnd = False
- self.mStart = start
- self.mEnd = start + duration
- self.mDuration = True
-
- # Remove existing DTSTART & DTEND & DURATION & DUE items
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
- self.removeProperties(definitions.cICalProperty_DUE)
-
- # Now create properties
- prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
- self.addProperty(prop)
-
- # If its an all day event and the duration is one day, ignore it
- if (not start.isDateOnly() or (duration.getWeeks() != 0)
- or (duration.getDays() > 1)):
- prop = PyCalendarProperty(definitions.cICalProperty_DURATION, duration)
- self.addProperty(prop)
-
-
- def editRecurrenceSet(self, recurs):
- # Must have items
- if self.mRecurrences is None:
- self.mRecurrences = PyCalendarRecurrenceSet()
-
- # Updated cached values
- self.mRecurrences = recurs
-
- # Remove existing RRULE, EXRULE, RDATE & EXDATE
- self.removeProperties(definitions.cICalProperty_RRULE)
- self.removeProperties(definitions.cICalProperty_EXRULE)
- self.removeProperties(definitions.cICalProperty_RDATE)
- self.removeProperties(definitions.cICalProperty_EXDATE)
-
- # Now create properties
- for iter in self.mRecurrences.getRules():
- prop = PyCalendarProperty(definitions.cICalProperty_RRULE, iter)
- self.addProperty(prop)
- for iter in self.getExrules():
- prop = PyCalendarProperty(definitions.cICalProperty_EXRULE, iter)
- self.addProperty(prop)
- for iter in self.mRecurrences.getDates():
- prop = PyCalendarProperty(definitions.cICalProperty_RDATE, iter)
- self.addProperty(prop)
- for iter in self.mRecurrences.getExdates():
- prop = PyCalendarProperty(definitions.cICalProperty_EXDATE, iter)
- self.addProperty(prop)
-
-
- def excludeRecurrence(self, start):
- # Must have items
- if self.mRecurrences is None:
- return
-
- # Add to recurrence set and clear cache
- self.mRecurrences.subtract(start)
-
- # Add property
- prop = PyCalendarProperty(definitions.cICalProperty_EXDATE, start)
- self.addProperty(prop)
-
-
- def excludeFutureRecurrence(self, start):
- # Must have items
- if self.mRecurrences is None:
- return
-
- # Adjust RRULES to end before start
- self.mRecurrences.excludeFutureRecurrence(start)
-
- # Remove existing RRULE & RDATE
- self.removeProperties(definitions.cICalProperty_RRULE)
- self.removeProperties(definitions.cICalProperty_RDATE)
-
- # Now create properties
- for iter in self.mRecurrences.getRules():
- prop = PyCalendarProperty(definitions.cICalProperty_RRULE, iter)
- self.addProperty(prop)
- for iter in self.mRecurrences.getDates():
- prop = PyCalendarProperty(definitions.cICalProperty_RDATE, iter)
- self.addProperty(prop)
-
-
- def initFromMaster(self):
- # Only if not master
- if self.recurring():
- # Redo this to get cached values from master
- self.finalise()
-
- # If this component does not have its own start property, use the
- # recurrence id
- # i.e. the start time of this instance has not changed - something
- # else has
- if not self.hasProperty(definitions.cICalProperty_DTSTART):
- self.mStart = self.mRecurrenceID
-
- # If this component does not have its own end/duration property,
- # the determine
- # the end from the master duration
- if (not self.hasProperty(definitions.cICalProperty_DTEND) and
- not self.hasProperty(definitions.cICalProperty_DURATION)):
- # End is based on original events settings
- self.mEnd = self.mStart + (self.mMaster.getEnd() - self.mMaster.getStart())
-
- # If this instance has a duration, but no start of its own, then we
- # need to readjust the end
- # to account for the start being changed to the recurrence id
- elif (self.hasProperty(definitions.cICalProperty_DURATION) and
- not self.hasProperty(definitions.cICalProperty_DTSTART)):
- temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
- self.mEnd = self.mStart + temp
-
-
- def createExpanded(self, master, recurid):
- return PyCalendarComponentExpanded(master, recurid)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcontainerbasepyfromrev11912PyCalendarbranchesjson2srcpycalendarcontainerbasepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/containerbase.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/containerbase.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/containerbase.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/containerbase.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,257 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 cStringIO import StringIO
+from pycalendar.componentbase import ComponentBase
+from pycalendar.exceptions import InvalidData, ValidationError
+from pycalendar.parser import ParserContext
+from pycalendar.utils import readFoldedLine
+import json
+
+class ContainerBase(ComponentBase):
+ """
+ Represents the top-level component (i.e., VCALENDAR or vCARD)
+ """
+
+ sProdID = "-//calendarserver.org//PyCalendar v1//EN"
+ sDomain = "calendarserver.org"
+
+ # These must be set by derived classes
+ sContainerDescriptor = None
+ sComponentType = None
+ sPropertyType = None
+
+ sFormatText = None
+ sFormatJSON = None
+
+ @classmethod
+ def setPRODID(cls, prodid):
+ cls.sProdID = prodid
+
+
+ @classmethod
+ def setDomain(cls, domain):
+ cls.sDomain = domain
+
+
+ def __init__(self, add_defaults=True):
+ super(ContainerBase, self).__init__()
+
+ if add_defaults:
+ self.addDefaultProperties()
+
+
+ def duplicate(self):
+ return super(ContainerBase, self).duplicate()
+
+
+ def getType(self):
+ raise NotImplementedError
+
+
+ def finalise(self):
+ pass
+
+
+ def validate(self, doFix=False, doRaise=False):
+ """
+ Validate the data in this component and optionally fix any problems. Return
+ a tuple containing two lists: the first describes problems that were fixed, the
+ second problems that were not fixed. Caller can then decide what to do with unfixed
+ issues.
+ """
+
+ # Optional raise behavior
+ fixed, unfixed = super(ContainerBase, self).validate(doFix)
+ if doRaise and unfixed:
+ raise ValidationError(";".join(unfixed))
+ return fixed, unfixed
+
+
+ @classmethod
+ def parseData(cls, data, format=None):
+ """
+ Parse a source of data that can either be a stream (file like object) or a string. Also,
+ it can be in text or json formats.
+
+ @param data: the data to parse
+ @type data: C{str} or C{File-like}
+ @param format: format (MIME media type) of data.
+ @type format: C{str}
+ """
+
+ if format is None or format == cls.sFormatText:
+ return cls.parseTextData(data)
+
+ elif format == cls.sFormatJSON:
+ return cls.parseJSONData(data)
+
+
+ @classmethod
+ def parseText(cls, data):
+ return cls.parseTextData(data)
+
+
+ @classmethod
+ def parseTextData(cls, data):
+ if isinstance(data, str):
+ data = StringIO(data)
+ cal = cls(add_defaults=False)
+ if cal.parse(data):
+ return cal
+ else:
+ return None
+
+
+ def parse(self, ins):
+
+ result = False
+
+ self.setProperties({})
+
+ LOOK_FOR_CONTAINER = 0
+ GET_PROPERTY_OR_COMPONENT = 1
+
+ state = LOOK_FOR_CONTAINER
+
+ # Get lines looking for start of calendar
+ lines = [None, None]
+ comp = self
+ compend = None
+ componentstack = []
+
+ while readFoldedLine(ins, lines):
+
+ line = lines[0]
+
+ if state == LOOK_FOR_CONTAINER:
+
+ # Look for start
+ if line == self.getBeginDelimiter():
+ # Next state
+ state = GET_PROPERTY_OR_COMPONENT
+
+ # Indicate success at this point
+ result = True
+
+ # Handle blank line
+ elif len(line) == 0:
+ # Raise if requested, otherwise just ignore
+ if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+ raise InvalidData("%s data has blank lines" % (self.sContainerDescriptor,))
+
+ # Unrecognized data
+ else:
+ raise InvalidData("%s data not recognized" % (self.sContainerDescriptor,), line)
+
+ elif state == GET_PROPERTY_OR_COMPONENT:
+
+ # Parse property or look for start of component
+ if line.startswith("BEGIN:") and self.sComponentType is not None:
+
+ # Push previous details to stack
+ componentstack.append((comp, compend,))
+
+ # Start a new component
+ comp = self.sComponentType.makeComponent(line[6:], comp)
+ compend = comp.getEndDelimiter()
+
+ # Look for end of object
+ elif line == self.getEndDelimiter():
+
+ # Finalise the current calendar
+ self.finalise()
+
+ # Change state
+ state = LOOK_FOR_CONTAINER
+
+ # Look for end of current component
+ elif line == compend:
+
+ # Finalise the component (this caches data from the properties)
+ comp.finalise()
+
+ # Embed component in parent and reset to use parent
+ componentstack[-1][0].addComponent(comp)
+ comp, compend = componentstack.pop()
+
+ # Blank line
+ elif len(line) == 0:
+ # Raise if requested, otherwise just ignore
+ if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+ raise InvalidData("%s data has blank lines" % (self.sContainerDescriptor,))
+
+ # Must be a property
+ else:
+
+ # Parse parameter/value for top-level calendar item
+ prop = self.sPropertyType.parseText(line)
+
+ # Check for valid property
+ if comp is self:
+ if not comp.validProperty(prop):
+ raise InvalidData("Invalid property", str(prop))
+ else:
+ comp.addProperty(prop)
+ else:
+ comp.addProperty(prop)
+
+ # Check for truncated data
+ if state != LOOK_FOR_CONTAINER:
+ raise InvalidData("%s data not complete" % (self.sContainerDescriptor,))
+
+ # Validate some things
+ if result and not self.hasProperty("VERSION"):
+ raise InvalidData("%s missing VERSION" % (self.sContainerDescriptor,))
+
+ return result
+
+
+ @classmethod
+ def parseJSONData(cls, data):
+ if not isinstance(data, str):
+ data = data.read()
+ try:
+ jobject = json.loads(data)
+ except ValueError, e:
+ raise InvalidData(e, data)
+ return cls.parseJSON(jobject, None, cls(add_defaults=False))
+
+
+ def getText(self, format=None):
+
+ if format is None or format == self.sFormatText:
+ s = StringIO()
+ self.generate(s)
+ return s.getvalue()
+ elif format == self.sFormatJSON:
+ return self.getTextJSON()
+ else:
+ return None
+
+
+ def getTextJSON(self):
+ jobject = []
+ self.writeJSON(jobject)
+ return json.dumps(jobject[0], indent=2, separators=(',', ':'))
+
+
+ def addDefaultProperties(self):
+ raise NotImplementedError
+
+
+ def validProperty(self, prop):
+ raise NotImplementedError
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendardatetimepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/datetime.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/datetime.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/datetime.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,18 +14,17 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import definitions
-from pycalendar import locale
</del><ins>+from pycalendar import locale, xmldefinitions, xmlutils
</ins><span class="cx"> from pycalendar import utils
</span><del>-from pycalendar import xmldefs
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.duration import Duration
+from pycalendar.icalendar import definitions
+from pycalendar.timezone import Timezone
</ins><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import time
</span><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx">
</span><del>-class PyCalendarDateTime(ValueMixin):
</del><ins>+class DateTime(ValueMixin):
</ins><span class="cx">
</span><span class="cx"> SUNDAY = 0
</span><span class="cx"> MONDAY = 1
</span><span class="lines">@@ -83,7 +82,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- other = PyCalendarDateTime(self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</del><ins>+ other = DateTime(self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</ins><span class="cx">
</span><span class="cx"> other.mDateOnly = self.mDateOnly
</span><span class="cx">
</span><span class="lines">@@ -104,7 +103,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __repr__(self):
</span><del>- return "PyCalendarDateTime: %s" % (self.getText(),)
</del><ins>+ return "DateTime: %s" % (self.getText(),)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __hash__(self):
</span><span class="lines">@@ -122,7 +121,7 @@
</span><span class="cx">
</span><span class="cx"> def __sub__(self, dateorduration):
</span><span class="cx">
</span><del>- if isinstance(dateorduration, PyCalendarDateTime):
</del><ins>+ if isinstance(dateorduration, DateTime):
</ins><span class="cx">
</span><span class="cx"> date = dateorduration
</span><span class="cx">
</span><span class="lines">@@ -151,9 +150,9 @@
</span><span class="cx"> else:
</span><span class="cx"> # Do diff of date-time in seconds
</span><span class="cx"> diff = self.getPosixTime() - date.getPosixTime()
</span><del>- return PyCalendarDuration(duration=diff)
</del><ins>+ return Duration(duration=diff)
</ins><span class="cx">
</span><del>- elif isinstance(dateorduration, PyCalendarDuration):
</del><ins>+ elif isinstance(dateorduration, Duration):
</ins><span class="cx">
</span><span class="cx"> duration = dateorduration
</span><span class="cx"> result = self.duplicate()
</span><span class="lines">@@ -216,7 +215,7 @@
</span><span class="cx">
</span><span class="cx"> # If they have the same timezone do simple compare - no posix calc
</span><span class="cx"> # needed
</span><del>- elif (PyCalendarTimezone.same(self.mTZUTC, self.mTZID, comp.mTZUTC, comp.mTZID)):
</del><ins>+ elif (Timezone.same(self.mTZUTC, self.mTZID, comp.mTZUTC, comp.mTZID)):
</ins><span class="cx"> if self.mYear == comp.mYear:
</span><span class="cx"> if self.mMonth == comp.mMonth:
</span><span class="cx"> if self.mDay == comp.mDay:
</span><span class="lines">@@ -301,6 +300,14 @@
</span><span class="cx"> self.changed()
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def setYYMMDD(self, year, month, days):
+ if (self.mYear != year) or (self.mMonth != month) or (self.mDay != days):
+ self.mYear = year
+ self.mMonth = month
+ self.mDay = days
+ self.changed()
+
+
</ins><span class="cx"> def getYear(self):
</span><span class="cx"> return self.mYear
</span><span class="cx">
</span><span class="lines">@@ -426,14 +433,14 @@
</span><span class="cx"> return
</span><span class="cx">
</span><span class="cx"> # What day does the current year start on, and diff that with the current day
</span><del>- temp = PyCalendarDateTime(year=self.mYear, month=1, day=1)
</del><ins>+ temp = DateTime(year=self.mYear, month=1, day=1)
</ins><span class="cx"> first_day = temp.getDayOfWeek()
</span><span class="cx"> current_day = self.getDayOfWeek()
</span><span class="cx">
</span><span class="cx"> # Calculate and set yearday for start of week. The first week is the one that contains at least
</span><span class="cx"> # four days (with week start defaulting to MONDAY), so that means the 1st of January would fall
</span><span class="cx"> # on MO, TU, WE, TH.
</span><del>- if first_day in (PyCalendarDateTime.MONDAY, PyCalendarDateTime.TUESDAY, PyCalendarDateTime.WEDNESDAY, PyCalendarDateTime.THURSDAY):
</del><ins>+ if first_day in (DateTime.MONDAY, DateTime.TUESDAY, DateTime.WEDNESDAY, DateTime.THURSDAY):
</ins><span class="cx"> year_day = (weekno - 1) * 7 + current_day - first_day
</span><span class="cx"> else:
</span><span class="cx"> year_day = weekno * 7 + current_day - first_day
</span><span class="lines">@@ -453,7 +460,7 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> # What day does the current year start on
</span><del>- temp = PyCalendarDateTime(year=self.mYear, month=1, day=1)
</del><ins>+ temp = DateTime(year=self.mYear, month=1, day=1)
</ins><span class="cx"> first_day = temp.getDayOfWeek()
</span><span class="cx"> if first_day == 0:
</span><span class="cx"> first_day = 7
</span><span class="lines">@@ -467,13 +474,13 @@
</span><span class="cx"> # Might need to adjust forward/backwards based on year boundaries
</span><span class="cx"> if week_no == 0:
</span><span class="cx"> # Last week of previous year
</span><del>- temp = PyCalendarDateTime(year=self.mYear - 1, month=12, day=31)
</del><ins>+ temp = DateTime(year=self.mYear - 1, month=12, day=31)
</ins><span class="cx"> week_no = temp.getWeekNo()
</span><span class="cx"> elif week_no == 53:
</span><span class="cx"> # Might be first week of next year
</span><del>- temp = PyCalendarDateTime(year=self.mYear + 1, month=1, day=1)
</del><ins>+ temp = DateTime(year=self.mYear + 1, month=1, day=1)
</ins><span class="cx"> first_day = temp.getDayOfWeek()
</span><del>- if first_day in (PyCalendarDateTime.MONDAY, PyCalendarDateTime.TUESDAY, PyCalendarDateTime.WEDNESDAY, PyCalendarDateTime.THURSDAY):
</del><ins>+ if first_day in (DateTime.MONDAY, DateTime.TUESDAY, DateTime.WEDNESDAY, DateTime.THURSDAY):
</ins><span class="cx"> week_no = 1
</span><span class="cx">
</span><span class="cx"> return week_no
</span><span class="lines">@@ -579,7 +586,7 @@
</span><span class="cx">
</span><span class="cx"> def getDayOfWeek(self):
</span><span class="cx"> # Count days since 01-Jan-1970 which was a Thursday
</span><del>- result = PyCalendarDateTime.THURSDAY + self.daysSince1970()
</del><ins>+ result = DateTime.THURSDAY + self.daysSince1970()
</ins><span class="cx"> result %= 7
</span><span class="cx"> if result < 0:
</span><span class="cx"> result += 7
</span><span class="lines">@@ -686,7 +693,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getTimezone(self):
</span><del>- return PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+ return Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setTimezone(self, tzid):
</span><span class="lines">@@ -711,7 +718,7 @@
</span><span class="cx"> # Cache and restore and adjust the posix value to avoid a recalc since it won't change during this adjust
</span><span class="cx"> tempPosix = self.mPosixTime if self.mPosixTimeCached else None
</span><span class="cx">
</span><del>- utc = PyCalendarTimezone(utc=True)
</del><ins>+ utc = Timezone(utc=True)
</ins><span class="cx">
</span><span class="cx"> offset_from = self.timeZoneSecondsOffset()
</span><span class="cx"> self.setTimezone(utc)
</span><span class="lines">@@ -735,7 +742,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setToday(self):
</span><del>- tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+ tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx"> self.copy_ICalendarDateTime(self.getToday(tz))
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -745,24 +752,24 @@
</span><span class="cx"> now = time.time()
</span><span class="cx"> now_tm = time.localtime(now)
</span><span class="cx">
</span><del>- temp = PyCalendarDateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, tzid=tzid)
</del><ins>+ temp = DateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, tzid=tzid)
</ins><span class="cx"> return temp
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setNow(self):
</span><del>- tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+ tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx"> self.copy_ICalendarDateTime(self.getNow(tz))
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @staticmethod
</span><span class="cx"> def getNow(tzid):
</span><del>- utc = PyCalendarDateTime.getNowUTC()
- utc.adjustTimezone(tzid if tzid is not None else PyCalendarTimezone())
</del><ins>+ utc = DateTime.getNowUTC()
+ utc.adjustTimezone(tzid if tzid is not None else Timezone())
</ins><span class="cx"> return utc
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setNowUTC(self):
</span><del>- self.copy_PyCalendarDateTime(self.getNowUTC())
</del><ins>+ self.copy_DateTime(self.getNowUTC())
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @staticmethod
</span><span class="lines">@@ -770,9 +777,9 @@
</span><span class="cx"> # Get from posix time
</span><span class="cx"> now = time.time()
</span><span class="cx"> now_tm = time.gmtime(now)
</span><del>- tzid = PyCalendarTimezone(utc=True)
</del><ins>+ tzid = Timezone(utc=True)
</ins><span class="cx">
</span><del>- return PyCalendarDateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, hours=now_tm.tm_hour, minutes=now_tm.tm_min, seconds=now_tm.tm_sec, tzid=tzid)
</del><ins>+ return DateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, hours=now_tm.tm_hour, minutes=now_tm.tm_min, seconds=now_tm.tm_sec, tzid=tzid)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def recur(self, freq, interval):
</span><span class="lines">@@ -809,7 +816,7 @@
</span><span class="cx">
</span><span class="cx"> buf = StringIO.StringIO()
</span><span class="cx">
</span><del>- if locale == PyCalendarDateTime.FULLDATE:
</del><ins>+ if locale == DateTime.FULLDATE:
</ins><span class="cx"> buf.write(locale.getDay(self.getDayOfWeek(), locale.LONG))
</span><span class="cx"> buf.write(", ")
</span><span class="cx"> buf.write(locale.getMonth(self.mMonth, locale.LONG))
</span><span class="lines">@@ -817,7 +824,7 @@
</span><span class="cx"> buf.write(str(self.mDay))
</span><span class="cx"> buf.write(", ")
</span><span class="cx"> buf.write(str(self.mYear))
</span><del>- elif locale == PyCalendarDateTime.ABBREVDATE:
</del><ins>+ elif locale == DateTime.ABBREVDATE:
</ins><span class="cx"> buf.write(locale.getDay(self.getDayOfWeek(), locale.SHORT))
</span><span class="cx"> buf.write(", ")
</span><span class="cx"> buf.write(locale.getMonth(self.mMonth, locale.SHORT))
</span><span class="lines">@@ -825,25 +832,25 @@
</span><span class="cx"> buf.write(str(self.mDay))
</span><span class="cx"> buf.write(", ")
</span><span class="cx"> buf.write(str(self.mYear))
</span><del>- elif locale == PyCalendarDateTime.NUMERICDATE:
</del><ins>+ elif locale == DateTime.NUMERICDATE:
</ins><span class="cx"> buf.write(str(self.mMonth))
</span><span class="cx"> buf.write("/")
</span><span class="cx"> buf.write(str(self.mDay))
</span><span class="cx"> buf.write("/")
</span><span class="cx"> buf.write(str(self.mYear))
</span><del>- elif locale == PyCalendarDateTime.FULLDATENOYEAR:
</del><ins>+ elif locale == DateTime.FULLDATENOYEAR:
</ins><span class="cx"> buf.write(locale.getDay(self.getDayOfWeek(), locale.LONG))
</span><span class="cx"> buf.write(", ")
</span><span class="cx"> buf.write(locale.getMonth(self.mMonth, locale.LONG))
</span><span class="cx"> buf.write(" ")
</span><span class="cx"> buf.write(str(self.mDay))
</span><del>- elif locale == PyCalendarDateTime.ABBREVDATENOYEAR:
</del><ins>+ elif locale == DateTime.ABBREVDATENOYEAR:
</ins><span class="cx"> buf.write(locale.getDay(self. getDayOfWeek(), locale.SHORT))
</span><span class="cx"> buf.write(", ")
</span><span class="cx"> buf.write(locale.getMonth(self.mMonth, locale.SHORT))
</span><span class="cx"> buf.write(" ")
</span><span class="cx"> buf.write(str(self.mDay))
</span><del>- elif locale == PyCalendarDateTime.NUMERICDATENOYEAR:
</del><ins>+ elif locale == DateTime.NUMERICDATENOYEAR:
</ins><span class="cx"> buf.write(str(self.mMonth))
</span><span class="cx"> buf.write("/")
</span><span class="cx"> buf.write(str(self.mDay))
</span><span class="lines">@@ -935,6 +942,7 @@
</span><span class="cx"> else:
</span><span class="cx"> return "%04d-%02d-%02dT%02d:%02d:%02d" % (self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</span><span class="cx">
</span><ins>+ getJSONText = getXMLText
</ins><span class="cx">
</span><span class="cx"> @classmethod
</span><span class="cx"> def parseText(cls, data, fullISO=False):
</span><span class="lines">@@ -1031,7 +1039,7 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar:
</span><span class="cx"> # parse format YYYYMMDD[THHMMSS[Z]]
</span><del>- # vCard (fullISO)
</del><ins>+ # vCard (fullISO), jCal
</ins><span class="cx"> # parse format YYYY[-]MM[-]DD[THH[:]MM[:]SS[(Z/(+/-)HHMM]]
</span><span class="cx">
</span><span class="cx"> try:
</span><span class="lines">@@ -1086,13 +1094,21 @@
</span><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx"> value = XML.SubElement(
</span><span class="cx"> node,
</span><del>- xmldefs.makeTag(
</del><ins>+ xmlutils.makeTag(
</ins><span class="cx"> namespace,
</span><del>- xmldefs.value_date if self.isDateOnly() else xmldefs.value_date_time
</del><ins>+ xmldefinitions.value_date if self.isDateOnly() else xmldefinitions.value_date_time
</ins><span class="cx"> ))
</span><span class="cx"> value.text = self.getXMLText()
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parseJSON(self, jobject):
+ self.parse(str(jobject), True)
+
+
+ def writeJSON(self, jobject):
+ jobject.append(self.getJSONText())
+
+
</ins><span class="cx"> def normalise(self):
</span><span class="cx"> # Normalise seconds
</span><span class="cx"> normalised_secs = self.mSeconds % 60
</span><span class="lines">@@ -1160,13 +1176,13 @@
</span><span class="cx"> if self.mTZUTC:
</span><span class="cx"> return 0
</span><span class="cx"> if self.mTZOffset is None:
</span><del>- tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+ tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx"> self.mTZOffset = tz.timeZoneSecondsOffset(self)
</span><span class="cx"> return self.mTZOffset
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def timeZoneDescriptor(self):
</span><del>- tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+ tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx"> return tz.timeZoneDescriptor(self)
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendardatetimevaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/datetimevalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/datetimevalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/datetimevalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,42 +14,26 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.datetime import DateTime
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
</ins><span class="cx">
</span><del>-class PyCalendarDateTimeValue(PyCalendarValue):
</del><ins>+class DateTimeValue(WrapperValue, Value):
</ins><span class="cx">
</span><del>- def __init__(self, value=None):
- self.mValue = value if value is not None else PyCalendarDateTime()
</del><ins>+ _wrappedClass = DateTime
+ _wrappedType = None # Depends on actual value
</ins><span class="cx">
</span><del>-
- def duplicate(self):
- return PyCalendarDateTimeValue(self.mValue.duplicate())
-
-
</del><span class="cx"> def getType(self):
</span><del>- return (PyCalendarValue.VALUETYPE_DATETIME, PyCalendarValue.VALUETYPE_DATE)[self.mValue.isDateOnly()]
</del><ins>+ return (Value.VALUETYPE_DATETIME, Value.VALUETYPE_DATE)[self.mValue.isDateOnly()]
</ins><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data, fullISO=False):
- self.mValue.parse(data, fullISO)
</del><ins>+ def parse(self, data, variant):
+ self.mValue.parse(data, fullISO=(variant == "vcard"))
</ins><span class="cx">
</span><span class="cx">
</span><del>- def generate(self, os):
- self.mValue.generate(os)
-
-
</del><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx"> self.mValue.writeXML(node, namespace)
</span><span class="cx">
</span><del>-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_DATE, PyCalendarDateTimeValue, xmldefs.value_date)
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_DATETIME, PyCalendarDateTimeValue, xmldefs.value_date_time)
</del><ins>+Value.registerType(Value.VALUETYPE_DATE, DateTimeValue, xmldefinitions.value_date)
+Value.registerType(Value.VALUETYPE_DATETIME, DateTimeValue, xmldefinitions.value_date_time)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendardefinitionspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/definitions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/definitions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/definitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,349 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# 5545 Components
-
-cICalComponent_VCALENDAR = "VCALENDAR"
-cICalComponent_VEVENT = "VEVENT"
-cICalComponent_VTODO = "VTODO"
-cICalComponent_VJOURNAL = "VJOURNAL"
-cICalComponent_VFREEBUSY = "VFREEBUSY"
-cICalComponent_VTIMEZONE = "VTIMEZONE"
-cICalComponent_VALARM = "VALARM"
-cICalComponent_STANDARD = "STANDARD"
-cICalComponent_DAYLIGHT = "DAYLIGHT"
-
-# 5545 Calendar Property Attributes
-
-# 5545 Section 3.2
-cICalAttribute_ALTREP = "ALTREP"
-cICalAttribute_CN = "CN"
-cICalAttribute_CUTYPE = "CUTYPE"
-cICalAttribute_DELEGATED_FROM = "DELEGATED-FROM"
-cICalAttribute_DELEGATED_TO = "DELEGATED-TO"
-cICalAttribute_DIR = "DIR"
-cICalAttribute_ENCODING = "ENCODING"
-cICalAttribute_FMTTYPE = "FMTTYPE"
-cICalAttribute_FBTYPE = "FBTYPE"
-cICalAttribute_LANGUAGE = "LANGUAGE"
-cICalAttribute_MEMBER = "MEMBER"
-cICalAttribute_PARTSTAT = "PARTSTAT"
-cICalAttribute_RANGE = "RANGE"
-cICalAttribute_RELATED = "RELATED"
-cICalAttribute_RELTYPE = "RELTYPE"
-cICalAttribute_ROLE = "ROLE"
-cICalAttribute_RSVP = "RSVP"
-cICalAttribute_RSVP_TRUE = "TRUE"
-cICalAttribute_RSVP_FALSE = "FALSE"
-cICalAttribute_SENT_BY = "SENT-BY"
-cICalAttribute_TZID = "TZID"
-cICalAttribute_VALUE = "VALUE"
-
-# 5545 Section 3.2.9
-cICalAttribute_FBTYPE_FREE = "FREE"
-cICalAttribute_FBTYPE_BUSY = "BUSY"
-cICalAttribute_FBTYPE_BUSYUNAVAILABLE = "BUSY-UNAVAILABLE"
-cICalAttribute_FBTYPE_BUSYTENTATIVE = "BUSY-TENTATIVE"
-
-# 5545 Section 3.2.12
-ePartStat_NeedsAction = 0
-ePartStat_Accepted = 1
-ePartStat_Declined = 2
-ePartStat_Tentative = 3
-ePartStat_Delegated = 4
-ePartStat_Completed = 5
-ePartStat_InProcess = 6
-
-cICalAttribute_PARTSTAT_NEEDSACTION = "NEEDS-ACTION"
-cICalAttribute_PARTSTAT_ACCEPTED = "ACCEPTED"
-cICalAttribute_PARTSTAT_DECLINED = "DECLINED"
-cICalAttribute_PARTSTAT_TENTATIVE = "TENTATIVE"
-cICalAttribute_PARTSTAT_DELEGATED = "DELEGATED"
-cICalAttribute_PARTSTAT_COMPLETED = "COMPLETE"
-cICalAttribute_PARTSTAT_INPROCESS = "IN-PROCESS"
-
-# 5545 Section 3.2.13
-cICalAttribute_RANGE_THISANDFUTURE = "THISANDFUTURE"
-cICalAttribute_RANGE_THISANDPRIOR = "THISANDPRIOR" # 2445 only
-
-# 5545 Section 3.2.14
-cICalAttribute_RELATED_START = "START"
-cICalAttribute_RELATED_END = "END"
-
-# 5545 Section 3.2.16
-ePartRole_Chair = 0
-ePartRole_Required = 1
-ePartRole_Optional = 2
-ePartRole_Non = 3
-
-cICalAttribute_ROLE_CHAIR = "CHAIR"
-cICalAttribute_ROLE_REQ_PART = "REQ-PARTICIPANT"
-cICalAttribute_ROLE_OPT_PART = "OPT-PARTICIPANT"
-cICalAttribute_ROLE_NON_PART = "NON-PARTICIPANT"
-
-# 5545 Section 3.2.3
-eCutype_Individual = 0
-eCutype_Group = 1
-eCutype_Resource = 2
-eCutype_Room = 3
-eCutype_Unknown = 4
-
-cICalAttribute_CUTYPE_INDIVIDUAL = "INDIVIDUAL"
-cICalAttribute_CUTYPE_GROUP = "GROUP"
-cICalAttribute_CUTYPE_RESOURCE = "RESOURCE"
-cICalAttribute_CUTYPE_ROOM = "ROOM"
-cICalAttribute_CUTYPE_UNKNOWN = "UNKNOWN"
-
-# 5545 Value types
-
-# 5545 Section 3.3
-cICalValue_BINARY = "BINARY"
-cICalValue_BOOLEAN = "BOOLEAN"
-cICalValue_CAL_ADDRESS = "CAL-ADDRESS"
-cICalValue_DATE = "DATE"
-cICalValue_DATE_TIME = "DATE-TIME"
-cICalValue_DURATION = "DURATION"
-cICalValue_FLOAT = "FLOAT"
-cICalValue_INTEGER = "INTEGER"
-cICalValue_PERIOD = "PERIOD"
-cICalValue_RECUR = "RECUR"
-cICalValue_TEXT = "TEXT"
-cICalValue_TIME = "TIME"
-cICalValue_URI = "URI"
-cICalValue_UTC_OFFSET = "UTC-OFFSET"
-
-# 5545 Calendar Properties
-
-# 5545 Section 3.7
-
-cICalProperty_CALSCALE = "CALSCALE"
-cICalProperty_METHOD = "METHOD"
-cICalProperty_PRODID = "PRODID"
-cICalProperty_VERSION = "VERSION"
-
-# Apple Extensions
-cICalProperty_XWRCALNAME = "X-WR-CALNAME"
-cICalProperty_XWRCALDESC = "X-WR-CALDESC"
-cICalProperty_XWRALARMUID = "X-WR-ALARMUID"
-
-# 5545 Component Property names
-
-# 5545 Section 3.8.1
-cICalProperty_ATTACH = "ATTACH"
-cICalProperty_CATEGORIES = "CATEGORIES"
-cICalProperty_CLASS = "CLASS"
-cICalProperty_COMMENT = "COMMENT"
-cICalProperty_DESCRIPTION = "DESCRIPTION"
-cICalProperty_GEO = "GEO"
-cICalProperty_LOCATION = "LOCATION"
-cICalProperty_PERCENT_COMPLETE = "PERCENT-COMPLETE"
-cICalProperty_PRIORITY = "PRIORITY"
-cICalProperty_RESOURCES = "RESOURCES"
-cICalProperty_STATUS = "STATUS"
-cICalProperty_SUMMARY = "SUMMARY"
-
-# 5545 Section 3.8.2
-cICalProperty_COMPLETED = "COMPLETED"
-cICalProperty_DTEND = "DTEND"
-cICalProperty_DUE = "DUE"
-cICalProperty_DTSTART = "DTSTART"
-cICalProperty_DURATION = "DURATION"
-cICalProperty_FREEBUSY = "FREEBUSY"
-cICalProperty_TRANSP = "TRANSP"
-cICalProperty_OPAQUE = "OPAQUE"
-cICalProperty_TRANSPARENT = "TRANSPARENT"
-
-# 5545 Section 3.8.3
-cICalProperty_TZID = "TZID"
-cICalProperty_TZNAME = "TZNAME"
-cICalProperty_TZOFFSETFROM = "TZOFFSETFROM"
-cICalProperty_TZOFFSETTO = "TZOFFSETTO"
-cICalProperty_TZURL = "TZURL"
-
-# 5545 Section 3.8.4
-cICalProperty_ATTENDEE = "ATTENDEE"
-cICalProperty_CONTACT = "CONTACT"
-cICalProperty_ORGANIZER = "ORGANIZER"
-cICalProperty_RECURRENCE_ID = "RECURRENCE-ID"
-cICalProperty_RELATED_TO = "RELATED-TO"
-cICalProperty_URL = "URL"
-cICalProperty_UID = "UID"
-
-# 5545 Section 3.8.5
-cICalProperty_EXDATE = "EXDATE"
-cICalProperty_EXRULE = "EXRULE" # 2445 only
-cICalProperty_RDATE = "RDATE"
-cICalProperty_RRULE = "RRULE"
-
-# 5545 Section 3.8.6
-cICalProperty_ACTION = "ACTION"
-cICalProperty_REPEAT = "REPEAT"
-cICalProperty_TRIGGER = "TRIGGER"
-
-# 5545 Section 3.8.7
-cICalProperty_CREATED = "CREATED"
-cICalProperty_DTSTAMP = "DTSTAMP"
-cICalProperty_LAST_MODIFIED = "LAST-MODIFIED"
-cICalProperty_SEQUENCE = "SEQUENCE"
-
-# 5545 Section 3.8.8.3
-cICalProperty_REQUEST_STATUS = "REQUEST-STATUS"
-
-# Enums
-# Use ascending order for sensible sorting
-
-# 5545 Section 3.3.10
-
-eRecurrence_SECONDLY = 0
-eRecurrence_MINUTELY = 1
-eRecurrence_HOURLY = 2
-eRecurrence_DAILY = 3
-eRecurrence_WEEKLY = 4
-eRecurrence_MONTHLY = 5
-eRecurrence_YEARLY = 6
-
-eRecurrence_FREQ = 0
-eRecurrence_UNTIL = 1
-eRecurrence_COUNT = 2
-eRecurrence_INTERVAL = 3
-eRecurrence_BYSECOND = 4
-eRecurrence_BYMINUTE = 5
-eRecurrence_BYHOUR = 6
-eRecurrence_BYDAY = 7
-eRecurrence_BYMONTHDAY = 8
-eRecurrence_BYYEARDAY = 9
-eRecurrence_BYWEEKNO = 10
-eRecurrence_BYMONTH = 11
-eRecurrence_BYSETPOS = 12
-eRecurrence_WKST = 13
-
-cICalValue_RECUR_FREQ = "FREQ"
-cICalValue_RECUR_FREQ_LEN = 5
-
-cICalValue_RECUR_SECONDLY = "SECONDLY"
-cICalValue_RECUR_MINUTELY = "MINUTELY"
-cICalValue_RECUR_HOURLY = "HOURLY"
-cICalValue_RECUR_DAILY = "DAILY"
-cICalValue_RECUR_WEEKLY = "WEEKLY"
-cICalValue_RECUR_MONTHLY = "MONTHLY"
-cICalValue_RECUR_YEARLY = "YEARLY"
-
-cICalValue_RECUR_UNTIL = "UNTIL"
-cICalValue_RECUR_COUNT = "COUNT"
-
-cICalValue_RECUR_INTERVAL = "INTERVAL"
-cICalValue_RECUR_BYSECOND = "BYSECOND"
-cICalValue_RECUR_BYMINUTE = "BYMINUTE"
-cICalValue_RECUR_BYHOUR = "BYHOUR"
-cICalValue_RECUR_BYDAY = "BYDAY"
-cICalValue_RECUR_BYMONTHDAY = "BYMONTHDAY"
-cICalValue_RECUR_BYYEARDAY = "BYYEARDAY"
-cICalValue_RECUR_BYWEEKNO = "BYWEEKNO"
-cICalValue_RECUR_BYMONTH = "BYMONTH"
-cICalValue_RECUR_BYSETPOS = "BYSETPOS"
-cICalValue_RECUR_WKST = "WKST"
-
-eRecurrence_WEEKDAY_SU = 0
-eRecurrence_WEEKDAY_MO = 1
-eRecurrence_WEEKDAY_TU = 2
-eRecurrence_WEEKDAY_WE = 3
-eRecurrence_WEEKDAY_TH = 4
-eRecurrence_WEEKDAY_FR = 5
-eRecurrence_WEEKDAY_SA = 6
-
-cICalValue_RECUR_WEEKDAY_SU = "SU"
-cICalValue_RECUR_WEEKDAY_MO = "MO"
-cICalValue_RECUR_WEEKDAY_TU = "TU"
-cICalValue_RECUR_WEEKDAY_WE = "WE"
-cICalValue_RECUR_WEEKDAY_TH = "TH"
-cICalValue_RECUR_WEEKDAY_FR = "FR"
-cICalValue_RECUR_WEEKDAY_SA = "SA"
-
-# 5545 Section 3.8.1.11
-eStatus_VEvent_None = 0
-eStatus_VEvent_Confirmed = 1
-eStatus_VEvent_Tentative = 2
-eStatus_VEvent_Cancelled = 3
-
-eStatus_VToDo_None = 0
-eStatus_VToDo_NeedsAction = 1
-eStatus_VToDo_InProcess = 2
-eStatus_VToDo_Completed = 3
-eStatus_VToDo_Cancelled = 4
-
-eStatus_VJournal_None = 0
-eStatus_VJournal_Final = 1
-eStatus_VJournal_Draft = 2
-eStatus_VJournal_Cancelled = 3
-
-cICalProperty_STATUS_TENTATIVE = "TENTATIVE"
-cICalProperty_STATUS_CONFIRMED = "CONFIRMED"
-cICalProperty_STATUS_CANCELLED = "CANCELLED"
-cICalProperty_STATUS_NEEDS_ACTION = "NEEDS-ACTION"
-cICalProperty_STATUS_COMPLETED = "COMPLETED"
-cICalProperty_STATUS_IN_PROCESS = "IN-PROCESS"
-cICalProperty_STATUS_DRAFT = "DRAFT"
-cICalProperty_STATUS_FINAL = "FINAL"
-
-# 5545 Section 3.8.6.1
-eAction_VAlarm_Audio = 0
-eAction_VAlarm_Display = 1
-eAction_VAlarm_Email = 2
-eAction_VAlarm_Procedure = 3
-eAction_VAlarm_Unknown = 4
-
-cICalProperty_ACTION_AUDIO = "AUDIO"
-cICalProperty_ACTION_DISPLAY = "DISPLAY"
-cICalProperty_ACTION_EMAIL = "EMAIL"
-cICalProperty_ACTION_PROCEDURE = "PROCEDURE"
-
-# Extensions: draft-daboo-calendar-availability-02
-
-# Section 3.1
-cICalComponent_VAVAILABILITY = "VAVAILABILITY"
-cICalComponent_AVAILABLE = "AVAILABLE"
-
-# Section 3.2
-cICalProperty_BUSYTYPE = "BUSYTYPE"
-
-# Extensions: draft-daboo-valarm-extensions-03
-
-# Section 5
-eAction_VAlarm_URI = 5
-cICalProperty_ACTION_URI = "URI"
-
-# Section 7.1
-cICalProperty_ACKNOWLEDGED = "ACKNOWLEDGED"
-
-eAction_VAlarm_None = 6
-cICalProperty_ACTION_NONE = "NONE"
-
-# Mulberry extensions
-cICalProperty_ACTION_X_SPEAKTEXT = "X-MULBERRY-SPEAK-TEXT"
-cICalProperty_ALARM_X_LASTTRIGGER = "X-MULBERRY-LAST-TRIGGER"
-
-cICalProperty_ALARM_X_ALARMSTATUS = "X-MULBERRY-ALARM-STATUS"
-
-eAlarm_Status_Pending = 0
-eAlarm_Status_Completed = 1
-eAlarm_Status_Disabled = 2
-
-cICalProperty_ALARM_X_ALARMSTATUS_PENDING = "PENDING"
-cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED = "COMPLETED"
-cICalProperty_ALARM_X_ALARMSTATUS_DISABLED = "DISABLED"
-
-cICalAttribute_ORGANIZER_X_IDENTITY = "X-MULBERRY-IDENTITY"
-cICalAttribute_ATTENDEE_X_NEEDS_ITIP = "X-MULBERRY-NEEDS-ITIP"
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendardurationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/duration.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/duration.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/duration.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> from pycalendar.stringutils import strtoul
</span><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx">
</span><del>-class PyCalendarDuration(ValueMixin):
</del><ins>+class Duration(ValueMixin):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, duration=None, weeks=0, days=0, hours=0, minutes=0, seconds=0):
</span><span class="cx"> self.mForward = True
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- other = PyCalendarDuration(None)
</del><ins>+ other = Duration(None)
</ins><span class="cx"> other.mForward = self.mForward
</span><span class="cx">
</span><span class="cx"> other.mWeeks = self.mWeeks
</span><span class="lines">@@ -270,3 +270,11 @@
</span><span class="cx">
</span><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx"> node.text = self.getText()
</span><ins>+
+
+ def parseJSON(self, jobject):
+ self.parse(str(jobject))
+
+
+ def writeJSON(self, jobject):
+ jobject.append(self.getText())
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendardurationvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/durationvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/durationvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/durationvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,42 +14,14 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.duration import Duration
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
</ins><span class="cx">
</span><del>-class PyCalendarDurationValue(PyCalendarValue):
</del><ins>+class DurationValue(WrapperValue, Value):
</ins><span class="cx">
</span><del>- def __init__(self, value=None):
- self.mValue = value if value is not None else PyCalendarDuration()
</del><ins>+ _wrappedClass = Duration
+ _wrappedType = Value.VALUETYPE_DURATION
</ins><span class="cx">
</span><del>-
- def duplicate(self):
- return PyCalendarDurationValue(self.mValue.duplicate())
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_DURATION
-
-
- def parse(self, data):
- self.mValue.parse(data)
-
-
- def generate(self, os):
- self.mValue.generate(os)
-
-
- def writeXML(self, node, namespace):
- value = self.getXMLNode(node, namespace)
- value.text = self.mValue.writeXML()
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_DURATION, PyCalendarDurationValue, xmldefs.value_duration)
</del><ins>+Value.registerType(Value.VALUETYPE_DURATION, DurationValue, xmldefinitions.value_duration)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarexceptionspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/exceptions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/exceptions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/exceptions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-class PyCalendarError(Exception):
</del><ins>+class ErrorBase(Exception):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, reason, data=""):
</span><span class="cx"> self.mReason = reason
</span><span class="lines">@@ -22,23 +22,28 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-class PyCalendarInvalidData(PyCalendarError):
</del><ins>+class InvalidData(ErrorBase):
</ins><span class="cx"> pass
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-class PyCalendarInvalidProperty(PyCalendarError):
</del><ins>+class InvalidComponent(ErrorBase):
</ins><span class="cx"> pass
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-class PyCalendarValidationError(PyCalendarError):
</del><ins>+class InvalidProperty(ErrorBase):
</ins><span class="cx"> pass
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-class PyCalendarNoTimezoneInDatabase(Exception):
</del><ins>+class ValidationError(ErrorBase):
+ pass
</ins><span class="cx">
</span><ins>+
+
+class NoTimezoneInDatabase(Exception):
+
</ins><span class="cx"> def __init__(self, dbpath, tzid):
</span><span class="cx"> self.mTZDBpath = dbpath
</span><span class="cx"> self.mTZID = tzid
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarfloatvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarfloatvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/floatvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/floatvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/floatvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/floatvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# iCalendar float value
+
+from pycalendar import xmldefinitions
+from pycalendar.value import Value
+
+class FloatValue(Value):
+
+ def __init__(self, value=None):
+ self.mValue = value if value is not None else 0.0
+
+
+ def duplicate(self):
+ return FloatValue(self.mValue)
+
+
+ def getType(self):
+ return Value.VALUETYPE_FLOAT
+
+
+ def parse(self, data, variant):
+ self.mValue = float(data)
+
+
+ # os - StringIO object
+ def generate(self, os):
+ try:
+ os.write(str(self.mValue))
+ except:
+ pass
+
+
+ def writeXML(self, node, namespace):
+ value = self.getXMLNode(node, namespace)
+ value.text = str(self.mValue)
+
+
+ def parseJSONValue(self, jobject):
+ self.mValue = float(jobject)
+
+
+ def writeJSONValue(self, jobject):
+ jobject.append(self.mValue)
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
+
+Value.registerType(Value.VALUETYPE_FLOAT, FloatValue, xmldefinitions.value_float)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarfreebusypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/freebusy.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/freebusy.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/freebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,56 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-class PyCalendarFreeBusy(object):
-
- FREE = 0
- BUSYTENTATIVE = 1
- BUSYUNAVAILABLE = 2
- BUSY = 3
-
- def __init__(self, type=None, period=None):
-
- self.mType = type if type else PyCalendarFreeBusy.FREE
- self.mPeriod = period.duplicate() if period is not None else None
-
-
- def duplicate(self):
- return PyCalendarFreeBusy(self.mType, self.mPeriod)
-
-
- def setType(self, type):
- self.mType = type
-
-
- def getType(self):
- return self.mType
-
-
- def setPeriod(self, period):
- self.mPeriod = period.duplicate()
-
-
- def getPeriod(self):
- return self.mPeriod
-
-
- def isPeriodOverlap(self, period):
- return self.mPeriod.isPeriodOverlap(period)
-
-
- def resolveOverlaps(self, fb):
- # TODO:
- pass
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendargeovaluepyfromrev11912PyCalendarbranchesjson2srcpycalendargeovaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/geovalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/geovalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/geovalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/geovalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,88 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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.
+##
+
+# iCalendar REQUEST-STATUS value
+
+from pycalendar import xmlutils
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar import xmldefinitions
+from pycalendar.value import Value
+from pycalendar import xmldefinitions as xmldefinitions_top
+import xml.etree.cElementTree as XML
+
+class GeoValue(Value):
+ """
+ The value is a list of 2 floats
+ """
+
+ def __init__(self, value=None):
+ self.mValue = value if value is not None else [0.0, 0.0]
+
+
+ def __hash__(self):
+ return hash(tuple(self.mValue))
+
+
+ def duplicate(self):
+ return GeoValue(self.mValue[:])
+
+
+ def getType(self):
+ return Value.VALUETYPE_GEO
+
+
+ def parse(self, data, variant="icalendar"):
+
+ splits = data.split(";")
+ if len(splits) != 2:
+ raise InvalidData("GEO value incorrect", data)
+ try:
+ self.mValue = [float(splits[0]), float(splits[1])]
+ except ValueError:
+ raise InvalidData("GEO value incorrect", data)
+
+
+ # os - StringIO object
+ def generate(self, os):
+ os.write("%s;%s" % (self.mValue[0], self.mValue[1],))
+
+
+ def writeXML(self, node, namespace):
+ value = self.getXMLNode(node, namespace)
+
+ latitude = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.geo_latitude))
+ latitude.text = self.mValue[0]
+
+ longitude = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.geo_longitude))
+ longitude.text = self.mValue[1]
+
+
+ def parseJSONValue(self, jobject):
+ self.mValue = jobject
+
+
+ def writeJSONValue(self, jobject):
+ jobject.append(list(self.mValue))
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
+
+Value.registerType(Value.VALUETYPE_GEO, GeoValue, xmldefinitions.geo, xmldefinitions_top.value_float)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendar__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendaravailablepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendaravailablepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/available.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/available.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/available.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/available.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class Available(ComponentRecur):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_UID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_CREATED,
+ definitions.cICalProperty_DESCRIPTION,
+ definitions.cICalProperty_GEO,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_LOCATION,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_RRULE,
+ definitions.cICalProperty_SEQUENCE,
+ definitions.cICalProperty_SUMMARY,
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+ super(Available, self).__init__(parent=parent)
+
+
+ def duplicate(self, parent=None):
+ return super(Available, self).duplicate(parent=parent)
+
+
+ def getType(self):
+ return definitions.cICalComponent_AVAILABLE
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems, else raise. If
+ loggedProblems is not None it must be a C{list} and problem descriptions are appended
+ to that.
+ """
+
+ fixed, unfixed = super(Available, self).validate(doFix)
+
+ # Extra constraint: only one of DTEND or DURATION
+ if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
+ # Fix by removing the DTEND
+ logProblem = "[%s] Properties must not both be present: %s, %s" % (
+ self.getType(),
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ )
+ if doFix:
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ fixed.append(logProblem)
+ else:
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_DTEND,
+ )
+Component.registerComponent(definitions.cICalComponent_AVAILABLE, Available)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcalendarpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcalendarpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/calendar.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/calendar.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/calendar.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,607 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 cStringIO import StringIO
+from pycalendar import xmlutils
+from pycalendar.containerbase import ContainerBase
+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar import definitions, xmldefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentexpanded import ComponentExpanded
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.freebusy import FreeBusy
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.parser import ParserContext
+from pycalendar.period import Period
+from pycalendar.utils import readFoldedLine
+import collections
+import json
+import xml.etree.cElementTree as XML
+
+class Calendar(ContainerBase):
+
+ REMOVE_ALL = 0
+ REMOVE_ONLY_THIS = 1
+ REMOVE_THIS_AND_FUTURE = 2
+
+ FIND_EXACT = 0
+ FIND_MASTER = 1
+
+ sContainerDescriptor = "iCalendar"
+ sComponentType = Component
+ sPropertyType = Property
+
+ sFormatText = "text/calendar"
+ sFormatJSON = "application/calendar+json"
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_PRODID,
+ definitions.cICalProperty_VERSION,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_CALSCALE,
+ definitions.cICalProperty_METHOD,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None, add_defaults=True):
+ super(Calendar, self).__init__(add_defaults=add_defaults)
+
+ self.mName = ""
+ self.mDescription = ""
+ self.mMasterComponentsByTypeAndUID = collections.defaultdict(lambda: collections.defaultdict(list))
+ self.mOverriddenComponentsByUID = collections.defaultdict(list)
+
+
+ def duplicate(self):
+ other = super(Calendar, self).duplicate()
+ other.mName = self.mName
+ other.mDescription = self.mDescription
+ return other
+
+
+ def getType(self):
+ return definitions.cICalComponent_VCALENDAR
+
+
+ def getName(self):
+ return self.mName
+
+
+ def setName(self, name):
+ self.mName = name
+
+
+ def editName(self, name):
+ if self.mName != name:
+ # Updated cached value
+ self.mName = name
+
+ # Remove existing items
+ self.removeProperties(definitions.cICalProperty_XWRCALNAME)
+
+ # Now create properties
+ if len(name):
+ self.ddProperty(Property(definitions.cICalProperty_XWRCALNAME, name))
+
+
+ def getDescription(self):
+ return self.mDescription
+
+
+ def setDescription(self, description):
+ self.mDescription = description
+
+
+ def editDescription(self, description):
+ if self.mDescription != description:
+ # Updated cached value
+ self.mDescription = description
+
+ # Remove existing items
+ self.removeProperties(definitions.cICalProperty_XWRCALDESC)
+
+ # Now create properties
+ if len(description):
+ self.addProperty(Property(definitions.cICalProperty_XWRCALDESC, description))
+
+
+ def getMethod(self):
+ result = ""
+ if self.hasProperty(definitions.cICalProperty_METHOD):
+ result = self.loadValueString(definitions.cICalProperty_METHOD)
+ return result
+
+
+ def changeUID(self, oldUID, newUID):
+ """
+ Change the UID of all components with a matching UID to a new value. We need to
+ do this at the calendar level because this object maintains mappings based on UID
+ which need to be updated whenever the UID changes.
+
+ @param oldUID: the old value to match
+ @type oldUID: C{str}
+ @param newUID: the new value to match
+ @type newUID: C{str}
+ """
+
+ # Each component
+ for component in self.mComponents:
+ if component.getUID() == oldUID:
+ component.setUID(newUID)
+
+ # Maps
+ if oldUID in self.mOverriddenComponentsByUID:
+ self.mOverriddenComponentsByUID[newUID] = self.mOverriddenComponentsByUID[oldUID]
+ del self.mOverriddenComponentsByUID[oldUID]
+ for ctype in self.mMasterComponentsByTypeAndUID:
+ if oldUID in self.mMasterComponentsByTypeAndUID[ctype]:
+ self.mMasterComponentsByTypeAndUID[ctype][newUID] = self.mMasterComponentsByTypeAndUID[ctype][oldUID]
+ del self.mMasterComponentsByTypeAndUID[ctype][oldUID]
+
+
+ def finalise(self):
+ # Get calendar name if present
+
+ # Get X-WR-CALNAME
+ temps = self.loadValueString(definitions.cICalProperty_XWRCALNAME)
+ if temps is not None:
+ self.mName = temps
+
+ # Get X-WR-CALDESC
+ temps = self.loadValueString(definitions.cICalProperty_XWRCALDESC)
+ if temps is not None:
+ self.mDescription = temps
+
+
+ def sortedComponentNames(self):
+ return (
+ definitions.cICalComponent_VTIMEZONE,
+ definitions.cICalComponent_VEVENT,
+ definitions.cICalComponent_VTODO,
+ definitions.cICalComponent_VJOURNAL,
+ definitions.cICalComponent_VFREEBUSY,
+ definitions.cICalComponent_VAVAILABILITY,
+ )
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_VERSION,
+ definitions.cICalProperty_CALSCALE,
+ definitions.cICalProperty_METHOD,
+ definitions.cICalProperty_PRODID,
+ )
+
+
+ def parse(self, ins):
+
+ result = super(Calendar, self).parse(ins)
+
+ # We need to store all timezones in the static object so they can be accessed by any date object
+ from pycalendar.timezonedb import TimezoneDatabase
+ TimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
+
+ return result
+
+
+ def parseComponent(self, ins):
+
+ result = None
+
+ LOOK_FOR_VCALENDAR = 0
+ GET_PROPERTY_OR_COMPONENT = 1
+ GOT_VCALENDAR = 4
+
+ state = LOOK_FOR_VCALENDAR
+
+ # Get lines looking for start of calendar
+ lines = [None, None]
+ comp = self
+ compend = None
+ componentstack = []
+ got_timezone = False
+
+ while readFoldedLine(ins, lines):
+
+ line = lines[0]
+
+ if state == LOOK_FOR_VCALENDAR:
+
+ # Look for start
+ if line == self.getBeginDelimiter():
+ # Next state
+ state = GET_PROPERTY_OR_COMPONENT
+
+ # Handle blank line
+ elif len(line) == 0:
+ # Raise if requested, otherwise just ignore
+ if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+ raise InvalidData("iCalendar data has blank lines")
+
+ # Unrecognized data
+ else:
+ raise InvalidData("iCalendar data not recognized", line)
+
+ elif state == GET_PROPERTY_OR_COMPONENT:
+
+ # Parse property or look for start of component
+ if line.startswith("BEGIN:"):
+
+ # Push previous details to stack
+ componentstack.append((comp, compend,))
+
+ # Start a new component
+ comp = self.sComponentType.makeComponent(line[6:], comp)
+ compend = comp.getEndDelimiter()
+
+ # Cache as result - but only the first one, we ignore the rest
+ if result is None:
+ result = comp
+
+ # Look for timezone component to trigger timezone merge only if one is present
+ if comp.getType() == definitions.cICalComponent_VTIMEZONE:
+ got_timezone = True
+
+ elif line == self.getEndDelimiter():
+
+ # Change state
+ state = GOT_VCALENDAR
+
+ # Look for end of current component
+ elif line == compend:
+
+ # Finalise the component (this caches data from the properties)
+ comp.finalise()
+
+ # Embed component in parent and reset to use parent
+ componentstack[-1][0].addComponent(comp)
+ comp, compend = componentstack.pop()
+
+ # Blank line
+ elif len(line) == 0:
+ # Raise if requested, otherwise just ignore
+ if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+ raise InvalidData("iCalendar data has blank lines")
+
+ # Ignore top-level items
+ elif comp is self:
+ pass
+
+ # Must be a property
+ else:
+
+ # Parse parameter/value for top-level calendar item
+ prop = self.sPropertyType.parseText(line)
+
+ # Check for valid property
+ if comp is not self:
+ comp.addProperty(prop)
+
+ # Exit if we have one - ignore all the rest
+ if state == GOT_VCALENDAR:
+ break
+
+ # We need to store all timezones in the static object so they can be accessed by any date object
+ # Only do this if we read in a timezone
+ if got_timezone:
+ from pycalendar.timezonedb import TimezoneDatabase
+ TimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
+
+ return result
+
+
+ def addComponent(self, component):
+ """
+ Override to track components by UID.
+ """
+ super(Calendar, self).addComponent(component)
+
+ if isinstance(component, ComponentRecur):
+ uid = component.getUID()
+ rid = component.getRecurrenceID()
+ if rid:
+ self.mOverriddenComponentsByUID[uid].append(component)
+ else:
+ self.mMasterComponentsByTypeAndUID[component.getType()][uid] = component
+
+
+ def removeComponent(self, component):
+ """
+ Override to track components by UID.
+ """
+ super(Calendar, self).removeComponent(component)
+
+ if isinstance(component, ComponentRecur):
+ uid = component.getUID()
+ rid = component.getRecurrenceID()
+ if rid:
+ self.mOverriddenComponentsByUID[uid].remove(component)
+ else:
+ del self.mMasterComponentsByTypeAndUID[component.getType()][uid]
+
+
+ def getText(self, includeTimezones=False, format=None):
+
+ if format is None or format == self.sFormatText:
+ s = StringIO()
+ self.generate(s, includeTimezones=includeTimezones)
+ return s.getvalue()
+ elif format == self.sFormatJSON:
+ return self.getTextJSON(includeTimezones)
+
+
+ def generate(self, os, includeTimezones=False):
+ # Make sure all required timezones are in this object
+ if includeTimezones:
+ self.includeTimezones()
+ super(Calendar, self).generate(os)
+
+
+ def getTextXML(self, includeTimezones=False):
+ node = self.writeXML(includeTimezones)
+ return xmlutils.toString(node)
+
+
+ def writeXML(self, includeTimezones=False):
+ # Make sure all required timezones are in this object
+ if includeTimezones:
+ self.includeTimezones()
+
+ # Root node structure
+ root = XML.Element(xmlutils.makeTag(xmldefinitions.iCalendar20_namespace, xmldefinitions.icalendar))
+ super(Calendar, self).writeXML(root, xmldefinitions.iCalendar20_namespace)
+ return root
+
+
+ def getTextJSON(self, includeTimezones=False):
+ jobject = []
+ self.writeJSON(jobject, includeTimezones)
+ return json.dumps(jobject[0], indent=2, separators=(',', ':'))
+
+
+ def writeJSON(self, jobject, includeTimezones=False):
+ # Make sure all required timezones are in this object
+ if includeTimezones:
+ self.includeTimezones()
+
+ # Root node structure
+ super(Calendar, self).writeJSON(jobject)
+
+
+ # Get expanded components
+ def getVEvents(self, period, list, all_day_at_top=True):
+ # Look at each VEvent
+ for vevent in self.getComponents(definitions.cICalComponent_VEVENT):
+ vevent.expandPeriod(period, list)
+
+ if (all_day_at_top):
+ list.sort(ComponentExpanded.sort_by_dtstart_allday)
+ else:
+ list.sort(ComponentExpanded.sort_by_dtstart)
+
+
+ def getVToDos(self, only_due, all_dates, upto_due_date, list):
+ # Get current date-time less one day to test for completed events during the last day
+ minusoneday = DateTime()
+ minusoneday.setNowUTC()
+ minusoneday.offsetDay(-1)
+
+ today = DateTime()
+ today.setToday()
+
+ # Look at each VToDo
+ for vtodo in self.getComponents(definitions.cICalComponent_VTODO):
+
+ # Filter out done (that were complted more than a day ago) or cancelled to dos if required
+ if only_due:
+ if vtodo.getStatus() == definitions.eStatus_VToDo_Cancelled:
+ continue
+ elif ((vtodo.getStatus() == definitions.eStatus_VToDo_Completed) and
+ (not vtodo.hasCompleted() or (vtodo.getCompleted() < minusoneday))):
+ continue
+
+ # Filter out those with end after chosen date if required
+ if not all_dates:
+ if vtodo.hasEnd() and (vtodo.getEnd() > upto_due_date):
+ continue
+ elif not vtodo.hasEnd() and (today > upto_due_date):
+ continue
+
+ # TODO: fix this
+ #list.append(ComponentExpandedShared(ComponentExpanded(vtodo, None)))
+
+
+ def getRecurrenceInstancesItems(self, type, uid, items):
+ # Get instances from list
+ items.extend(self.mOverriddenComponentsByUID.get(uid, ()))
+
+
+ def getRecurrenceInstancesIds(self, type, uid, ids):
+ # Get instances from list
+ ids.extend([comp.getRecurrenceID() for comp in self.mOverriddenComponentsByUID.get(uid, ())])
+
+
+ # Freebusy generation
+ def getVFreeBusyList(self, period, list):
+ # Look at each VFreeBusy
+ for vfreebusy in self.getComponents(definitions.cICalComponent_VFREEBUSY):
+ vfreebusy.expandPeriod(period, list)
+
+
+ def getVFreeBusyFB(self, period, fb):
+ # First create expanded set
+ # TODO: fix this
+ #list = ExpandedComponents()
+ self.getVEvents(period, list)
+ if len(list) == 0:
+ return
+
+ # Get start/end list for each non-all-day expanded components
+ dtstart = []
+ dtend = []
+ for dt in list:
+
+ # Ignore if all-day
+ if dt.getInstanceStart().isDateOnly():
+ continue
+
+ # Ignore if transparent to free-busy
+ transp = ""
+ if dt.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
+ continue
+
+ # Add start/end to list
+ dtstart.append(dt.getInstanceStart())
+ dtend.append(dt.getInstanceEnd())
+
+ # No longer need the expanded items
+ list.clear()
+
+ # Create non-overlapping periods as properties in the freebusy component
+ temp = Period(dtstart.front(), dtend.front())
+ dtstart_iter = dtstart.iter()
+ dtstart_iter.next()
+ dtend_iter = dtend.iter()
+ dtend_iter.next()
+ for i in i:
+
+ # Check for non-overlap
+ if dtstart_iter > temp.getEnd():
+
+ # Current period is complete
+ fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp))
+
+ # Reset period to new range
+ temp = Period(dtstart_iter, dtend_iter)
+
+ # They overlap - check for extended end
+ if dtend_iter > temp.getEnd():
+
+ # Extend the end
+ temp = Period(temp.getStart(), dtend_iter)
+
+ # Add remaining period as property
+ fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp))
+
+
+ def getFreeBusy(self, period, fb):
+ # First create expanded set
+
+ list = []
+ self.getVEvents(period, list)
+
+ # Get start/end list for each non-all-day expanded components
+ for comp in list:
+
+ # Ignore if all-day
+ if comp.getInstanceStart().isDateOnly():
+ continue
+
+ # Ignore if transparent to free-busy
+ transp = ""
+ if comp.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
+ continue
+
+ # Add free busy item to list
+ status = comp.getMaster().getStatus()
+ if status in (definitions.eStatus_VEvent_None, definitions.eStatus_VEvent_Confirmed):
+ fb.append(FreeBusy(FreeBusy.BUSY, Period(comp.getInstanceStart(), comp.getInstanceEnd())))
+ elif status == definitions.eStatus_VEvent_Tentative:
+ fb.append(FreeBusy(FreeBusy.BUSYTENTATIVE, Period(comp.getInstanceStart(), comp.getInstanceEnd())))
+ break
+ elif status == definitions.eStatus_VEvent_Cancelled:
+ # Cancelled => does not contribute to busy time
+ pass
+
+ # Now get the VFREEBUSY info
+ list2 = []
+ self.getVFreeBusy(period, list2)
+
+ # Get start/end list for each free-busy
+ for comp in list2:
+
+ # Expand component and add free busy info to list
+ comp.expandPeriod(period, fb)
+
+ # Add remaining period as property
+ FreeBusy.resolveOverlaps(fb)
+
+
+ def getTimezoneOffsetSeconds(self, tzid, dt):
+ # Find timezone that matches the name (which is the same as the map key)
+ timezone = self.getTimezone(tzid)
+ return timezone.getTimezoneOffsetSeconds(dt) if timezone else 0
+
+
+ def getTimezoneDescriptor(self, tzid, dt):
+ # Find timezone that matches the name (which is the same as the map key)
+ timezone = self.getTimezone(tzid)
+ return timezone.getTimezoneDescriptor(dt) if timezone else ""
+
+
+ def getTimezone(self, tzid):
+ # Find timezone that matches the name (which is the same as the map key)
+ for timezone in self.getComponents(definitions.cICalComponent_VTIMEZONE):
+ if timezone.getID() == tzid:
+ return timezone
+ else:
+ return None
+
+
+ def addDefaultProperties(self):
+ self.addProperty(Property(definitions.cICalProperty_PRODID, Calendar.sProdID))
+ self.addProperty(Property(definitions.cICalProperty_VERSION, "2.0"))
+ self.addProperty(Property(definitions.cICalProperty_CALSCALE, "GREGORIAN"))
+
+
+ def validProperty(self, prop):
+ if prop.getName() == definitions.cICalProperty_VERSION:
+
+ tvalue = prop.getTextValue()
+ if ((tvalue is None) or (tvalue.getValue() != "2.0")):
+ return False
+
+ elif prop.getName() == definitions.cICalProperty_CALSCALE:
+
+ tvalue = prop.getTextValue()
+ if ((tvalue is None) or (tvalue.getValue() != "GREGORIAN")):
+ return False
+
+ return True
+
+
+ def includeTimezones(self):
+ # Get timezone names from each component
+ tzids = set()
+ for component in self.mComponents:
+ if component.getType() != definitions.cICalComponent_VTIMEZONE:
+ component.getTimezones(tzids)
+
+ # Make sure each timezone is in current calendar
+ from pycalendar.timezonedb import TimezoneDatabase
+ for tzid in tzids:
+ tz = self.getTimezone(tzid)
+ if tz is None:
+ # Find it in the static object
+ tz = TimezoneDatabase.getTimezone(tzid)
+ if tz is not None:
+ dup = tz.duplicate()
+ self.addComponent(dup)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcomponentpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcomponentpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/component.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/component.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/component.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/component.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,212 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar import stringutils
+from pycalendar.componentbase import ComponentBase
+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.property import Property
+import os
+import time
+import uuid
+
+class Component(ComponentBase):
+
+ uid_ctr = 1
+
+ mapper = {}
+
+ sComponentType = None
+ sPropertyType = Property
+
+ @classmethod
+ def registerComponent(cls, name, comptype):
+ cls.mapper[name] = comptype
+
+
+ @classmethod
+ def makeComponent(cls, compname, parent):
+ try:
+ return cls.mapper[compname](parent=parent)
+ except KeyError:
+ return cls.mapper[definitions.cICalComponent_UNKNOWN](parent=parent, comptype=compname)
+
+
+ def __init__(self, parent=None):
+
+ super(Component, self).__init__(parent)
+ self.mUID = ""
+ self.mSeq = 0
+ self.mOriginalSeq = 0
+ self.mChanged = False
+
+
+ def duplicate(self, parent=None, **args):
+
+ other = super(Component, self).duplicate(parent=parent, **args)
+ other.mUID = self.mUID
+ other.mSeq = self.mSeq
+ other.mOriginalSeq = self.mOriginalSeq
+
+ other.mChanged = self.mChanged
+
+ return other
+
+
+ def __repr__(self):
+ return "%s: UID: %s" % (self.getType(), self.getMapKey(),)
+
+
+ def getMimeComponentName(self):
+ raise NotImplementedError
+
+
+ def getMapKey(self):
+ if hasattr(self, "mMapKey"):
+ return self.mMapKey
+ elif self.mUID:
+ return self.mUID
+ else:
+ self.mMapKey = str(uuid.uuid4())
+ return self.mMapKey
+
+
+ def getSortKey(self):
+ return self.getMapKey()
+
+
+ def getMasterKey(self):
+ return self.mUID
+
+
+ def getUID(self):
+ return self.mUID
+
+
+ def setUID(self, uid):
+ if uid:
+ self.mUID = uid
+ else:
+ # Get left-side of UID (first 24 chars of MD5 digest of time, pid
+ # and ctr)
+ lhs_txt = ""
+ lhs_txt += str(time.time())
+ lhs_txt += "."
+ lhs_txt += str(os.getpid())
+ lhs_txt += "."
+ lhs_txt += str(Component.uid_ctr)
+ Component.uid_ctr += 1
+ lhs = stringutils.md5digest(lhs_txt)
+
+ # Get right side (domain) of message-id
+ rhs = None
+
+ # Use app name
+ from pycalendar.icalendar.calendar import Calendar
+ domain = Calendar.sDomain
+ domain += str(Component.uid_ctr)
+
+ # Use first 24 chars of MD5 digest of the domain as the
+ # right-side of message-id
+ rhs = stringutils.md5digest(domain)
+
+ # Generate the UID string
+ new_uid = lhs
+ new_uid += "@"
+ new_uid += rhs
+
+ self.mUID = new_uid
+
+ self.removeProperties(definitions.cICalProperty_UID)
+
+ prop = Property(definitions.cICalProperty_UID, self.mUID)
+ self.addProperty(prop)
+
+
+ def getSeq(self):
+ return self.mSeq
+
+
+ def setSeq(self, seq):
+ self.mSeq = seq
+
+ self.removeProperties(definitions.cICalProperty_SEQUENCE)
+
+ prop = Property(definitions.cICalProperty_SEQUENCE, self.mSeq)
+ self.addProperty(prop)
+
+
+ def getOriginalSeq(self):
+ return self.mOriginalSeq
+
+
+ def getChanged(self):
+ return self.mChanged
+
+
+ def setChanged(self, changed):
+ self.mChanged = changed
+
+
+ def initDTSTAMP(self):
+ self.removeProperties(definitions.cICalProperty_DTSTAMP)
+
+ prop = Property(definitions.cICalProperty_DTSTAMP,
+ DateTime.getNowUTC())
+ self.addProperty(prop)
+
+
+ def updateLastModified(self):
+ self.removeProperties(definitions.cICalProperty_LAST_MODIFIED)
+
+ prop = Property(definitions.cICalProperty_LAST_MODIFIED,
+ DateTime.getNowUTC())
+ self.addProperty(prop)
+
+
+ def finalise(self):
+ # Get UID
+ temps = self.loadValueString(definitions.cICalProperty_UID)
+ if temps is not None:
+ self.mUID = temps
+
+ # Get SEQ
+ temp = self.loadValueInteger(definitions.cICalProperty_SEQUENCE)
+ if temp is not None:
+ self.mSeq = temp
+
+ # Cache the original sequence when the component is read in.
+ # This will be used to synchronise changes between two instances of the
+ # same calendar
+ self.mOriginalSeq = self.mSeq
+
+
+ def canGenerateInstance(self):
+ return True
+
+
+ def getTimezones(self, tzids):
+ # Look for all date-time properties
+ for props in self.mProperties.itervalues():
+ for prop in props:
+ # Try to get a date-time value from the property
+ dtv = prop.getDateTimeValue()
+ if dtv is not None:
+ # Add timezone id if appropriate
+ if dtv.getValue().getTimezoneID():
+ tzids.add(dtv.getValue().getTimezoneID())
+
+Component.sComponentType = Component
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcomponentexpandedpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcomponentexpandedpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/componentexpanded.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,158 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+
+class ComponentExpanded(object):
+
+ @staticmethod
+ def sort_by_dtstart_allday(e1, e2):
+
+ if e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly():
+ return e1.mInstanceStart < e2.mInstanceStart
+ elif e1.mInstanceStart.isDateOnly():
+ return True
+ elif e2.mInstanceStart.isDateOnly():
+ return False
+ elif e1.mInstanceStart == e2.mInstanceStart:
+ if e1.mInstanceEnd == e2.mInstanceEnd:
+ # Put ones created earlier in earlier columns in day view
+ return e1.getOwner().getStamp() < e2.getOwner().getStamp()
+ else:
+ # Put ones that end later in earlier columns in day view
+ return e1.mInstanceEnd > e2.mInstanceEnd
+ else:
+ return e1.mInstanceStart < e2.mInstanceStart
+
+
+ @staticmethod
+ def sort_by_dtstart(e1, e2):
+ if e1.mInstanceStart == e2.mInstanceStart:
+ if (e1.mInstanceStart.isDateOnly() and not e2.mInstanceStart.isDateOnly() or
+ not e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly()):
+ return e1.mInstanceStart.isDateOnly()
+ else:
+ return False
+ else:
+ return e1.mInstanceStart < e2.mInstanceStart
+
+
+ def __init__(self, owner, rid):
+
+ self.mOwner = owner
+ self.initFromOwner(rid)
+
+
+ def duplicate(self):
+ other = ComponentExpanded(self.mOwner, None)
+ other.mInstanceStart = self.mInstanceStart.duplicate()
+ other.mInstanceEnd = self.mInstanceEnd.duplicate()
+ other.mRecurring = self.mRecurring
+ return other
+
+
+ def close(self):
+ # Clean-up
+ self.mOwner = None
+
+
+ def getOwner(self):
+ return self.mOwner
+
+
+ def getMaster(self):
+ return self.mOwner
+
+
+ def getTrueMaster(self):
+ return self.mOwner.getMaster()
+
+
+ def getInstanceStart(self):
+ return self.mInstanceStart
+
+
+ def getInstanceEnd(self):
+ return self.mInstanceEnd
+
+
+ def recurring(self):
+ return self.mRecurring
+
+
+ def isNow(self):
+ # Check instance start/end against current date-time
+ now = DateTime.getNowUTC()
+ return self.mInstanceStart <= now and self.mInstanceEnd > now
+
+
+ def initFromOwner(self, rid):
+ # There are four possibilities here:
+ #
+ # 1: this instance is the instance for the master component
+ #
+ # 2: this instance is an expanded instance derived directly from the
+ # master component
+ #
+ # 3: This instance is the instance for a slave (overridden recurrence
+ # instance)
+ #
+ # 4: This instance is the expanded instance for a slave with a RANGE
+ # parameter
+ #
+
+ # rid is not set if the owner is the master (case 1)
+ if rid is None:
+ # Just get start/end from owner
+ self.mInstanceStart = self.mOwner.getStart()
+ self.mInstanceEnd = self.mOwner.getEnd()
+ self.mRecurring = False
+
+ # If the owner is not a recurrence instance then it is case 2
+ elif not self.mOwner.isRecurrenceInstance():
+ # Derive start/end from rid and duration of master
+
+ # Start of the recurrence instance is the recurrence id
+ self.mInstanceStart = rid
+
+ # End is based on original events settings
+ if self.mOwner.hasEnd():
+ self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
+ else:
+ self.mInstanceEnd = self.mInstanceStart.duplicate()
+
+ self.mRecurring = True
+
+ # If the owner is a recurrence item and the passed in rid is the same
+ # as the component rid we have case 3
+ elif rid == self.mOwner.getRecurrenceID():
+ # Derive start/end directly from the owner
+ self.mInstanceStart = self.mOwner.getStart()
+ self.mInstanceEnd = self.mOwner.getEnd()
+
+ self.mRecurring = True
+
+ # case 4 - the complicated one!
+ else:
+ # We need to use the rid as the starting point, but adjust it by
+ # the offset between the slave's
+ # rid and its start
+ self.mInstanceStart = rid + (self.mOwner.getStart() - self.mOwner.getRecurrenceID())
+
+ # End is based on duration of owner
+ self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
+
+ self.mRecurring = True
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcomponentrecurpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcomponentrecurpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/componentrecur.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,717 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentexpanded import ComponentExpanded
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.recurrenceset import RecurrenceSet
+from pycalendar.timezone import Timezone
+from pycalendar.utils import set_difference
+import uuid
+
+class ComponentRecur(Component):
+
+ propertyCardinality_STATUS_Fix = (
+ definitions.cICalProperty_STATUS,
+ )
+
+ @staticmethod
+ def mapKey(uid, rid=None):
+ if uid:
+ result = "u:" + uid
+ if rid is not None:
+ result += rid
+ return result
+ else:
+ return None
+
+
+ @staticmethod
+ def sort_by_dtstart_allday(e1, e2):
+
+ if e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly():
+ return e1.self.mStart < e2.self.mStart
+ elif e1.self.mStart.isDateOnly():
+ return True
+ elif (e2.self.mStart.isDateOnly()):
+ return False
+ elif e1.self.mStart == e2.self.mStart:
+ if e1.self.mEnd == e2.self.mEnd:
+ # Put ones created earlier in earlier columns in day view
+ return e1.self.mStamp < e2.self.mStamp
+ else:
+ # Put ones that end later in earlier columns in day view
+ return e1.self.mEnd > e2.self.mEnd
+ else:
+ return e1.self.mStart < e2.self.mStart
+
+
+ @staticmethod
+ def sort_by_dtstart(e1, e2):
+ if e1.self.mStart == e2.self.mStart:
+ if (e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly() or
+ not e1.self.mStart.isDateOnly() and not e2.self.mStart.isDateOnly()):
+ return False
+ else:
+ return e1.self.mStart.isDateOnly()
+ else:
+ return e1.self.mStart < e2.self.mStart
+
+
+ def __init__(self, parent=None):
+ super(ComponentRecur, self).__init__(parent=parent)
+ self.mMaster = self
+ self.mMapKey = None
+ self.mSummary = None
+ self.mStamp = DateTime()
+ self.mHasStamp = False
+ self.mStart = DateTime()
+ self.mHasStart = False
+ self.mEnd = DateTime()
+ self.mHasEnd = False
+ self.mDuration = False
+ self.mHasRecurrenceID = False
+ self.mAdjustFuture = False
+ self.mAdjustPrior = False
+ self.mRecurrenceID = None
+ self.mRecurrences = None
+
+ # This is a special check we do only for STATUS due to a calendarserver bug
+ self.cardinalityChecks += (
+ self.check_cardinality_STATUS_Fix,
+ )
+
+
+ def duplicate(self, parent=None):
+ other = super(ComponentRecur, self).duplicate(parent=parent)
+
+ # Special determination of master
+ other.mMaster = self.mMaster if self.recurring() else self
+
+ other.mMapKey = self.mMapKey
+
+ other.mSummary = self.mSummary
+
+ if (self.mStamp is not None):
+ other.mStamp = self.mStamp.duplicate()
+ other.mHasStamp = self.mHasStamp
+
+ other.mStart = self.mStart.duplicate()
+ other.mHasStart = self.mHasStart
+ other.mEnd = self.mEnd.duplicate()
+ other.mHasEnd = self.mHasEnd
+ other.mDuration = self.mDuration
+
+ other.mHasRecurrenceID = self.mHasRecurrenceID
+ other.mAdjustFuture = self.mAdjustFuture
+ other.mAdjustPrior = self.mAdjustPrior
+ if self.mRecurrenceID is not None:
+ other.mRecurrenceID = self.mRecurrenceID.duplicate()
+
+ other._resetRecurrenceSet()
+
+ return other
+
+
+ def canGenerateInstance(self):
+ return not self.mHasRecurrenceID
+
+
+ def recurring(self):
+ return (self.mMaster is not None) and (self.mMaster is not self)
+
+
+ def setMaster(self, master):
+ self.mMaster = master
+ self.initFromMaster()
+
+
+ def getMaster(self):
+ return self.mMaster
+
+
+ def getMapKey(self):
+
+ if self.mMapKey is None:
+ self.mMapKey = str(uuid.uuid4())
+ return self.mMapKey
+
+
+ def getMasterKey(self):
+ return ComponentRecur.mapKey(self.mUID)
+
+
+ def initDTSTAMP(self):
+ # Save new one
+ super(ComponentRecur, self).initDTSTAMP()
+
+ # Get the new one
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
+ self.mHasStamp = temp is not None
+ if self.mHasStamp:
+ self.mStamp = temp
+
+
+ def getStamp(self):
+ return self.mStamp
+
+
+ def hasStamp(self):
+ return self.mHasStamp
+
+
+ def getStart(self):
+ return self.mStart
+
+
+ def hasStart(self):
+ return self.mHasStart
+
+
+ def getEnd(self):
+ return self.mEnd
+
+
+ def hasEnd(self):
+ return self.mHasEnd
+
+
+ def useDuration(self):
+ return self.mDuration
+
+
+ def isRecurrenceInstance(self):
+ return self.mHasRecurrenceID
+
+
+ def isAdjustFuture(self):
+ return self.mAdjustFuture
+
+
+ def isAdjustPrior(self):
+ return self.mAdjustPrior
+
+
+ def getRecurrenceID(self):
+ return self.mRecurrenceID
+
+
+ def isRecurring(self):
+ return (self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
+
+
+ def getRecurrenceSet(self):
+ return self.mRecurrences
+
+
+ def setUID(self, uid):
+ super(ComponentRecur, self).setUID(uid)
+
+ # Update the map key
+ if self.mHasRecurrenceID:
+ self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
+ else:
+ self.mMapKey = self.mapKey(self.mUID)
+
+
+ def getSummary(self):
+ return self.mSummary
+
+
+ def setSummary(self, summary):
+ self.mSummary = summary
+
+
+ def getDescription(self):
+ # Get DESCRIPTION
+ txt = self.loadValueString(definitions.cICalProperty_DESCRIPTION)
+ if txt is not None:
+ return txt
+ else:
+ return ""
+
+
+ def getLocation(self):
+ # Get LOCATION
+ txt = self.loadValueString(definitions.cICalProperty_LOCATION)
+ if txt is not None:
+ return txt
+ else:
+ return ""
+
+
+ def finalise(self):
+ super(ComponentRecur, self).finalise()
+
+ # Get DTSTAMP
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
+ self.mHasStamp = temp is not None
+ if self.mHasStamp:
+ self.mStamp = temp
+
+ # Get DTSTART
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
+ self.mHasStart = temp is not None
+ if self.mHasStart:
+ self.mStart = temp
+
+ # Get DTEND
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
+ if temp is None:
+ # Try DURATION instead
+ temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+ if temp is not None:
+ self.mHasEnd = False
+ self.mEnd = self.mStart + temp
+ self.mDuration = True
+ else:
+ # If no end or duration then use the start (bumped by one day for
+ # an all day event)
+ self.mHasEnd = False
+ self.mEnd = self.mStart.duplicate()
+ if self.mEnd.isDateOnly():
+ self.mEnd.offsetDay(1)
+ self.mDuration = False
+ else:
+ self.mHasEnd = True
+ self.mEnd = temp
+ self.mDuration = False
+
+ # Get SUMMARY
+ temp = self.loadValueString(definitions.cICalProperty_SUMMARY)
+ if temp is not None:
+ self.mSummary = temp
+
+ # Get RECURRENCE-ID
+ self.mHasRecurrenceID = (self.countProperty(definitions.cICalProperty_RECURRENCE_ID) != 0)
+ if self.mHasRecurrenceID:
+ self.mRecurrenceID = self.loadValueDateTime(definitions.cICalProperty_RECURRENCE_ID)
+
+ # Update the map key
+ if self.mHasRecurrenceID:
+ self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
+
+ # Also get the RANGE parameter
+ attrs = self.findFirstProperty(definitions.cICalProperty_RECURRENCE_ID).getParameters()
+ if definitions.cICalParameter_RANGE in attrs:
+ self.mAdjustFuture = (attrs[definitions.cICalParameter_RANGE][0].getFirstValue() == definitions.cICalParameter_RANGE_THISANDFUTURE)
+ self.mAdjustPrior = (attrs[definitions.cICalParameter_RANGE][0].getFirstValue() == definitions.cICalParameter_RANGE_THISANDPRIOR)
+ else:
+ self.mAdjustFuture = False
+ self.mAdjustPrior = False
+ else:
+ self.mMapKey = self.mapKey(self.mUID)
+
+ self._resetRecurrenceSet()
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems. Return
+ a tuple containing two lists: the first describes problems that were fixed, the
+ second problems that were not fixed. Caller can then decide what to do with unfixed
+ issues.
+ """
+
+ # Do normal checks
+ fixed, unfixed = super(ComponentRecur, self).validate(doFix)
+
+ # Check that any UNTIL value matches that for DTSTART
+ if self.mHasStart and self.mRecurrences:
+ dtutc = self.mStart.duplicateAsUTC()
+ for rrule in self.mRecurrences.getRules():
+ if rrule.getUseUntil():
+ if rrule.getUntil().isDateOnly() ^ self.mStart.isDateOnly():
+ logProblem = "[%s] Value types must match: %s, %s" % (
+ self.getType(),
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalValue_RECUR_UNTIL,
+ )
+ if doFix:
+ rrule.getUntil().setDateOnly(self.mStart.isDateOnly())
+ if not self.mStart.isDateOnly():
+ rrule.getUntil().setHHMMSS(dtutc.getHours(), dtutc.getMinutes(), dtutc.getSeconds())
+ rrule.getUntil().setTimezone(Timezone(utc=True))
+ self.mRecurrences.changed()
+ fixed.append(logProblem)
+ else:
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ def check_cardinality_STATUS_Fix(self, fixed, unfixed, doFix):
+ """
+ Special for bug with STATUS where STATUS:CANCELLED is added alongside
+ another STATUS. In this case we want STATUS:CANCELLED to win.
+ """
+ for propname in self.propertyCardinality_STATUS_Fix:
+ if self.countProperty(propname) > 1:
+ logProblem = "[%s] Too many properties: %s" % (self.getType(), propname)
+ if doFix:
+ # Check that one of them is STATUS:CANCELLED
+ for prop in self.getProperties(propname):
+ if prop.getTextValue().getValue().upper() == definitions.cICalProperty_STATUS_CANCELLED:
+ self.removeProperties(propname)
+ self.addProperty(Property(propname, definitions.cICalProperty_STATUS_CANCELLED))
+ fixed.append(logProblem)
+ break
+ else:
+ unfixed.append(logProblem)
+ else:
+ unfixed.append(logProblem)
+
+
+ def _resetRecurrenceSet(self):
+ # May need to create items
+ self.mRecurrences = None
+ if ((self.countProperty(definitions.cICalProperty_RRULE) != 0) or
+ (self.countProperty(definitions.cICalProperty_RDATE) != 0) or
+ (self.countProperty(definitions.cICalProperty_EXRULE) != 0) or
+ (self.countProperty(definitions.cICalProperty_EXDATE) != 0)):
+
+ self.mRecurrences = RecurrenceSet()
+
+ # Get RRULEs
+ self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
+
+ # Get RDATEs
+ self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
+
+ # Get EXRULEs
+ self.loadValueRRULE(definitions.cICalProperty_EXRULE, self.mRecurrences, False)
+
+ # Get EXDATEs
+ self.loadValueRDATE(definitions.cICalProperty_EXDATE, self.mRecurrences, False)
+
+
+ def FixStartEnd(self):
+ # End is always greater than start if start exists
+ if self.mHasStart and self.mEnd <= self.mStart:
+ # Use the start
+ self.mEnd = self.mStart.duplicate()
+ self.mDuration = False
+
+ # Adjust to approriate non-inclusive end point
+ if self.mStart.isDateOnly():
+ self.mEnd.offsetDay(1)
+
+ # For all day events it makes sense to use duration
+ self.mDuration = True
+ else:
+ # Use end of current day
+ self.mEnd.offsetDay(1)
+ self.mEnd.setHHMMSS(0, 0, 0)
+
+
+ def expandPeriod(self, period, results):
+ # Check for recurrence and True master
+ if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
+ and not self.isRecurrenceInstance()):
+ # Expand recurrences within the range
+ items = []
+ self.mRecurrences.expand(self.mStart, period, items)
+
+ # Look for overridden recurrence items
+ cal = self.mParentComponent
+ if cal is not None:
+ # Remove recurrence instances from the list of items
+ recurs = []
+ cal.getRecurrenceInstancesIds(definitions.cICalComponent_VEVENT, self.getUID(), recurs)
+ recurs.sort()
+ if len(recurs) != 0:
+ temp = []
+ temp = set_difference(items, recurs)
+ items = temp
+
+ # Now get actual instances
+ instances = []
+ cal.getRecurrenceInstancesItems(definitions.cICalComponent_VEVENT, self.getUID(), instances)
+
+ # Get list of each ones with RANGE
+ prior = []
+ future = []
+ for iter in instances:
+ if iter.isAdjustPrior():
+ prior.append(iter)
+ if iter.isAdjustFuture():
+ future.append(iter)
+
+ # Check for special behaviour
+ if len(prior) + len(future) == 0:
+ # Add each expanded item
+ for iter in items:
+ results.append(self.createExpanded(self, iter))
+ else:
+ # Sort each list first
+ prior.sort(self.sort_by_dtstart)
+ future.sort(self.sort_by_dtstart)
+
+ # Add each expanded item
+ for iter1 in items:
+
+ # Now step through each using the slave item
+ # instead of the master as appropriate
+ slave = None
+
+ # Find most appropriate THISANDPRIOR item
+ for i in range(len(prior) - 1, 0, -1):
+ riter2 = prior[i]
+ if riter2.getStart() > iter1:
+ slave = riter2
+ break
+
+ # Find most appropriate THISANDFUTURE item
+ for i in range(len(future) - 1, 0, -1):
+ riter2 = future.elementAt(i)
+ if riter2.getStart() < iter1:
+ slave = riter2
+ break
+
+ if slave is None:
+ slave = self
+ results.append(self.createExpanded(slave, iter1))
+ else:
+ # Add each expanded item
+ for iter in items:
+ results.append(self.createExpanded(self, iter))
+
+ elif self.withinPeriod(period):
+ if self.isRecurrenceInstance():
+ rid = self.mRecurrenceID
+ else:
+ rid = None
+ results.append(ComponentExpanded(self, rid))
+
+
+ def withinPeriod(self, period):
+ # Check for recurrence
+ if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()):
+ items = []
+ self.mRecurrences.expand(self.mStart, period, items)
+ return len(items) != 0
+ else:
+ # Does event span the period (assume self.mEnd > self.mStart)
+ # Check start (inclusive) and end (exclusive)
+ if self.mEnd <= period.getStart() or self.mStart >= period.getEnd():
+ return False
+ else:
+ return True
+
+
+ def changedRecurrence(self):
+ # Clear cached values
+ if self.mRecurrences is not None:
+ self.mRecurrences.changed()
+
+
+ # Editing
+ def editSummary(self, summary):
+ # Updated cached value
+ self.mSummary = summary
+
+ # Remove existing items
+ self.editProperty(definitions.cICalProperty_SUMMARY, summary)
+
+
+ def editDetails(self, description, location):
+
+ # Edit existing items
+ self.editProperty(definitions.cICalProperty_DESCRIPTION, description)
+ self.editProperty(definitions.cICalProperty_LOCATION, location)
+
+
+ def editTiming(self):
+ # Updated cached values
+ self.mHasStart = False
+ self.mHasEnd = False
+ self.mDuration = False
+ self.mStart.setToday()
+ self.mEnd.setToday()
+
+ # Remove existing DTSTART & DTEND & DURATION & DUE items
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+ self.removeProperties(definitions.cICalProperty_DUE)
+
+
+ def editTimingDue(self, due):
+ # Updated cached values
+ self.mHasStart = False
+ self.mHasEnd = True
+ self.mDuration = False
+ self.mStart = due
+ self.mEnd = due
+
+ # Remove existing DUE & DTSTART & DTEND & DURATION items
+ self.removeProperties(definitions.cICalProperty_DUE)
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+
+ # Now create properties
+ prop = Property(definitions.cICalProperty_DUE, due)
+ self.addProperty(prop)
+
+
+ def editTimingStartEnd(self, start, end):
+ # Updated cached values
+ self.mHasStart = self.mHasEnd = True
+ self.mStart = start
+ self.mEnd = end
+ self.mDuration = False
+ self.FixStartEnd()
+ # Remove existing DTSTART & DTEND & DURATION & DUE items
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+ self.removeProperties(definitions.cICalProperty_DUE)
+
+ # Now create properties
+ prop = Property(definitions.cICalProperty_DTSTART, start)
+ self.addProperty(prop)
+
+ # If its an all day event and the end one day after the start, ignore it
+ temp = start.duplicate()
+ temp.offsetDay(1)
+ if not start.isDateOnly() or end != temp:
+ prop = Property(definitions.cICalProperty_DTEND, end)
+ self.addProperty(prop)
+
+
+ def editTimingStartDuration(self, start, duration):
+ # Updated cached values
+ self.mHasStart = True
+ self.mHasEnd = False
+ self.mStart = start
+ self.mEnd = start + duration
+ self.mDuration = True
+
+ # Remove existing DTSTART & DTEND & DURATION & DUE items
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+ self.removeProperties(definitions.cICalProperty_DUE)
+
+ # Now create properties
+ prop = Property(definitions.cICalProperty_DTSTART, start)
+ self.addProperty(prop)
+
+ # If its an all day event and the duration is one day, ignore it
+ if (not start.isDateOnly() or (duration.getWeeks() != 0)
+ or (duration.getDays() > 1)):
+ prop = Property(definitions.cICalProperty_DURATION, duration)
+ self.addProperty(prop)
+
+
+ def editRecurrenceSet(self, recurs):
+ # Must have items
+ if self.mRecurrences is None:
+ self.mRecurrences = RecurrenceSet()
+
+ # Updated cached values
+ self.mRecurrences = recurs
+
+ # Remove existing RRULE, EXRULE, RDATE & EXDATE
+ self.removeProperties(definitions.cICalProperty_RRULE)
+ self.removeProperties(definitions.cICalProperty_EXRULE)
+ self.removeProperties(definitions.cICalProperty_RDATE)
+ self.removeProperties(definitions.cICalProperty_EXDATE)
+
+ # Now create properties
+ for iter in self.mRecurrences.getRules():
+ prop = Property(definitions.cICalProperty_RRULE, iter)
+ self.addProperty(prop)
+ for iter in self.getExrules():
+ prop = Property(definitions.cICalProperty_EXRULE, iter)
+ self.addProperty(prop)
+ for iter in self.mRecurrences.getDates():
+ prop = Property(definitions.cICalProperty_RDATE, iter)
+ self.addProperty(prop)
+ for iter in self.mRecurrences.getExdates():
+ prop = Property(definitions.cICalProperty_EXDATE, iter)
+ self.addProperty(prop)
+
+
+ def excludeRecurrence(self, start):
+ # Must have items
+ if self.mRecurrences is None:
+ return
+
+ # Add to recurrence set and clear cache
+ self.mRecurrences.subtract(start)
+
+ # Add property
+ prop = Property(definitions.cICalProperty_EXDATE, start)
+ self.addProperty(prop)
+
+
+ def excludeFutureRecurrence(self, start):
+ # Must have items
+ if self.mRecurrences is None:
+ return
+
+ # Adjust RRULES to end before start
+ self.mRecurrences.excludeFutureRecurrence(start)
+
+ # Remove existing RRULE & RDATE
+ self.removeProperties(definitions.cICalProperty_RRULE)
+ self.removeProperties(definitions.cICalProperty_RDATE)
+
+ # Now create properties
+ for iter in self.mRecurrences.getRules():
+ prop = Property(definitions.cICalProperty_RRULE, iter)
+ self.addProperty(prop)
+ for iter in self.mRecurrences.getDates():
+ prop = Property(definitions.cICalProperty_RDATE, iter)
+ self.addProperty(prop)
+
+
+ def initFromMaster(self):
+ # Only if not master
+ if self.recurring():
+ # Redo this to get cached values from master
+ self.finalise()
+
+ # If this component does not have its own start property, use the
+ # recurrence id
+ # i.e. the start time of this instance has not changed - something
+ # else has
+ if not self.hasProperty(definitions.cICalProperty_DTSTART):
+ self.mStart = self.mRecurrenceID
+
+ # If this component does not have its own end/duration property,
+ # the determine
+ # the end from the master duration
+ if (not self.hasProperty(definitions.cICalProperty_DTEND) and
+ not self.hasProperty(definitions.cICalProperty_DURATION)):
+ # End is based on original events settings
+ self.mEnd = self.mStart + (self.mMaster.getEnd() - self.mMaster.getStart())
+
+ # If this instance has a duration, but no start of its own, then we
+ # need to readjust the end
+ # to account for the start being changed to the recurrence id
+ elif (self.hasProperty(definitions.cICalProperty_DURATION) and
+ not self.hasProperty(definitions.cICalProperty_DTSTART)):
+ temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+ self.mEnd = self.mStart + temp
+
+
+ def createExpanded(self, master, recurid):
+ return ComponentExpanded(master, recurid)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendardefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendardefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/definitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/definitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/definitions.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/definitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,372 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# 5545 Components
+
+cICalComponent_VCALENDAR = "VCALENDAR"
+cICalComponent_VEVENT = "VEVENT"
+cICalComponent_VTODO = "VTODO"
+cICalComponent_VJOURNAL = "VJOURNAL"
+cICalComponent_VFREEBUSY = "VFREEBUSY"
+cICalComponent_VTIMEZONE = "VTIMEZONE"
+cICalComponent_VALARM = "VALARM"
+cICalComponent_STANDARD = "STANDARD"
+cICalComponent_DAYLIGHT = "DAYLIGHT"
+cICalComponent_UNKNOWN = "UNKNOWN"
+
+# 5545 Calendar Property Parameters
+
+# 5545 Section 3.2
+cICalParameter_ALTREP = "ALTREP"
+cICalParameter_CN = "CN"
+cICalParameter_CUTYPE = "CUTYPE"
+cICalParameter_DELEGATED_FROM = "DELEGATED-FROM"
+cICalParameter_DELEGATED_TO = "DELEGATED-TO"
+cICalParameter_DIR = "DIR"
+cICalParameter_ENCODING = "ENCODING"
+cICalParameter_FMTTYPE = "FMTTYPE"
+cICalParameter_FBTYPE = "FBTYPE"
+cICalParameter_LANGUAGE = "LANGUAGE"
+cICalParameter_MEMBER = "MEMBER"
+cICalParameter_PARTSTAT = "PARTSTAT"
+cICalParameter_RANGE = "RANGE"
+cICalParameter_RELATED = "RELATED"
+cICalParameter_RELTYPE = "RELTYPE"
+cICalParameter_ROLE = "ROLE"
+cICalParameter_RSVP = "RSVP"
+cICalParameter_RSVP_TRUE = "TRUE"
+cICalParameter_RSVP_FALSE = "FALSE"
+cICalParameter_SENT_BY = "SENT-BY"
+cICalParameter_TZID = "TZID"
+cICalParameter_VALUE = "VALUE"
+
+# 5545 Section 3.2.9
+cICalParameter_FBTYPE_FREE = "FREE"
+cICalParameter_FBTYPE_BUSY = "BUSY"
+cICalParameter_FBTYPE_BUSYUNAVAILABLE = "BUSY-UNAVAILABLE"
+cICalParameter_FBTYPE_BUSYTENTATIVE = "BUSY-TENTATIVE"
+
+# 5545 Section 3.2.12
+ePartStat_NeedsAction = 0
+ePartStat_Accepted = 1
+ePartStat_Declined = 2
+ePartStat_Tentative = 3
+ePartStat_Delegated = 4
+ePartStat_Completed = 5
+ePartStat_InProcess = 6
+
+cICalParameter_PARTSTAT_NEEDSACTION = "NEEDS-ACTION"
+cICalParameter_PARTSTAT_ACCEPTED = "ACCEPTED"
+cICalParameter_PARTSTAT_DECLINED = "DECLINED"
+cICalParameter_PARTSTAT_TENTATIVE = "TENTATIVE"
+cICalParameter_PARTSTAT_DELEGATED = "DELEGATED"
+cICalParameter_PARTSTAT_COMPLETED = "COMPLETE"
+cICalParameter_PARTSTAT_INPROCESS = "IN-PROCESS"
+
+# 5545 Section 3.2.13
+cICalParameter_RANGE_THISANDFUTURE = "THISANDFUTURE"
+cICalParameter_RANGE_THISANDPRIOR = "THISANDPRIOR" # 2445 only
+
+# 5545 Section 3.2.14
+cICalParameter_RELATED_START = "START"
+cICalParameter_RELATED_END = "END"
+
+# 5545 Section 3.2.16
+ePartRole_Chair = 0
+ePartRole_Required = 1
+ePartRole_Optional = 2
+ePartRole_Non = 3
+
+cICalParameter_ROLE_CHAIR = "CHAIR"
+cICalParameter_ROLE_REQ_PART = "REQ-PARTICIPANT"
+cICalParameter_ROLE_OPT_PART = "OPT-PARTICIPANT"
+cICalParameter_ROLE_NON_PART = "NON-PARTICIPANT"
+
+# 5545 Section 3.2.3
+eCutype_Individual = 0
+eCutype_Group = 1
+eCutype_Resource = 2
+eCutype_Room = 3
+eCutype_Unknown = 4
+
+cICalParameter_CUTYPE_INDIVIDUAL = "INDIVIDUAL"
+cICalParameter_CUTYPE_GROUP = "GROUP"
+cICalParameter_CUTYPE_RESOURCE = "RESOURCE"
+cICalParameter_CUTYPE_ROOM = "ROOM"
+cICalParameter_CUTYPE_UNKNOWN = "UNKNOWN"
+
+# 5545 Value types
+
+# 5545 Section 3.3
+cICalValue_BINARY = "BINARY"
+cICalValue_BOOLEAN = "BOOLEAN"
+cICalValue_CAL_ADDRESS = "CAL-ADDRESS"
+cICalValue_DATE = "DATE"
+cICalValue_DATE_TIME = "DATE-TIME"
+cICalValue_DURATION = "DURATION"
+cICalValue_FLOAT = "FLOAT"
+cICalValue_INTEGER = "INTEGER"
+cICalValue_PERIOD = "PERIOD"
+cICalValue_RECUR = "RECUR"
+cICalValue_TEXT = "TEXT"
+cICalValue_TIME = "TIME"
+cICalValue_URI = "URI"
+cICalValue_UTC_OFFSET = "UTC-OFFSET"
+
+# 5545 Calendar Properties
+
+# 5545 Section 3.7
+
+cICalProperty_CALSCALE = "CALSCALE"
+cICalProperty_METHOD = "METHOD"
+cICalProperty_PRODID = "PRODID"
+cICalProperty_VERSION = "VERSION"
+
+# Apple Extensions
+cICalProperty_XWRCALNAME = "X-WR-CALNAME"
+cICalProperty_XWRCALDESC = "X-WR-CALDESC"
+cICalProperty_XWRALARMUID = "X-WR-ALARMUID"
+
+# 5545 Component Property names
+
+# 5545 Section 3.8.1
+cICalProperty_ATTACH = "ATTACH"
+cICalProperty_CATEGORIES = "CATEGORIES"
+cICalProperty_CLASS = "CLASS"
+cICalProperty_COMMENT = "COMMENT"
+cICalProperty_DESCRIPTION = "DESCRIPTION"
+cICalProperty_GEO = "GEO"
+cICalProperty_LOCATION = "LOCATION"
+cICalProperty_PERCENT_COMPLETE = "PERCENT-COMPLETE"
+cICalProperty_PRIORITY = "PRIORITY"
+cICalProperty_RESOURCES = "RESOURCES"
+cICalProperty_STATUS = "STATUS"
+cICalProperty_SUMMARY = "SUMMARY"
+
+# 5545 Section 3.8.2
+cICalProperty_COMPLETED = "COMPLETED"
+cICalProperty_DTEND = "DTEND"
+cICalProperty_DUE = "DUE"
+cICalProperty_DTSTART = "DTSTART"
+cICalProperty_DURATION = "DURATION"
+cICalProperty_FREEBUSY = "FREEBUSY"
+cICalProperty_TRANSP = "TRANSP"
+cICalProperty_OPAQUE = "OPAQUE"
+cICalProperty_TRANSPARENT = "TRANSPARENT"
+
+# 5545 Section 3.8.3
+cICalProperty_TZID = "TZID"
+cICalProperty_TZNAME = "TZNAME"
+cICalProperty_TZOFFSETFROM = "TZOFFSETFROM"
+cICalProperty_TZOFFSETTO = "TZOFFSETTO"
+cICalProperty_TZURL = "TZURL"
+
+# 5545 Section 3.8.4
+cICalProperty_ATTENDEE = "ATTENDEE"
+cICalProperty_CONTACT = "CONTACT"
+cICalProperty_ORGANIZER = "ORGANIZER"
+cICalProperty_RECURRENCE_ID = "RECURRENCE-ID"
+cICalProperty_RELATED_TO = "RELATED-TO"
+cICalProperty_URL = "URL"
+cICalProperty_UID = "UID"
+
+# 5545 Section 3.8.5
+cICalProperty_EXDATE = "EXDATE"
+cICalProperty_EXRULE = "EXRULE" # 2445 only
+cICalProperty_RDATE = "RDATE"
+cICalProperty_RRULE = "RRULE"
+
+# 5545 Section 3.8.6
+cICalProperty_ACTION = "ACTION"
+cICalProperty_REPEAT = "REPEAT"
+cICalProperty_TRIGGER = "TRIGGER"
+
+# 5545 Section 3.8.7
+cICalProperty_CREATED = "CREATED"
+cICalProperty_DTSTAMP = "DTSTAMP"
+cICalProperty_LAST_MODIFIED = "LAST-MODIFIED"
+cICalProperty_SEQUENCE = "SEQUENCE"
+
+# 5545 Section 3.8.8.3
+cICalProperty_REQUEST_STATUS = "REQUEST-STATUS"
+
+# Enums
+# Use ascending order for sensible sorting
+
+# 5545 Section 3.3.10
+
+eRecurrence_SECONDLY = 0
+eRecurrence_MINUTELY = 1
+eRecurrence_HOURLY = 2
+eRecurrence_DAILY = 3
+eRecurrence_WEEKLY = 4
+eRecurrence_MONTHLY = 5
+eRecurrence_YEARLY = 6
+
+eRecurrence_FREQ = 0
+eRecurrence_UNTIL = 1
+eRecurrence_COUNT = 2
+eRecurrence_INTERVAL = 3
+eRecurrence_BYSECOND = 4
+eRecurrence_BYMINUTE = 5
+eRecurrence_BYHOUR = 6
+eRecurrence_BYDAY = 7
+eRecurrence_BYMONTHDAY = 8
+eRecurrence_BYYEARDAY = 9
+eRecurrence_BYWEEKNO = 10
+eRecurrence_BYMONTH = 11
+eRecurrence_BYSETPOS = 12
+eRecurrence_WKST = 13
+
+cICalValue_RECUR_FREQ = "FREQ"
+cICalValue_RECUR_FREQ_LEN = 5
+
+cICalValue_RECUR_SECONDLY = "SECONDLY"
+cICalValue_RECUR_MINUTELY = "MINUTELY"
+cICalValue_RECUR_HOURLY = "HOURLY"
+cICalValue_RECUR_DAILY = "DAILY"
+cICalValue_RECUR_WEEKLY = "WEEKLY"
+cICalValue_RECUR_MONTHLY = "MONTHLY"
+cICalValue_RECUR_YEARLY = "YEARLY"
+
+cICalValue_RECUR_UNTIL = "UNTIL"
+cICalValue_RECUR_COUNT = "COUNT"
+
+cICalValue_RECUR_INTERVAL = "INTERVAL"
+cICalValue_RECUR_BYSECOND = "BYSECOND"
+cICalValue_RECUR_BYMINUTE = "BYMINUTE"
+cICalValue_RECUR_BYHOUR = "BYHOUR"
+cICalValue_RECUR_BYDAY = "BYDAY"
+cICalValue_RECUR_BYMONTHDAY = "BYMONTHDAY"
+cICalValue_RECUR_BYYEARDAY = "BYYEARDAY"
+cICalValue_RECUR_BYWEEKNO = "BYWEEKNO"
+cICalValue_RECUR_BYMONTH = "BYMONTH"
+cICalValue_RECUR_BYSETPOS = "BYSETPOS"
+cICalValue_RECUR_WKST = "WKST"
+
+eRecurrence_WEEKDAY_SU = 0
+eRecurrence_WEEKDAY_MO = 1
+eRecurrence_WEEKDAY_TU = 2
+eRecurrence_WEEKDAY_WE = 3
+eRecurrence_WEEKDAY_TH = 4
+eRecurrence_WEEKDAY_FR = 5
+eRecurrence_WEEKDAY_SA = 6
+
+cICalValue_RECUR_WEEKDAY_SU = "SU"
+cICalValue_RECUR_WEEKDAY_MO = "MO"
+cICalValue_RECUR_WEEKDAY_TU = "TU"
+cICalValue_RECUR_WEEKDAY_WE = "WE"
+cICalValue_RECUR_WEEKDAY_TH = "TH"
+cICalValue_RECUR_WEEKDAY_FR = "FR"
+cICalValue_RECUR_WEEKDAY_SA = "SA"
+
+# 5545 Section 3.8.1.11
+eStatus_VEvent_None = 0
+eStatus_VEvent_Confirmed = 1
+eStatus_VEvent_Tentative = 2
+eStatus_VEvent_Cancelled = 3
+
+eStatus_VToDo_None = 0
+eStatus_VToDo_NeedsAction = 1
+eStatus_VToDo_InProcess = 2
+eStatus_VToDo_Completed = 3
+eStatus_VToDo_Cancelled = 4
+
+eStatus_VJournal_None = 0
+eStatus_VJournal_Final = 1
+eStatus_VJournal_Draft = 2
+eStatus_VJournal_Cancelled = 3
+
+cICalProperty_STATUS_TENTATIVE = "TENTATIVE"
+cICalProperty_STATUS_CONFIRMED = "CONFIRMED"
+cICalProperty_STATUS_CANCELLED = "CANCELLED"
+cICalProperty_STATUS_NEEDS_ACTION = "NEEDS-ACTION"
+cICalProperty_STATUS_COMPLETED = "COMPLETED"
+cICalProperty_STATUS_IN_PROCESS = "IN-PROCESS"
+cICalProperty_STATUS_DRAFT = "DRAFT"
+cICalProperty_STATUS_FINAL = "FINAL"
+
+# 5545 Section 3.8.6.1
+eAction_VAlarm_Audio = 0
+eAction_VAlarm_Display = 1
+eAction_VAlarm_Email = 2
+eAction_VAlarm_Procedure = 3
+eAction_VAlarm_Unknown = 4
+
+cICalProperty_ACTION_AUDIO = "AUDIO"
+cICalProperty_ACTION_DISPLAY = "DISPLAY"
+cICalProperty_ACTION_EMAIL = "EMAIL"
+cICalProperty_ACTION_PROCEDURE = "PROCEDURE"
+
+# Extensions: draft-daboo-calendar-availability-02
+
+# Section 3.1
+cICalComponent_VAVAILABILITY = "VAVAILABILITY"
+cICalComponent_AVAILABLE = "AVAILABLE"
+
+# Section 3.2
+cICalProperty_BUSYTYPE = "BUSYTYPE"
+
+
+# Extensions: draft-daboo-valarm-extensions-03
+
+# Section 5
+eAction_VAlarm_URI = 5
+cICalProperty_ACTION_URI = "URI"
+
+# Section 7.1
+cICalProperty_ACKNOWLEDGED = "ACKNOWLEDGED"
+
+eAction_VAlarm_None = 6
+cICalProperty_ACTION_NONE = "NONE"
+
+
+# Extensions: draft-york-vpoll-00.txt
+
+# Section 4.1
+cICalParamater_PUBLIC_COMMENT = "PUBLIC-COMMENT"
+cICalParamater_RESPONSE = "RESPONSE"
+cICalParamater_STAY_INFORMED = "STAY-INFORMED"
+
+# Section 4.2
+cICalProperty_ACCEPT_RESPONSE = "ACCEPT-RESPONSE"
+cICalProperty_POLL_ITEM_ID = "POLL-ITEM-ID"
+cICalProperty_POLL_WINNER = "POLL-WINNER"
+cICalProperty_POLL_MODE = "POLL-MODE"
+cICalProperty_POLL_MODE_BASIC = "BASIC"
+cICalProperty_POLL_PROPERTIES = "POLL-PROPERTIES"
+cICalProperty_VOTER = "VOTER"
+
+# Section 4.3
+cICalComponent_VPOLL = "VPOLL"
+
+
+# Mulberry extensions
+cICalProperty_ACTION_X_SPEAKTEXT = "X-MULBERRY-SPEAK-TEXT"
+cICalProperty_ALARM_X_LASTTRIGGER = "X-MULBERRY-LAST-TRIGGER"
+
+cICalProperty_ALARM_X_ALARMSTATUS = "X-MULBERRY-ALARM-STATUS"
+
+eAlarm_Status_Pending = 0
+eAlarm_Status_Completed = 1
+eAlarm_Status_Disabled = 2
+
+cICalProperty_ALARM_X_ALARMSTATUS_PENDING = "PENDING"
+cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED = "COMPLETED"
+cICalProperty_ALARM_X_ALARMSTATUS_DISABLED = "DISABLED"
+
+cICalParameter_ORGANIZER_X_IDENTITY = "X-MULBERRY-IDENTITY"
+cICalParameter_ATTENDEE_X_NEEDS_ITIP = "X-MULBERRY-NEEDS-ITIP"
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarfreebusypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarfreebusypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/freebusy.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+class FreeBusy(object):
+
+ FREE = 0
+ BUSYTENTATIVE = 1
+ BUSYUNAVAILABLE = 2
+ BUSY = 3
+
+ def __init__(self, type=None, period=None):
+
+ self.mType = type if type else FreeBusy.FREE
+ self.mPeriod = period.duplicate() if period is not None else None
+
+
+ def duplicate(self):
+ return FreeBusy(self.mType, self.mPeriod)
+
+
+ def setType(self, type):
+ self.mType = type
+
+
+ def getType(self):
+ return self.mType
+
+
+ def setPeriod(self, period):
+ self.mPeriod = period.duplicate()
+
+
+ def getPeriod(self):
+ return self.mPeriod
+
+
+ def isPeriodOverlap(self, period):
+ return self.mPeriod.isPeriodOverlap(period)
+
+
+ def resolveOverlaps(self, fb):
+ # TODO:
+ pass
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendaritipdefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendaritipdefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/itipdefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# 2446 Section 3
+
+cICalMethod_PUBLISH = "PUBLISH"
+cICalMethod_REQUEST = "REQUEST"
+cICalMethod_REFRESH = "REFRESH"
+cICalMethod_CANCEL = "CANCEL"
+cICalMethod_ADD = "ADD"
+cICalMethod_REPLY = "REPLY"
+cICalMethod_COUNTER = "COUNTER"
+cICalMethod_DECLINECOUNTER = "DECLINECOUNTER"
+
+# 2447 Section 2.4
+cICalMIMEMethod_PUBLISH = "publish"
+cICalMIMEMethod_REQUEST = "request"
+cICalMIMEMethod_REFRESH = "refresh"
+cICalMIMEMethod_CANCEL = "cancel"
+cICalMIMEMethod_ADD = "add"
+cICalMIMEMethod_REPLY = "reply"
+cICalMIMEMethod_COUNTER = "counter"
+cICalMIMEMethod_DECLINECOUNTER = "declinecounter"
+
+cICalMIMEComponent_VEVENT = "vevent"
+cICalMIMEComponent_VTODO = "vtodo"
+cICalMIMEComponent_VJOURNAL = "vjournal"
+cICalMIMEComponent_VFREEBUSY = "vfreebusy"
+cICalMIMEComponent_VAVAILABILITY = "vavailability"
+
+# VPOLL extensions draft-york-vpoll-00.txt
+
+# Section 6.1
+cICalMethod_POLLSTATUS = "POLLSTATUS"
+cICalMIMEMethod_POLLSTATUS = "pollstatus"
+cICalMIMEComponent_VPOLL = "vpoll"
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarpropertypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarpropertypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/property.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/property.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/property.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,358 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.parameter import Parameter
+from pycalendar.datetime import DateTime
+from pycalendar.datetimevalue import DateTimeValue
+from pycalendar.duration import Duration
+from pycalendar.durationvalue import DurationValue
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.recurrence import Recurrence
+from pycalendar.icalendar.recurrencevalue import RecurrenceValue
+from pycalendar.icalendar.requeststatusvalue import RequestStatusValue
+from pycalendar.multivalue import MultiValue
+from pycalendar.period import Period
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.property import PropertyBase
+from pycalendar.utcoffsetvalue import UTCOffsetValue
+from pycalendar.value import Value
+
+class Property(PropertyBase):
+
+ sDefaultValueTypeMap = {
+
+ # 5545 Section 3.7
+ definitions.cICalProperty_CALSCALE : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_METHOD : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_PRODID : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_VERSION : Value.VALUETYPE_TEXT,
+
+ # 5545 Section 3.8.1
+ definitions.cICalProperty_ATTACH : Value.VALUETYPE_URI,
+ definitions.cICalProperty_CATEGORIES : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_CLASS : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_COMMENT : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_DESCRIPTION : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_GEO : Value.VALUETYPE_FLOAT,
+ definitions.cICalProperty_LOCATION : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_PERCENT_COMPLETE : Value.VALUETYPE_INTEGER,
+ definitions.cICalProperty_PRIORITY : Value.VALUETYPE_INTEGER,
+ definitions.cICalProperty_RESOURCES : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_STATUS : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_SUMMARY : Value.VALUETYPE_TEXT,
+
+ # 5545 Section 3.8.2
+ definitions.cICalProperty_COMPLETED : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_DTEND : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_DUE : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_DTSTART : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_DURATION : Value.VALUETYPE_DURATION,
+ definitions.cICalProperty_FREEBUSY : Value.VALUETYPE_PERIOD,
+ definitions.cICalProperty_TRANSP : Value.VALUETYPE_TEXT,
+
+ # 5545 Section 3.8.3
+ definitions.cICalProperty_TZID : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_TZNAME : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_TZOFFSETFROM : Value.VALUETYPE_UTC_OFFSET,
+ definitions.cICalProperty_TZOFFSETTO : Value.VALUETYPE_UTC_OFFSET,
+ definitions.cICalProperty_TZURL : Value.VALUETYPE_URI,
+
+ # 5545 Section 3.8.4
+ definitions.cICalProperty_ATTENDEE : Value.VALUETYPE_CALADDRESS,
+ definitions.cICalProperty_CONTACT : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_ORGANIZER : Value.VALUETYPE_CALADDRESS,
+ definitions.cICalProperty_RECURRENCE_ID : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_RELATED_TO : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_URL : Value.VALUETYPE_URI,
+ definitions.cICalProperty_UID : Value.VALUETYPE_TEXT,
+
+ # 5545 Section 3.8.5
+ definitions.cICalProperty_EXDATE : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_EXRULE : Value.VALUETYPE_RECUR, # 2445 only
+ definitions.cICalProperty_RDATE : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_RRULE : Value.VALUETYPE_RECUR,
+
+ # 5545 Section 3.8.6
+ definitions.cICalProperty_ACTION : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_REPEAT : Value.VALUETYPE_INTEGER,
+ definitions.cICalProperty_TRIGGER : Value.VALUETYPE_DURATION,
+
+ # 5545 Section 3.8.7
+ definitions.cICalProperty_CREATED : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_DTSTAMP : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_LAST_MODIFIED : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_SEQUENCE : Value.VALUETYPE_INTEGER,
+
+ # 5545 Section 3.8.8
+ definitions.cICalProperty_REQUEST_STATUS : Value.VALUETYPE_TEXT,
+
+ # Extensions: draft-daboo-valarm-extensions-03
+ definitions.cICalProperty_ACKNOWLEDGED : Value.VALUETYPE_DATETIME,
+
+ # Extensions: draft-york-vpoll-00.txt
+ # Section 4.2
+ definitions.cICalProperty_ACCEPT_RESPONSE : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_POLL_ITEM_ID : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_POLL_WINNER : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_POLL_MODE : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_POLL_PROPERTIES : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_VOTER : Value.VALUETYPE_CALADDRESS,
+
+ # Apple Extensions
+ definitions.cICalProperty_XWRCALNAME : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_XWRCALDESC : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_XWRALARMUID : Value.VALUETYPE_TEXT,
+
+ # Mulberry extensions
+ definitions.cICalProperty_ACTION_X_SPEAKTEXT : Value.VALUETYPE_TEXT,
+ definitions.cICalProperty_ALARM_X_LASTTRIGGER : Value.VALUETYPE_DATETIME,
+ definitions.cICalProperty_ALARM_X_ALARMSTATUS : Value.VALUETYPE_TEXT,
+ }
+
+ sValueTypeMap = {
+
+ # 5545 Section 3.3
+ definitions.cICalValue_BINARY : Value.VALUETYPE_BINARY,
+ definitions.cICalValue_BOOLEAN : Value.VALUETYPE_BOOLEAN,
+ definitions.cICalValue_CAL_ADDRESS : Value.VALUETYPE_CALADDRESS,
+ definitions.cICalValue_DATE : Value.VALUETYPE_DATE,
+ definitions.cICalValue_DATE_TIME : Value.VALUETYPE_DATETIME,
+ definitions.cICalValue_DURATION : Value.VALUETYPE_DURATION,
+ definitions.cICalValue_FLOAT : Value.VALUETYPE_FLOAT,
+ definitions.cICalValue_INTEGER : Value.VALUETYPE_INTEGER,
+ definitions.cICalValue_PERIOD : Value.VALUETYPE_PERIOD,
+ definitions.cICalValue_RECUR : Value.VALUETYPE_RECUR,
+ definitions.cICalValue_TEXT : Value.VALUETYPE_TEXT,
+ definitions.cICalValue_TIME : Value.VALUETYPE_TIME,
+ definitions.cICalValue_URI : Value.VALUETYPE_URI,
+ definitions.cICalValue_UTC_OFFSET : Value.VALUETYPE_UTC_OFFSET,
+ }
+
+ sTypeValueMap = {
+
+ # 5545 Section 3.3
+ Value.VALUETYPE_BINARY : definitions.cICalValue_BINARY,
+ Value.VALUETYPE_BOOLEAN : definitions.cICalValue_BOOLEAN,
+ Value.VALUETYPE_CALADDRESS : definitions.cICalValue_CAL_ADDRESS,
+ Value.VALUETYPE_DATE : definitions.cICalValue_DATE,
+ Value.VALUETYPE_DATETIME : definitions.cICalValue_DATE_TIME,
+ Value.VALUETYPE_DURATION : definitions.cICalValue_DURATION,
+ Value.VALUETYPE_FLOAT : definitions.cICalValue_FLOAT,
+ Value.VALUETYPE_GEO : definitions.cICalValue_FLOAT,
+ Value.VALUETYPE_INTEGER : definitions.cICalValue_INTEGER,
+ Value.VALUETYPE_PERIOD : definitions.cICalValue_PERIOD,
+ Value.VALUETYPE_RECUR : definitions.cICalValue_RECUR,
+ Value.VALUETYPE_TEXT : definitions.cICalValue_TEXT,
+ Value.VALUETYPE_REQUEST_STATUS : definitions.cICalValue_TEXT,
+ Value.VALUETYPE_TIME : definitions.cICalValue_TIME,
+ Value.VALUETYPE_URI : definitions.cICalValue_URI,
+ Value.VALUETYPE_UTC_OFFSET : definitions.cICalValue_UTC_OFFSET,
+ }
+
+ sMultiValues = set((
+ definitions.cICalProperty_CATEGORIES,
+ definitions.cICalProperty_RESOURCES,
+ definitions.cICalProperty_FREEBUSY,
+ definitions.cICalProperty_EXDATE,
+ definitions.cICalProperty_RDATE,
+ definitions.cICalProperty_POLL_PROPERTIES,
+ ))
+
+ sSpecialVariants = {
+ definitions.cICalProperty_GEO : Value.VALUETYPE_GEO,
+ definitions.cICalProperty_REQUEST_STATUS: Value.VALUETYPE_REQUEST_STATUS,
+ }
+
+ sVariant = "ical"
+
+ sValue = definitions.cICalParameter_VALUE
+ sText = definitions.cICalValue_TEXT
+
+ def __init__(self, name=None, value=None, valuetype=None):
+
+ super(Property, self).__init__(name, value, valuetype)
+
+ # The None check speeds up .duplicate()
+ if value is None:
+ pass
+
+ # Order these based on most likely occurrence to speed up this method
+ elif isinstance(value, str):
+ self._init_attr_value_text(value, valuetype if valuetype else self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN))
+
+ elif isinstance(value, DateTime):
+ self._init_attr_value_datetime(value)
+
+ elif isinstance(value, Duration):
+ self._init_attr_value_duration(value)
+
+ elif isinstance(value, Recurrence):
+ self._init_attr_value_recur(value)
+
+ elif isinstance(value, Period):
+ self._init_attr_value_period(value)
+
+ elif isinstance(value, int):
+ self._init_attr_value_int(value)
+
+ elif isinstance(value, list):
+ if name.upper() == definitions.cICalProperty_REQUEST_STATUS:
+ self._init_attr_value_requeststatus(value)
+ else:
+ period_list = False
+ if len(value) != 0:
+ period_list = isinstance(value[0], Period)
+ if period_list:
+ self._init_attr_value_periodlist(value)
+ else:
+ self._init_attr_value_datetimelist(value)
+
+ elif isinstance(value, UTCOffsetValue):
+ self._init_attr_value_utcoffset(value)
+
+
+ def duplicate(self):
+ other = Property(self.mName)
+ for attrname, attrs in self.mParameters.items():
+ other.mParameters[attrname] = [i.duplicate() for i in attrs]
+ other.mValue = self.mValue.duplicate()
+
+ return other
+
+
+ def __hash__(self):
+ return hash((
+ self.mName,
+ tuple([tuple(self.mParameters[attrname]) for attrname in sorted(self.mParameters.keys())]),
+ self.mValue,
+ ))
+
+
+ def __eq__(self, other):
+ if not isinstance(other, Property):
+ return False
+ return self.mName == other.mName and self.mValue == other.mValue and self.mParameters == other.mParameters
+
+
+ def getRecurrenceValue(self):
+
+ if isinstance(self.mValue, RecurrenceValue):
+ return self.mValue
+ else:
+ return None
+
+
+ def _postCreateValue(self, value_type):
+ """
+ Do some extra work after creating a value in this property.
+
+ @param value_type: the iCalendar VALUE type for this property
+ @type value_type: C{str}
+ """
+
+ # Look for TZID parameter
+ if value_type in (Value.VALUETYPE_TIME, Value.VALUETYPE_DATETIME) and self.hasParameter(definitions.cICalParameter_TZID):
+ tzid = self.getParameterValue(definitions.cICalParameter_TZID)
+
+ if isinstance(self.mValue, DateTimeValue):
+ self.mValue.getValue().setTimezoneID(tzid)
+
+ elif isinstance(self.mValue, MultiValue):
+ for item in self.mValue.getValues():
+ if isinstance(item, DateTimeValue):
+ item.getValue().setTimezoneID(tzid)
+
+
+ # Creation
+ def _init_attr_value_requeststatus(self, reqstatus):
+ # Value
+ self.mValue = RequestStatusValue(reqstatus)
+
+ # Parameters
+ self.setupValueParameter()
+
+
+ def _init_attr_value_datetime(self, dt):
+ # Value
+ self.mValue = DateTimeValue(value=dt)
+
+ # Parameters
+ self.setupValueParameter()
+
+ # Look for timezone
+ if not dt.isDateOnly() and dt.local():
+ if definitions.cICalParameter_TZID in self.mParameters:
+ del self.mParameters[definitions.cICalParameter_TZID]
+ self.mParameters.setdefault(definitions.cICalParameter_TZID, []).append(
+ Parameter(name=definitions.cICalParameter_TZID, value=dt.getTimezoneID()))
+
+
+ def _init_attr_value_datetimelist(self, dtl):
+ # Value
+ date_only = (len(dtl) > 0) and dtl[0].isDateOnly()
+ if date_only:
+ self.mValue = MultiValue(Value.VALUETYPE_DATE)
+ else:
+ self.mValue = MultiValue(Value.VALUETYPE_DATETIME)
+
+ for dt in dtl:
+ self.mValue.addValue(DateTimeValue(dt))
+
+ # Parameters
+ self.setupValueParameter()
+
+ # Look for timezone
+ if ((len(dtl) > 0)
+ and not dtl[0].isDateOnly()
+ and dtl[0].local()):
+ if definitions.cICalParameter_TZID in self.mParameters:
+ del self.mParameters[definitions.cICalParameter_TZID]
+ self.mParameters.setdefault(definitions.cICalParameter_TZID, []).append(
+ Parameter(name=definitions.cICalParameter_TZID, value=dtl[0].getTimezoneID()))
+
+
+ def _init_attr_value_periodlist(self, periodlist):
+ # Value
+ self.mValue = MultiValue(Value.VALUETYPE_PERIOD)
+ for period in periodlist:
+ self.mValue.addValue(PeriodValue(period))
+
+ # Parameters
+ self.setupValueParameter()
+
+
+ def _init_attr_value_duration(self, du):
+ # Value
+ self.mValue = DurationValue(value=du)
+
+ # Parameters
+ self.setupValueParameter()
+
+
+ def _init_attr_value_period(self, pe):
+ # Value
+ self.mValue = PeriodValue(value=pe)
+
+ # Parameters
+ self.setupValueParameter()
+
+
+ def _init_attr_value_recur(self, recur):
+ # Value
+ self.mValue = RecurrenceValue(value=recur)
+
+ # Parameters
+ self.setupValueParameter()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrecurrencepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrecurrencepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/recurrence.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,1710 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar import xmlutils
+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions, xmldefinitions
+from pycalendar.period import Period
+from pycalendar.valueutils import ValueMixin
+import cStringIO as StringIO
+import xml.etree.cElementTree as XML
+
+def WeekDayNumCompare_compare(w1, w2):
+
+ if w1[0] < w2[0]:
+ return -1
+ elif w1[0] > w2[0]:
+ return 1
+ elif w1[1] < w2[1]:
+ return -1
+ elif w1[1] > w2[1]:
+ return 1
+ else:
+ return 0
+
+
+
+def WeekDayNumSort_less_than(w1, w2):
+
+ return (w1[0] < w2[0]) or (w1[0] == w2[0]) and (w1[1] < w2[1])
+
+
+
+class Recurrence(ValueMixin):
+
+ cFreqMap = {
+ definitions.cICalValue_RECUR_SECONDLY : definitions.eRecurrence_SECONDLY,
+ definitions.cICalValue_RECUR_MINUTELY : definitions.eRecurrence_MINUTELY,
+ definitions.cICalValue_RECUR_HOURLY : definitions.eRecurrence_HOURLY,
+ definitions.cICalValue_RECUR_DAILY : definitions.eRecurrence_DAILY,
+ definitions.cICalValue_RECUR_WEEKLY : definitions.eRecurrence_WEEKLY,
+ definitions.cICalValue_RECUR_MONTHLY : definitions.eRecurrence_MONTHLY,
+ definitions.cICalValue_RECUR_YEARLY : definitions.eRecurrence_YEARLY,
+ }
+
+ cFreqToXMLMap = {
+ definitions.eRecurrence_SECONDLY: xmldefinitions.recur_freq_secondly,
+ definitions.eRecurrence_MINUTELY: xmldefinitions.recur_freq_minutely,
+ definitions.eRecurrence_HOURLY: xmldefinitions.recur_freq_hourly,
+ definitions.eRecurrence_DAILY: xmldefinitions.recur_freq_daily,
+ definitions.eRecurrence_WEEKLY: xmldefinitions.recur_freq_weekly,
+ definitions.eRecurrence_MONTHLY: xmldefinitions.recur_freq_monthly,
+ definitions.eRecurrence_YEARLY: xmldefinitions.recur_freq_yearly,
+ }
+
+ cRecurMap = {
+ definitions.cICalValue_RECUR_FREQ : definitions.eRecurrence_FREQ,
+ definitions.cICalValue_RECUR_UNTIL : definitions.eRecurrence_UNTIL,
+ definitions.cICalValue_RECUR_COUNT : definitions.eRecurrence_COUNT,
+ definitions.cICalValue_RECUR_INTERVAL : definitions.eRecurrence_INTERVAL,
+ definitions.cICalValue_RECUR_BYSECOND : definitions.eRecurrence_BYSECOND,
+ definitions.cICalValue_RECUR_BYMINUTE : definitions.eRecurrence_BYMINUTE,
+ definitions.cICalValue_RECUR_BYHOUR : definitions.eRecurrence_BYHOUR,
+ definitions.cICalValue_RECUR_BYDAY : definitions.eRecurrence_BYDAY,
+ definitions.cICalValue_RECUR_BYMONTHDAY : definitions.eRecurrence_BYMONTHDAY,
+ definitions.cICalValue_RECUR_BYYEARDAY : definitions.eRecurrence_BYYEARDAY,
+ definitions.cICalValue_RECUR_BYWEEKNO : definitions.eRecurrence_BYWEEKNO,
+ definitions.cICalValue_RECUR_BYMONTH : definitions.eRecurrence_BYMONTH,
+ definitions.cICalValue_RECUR_BYSETPOS : definitions.eRecurrence_BYSETPOS,
+ definitions.cICalValue_RECUR_WKST : definitions.eRecurrence_WKST,
+ }
+
+ cWeekdayMap = {
+ definitions.cICalValue_RECUR_WEEKDAY_SU : definitions.eRecurrence_WEEKDAY_SU,
+ definitions.cICalValue_RECUR_WEEKDAY_MO : definitions.eRecurrence_WEEKDAY_MO,
+ definitions.cICalValue_RECUR_WEEKDAY_TU : definitions.eRecurrence_WEEKDAY_TU,
+ definitions.cICalValue_RECUR_WEEKDAY_WE : definitions.eRecurrence_WEEKDAY_WE,
+ definitions.cICalValue_RECUR_WEEKDAY_TH : definitions.eRecurrence_WEEKDAY_TH,
+ definitions.cICalValue_RECUR_WEEKDAY_FR : definitions.eRecurrence_WEEKDAY_FR,
+ definitions.cICalValue_RECUR_WEEKDAY_SA : definitions.eRecurrence_WEEKDAY_SA,
+ }
+
+ cWeekdayRecurMap = dict([(v, k) for k, v in cWeekdayMap.items()])
+
+ cUnknownIndex = -1
+
+ def __init__(self):
+ self.init_Recurrence()
+
+
+ def duplicate(self):
+ other = Recurrence()
+
+ other.mFreq = self.mFreq
+
+ other.mUseCount = self.mUseCount
+ other.mCount = self.mCount
+ other.mUseUntil = self.mUseUntil
+ if other.mUseUntil:
+ other.mUntil = self.mUntil.duplicate()
+
+ other.mInterval = self.mInterval
+ if self.mBySeconds is not None:
+ other.mBySeconds = self.mBySeconds[:]
+ if self.mByMinutes is not None:
+ other.mByMinutes = self.mByMinutes[:]
+ if self.mByHours is not None:
+ other.mByHours = self.mByHours[:]
+ if self.mByDay is not None:
+ other.mByDay = self.mByDay[:]
+ if self.mByMonthDay is not None:
+ other.mByMonthDay = self.mByMonthDay[:]
+ if self.mByYearDay is not None:
+ other.mByYearDay = self.mByYearDay[:]
+ if self.mByWeekNo is not None:
+ other.mByWeekNo = self.mByWeekNo[:]
+ if self.mByMonth is not None:
+ other.mByMonth = self.mByMonth[:]
+ if self.mBySetPos is not None:
+ other.mBySetPos = self.mBySetPos[:]
+ other.mWeekstart = self.mWeekstart
+
+ other.mCached = self.mCached
+ if self.mCacheStart:
+ other.mCacheStart = self.mCacheStart.duplicate()
+ if self.mCacheUpto:
+ other.mCacheUpto = self.mCacheUpto.duplicate()
+ other.mFullyCached = self.mFullyCached
+ if self.mRecurrences:
+ other.mRecurrences = self.mRecurrences[:]
+
+ return other
+
+
+ def init_Recurrence(self):
+ self.mFreq = definitions.eRecurrence_YEARLY
+
+ self.mUseCount = False
+ self.mCount = 0
+
+ self.mUseUntil = False
+ self.mUntil = None
+
+ self.mInterval = 1
+ self.mBySeconds = None
+ self.mByMinutes = None
+ self.mByHours = None
+ self.mByDay = None
+ self.mByMonthDay = None
+ self.mByYearDay = None
+ self.mByWeekNo = None
+ self.mByMonth = None
+ self.mBySetPos = None
+ self.mWeekstart = definitions.eRecurrence_WEEKDAY_MO
+
+ self.mCached = False
+ self.mCacheStart = None
+ self.mCacheUpto = None
+ self.mFullyCached = False
+ self.mRecurrences = None
+
+
+ def __hash__(self):
+ return hash((
+ self.mFreq,
+ self.mUseCount,
+ self.mCount,
+ self.mUseUntil,
+ self.mUntil,
+ self.mInterval,
+ tuple(self.mBySeconds) if self.mBySeconds else None,
+ tuple(self.mByMinutes) if self.mByMinutes else None,
+ tuple(self.mByHours) if self.mByHours else None,
+ tuple(self.mByDay) if self.mByDay else None,
+ tuple(self.mByMonthDay) if self.mByMonthDay else None,
+ tuple(self.mByYearDay) if self.mByYearDay else None,
+ tuple(self.mByWeekNo) if self.mByWeekNo else None,
+ tuple(self.mByMonth) if self.mByMonth else None,
+ tuple(self.mBySetPos) if self.mBySetPos else None,
+ self.mWeekstart,
+ ))
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+ def __eq__(self, other):
+ if not isinstance(other, Recurrence):
+ return False
+ return self.equals(other)
+
+
+ def equals(self, comp):
+ return (self.mFreq == comp.mFreq) \
+ and (self.mUseCount == comp.mUseCount) and (self.mCount == comp.mCount) \
+ and (self.mUseUntil == comp.mUseUntil) and (self.mUntil == comp.mUntil) \
+ and (self.mInterval == comp.mInterval) \
+ and self.equalsNum(self.mBySeconds, comp.mBySeconds) \
+ and self.equalsNum(self.mByMinutes, comp.mByMinutes) \
+ and self.equalsNum(self.mByHours, comp.mByHours) \
+ and self.equalsDayNum(self.mByDay, comp.mByDay) \
+ and self.equalsNum(self.mByMonthDay, comp.mByMonthDay) \
+ and self.equalsNum(self.mByYearDay, comp.mByYearDay) \
+ and self.equalsNum(self.mByWeekNo, comp.mByWeekNo) \
+ and self.equalsNum(self.mByMonth, comp.mByMonth) \
+ and self.equalsNum(self.mBySetPos, comp.mBySetPos) \
+ and (self.mWeekstart == comp.mWeekstart)
+
+
+ def equalsNum(self, items1, items2):
+ # Check sizes first
+ if items1 is None:
+ items1 = []
+ if items2 is None:
+ items2 = []
+ if len(items1) != len(items2):
+ return False
+ elif len(items1) == 0:
+ return True
+
+ # Copy and sort each one for comparison
+ temp1 = items1[:]
+ temp2 = items2[:]
+ temp1.sort()
+ temp2.sort()
+
+ for i in range(0, len(temp1)):
+ if temp1[i] != temp2[i]:
+ return False
+ return True
+
+
+ def equalsDayNum(self, items1, items2):
+ # Check sizes first
+ if items1 is None:
+ items1 = []
+ if items2 is None:
+ items2 = []
+ if len(items1) != len(items2):
+ return False
+ elif len(items1) == 0:
+ return True
+
+ # Copy and sort each one for comparison
+ temp1 = items1[:]
+ temp2 = items2[:]
+ temp1.sort()
+ temp2.sort()
+
+ for i in range(0, len(temp1)):
+ if temp1[i] != temp2[i]:
+ return False
+ return True
+
+
+ def _setAndclearIfChanged(self, attr, value):
+ if getattr(self, attr) != value:
+ self.clear()
+ setattr(self, attr, value)
+
+
+ def getFreq(self):
+ return self.mFreq
+
+
+ def setFreq(self, freq):
+ self._setAndclearIfChanged("mFreq", freq)
+
+
+ def getUseUntil(self):
+ return self.mUseUntil
+
+
+ def setUseUntil(self, use_until):
+ self._setAndclearIfChanged("mUseUntil", use_until)
+
+
+ def getUntil(self):
+ return self.mUntil
+
+
+ def setUntil(self, until):
+ self._setAndclearIfChanged("mUntil", until)
+
+
+ def getUseCount(self):
+ return self.mUseCount
+
+
+ def setUseCount(self, use_count):
+ self._setAndclearIfChanged("mUseCount", use_count)
+
+
+ def getCount(self):
+ return self.mCount
+
+
+ def setCount(self, count):
+ self._setAndclearIfChanged("mCount", count)
+
+
+ def getInterval(self):
+ return self.mInterval
+
+
+ def setInterval(self, interval):
+ self._setAndclearIfChanged("mInterval", interval)
+
+
+ def getByMonth(self):
+ return self.mByMonth
+
+
+ def setByMonth(self, by):
+ self._setAndclearIfChanged("mByMonth", by[:])
+
+
+ def getByMonthDay(self):
+ return self.mByMonthDay
+
+
+ def setByMonthDay(self, by):
+ self._setAndclearIfChanged("mByMonthDay", by[:])
+
+
+ def getByYearDay(self):
+ return self.mByYearDay
+
+
+ def setByYearDay(self, by):
+ self._setAndclearIfChanged("mByYearDay", by[:])
+
+
+ def getByDay(self):
+ return self.mByDay
+
+
+ def setByDay(self, by):
+ self._setAndclearIfChanged("mByDay", by[:])
+
+
+ def getBySetPos(self):
+ return self.mBySetPos
+
+
+ def setBySetPos(self, by):
+ self._setAndclearIfChanged("mBySetPos", by[:])
+
+
+ def parse(self, data):
+ self.init_Recurrence()
+
+ # Tokenise using ''
+ tokens = data.split(";")
+ tokens.reverse()
+
+ if len(tokens) == 0:
+ raise ValueError("Recurrence: Invalid recurrence rule value")
+
+ while len(tokens) != 0:
+ # Get next token
+ token = tokens.pop()
+ try:
+ tname, tvalue = token.split("=")
+ except ValueError:
+ raise ValueError("Recurrence: Invalid token '%s'" % (token,))
+
+ # Determine token type
+ index = Recurrence.cRecurMap.get(tname, Recurrence.cUnknownIndex)
+ if index == Recurrence.cUnknownIndex:
+ raise ValueError("Recurrence: Invalid token '%s'" % (tname,))
+
+ # Parse remainder based on index
+ if index == definitions.eRecurrence_FREQ:
+ # Get the FREQ value
+ index = Recurrence.cFreqMap.get(tvalue, Recurrence.cUnknownIndex)
+ if index == Recurrence.cUnknownIndex:
+ raise ValueError("Recurrence: Invalid FREQ value")
+ self.mFreq = index
+
+ elif index == definitions.eRecurrence_UNTIL:
+ if self.mUseCount:
+ raise ValueError("Recurrence: Can't have both UNTIL and COUNT")
+ self.mUseUntil = True
+ if self.mUntil is None:
+ self.mUntil = DateTime()
+ try:
+ self.mUntil.parse(tvalue)
+ except ValueError:
+ raise ValueError("Recurrence: Invalid UNTIL value")
+
+ elif index == definitions.eRecurrence_COUNT:
+ if self.mUseUntil:
+ raise ValueError("Recurrence: Can't have both UNTIL and COUNT")
+ self.mUseCount = True
+ try:
+ self.mCount = int(tvalue)
+ except ValueError:
+ raise ValueError("Recurrence: Invalid COUNT value")
+
+ # Must not be less than one
+ if self.mCount < 1:
+ raise ValueError("Recurrence: Invalid COUNT value")
+
+ elif index == definitions.eRecurrence_INTERVAL:
+ try:
+ self.mInterval = int(tvalue)
+ except ValueError:
+ raise ValueError("Recurrence: Invalid INTERVAL value")
+
+ # Must NOT be less than one
+ if self.mInterval < 1:
+ raise ValueError("Recurrence: Invalid INTERVAL value")
+
+ elif index == definitions.eRecurrence_BYSECOND:
+ if self.mBySeconds is not None:
+ raise ValueError("Recurrence: Only one BYSECOND allowed")
+ self.mBySeconds = []
+ self.parseList(tvalue, self.mBySeconds, 0, 60, errmsg="Recurrence: Invalid BYSECOND value")
+
+ elif index == definitions.eRecurrence_BYMINUTE:
+ if self.mByMinutes is not None:
+ raise ValueError("Recurrence: Only one BYMINUTE allowed")
+ self.mByMinutes = []
+ self.parseList(tvalue, self.mByMinutes, 0, 59, errmsg="Recurrence: Invalid BYMINUTE value")
+
+ elif index == definitions.eRecurrence_BYHOUR:
+ if self.mByHours is not None:
+ raise ValueError("Recurrence: Only one BYHOUR allowed")
+ self.mByHours = []
+ self.parseList(tvalue, self.mByHours, 0, 23, errmsg="Recurrence: Invalid BYHOUR value")
+
+ elif index == definitions.eRecurrence_BYDAY:
+ if self.mByDay is not None:
+ raise ValueError("Recurrence: Only one BYDAY allowed")
+ self.mByDay = []
+ self.parseListDW(tvalue, self.mByDay, errmsg="Recurrence: Invalid BYDAY value")
+
+ elif index == definitions.eRecurrence_BYMONTHDAY:
+ if self.mByMonthDay is not None:
+ raise ValueError("Recurrence: Only one BYMONTHDAY allowed")
+ self.mByMonthDay = []
+ self.parseList(tvalue, self.mByMonthDay, 1, 31, True, errmsg="Recurrence: Invalid BYMONTHDAY value")
+
+ elif index == definitions.eRecurrence_BYYEARDAY:
+ if self.mByYearDay is not None:
+ raise ValueError("Recurrence: Only one BYYEARDAY allowed")
+ self.mByYearDay = []
+ self.parseList(tvalue, self.mByYearDay, 1, 366, True, errmsg="Recurrence: Invalid BYYEARDAY value")
+
+ elif index == definitions.eRecurrence_BYWEEKNO:
+ if self.mByWeekNo is not None:
+ raise ValueError("Recurrence: Only one BYWEEKNO allowed")
+ self.mByWeekNo = []
+ self.parseList(tvalue, self.mByWeekNo, 1, 53, True, errmsg="Recurrence: Invalid BYWEEKNO value")
+
+ elif index == definitions.eRecurrence_BYMONTH:
+ if self.mByMonth is not None:
+ raise ValueError("Recurrence: Only one BYMONTH allowed")
+ self.mByMonth = []
+ self.parseList(tvalue, self.mByMonth, 1, 12, errmsg="Recurrence: Invalid BYMONTH value")
+
+ elif index == definitions.eRecurrence_BYSETPOS:
+ if self.mBySetPos is not None:
+ raise ValueError("Recurrence: Only one BYSETPOS allowed")
+ self.mBySetPos = []
+ self.parseList(tvalue, self.mBySetPos, allowNegative=True, errmsg="Recurrence: Invalid BYSETPOS value")
+
+ elif index == definitions.eRecurrence_WKST:
+ index = Recurrence.cWeekdayMap.get(tvalue, Recurrence.cUnknownIndex)
+ if (index == Recurrence.cUnknownIndex):
+ raise ValueError("Recurrence: Invalid WKST value")
+ self.mWeekstart = index
+
+
+ def parseList(self, txt, list, min=None, max=None, allowNegative=False, errmsg=""):
+
+ if "," in txt:
+ tokens = txt.split(",")
+ else:
+ tokens = (txt,)
+
+ for token in tokens:
+ value = int(token)
+ if not allowNegative and value < 0:
+ raise ValueError(errmsg)
+ avalue = abs(value)
+ if min is not None and avalue < min:
+ raise ValueError(errmsg)
+ if max is not None and avalue > max:
+ raise ValueError(errmsg)
+ list.append(value)
+
+
+ def parseListDW(self, txt, list, errmsg=""):
+
+ if "," in txt:
+ tokens = txt.split(",")
+ else:
+ tokens = (txt,)
+
+ for token in tokens:
+ # Get number if present
+ num = 0
+ if (len(token) > 0) and token[0] in "+-1234567890":
+ offset = 0
+ while (offset < len(token)) and token[offset] in "+-1234567890":
+ offset += 1
+
+ num = int(token[0:offset])
+ token = token[offset:]
+
+ anum = abs(num)
+ if anum < 1:
+ raise ValueError(errmsg)
+ if anum > 53:
+ raise ValueError(errmsg)
+
+ # Get day
+ index = Recurrence.cWeekdayMap.get(token, Recurrence.cUnknownIndex)
+ if (index == Recurrence.cUnknownIndex):
+ raise ValueError(errmsg)
+ wday = index
+
+ list.append((num, wday))
+
+
+ def generate(self, os):
+ try:
+ os.write(definitions.cICalValue_RECUR_FREQ)
+ os.write("=")
+
+ if self.mFreq == definitions.eRecurrence_SECONDLY:
+ os.write(definitions.cICalValue_RECUR_SECONDLY)
+
+ elif self.mFreq == definitions.eRecurrence_MINUTELY:
+ os.write(definitions.cICalValue_RECUR_MINUTELY)
+
+ elif self.mFreq == definitions.eRecurrence_HOURLY:
+ os.write(definitions.cICalValue_RECUR_HOURLY)
+
+ elif self.mFreq == definitions.eRecurrence_DAILY:
+ os.write(definitions.cICalValue_RECUR_DAILY)
+
+ elif self.mFreq == definitions.eRecurrence_WEEKLY:
+ os.write(definitions.cICalValue_RECUR_WEEKLY)
+
+ elif self.mFreq == definitions.eRecurrence_MONTHLY:
+ os.write(definitions.cICalValue_RECUR_MONTHLY)
+
+ elif self.mFreq == definitions.eRecurrence_YEARLY:
+ os.write(definitions.cICalValue_RECUR_YEARLY)
+
+ if self.mUseCount:
+ os.write(";")
+ os.write(definitions.cICalValue_RECUR_COUNT)
+ os.write("=")
+ os.write(str(self.mCount))
+ elif self.mUseUntil:
+ os.write(";")
+ os.write(definitions.cICalValue_RECUR_UNTIL)
+ os.write("=")
+ self.mUntil.generate(os)
+
+ if self.mInterval > 1:
+ os.write(";")
+ os.write(definitions.cICalValue_RECUR_INTERVAL)
+ os.write("=")
+ os.write(str(self.mInterval))
+
+ self.generateList(os, definitions.cICalValue_RECUR_BYSECOND, self.mBySeconds)
+ self.generateList(os, definitions.cICalValue_RECUR_BYMINUTE, self.mByMinutes)
+ self.generateList(os, definitions.cICalValue_RECUR_BYHOUR, self.mByHours)
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ os.write(";")
+ os.write(definitions.cICalValue_RECUR_BYDAY)
+ os.write("=")
+ comma = False
+ for iter in self.mByDay:
+ if comma:
+ os.write(",")
+ comma = True
+
+ if iter[0] != 0:
+ os.write(str(iter[0]))
+
+ if iter[1] == definitions.eRecurrence_WEEKDAY_SU:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
+
+ elif iter[1] == definitions.eRecurrence_WEEKDAY_MO:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+ elif iter[1] == definitions.eRecurrence_WEEKDAY_TU:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
+
+ elif iter[1] == definitions.eRecurrence_WEEKDAY_WE:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
+
+ elif iter[1] == definitions.eRecurrence_WEEKDAY_TH:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
+
+ elif iter[1] == definitions.eRecurrence_WEEKDAY_FR:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
+
+ elif iter[1] == definitions.eRecurrence_WEEKDAY_SA:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
+
+ self.generateList(os, definitions.cICalValue_RECUR_BYMONTHDAY, self.mByMonthDay)
+ self.generateList(os, definitions.cICalValue_RECUR_BYYEARDAY, self.mByYearDay)
+ self.generateList(os, definitions.cICalValue_RECUR_BYWEEKNO, self.mByWeekNo)
+ self.generateList(os, definitions.cICalValue_RECUR_BYMONTH, self.mByMonth)
+ self.generateList(os, definitions.cICalValue_RECUR_BYSETPOS, self.mBySetPos)
+
+ # MO is the default so we do not need it
+ if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
+ os.write(";")
+ os.write(definitions.cICalValue_RECUR_WKST)
+ os.write("=")
+
+ if self.mWeekstart == definitions.eRecurrence_WEEKDAY_SU:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
+
+ elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_MO:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+ elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TU:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
+
+ elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_WE:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
+
+ elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TH:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
+
+ elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_FR:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
+
+ elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_SA:
+ os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
+
+ except:
+ pass
+
+
+ def generateList(self, os, title, items):
+
+ if (items is not None) and (len(items) != 0):
+ os.write(";")
+ os.write(title)
+ os.write("=")
+ comma = False
+ for e in items:
+ if comma:
+ os.write(",")
+ comma = True
+ os.write(str(e))
+
+
+ def writeXML(self, node, namespace):
+
+ recur = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.value_recur))
+
+ freq = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_freq))
+ freq.text = self.cFreqToXMLMap[self.mFreq]
+
+ if self.mUseCount:
+ count = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_count))
+ count.text = str(self.mCount)
+ elif self.mUseUntil:
+ until = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_until))
+ self.mUntil.writeXML(until, namespace)
+
+ if self.mInterval > 1:
+ interval = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_interval))
+ interval.text = str(self.mInterval)
+
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_bysecond, self.mBySeconds)
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_byminute, self.mByMinutes)
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_byhour, self.mByHours)
+
+ if self.mByDay is not None and len(self.mByDay) != 0:
+ for iter in self.mByDay:
+ byday = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_byday))
+ data = ""
+ if iter[0] != 0:
+ data = str(iter[0])
+ data += self.cWeekdayRecurMap.get(iter[1], "")
+ byday.text = data
+
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_bymonthday, self.mByMonthDay)
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_byyearday, self.mByYearDay)
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_byweekno, self.mByWeekNo)
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_bymonth, self.mByMonth)
+ self.writeXMLList(recur, namespace, xmldefinitions.recur_bysetpos, self.mBySetPos)
+
+ # MO is the default so we do not need it
+ if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
+ wkst = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_wkst))
+ wkst.text = self.cWeekdayRecurMap.get(self.mWeekstart, definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+
+ def writeXMLList(self, node, namespace, name, items):
+ if items is not None and len(items) != 0:
+ for item in items:
+ child = XML.SubElement(node, xmlutils.makeTag(namespace, name))
+ child.text = str(item)
+
+
+ def parseJSON(self, jobject):
+ """
+ jCal splits the value into components. We need to convert that back to the
+ iCalendar string format, then parse it.
+ """
+
+ items = []
+ for name, value in jobject.items():
+ if name in (
+ "bysecond", "byminute", "byhour",
+ "bymonthday", "byyearday", "byweekno",
+ "bymonth", "bysetpos", "byday",
+ ):
+ if not isinstance(value, str) and not isinstance(value, unicode) and not isinstance(value, int):
+ value = ",".join(map(str, value))
+ elif name == "until":
+ value = value.replace("-", "").replace(":", "")
+ items.append("%s=%s" % (name.upper(), value,))
+ self.parse(";".join(items))
+
+
+ def writeJSON(self, jobject):
+ """
+ jCal splits the value into components. We need to convert that back to the
+ iCalendar string format, then parse it.
+ """
+ jdict = {}
+
+ jdict[xmldefinitions.recur_freq] = self.cFreqToXMLMap[self.mFreq]
+
+ if self.mUseCount:
+ jdict[xmldefinitions.recur_count] = self.mCount
+ elif self.mUseUntil:
+ jdict[xmldefinitions.recur_until] = self.mUntil.getXMLText()
+
+ if self.mInterval > 1:
+ jdict[xmldefinitions.recur_interval] = self.mInterval
+
+ if self.mBySeconds:
+ jdict[xmldefinitions.recur_bysecond] = self.mBySeconds
+ if self.mByMinutes:
+ jdict[xmldefinitions.recur_byminute] = self.mByMinutes
+ if self.mByHours:
+ jdict[xmldefinitions.recur_byhour] = self.mByHours
+
+ if self.mByDay is not None and len(self.mByDay) != 0:
+ items = []
+ for iter in self.mByDay:
+ data = ""
+ if iter[0] != 0:
+ data = str(iter[0])
+ data += self.cWeekdayRecurMap.get(iter[1], "")
+ items.append(data)
+ jdict[xmldefinitions.recur_byday] = items
+
+ if self.mByMonthDay:
+ jdict[xmldefinitions.recur_bymonthday] = self.mByMonthDay
+ if self.mByYearDay:
+ jdict[xmldefinitions.recur_byyearday] = self.mByYearDay
+ if self.mByWeekNo:
+ jdict[xmldefinitions.recur_byweekno] = self.mByWeekNo
+ if self.mByMonth:
+ jdict[xmldefinitions.recur_bymonth] = self.mByMonth
+ if self.mBySetPos:
+ jdict[xmldefinitions.recur_bysetpos] = self.mBySetPos
+
+ # MO is the default so we do not need it
+ if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
+ jdict[xmldefinitions.recur_wkst] = self.cWeekdayRecurMap.get(self.mWeekstart, definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+ jobject.append(jdict)
+
+
+ def hasBy(self):
+ return (self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
+ or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
+ or (self.mByHours is not None) and (len(self.mByHours) != 0) \
+ or (self.mByDay is not None) and (len(self.mByDay) != 0) \
+ or (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0) \
+ or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
+ or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0) \
+ or (self.mByMonth is not None) and (len(self.mByMonth) != 0) \
+ or (self.mBySetPos is not None) and (len(self.mBySetPos) != 0)
+
+
+ def isSimpleRule(self):
+ # One that has no BYxxx rules
+ return not self.hasBy()
+
+
+ def isAdvancedRule(self):
+ # One that has BYMONTH,
+ # BYMONTHDAY (with no negative value),
+ # BYDAY (with multiple unnumbered, or numbered with all the same number
+ # (1..4, -2, -1)
+ # BYSETPOS with +1, or -1 only
+ # no others
+
+ # First checks the ones we do not handle at all
+ if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
+ or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
+ or (self.mByHours is not None) and (len(self.mByHours) != 0) \
+ or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
+ or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0)):
+ return False
+
+ # Check BYMONTHDAY numbers (we can handle -7...-1, 1..31)
+ if self.mByMonthDay is not None:
+ for iter in self.mByMonthDay:
+ if (iter < -7) or (iter > 31) or (iter == 0):
+ return False
+
+ # Check BYDAY numbers
+ if self.mByDay is not None:
+ number = 0
+ first = True
+ for iter in self.mByDay:
+
+ # Get the first number
+ if (first):
+ number = iter[0]
+ first = False
+
+ # Check number range
+ if (number > 4) or (number < -2):
+ return False
+
+ # If current differs from last, then we have an error
+ elif number != iter[0]:
+ return False
+
+ # Check BYSETPOS numbers
+ if self.mBySetPos is not None:
+ if len(self.mBySetPos) > 1:
+ return False
+ if (len(self.mBySetPos) == 1) and (self.mBySetPos[0] != -1) and (self.mBySetPos[0] != 1):
+ return False
+
+ # If we get here it must be OK
+ return True
+
+
+ def getUIDescription(self):
+ try:
+ # For now just use iCal item
+ sout = StringIO()
+ self.generate(sout)
+ result = sout.getvalue()
+ except:
+ result = ""
+
+ return result
+
+
+ def expand(self, start, range, items, float_offset=0):
+
+ # Must have recurrence list at this point
+ if self.mRecurrences is None:
+ self.mRecurrences = []
+
+ # Wipe cache if start is different
+ if self.mCached and (start != self.mCacheStart):
+ self.mCached = False
+ self.mFullyCached = False
+ self.mRecurrences = []
+
+ # Is the current cache complete or does it extend past the requested
+ # range end
+ if not self.mCached or not self.mFullyCached \
+ and (self.mCacheUpto is None or self.mCacheUpto < range.getEnd()):
+ cache_range = range.duplicate()
+
+ # If partially cached just cache from previous cache end up to new
+ # end
+ if self.mCached:
+ cache_range = Period(self.mCacheUpto, range.getEnd())
+
+ # Simple expansion is one where there is no BYXXX rule part
+ if not self.hasBy():
+ self.mFullyCached = self.simpleExpand(start, cache_range, self.mRecurrences, float_offset)
+ else:
+ self.mFullyCached = self.complexExpand(start, cache_range, self.mRecurrences, float_offset)
+
+ # Set cache values
+ self.mCached = True
+ self.mCacheStart = start
+ self.mCacheUpto = range.getEnd()
+
+ # Just return the cached items in the requested range
+ limited = not self.mFullyCached
+ for iter in self.mRecurrences:
+ if range.isDateWithinPeriod(iter):
+ items.append(iter)
+ else:
+ limited = True
+ return limited
+
+
+ def simpleExpand(self, start, range, items, float_offset):
+ start_iter = start.duplicate()
+ ctr = 0
+
+ if self.mUseUntil:
+ float_until = self.mUntil.duplicate()
+ if start.floating():
+ float_until.setTimezoneID(0)
+ float_until.offsetSeconds(float_offset)
+
+ while True:
+ # Exit if after period we want
+ if range.isDateAfterPeriod(start_iter):
+ return False
+
+ # Add current one to list
+ items.append(start_iter.duplicate())
+
+ # Get next item
+ start_iter.recur(self.mFreq, self.mInterval)
+
+ # Check limits
+ if self.mUseCount:
+ # Bump counter and exit if over
+ ctr += 1
+ if ctr >= self.mCount:
+ return True
+ elif self.mUseUntil:
+ # Exit if next item is after until (its OK if its the same as
+ # UNTIL as UNTIL is inclusive)
+ if start_iter > float_until:
+ return True
+
+
+ def complexExpand(self, start, range, items, float_offset):
+ start_iter = start.duplicate()
+ ctr = 0
+
+ if self.mUseUntil:
+ float_until = self.mUntil.duplicate()
+ if start.floating():
+ float_until.setTimezoneID(None)
+ float_until.offsetSeconds(float_offset)
+
+ # Always add the initial instance DTSTART
+ if self.mUseCount:
+ # Bump counter and exit if over
+ ctr += 1
+ if ctr >= self.mCount:
+ return True
+
+ # Need to re-initialise start based on BYxxx rules
+ while True:
+ # Behaviour is based on frequency
+ set_items = []
+
+ if self.mFreq == definitions.eRecurrence_SECONDLY:
+ self.generateSecondlySet(start_iter, set_items)
+
+ elif self.mFreq == definitions.eRecurrence_MINUTELY:
+ self.generateMinutelySet(start_iter, set_items)
+
+ elif self.mFreq == definitions.eRecurrence_HOURLY:
+ self.generateHourlySet(start_iter, set_items)
+
+ elif self.mFreq == definitions.eRecurrence_DAILY:
+ self.generateDailySet(start_iter, set_items)
+
+ elif self.mFreq == definitions.eRecurrence_WEEKLY:
+ self.generateWeeklySet(start_iter, set_items)
+
+ elif self.mFreq == definitions.eRecurrence_MONTHLY:
+ self.generateMonthlySet(start_iter, set_items)
+
+ elif self.mFreq == definitions.eRecurrence_YEARLY:
+ self.generateYearlySet(start_iter, set_items)
+
+ # Always sort the set as BYxxx rules may not be sorted
+ #set_items.sort(cmp=DateTime.sort)
+ set_items.sort(key=lambda x: x.getPosixTime())
+
+ # Process each one in the generated set
+ for iter in set_items:
+
+ # Ignore if it is before the actual start - we need this
+ # because the expansion
+ # can go back in time from the real start, but we must exclude
+ # those when counting
+ # even if they are not within the requested range
+ if iter < start:
+ continue
+
+ # Exit if after period we want
+ if range.isDateAfterPeriod(iter):
+ return False
+
+ # Exit if beyond the UNTIL limit
+ if self.mUseUntil:
+ # Exit if next item is after until (its OK if its the same
+ # as UNTIL as UNTIL is inclusive)
+ if iter > float_until:
+ return True
+
+ # Special for start instance
+ if (ctr == 1) and (start == iter):
+ continue
+
+ # Add current one to list
+ items.append(iter)
+
+ # Check limits
+ if self.mUseCount:
+ # Bump counter and exit if over
+ ctr += 1
+ if ctr >= self.mCount:
+ return True
+
+ # Exit if after period we want
+ if range.isDateAfterPeriod(start_iter):
+ return False
+
+ # Get next item
+ start_iter.recur(self.mFreq, self.mInterval)
+
+
+ def clear(self):
+ self.mCached = False
+ self.mFullyCached = False
+ if self.mRecurrences is not None:
+ self.mRecurrences = []
+
+
+ # IMPORTANT ExcludeFutureRecurrence assumes mCacheStart is setup with the
+ # owning VEVENT's DTSTART
+ # Currently this method is only called when a recurrence is being removed
+ # so
+ # the recurrence data should be cached
+
+ # Exclude dates on or after the chosen one
+ def excludeFutureRecurrence(self, exclude):
+ # Expand the rule up to the exclude date
+ items = []
+ period = Period()
+ period.init(self.mCacheStart, exclude)
+ self.expand(self.mCacheStart, period, items)
+
+ # Adjust UNTIL or add one if no COUNT
+ if self.getUseUntil() or not self.getUseCount():
+ # The last one is just less than the exclude date
+ if len(items) != 0:
+ # Now use the data as the UNTIL
+ self.mUseUntil = True
+ self.mUntil = items[-1]
+
+ # Adjust COUNT
+ elif self.getUseCount():
+ # The last one is just less than the exclude date
+ self.mUseCount = True
+ self.mCount = len(items)
+
+ # Now clear out the cached set after making changes
+ self.clear()
+
+
+ def generateYearlySet(self, start, items):
+ # All possible BYxxx are valid, though some combinations are not
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ items[:] = self.byMonthExpand(items)
+
+ if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byWeekNoExpand(items)
+
+ if (self.mByYearDay is not None) and (len(self.mByYearDay) != 0):
+ items[:] = self.byYearDayExpand(items)
+
+ if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+ items[:] = self.byMonthDayExpand(items)
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ # BYDAY is complicated:
+ # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
+ # contracts the recurrence set
+ # else it expands it, but the expansion depends on the frequency
+ # and other BYxxx periodicities
+
+ if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
+ or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
+ items[:] = self.byDayLimit(items)
+ elif (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byDayExpandWeekly(items)
+ elif (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ items[:] = self.byDayExpandMonthly(items)
+ else:
+ items[:] = self.byDayExpandYearly(items)
+
+ if (self.mByHours is not None) and (len(self.mByHours) != 0):
+ items[:] = self.byHourExpand(items)
+
+ if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+ items[:] = self.byMinuteExpand(items)
+
+ if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+ items[:] = self.bySecondExpand(items)
+
+ if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def generateMonthlySet(self, start, items):
+ # Cannot have BYYEARDAY and BYWEEKNO
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ # BYMONTH limits the range of possible values
+ items[:] = self.byMonthLimit(items)
+ if (len(items) == 0):
+ return
+
+ # No BYWEEKNO
+
+ # No BYYEARDAY
+
+ if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+ items[:] = self.byMonthDayExpand(items)
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ # BYDAY is complicated:
+ # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
+ # contracts the recurrence set
+ # else it expands it, but the expansion depends on the frequency
+ # and other BYxxx periodicities
+
+ if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
+ or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
+ items[:] = self.byDayLimit(items)
+ else:
+ items[:] = self.byDayExpandMonthly(items)
+
+ if ((self.mByHours is not None) and (len(self.mByHours) != 0)):
+ items[:] = self.byHourExpand(items)
+
+ if ((self.mByMinutes is not None) and (len(self.mByMinutes) != 0)):
+ items[:] = self.byMinuteExpand(items)
+
+ if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0)):
+ items[:] = self.bySecondExpand(items)
+
+ if ((self.mBySetPos is not None) and (len(self.mBySetPos) != 0)):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def generateWeeklySet(self, start, items):
+ # Cannot have BYYEARDAY and BYMONTHDAY
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ # BYMONTH limits the range of possible values
+ items[:] = self.byMonthLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byWeekNoLimit(items)
+ if (len(items) == 0):
+ return
+
+ # No BYYEARDAY
+
+ # No BYMONTHDAY
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ items[:] = self.byDayExpandWeekly(items)
+
+ if (self.mByHours is not None) and (len(self.mByHours) != 0):
+ items[:] = self.byHourExpand(items)
+
+ if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+ items[:] = self.byMinuteExpand(items)
+
+ if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+ items[:] = self.bySecondExpand(items)
+
+ if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def generateDailySet(self, start, items):
+ # Cannot have BYYEARDAY
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ # BYMONTH limits the range of possible values
+ items[:] = self.byMonthLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byWeekNoLimit(items)
+ if (len(items) == 0):
+ return
+
+ # No BYYEARDAY
+
+ if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+ items[:] = self.byMonthDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ items[:] = self.byDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByHours is not None) and (len(self.mByHours) != 0):
+ items[:] = self.byHourExpand(items)
+
+ if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+ items[:] = self.byMinuteExpand(items)
+
+ if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+ items[:] = self.bySecondExpand(items)
+
+ if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def generateHourlySet(self, start, items):
+ # Cannot have BYYEARDAY
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ # BYMONTH limits the range of possible values
+ items[:] = self.byMonthLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byWeekNoLimit(items)
+ if (len(items) == 0):
+ return
+
+ # No BYYEARDAY
+
+ if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+ items[:] = self.byMonthDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ items[:] = self.byDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByHours is not None) and (len(self.mByHours) != 0):
+ items[:] = self.byHourLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+ items[:] = self.byMinuteExpand(items)
+
+ if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+ items[:] = self.bySecondExpand(items)
+
+ if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def generateMinutelySet(self, start, items):
+ # Cannot have BYYEARDAY
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ # BYMONTH limits the range of possible values
+ items[:] = self.byMonthLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byWeekNoLimit(items)
+ if (len(items) == 0):
+ return
+
+ # No BYYEARDAY
+
+ if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+ items[:] = self.byMonthDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ items[:] = self.byDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByHours is not None) and (len(self.mByHours) != 0):
+ items[:] = self.byHourLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+ items[:] = self.byMinuteLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+ items[:] = self.bySecondExpand(items)
+
+ if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def generateSecondlySet(self, start, items):
+ # Cannot have BYYEARDAY
+
+ # Start with initial date-time
+ items.append(start.duplicate())
+
+ if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+ # BYMONTH limits the range of possible values
+ items[:] = self.byMonthLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+ items[:] = self.byWeekNoLimit(items)
+ if (len(items) == 0):
+ return
+
+ # No BYYEARDAY
+
+ if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+ items[:] = self.byMonthDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByDay is not None) and (len(self.mByDay) != 0):
+ items[:] = self.byDayLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByHours is not None) and (len(self.mByHours) != 0):
+ items[:] = self.byHourLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+ items[:] = self.byMinuteLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+ items[:] = self.bySecondLimit(items)
+ if (len(items) == 0):
+ return
+
+ if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+ items[:] = self.bySetPosLimit(items)
+
+
+ def byMonthExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYMONTH and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByMonth:
+ temp = iter1.duplicate()
+ temp.setMonth(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def byWeekNoExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYWEEKNO and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByWeekNo:
+ temp = iter1.duplicate()
+ temp.setWeekNo(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def byYearDayExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYYEARDAY and generating a new date-time for it
+ # and insert into output
+ for iter2 in self.mByYearDay:
+ temp = iter1.duplicate()
+ temp.setYearDay(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def byMonthDayExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYMONTHDAY and generating a new date-time for it
+ # and insert into output
+ for iter2 in self.mByMonthDay:
+ temp = iter1.duplicate()
+ temp.setMonthDay(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def byDayExpandYearly(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYDAY and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByDay:
+ # Numeric value means specific instance
+ if iter2[0] != 0:
+ temp = iter1.duplicate()
+ temp.setDayOfWeekInYear(iter2[0], iter2[1])
+ output.append(temp)
+ else:
+ # Every matching day in the year
+ for i in range(1, 54):
+ temp = iter1.duplicate()
+ temp.setDayOfWeekInYear(i, iter2[1])
+ if temp.getYear() == (iter1).getYear():
+ output.append(temp)
+
+ return output
+
+
+ def byDayExpandMonthly(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYDAY and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByDay:
+ # Numeric value means specific instance
+ if iter2[0] != 0:
+ temp = iter1.duplicate()
+ temp.setDayOfWeekInMonth(iter2[0], iter2[1])
+ output.append(temp)
+ else:
+ # Every matching day in the month
+ for i in range(1, 7):
+ temp = iter1.duplicate()
+ temp.setDayOfWeekInMonth(i, iter2[1])
+ if temp.getMonth() == iter1.getMonth():
+ output.append(temp)
+
+ return output
+
+
+ def byDayExpandWeekly(self, dates):
+ # Must take into account the WKST value
+
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYDAY and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByDay:
+ # Numeric values are meaningless so ignore them
+ if iter2[0] == 0:
+ temp = iter1.duplicate()
+
+ # Determine amount of offset to apply to temp to shift it
+ # to the start of the week (backwards)
+ week_start_offset = self.mWeekstart - temp.getDayOfWeek()
+ if week_start_offset > 0:
+ week_start_offset -= 7
+
+ # Determine amount of offset from the start of the week to
+ # the day we want (forwards)
+ day_in_week_offset = iter2[1] - self.mWeekstart
+ if day_in_week_offset < 0:
+ day_in_week_offset += 7
+
+ # Apply offsets
+ temp.offsetDay(week_start_offset + day_in_week_offset)
+ output.append(temp)
+
+ return output
+
+
+ def byHourExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYHOUR and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByHours:
+ temp = iter1.duplicate()
+ temp.setHours(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def byMinuteExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYMINUTE and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mByMinutes:
+ temp = iter1.duplicate()
+ temp.setMinutes(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def bySecondExpand(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYSECOND and generating a new date-time for it and
+ # insert into output
+ for iter2 in self.mBySeconds:
+ temp = iter1.duplicate()
+ temp.setSeconds(iter2)
+ output.append(temp)
+
+ return output
+
+
+ def byMonthLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYMONTH and indicate keep if input month matches
+ keep = False
+ for iter2 in self.mByMonth:
+ keep = (iter1.getMonth() == iter2)
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def byWeekNoLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYWEEKNO and indicate keep if input month matches
+ keep = False
+ for iter2 in self.mByWeekNo:
+ keep = iter1.isWeekNo(iter2)
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def byMonthDayLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYMONTHDAY and indicate keep if input month
+ # matches
+ keep = False
+ for iter2 in self.mByMonthDay:
+ keep = iter1.isMonthDay(iter2)
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def byDayLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYDAY and indicate keep if input month matches
+ keep = False
+ for iter2 in self.mByDay:
+ keep = iter1.isDayOfWeekInMonth(iter2[0], iter2[1])
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def byHourLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYHOUR and indicate keep if input hour matches
+ keep = False
+ for iter2 in self.mByHours:
+ keep = (iter1.getHours() == iter2)
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def byMinuteLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYMINUTE and indicate keep if input minute matches
+ keep = False
+ for iter2 in self.mByMinutes:
+ keep = (iter1.getMinutes() == iter2)
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def bySecondLimit(self, dates):
+ # Loop over all input items
+ output = []
+ for iter1 in dates:
+ # Loop over each BYSECOND and indicate keep if input second matches
+ keep = False
+ for iter2 in self.mBySeconds:
+ keep = (iter1.getSeconds() == iter2)
+ if keep:
+ break
+
+ if keep:
+ output.append(iter1)
+
+ return output
+
+
+ def bySetPosLimit(self, dates):
+ # The input dates MUST be sorted in order for this to work properly
+ #dates.sort(cmp=DateTime.sort)
+ dates.sort(key=lambda x: x.getPosixTime())
+
+ # Loop over each BYSETPOS and extract the relevant component from the
+ # input array and add to the output
+ output = []
+ input_size = len(dates)
+ for iter in self.mBySetPos:
+ if iter > 0:
+ # Positive values are offset from the start
+ if iter <= input_size:
+ output.append(dates[iter - 1])
+ elif iter < 0:
+ # Negative values are offset from the end
+ if -iter <= input_size:
+ output.append(dates[input_size + iter])
+
+ return output
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrecurrencesetpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrecurrencesetpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/recurrenceset.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,312 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.utils import set_difference
+
+class RecurrenceSet(object):
+
+ def __init__(self):
+ self.mRrules = []
+ self.mExrules = []
+ self.mRdates = []
+ self.mExdates = []
+ self.mRperiods = []
+ self.mExperiods = []
+
+
+ def duplicate(self):
+ other = RecurrenceSet()
+ other.mRrules = [i.duplicate() for i in self.mRrules]
+ other.mExrules = [i.duplicate() for i in self.mExrules]
+ other.mRdates = [i.duplicate() for i in self.mRdates]
+ other.mExdates = [i.duplicate() for i in self.mExdates]
+ other.mRperiods = [i.duplicate() for i in self.mRperiods]
+ other.mExperiods = [i.duplicate() for i in self.mExperiods]
+ return other
+
+
+ def hasRecurrence(self):
+ return ((len(self.mRrules) != 0) or (len(self.mRdates) != 0) or (len(self.mRperiods) != 0)
+ or (len(self.mExrules) != 0) or (len(self.mExdates) != 0)
+ or (len(self.mExperiods) != 0))
+
+
+ def equals(self, comp):
+ # Look at RRULEs
+ if not self.equalsRules(self.mRrules, comp.self.mRrules):
+ return False
+
+ # Look at EXRULEs
+ if not self.equalsRules(self.mExrules, comp.self.mExrules):
+ return False
+
+ # Look at RDATEs
+ if not self.equalsDates(self.mRdates, comp.self.mRdates):
+ return False
+ if not self.equalsPeriods(self.mRperiods, comp.self.mRperiods):
+ return False
+
+ # Look at EXDATEs
+ if not self.equalsDates(self.mExdates, comp.self.mExdates):
+ return False
+ if not self.equalsPeriods(self.mExperiods, comp.self.mExperiods):
+ return False
+
+ # If we get here they match
+ return True
+
+
+ def equalsRules(self, rules1, rules2):
+ # Check sizes first
+ if len(rules1) != len(rules2):
+ return False
+ elif len(rules1) == 0:
+ return True
+
+ # Do sledge hammer O(n^2) approach as its not easy to sort these things
+ # for a smarter test.
+ # In most cases there will only be one rule anyway, so this should not
+ # be too painful.
+
+ temp2 = rules2[:]
+
+ for r1 in rules1:
+ found = False
+ for r2 in temp2:
+ if r1.equals(r2):
+ # Remove the one found so it is not tested again
+ temp2.remove(r2)
+ found = True
+ break
+
+ if not found:
+ return False
+
+ return True
+
+
+ def equalsDates(self, dates1, dates2):
+ # Check sizes first
+ if len(dates1) != len(dates2):
+ return False
+ elif len(dates1) == 0:
+ return True
+
+ # Copy each and sort for comparison
+ dt1 = dates1[:]
+ dt2 = dates2[:]
+
+ dt1.sort(key=lambda x: x.getPosixTime())
+ dt2.sort(key=lambda x: x.getPosixTime())
+
+ return dt1.equal(dt2)
+
+
+ def equalsPeriods(self, periods1, periods2):
+ # Check sizes first
+ if len(periods1) != len(periods2):
+ return False
+ elif len(periods1) == 0:
+ return True
+
+ # Copy each and sort for comparison
+ p1 = periods1[:]
+ p2 = periods2[:]
+
+ p1.sort()
+ p2.sort()
+
+ return p1.equal(p2)
+
+
+ def addRule(self, rule):
+ self.mRrules.append(rule)
+
+
+ def subtractRule(self, rule):
+ self.mExrules.append(rule)
+
+
+ def addDT(self, dt):
+ self.mRdates.append(dt)
+
+
+ def subtractDT(self, dt):
+ self.mExdates.append(dt)
+
+
+ def addPeriod(self, p):
+ self.mRperiods.append(p)
+
+
+ def subtractPeriod(self, p):
+ self.mExperiods.append(p)
+
+
+ def getRules(self):
+ return self.mRrules
+
+
+ def getExrules(self):
+ return self.mExrules
+
+
+ def getDates(self):
+ return self.mRdates
+
+
+ def getExdates(self):
+ return self.mExdates
+
+
+ def getPeriods(self):
+ return self.mRperiods
+
+
+ def getExperiods(self):
+ return self.mExperiods
+
+
+ def expand(self, start, range, items, float_offset=0):
+ # Need to return whether the limit was applied or not
+ limited = False
+
+ # Now create list of items to include
+ include = []
+
+ # Always include the initial DTSTART if within the range
+ if range.isDateWithinPeriod(start):
+ include.append(start)
+ else:
+ limited = True
+
+ # RRULES
+ for iter in self.mRrules:
+ if iter.expand(start, range, include, float_offset=float_offset):
+ limited = True
+
+ # RDATES
+ for iter in self.mRdates:
+ if range.isDateWithinPeriod(iter):
+ include.append(iter)
+ else:
+ limited = True
+ for iter in self.mRperiods:
+ if range.isPeriodOverlap(iter):
+ include.append(iter.getStart())
+ else:
+ limited = True
+
+ # Make sure the list is unique
+ include = [x for x in set(include)]
+ include.sort(key=lambda x: x.getPosixTime())
+
+ # Now create list of items to exclude
+ exclude = []
+
+ # EXRULES
+ for iter in self.mExrules:
+ iter.expand(start, range, exclude, float_offset=float_offset)
+
+ # EXDATES
+ for iter in self.mExdates:
+ if range.isDateWithinPeriod(iter):
+ exclude.append(iter)
+ for iter in self.mExperiods:
+ if range.isPeriodOverlap(iter):
+ exclude.append(iter.getStart())
+
+ # Make sure the list is unique
+ exclude = [x for x in set(exclude)]
+ exclude.sort(key=lambda x: x.getPosixTime())
+
+ # Add difference between to the two sets (include - exclude) to the
+ # results
+ items.extend(set_difference(include, exclude))
+ return limited
+
+
+ def changed(self):
+ # RRULES
+ for iter in self.mRrules:
+ iter.clear()
+
+ # EXRULES
+ for iter in self.mExrules:
+ iter.clear()
+
+
+ def excludeFutureRecurrence(self, exclude):
+ # Adjust RRULES to end before start
+ for iter in self.mRrules:
+ iter.excludeFutureRecurrence(exclude)
+
+ # Remove RDATES on or after start
+ self.mRdates.removeOnOrAfter(exclude)
+ for iter in self.mRperiods:
+ if iter > exclude:
+ self.mRperiods.remove(iter)
+
+
+ # UI operations
+ def isSimpleUI(self):
+ # Right now the Event dialog only handles a single RRULE (but we allow
+ # any number of EXDATES as deleted
+ # instances will appear as EXDATES)
+ if ((len(self.mRrules) > 1) or (len(self.mExrules) > 0)
+ or (len(self.mRdates) > 0) or (len(self.mRperiods) > 0)):
+ return False
+
+ # Also, check the rule iteself
+ elif len(self.mRrules) == 1:
+ return self.mRrules.firstElement().isSimpleRule()
+ else:
+ return True
+
+
+ def isAdvancedUI(self):
+ # Right now the Event dialog only handles a single RRULE
+ if ((len(self.mRrules) > 1) or (len(self.mExrules) > 0)
+ or (len(self.mRdates) > 0) or (len(self.mRperiods) > 0)):
+ return False
+
+ # Also, check the rule iteself
+ elif len(self.mRrules) == 1:
+ return self.mRrules.firstElement().isAdvancedRule()
+ else:
+ return True
+
+
+ def getUIRecurrence(self):
+ if len(self.mRrules) == 1:
+ return self.mRrules[0]
+ else:
+ return None
+
+
+ def getUIDescription(self):
+ # Check for anything
+ if not self.hasRecurrence():
+ return "No Recurrence"
+
+ # Look for a single RRULE and return its descriptor
+ if ((len(self.mRrules) == 1) and (len(self.mExrules) == 0) and (len(self.mRdates) == 0)
+ and (len(self.mExdates) == 0) and (len(self.mRperiods) == 0)
+ and (len(self.mExperiods) == 0)):
+ return self.mRrules.firstElement().getUIDescription()
+
+ # Indicate some form of complex recurrence
+ return "Multiple recurrence rules, dates or exclusions"
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrecurrencevaluepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrecurrencevaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/recurrencevalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar import xmldefinitions
+from pycalendar.icalendar.recurrence import Recurrence
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
+
+class RecurrenceValue(WrapperValue, Value):
+
+ _wrappedClass = Recurrence
+ _wrappedType = Value.VALUETYPE_RECUR
+
+ def writeXML(self, node, namespace):
+ self.mValue.writeXML(node, namespace)
+
+Value.registerType(Value.VALUETYPE_RECUR, RecurrenceValue, xmldefinitions.value_recur)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrequeststatusvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrequeststatusvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/requeststatusvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,117 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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.
+##
+
+# iCalendar REQUEST-STATUS value
+
+from pycalendar import utils, xmlutils
+from pycalendar.icalendar import xmldefinitions
+from pycalendar.parser import ParserContext
+from pycalendar.value import Value
+from pycalendar import xmldefinitions as xmldefinitions_top
+import xml.etree.cElementTree as XML
+
+class RequestStatusValue(Value):
+ """
+ The value is a list of strings (either 2 or 3 items)
+ """
+
+ def __init__(self, value=None):
+ self.mValue = value if value is not None else ["2.0", "Success"]
+
+
+ def __hash__(self):
+ return hash(tuple(self.mValue))
+
+
+ def duplicate(self):
+ return RequestStatusValue(self.mValue[:])
+
+
+ def getType(self):
+ return Value.VALUETYPE_REQUEST_STATUS
+
+
+ def parse(self, data, variant="icalendar"):
+
+ result = utils.parseTextList(data, always_list=True)
+ if len(result) == 1:
+ if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
+ if ";" in result[0]:
+ code, desc = result[0].split(";", 1)
+ else:
+ code = result[0]
+ desc = ""
+ rest = None
+ else:
+ raise ValueError
+ elif len(result) == 2:
+ code, desc = result
+ rest = None
+ elif len(result) == 3:
+ code, desc, rest = result
+ else:
+ if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
+ code, desc, rest = result[:3]
+ else:
+ raise ValueError
+
+ if "\\" in code and ParserContext.INVALID_REQUEST_STATUS_VALUE in (ParserContext.PARSER_IGNORE, ParserContext.PARSER_FIX):
+ code = code.replace("\\", "")
+ elif ParserContext.INVALID_REQUEST_STATUS_VALUE == ParserContext.PARSER_RAISE:
+ raise ValueError
+
+ # Decoding required
+ self.mValue = [code, desc, rest, ] if rest else [code, desc, ]
+
+
+ # os - StringIO object
+ def generate(self, os):
+ utils.generateTextList(os, self.mValue if len(self.mValue) < 3 or self.mValue[2] else self.mValue[:2])
+
+
+ def writeXML(self, node, namespace):
+ value = self.getXMLNode(node, namespace)
+
+ code = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.req_status_code))
+ code.text = self.mValue[0]
+
+ description = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.req_status_description))
+ description.text = self.mValue[1]
+
+ if len(self.mValue) == 3 and self.mValue[2]:
+ data = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.req_status_data))
+ data.text = self.mValue[2]
+
+
+ def parseJSONValue(self, jobject):
+ self.mValue = jobject
+
+
+ def writeJSONValue(self, jobject):
+ value = [self.mValue[0], self.mValue[1]]
+ if len(self.mValue) == 3:
+ value.append(self.mValue[2])
+ jobject.append(value)
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
+
+Value.registerType(Value.VALUETYPE_REQUEST_STATUS, RequestStatusValue, None, xmldefinitions_top.value_text)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendartests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_calendarpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_calendarpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_calendar.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,854 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.icalendar.property import Property
+from pycalendar.parser import ParserContext
+from pycalendar.period import Period
+import cStringIO as StringIO
+import difflib
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+ data = (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+X-WR-CALNAME:PayDay
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:DC3D0301C7790B38631F1FBB@ninevah.local
+DTSTART;VALUE=DATE:20040227
+DTSTAMP:20050211T173501Z
+RRULE:FREQ=MONTHLY;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR;BYSETPOS=-1
+SUMMARY:PAY DAY
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Alarm for Organizer!
+TRIGGER;RELATED=START:-PT15M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH:http://example.com/test.jpg
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH;ENCODING=BASE64;VALUE=BINARY:dGVzdA==
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VAVAILABILITY
+UID:20061005T133225Z-00001-availability@example.com
+DTSTART;TZID=America/Montreal:20060101T000000
+DTEND;TZID=America/Montreal:20060108T000000
+DTSTAMP:20061005T133225Z
+ORGANIZER:mailto:bernard@example.com
+BEGIN:AVAILABLE
+UID:20061005T133225Z-00001-A-availability@example.com
+DTSTART;TZID=America/Montreal:20060102T090000
+DTEND;TZID=America/Montreal:20060102T120000
+DTSTAMP:20061005T133225Z
+RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
+SUMMARY:Monday\\, Wednesday and Friday from 9:00 to 12:00
+END:AVAILABLE
+BEGIN:AVAILABLE
+UID:20061005T133225Z-00001-A-availability@example.com
+RECURRENCE-ID;TZID=America/Montreal:20060106T090000
+DTSTART;TZID=America/Montreal:20060106T120000
+DTEND;TZID=America/Montreal:20060106T170000
+DTSTAMP:20061005T133225Z
+SUMMARY:Friday override from 12:00 to 17:00
+END:AVAILABLE
+END:VAVAILABILITY
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VTODO
+UID:event1@ninevah.local
+CREATED:20060101T150000Z
+DTSTAMP:20051222T205953Z
+SUMMARY:event 1
+END:VTODO
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:X-COMPONENT
+UID:1234
+END:X-COMPONENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.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;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:uid4
+DTSTART;TZID=US/Pacific:20100207T170000
+DTEND;TZID=US/Pacific:20100207T173000
+CREATED:20100203T013849Z
+DTSTAMP:20100203T013909Z
+SEQUENCE:3
+SUMMARY:New Event
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:AUDIO
+ATTACH:Basso
+TRIGGER:-PT20M
+X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH:http://example.com/test.jpg
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+X-APPLE-STRUCTURED-LOCATION:geo:123.123,123.123
+X-Test:Some\, text.
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH:http://example.com/test.jpg
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123
+X-Test:Some\, text.
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+)
+ data2 = (
+ (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+X-TEST:Testing
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+X-TEST:Testing
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ ),
+)
+
+
+ def testRoundtrip(self):
+
+
+ def _doRoundtrip(caldata, resultdata=None):
+ test1 = resultdata if resultdata is not None else caldata
+
+ cal = Calendar()
+ cal.parse(StringIO.StringIO(caldata))
+
+ s = StringIO.StringIO()
+ cal.generate(s)
+ test2 = s.getvalue()
+
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+ for item in self.data:
+ _doRoundtrip(item)
+
+ for item1, item2 in self.data2:
+ _doRoundtrip(item1, item2)
+
+
+ def testRoundtripDuplicate(self):
+
+
+ def _doDuplicateRoundtrip(caldata):
+ cal = Calendar()
+ cal.parse(StringIO.StringIO(caldata))
+ cal = cal.duplicate()
+
+ s = StringIO.StringIO()
+ cal.generate(s)
+ self.assertEqual(caldata, s.getvalue())
+
+ for item in self.data:
+ _doDuplicateRoundtrip(item)
+
+
+ def testEquality(self):
+
+
+ def _doEquality(caldata):
+ cal1 = Calendar()
+ cal1.parse(StringIO.StringIO(caldata))
+
+ cal2 = Calendar()
+ cal2.parse(StringIO.StringIO(caldata))
+
+ self.assertEqual(cal1, cal2, "%s\n\n%s" % (cal1, cal2,))
+
+
+ def _doNonEquality(caldata):
+ cal1 = Calendar()
+ cal1.parse(StringIO.StringIO(caldata))
+
+ cal2 = Calendar()
+ cal2.parse(StringIO.StringIO(caldata))
+ cal2.addProperty(Property("X-FOO", "BAR"))
+
+ self.assertNotEqual(cal1, cal2)
+
+ for item in self.data:
+ _doEquality(item)
+ _doNonEquality(item)
+
+
+ def testParseComponent(self):
+
+ data1 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ data2 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ cal = Calendar()
+ cal.parse(StringIO.StringIO(data1))
+ cal.parseComponent(StringIO.StringIO(data2))
+ self.assertEqual(str(cal), result)
+
+
+ def testParseFail(self):
+
+ data = (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCARD
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+VERSION:2.0
+END:VCARD
+""".replace("\n", "\r\n"),
+
+"""BOGUS
+BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BOGUS
+
+BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+BOGUS
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+
+BOGUS
+""".replace("\n", "\r\n"),
+
+ )
+
+ for item in data:
+ self.assertRaises(InvalidData, Calendar.parseText, item)
+
+
+ def testParseBlank(self):
+
+ data = (
+"""
+BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""
+
+BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+
+
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+
+
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ )
+
+ save = ParserContext.BLANK_LINES_IN_DATA
+ for item in data:
+ ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_RAISE
+ self.assertRaises(InvalidData, Calendar.parseText, item)
+
+ ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_IGNORE
+ lines = item.split("\r\n")
+ result = "\r\n".join([line for line in lines if line]) + "\r\n"
+ self.assertEqual(str(Calendar.parseText(item)), result)
+
+ ParserContext.BLANK_LINES_IN_DATA = save
+
+
+ def testGetVEvents(self):
+
+ data = (
+ (
+ "Non-recurring match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (DateTime(2011, 6, 1),),
+ ),
+ (
+ "Non-recurring no-match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110501
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (),
+ ),
+ (
+ "Recurring match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (
+ DateTime(2011, 6, 1),
+ DateTime(2011, 6, 2),
+ ),
+ ),
+ (
+ "Recurring no match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110501
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (),
+ ),
+ (
+ "Recurring with override match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART:20110601T120000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110602T120000
+DTSTART;VALUE=DATE:20110602T130000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (
+ DateTime(2011, 6, 1, 12, 0, 0),
+ DateTime(2011, 6, 2, 13, 0, 0),
+ ),
+ ),
+ (
+ "Recurring with override no match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART:20110501T120000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110502T120000
+DTSTART;VALUE=DATE:20110502T130000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (),
+ ),
+ (
+ "Recurring partial match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110531
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (
+ DateTime(2011, 6, 1),
+ ),
+ ),
+ (
+ "Recurring with override partial match",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART:20110531T120000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110601T120000
+DTSTART;VALUE=DATE:20110601T130000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+ (
+ DateTime(2011, 6, 1, 13, 0, 0),
+ ),
+ ),
+ )
+
+ for title, caldata, result in data:
+ calendar = Calendar.parseText(caldata)
+ instances = []
+ calendar.getVEvents(
+ Period(
+ start=DateTime(2011, 6, 1),
+ end=DateTime(2011, 7, 1),
+ ),
+ instances
+ )
+ instances = tuple([instance.getInstanceStart() for instance in instances])
+ self.assertEqual(instances, result, "Failed in %s: got %s, expected %s" % (title, instances, result))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_componentrecurpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_componentrecurpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_componentrecur.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,66 @@
</span><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+ def testDuplicateWithRecurrenceChange(self):
+
+ data = (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;COUNT=400
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+)
+
+ cal1 = Calendar()
+ cal1.parse(StringIO.StringIO(data[0]))
+ cal2 = cal1.duplicate()
+ vevent = cal2.getComponents()[0]
+ rrules = vevent.getRecurrenceSet()
+ for rrule in rrules.getRules():
+ rrule.setUseCount(True)
+ rrule.setCount(400)
+ rrules.changed()
+
+ self.assertEqual(data[0], str(cal1))
+ self.assertEqual(data[1], str(cal2))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_i18npyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_i18npy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_i18n.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+# coding: utf-8
+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.parameter import Parameter
+from pycalendar.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+ def testAddCN(self):
+
+ data = (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+ORGANIZER:user01@example.com
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+ "まだ",
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+ORGANIZER;CN=まだ:user01@example.com
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+ )
+
+ cal1 = Calendar()
+ cal1.parse(StringIO.StringIO(data[0]))
+
+ vevent = cal1.getComponents("VEVENT")[0]
+ organizer = vevent.getProperties("ORGANIZER")[0]
+ organizer.addParameter(Parameter("CN", data[1]))
+
+ cal2 = Calendar()
+ cal2.parse(StringIO.StringIO(data[2]))
+
+ self.assertEqual(str(cal1), str(cal2))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_jsonpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_jsonpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_json.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,676 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar.calendar import Calendar
+from pycalendar.icalendar.property import Property
+import difflib
+import unittest
+
+class TestJSON(unittest.TestCase):
+
+ data = (
+ (
+"""BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20080205T191224Z
+DTSTART;VALUE=DATE:20081006
+SUMMARY:Planning meeting
+UID:4088E990AD89CB3DBB484909
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""[
+ "vcalendar",
+ [
+ [
+ "version",
+ {},
+ "text",
+ "2.0"
+ ],
+ [
+ "calscale",
+ {},
+ "text",
+ "GREGORIAN"
+ ],
+ [
+ "prodid",
+ {},
+ "text",
+ "-//Example Inc.//Example Calendar//EN"
+ ]
+ ],
+ [
+ [
+ "vevent",
+ [
+ [
+ "uid",
+ {},
+ "text",
+ "4088E990AD89CB3DBB484909"
+ ],
+ [
+ "dtstart",
+ {},
+ "date",
+ "2008-10-06"
+ ],
+ [
+ "dtstamp",
+ {},
+ "date-time",
+ "2008-02-05T19:12:24Z"
+ ],
+ [
+ "summary",
+ {},
+ "text",
+ "Planning meeting"
+ ]
+ ],
+ []
+ ]
+ ]
+]""",
+ ),
+ (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Example Corp.//Example Client//EN
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART;TZID=US/Eastern:20060102T120000
+DURATION:PT1H
+GEO:-123.45;67.89
+RRULE:FREQ=DAILY;COUNT=5
+RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H
+SUMMARY:Event #2
+DESCRIPTION:We are having a meeting all this week at 12 pm fo
+ r one hour\\, with an additional meeting on the first day 2 h
+ ours long.\\nPlease bring your own lunch for the 12 pm meetin
+ gs.
+UID:00959BC664CA650E933C892C@example.com
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART;TZID=US/Eastern:20060104T140000
+DURATION:PT1H
+RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+SUMMARY:Event #2 bis
+UID:00959BC664CA650E933C892C@example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""[
+ "vcalendar",
+ [
+ [
+ "version",
+ {},
+ "text",
+ "2.0"
+ ],
+ [
+ "prodid",
+ {},
+ "text",
+ "-//Example Corp.//Example Client//EN"
+ ]
+ ],
+ [
+ [
+ "vtimezone",
+ [
+ [
+ "tzid",
+ {},
+ "text",
+ "US/Eastern"
+ ],
+ [
+ "last-modified",
+ {},
+ "date-time",
+ "2004-01-10T03:28:45Z"
+ ]
+ ],
+ [
+ [
+ "daylight",
+ [
+ [
+ "dtstart",
+ {},
+ "date-time",
+ "2000-04-04T02:00:00"
+ ],
+ [
+ "rrule",
+ {},
+ "recur",
+ {
+ "bymonth":[
+ 4
+ ],
+ "freq":"YEARLY",
+ "byday":[
+ "1SU"
+ ]
+ }
+ ],
+ [
+ "tzname",
+ {},
+ "text",
+ "EDT"
+ ],
+ [
+ "tzoffsetfrom",
+ {},
+ "utc-offset",
+ "-05:00"
+ ],
+ [
+ "tzoffsetto",
+ {},
+ "utc-offset",
+ "-04:00"
+ ]
+ ],
+ []
+ ],
+ [
+ "standard",
+ [
+ [
+ "dtstart",
+ {},
+ "date-time",
+ "2000-10-26T02:00:00"
+ ],
+ [
+ "rrule",
+ {},
+ "recur",
+ {
+ "bymonth":[
+ 10
+ ],
+ "freq":"YEARLY",
+ "byday":[
+ "-1SU"
+ ]
+ }
+ ],
+ [
+ "tzname",
+ {},
+ "text",
+ "EST"
+ ],
+ [
+ "tzoffsetfrom",
+ {},
+ "utc-offset",
+ "-04:00"
+ ],
+ [
+ "tzoffsetto",
+ {},
+ "utc-offset",
+ "-05:00"
+ ]
+ ],
+ []
+ ]
+ ]
+ ],
+ [
+ "vevent",
+ [
+ [
+ "uid",
+ {},
+ "text",
+ "00959BC664CA650E933C892C@example.com"
+ ],
+ [
+ "dtstart",
+ {
+ "tzid":"US/Eastern"
+ },
+ "date-time",
+ "2006-01-02T12:00:00"
+ ],
+ [
+ "duration",
+ {},
+ "duration",
+ "PT1H"
+ ],
+ [
+ "description",
+ {},
+ "text",
+ "We are having a meeting all this week at 12 pm for one hour, with an additional meeting on the first day 2 hours long.\\nPlease bring your own lunch for the 12 pm meetings."
+ ],
+ [
+ "dtstamp",
+ {},
+ "date-time",
+ "2006-02-06T00:11:21Z"
+ ],
+ [
+ "geo",
+ {},
+ "float",
+ [
+ -123.45,
+ 67.89
+ ]
+ ],
+ [
+ "rdate",
+ {
+ "tzid":"US/Eastern"
+ },
+ "period",
+ [
+ "2006-01-02T15:00:00",
+ "PT2H"
+ ]
+ ],
+ [
+ "rrule",
+ {},
+ "recur",
+ {
+ "count":5,
+ "freq":"DAILY"
+ }
+ ],
+ [
+ "summary",
+ {},
+ "text",
+ "Event #2"
+ ]
+ ],
+ []
+ ],
+ [
+ "vevent",
+ [
+ [
+ "uid",
+ {},
+ "text",
+ "00959BC664CA650E933C892C@example.com"
+ ],
+ [
+ "recurrence-id",
+ {
+ "tzid":"US/Eastern"
+ },
+ "date-time",
+ "2006-01-04T12:00:00"
+ ],
+ [
+ "dtstart",
+ {
+ "tzid":"US/Eastern"
+ },
+ "date-time",
+ "2006-01-04T14:00:00"
+ ],
+ [
+ "duration",
+ {},
+ "duration",
+ "PT1H"
+ ],
+ [
+ "dtstamp",
+ {},
+ "date-time",
+ "2006-02-06T00:11:21Z"
+ ],
+ [
+ "summary",
+ {},
+ "text",
+ "Event #2 bis"
+ ]
+ ],
+ []
+ ]
+ ]
+]""",
+ ),
+ )
+
+ def testGenerateJSON(self):
+
+ def _doRoundtrip(caldata, resultdata):
+ test1 = resultdata
+
+ cal = Calendar.parseText(caldata)
+
+ test2 = cal.getTextJSON()
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+ for item1, item2 in self.data:
+ _doRoundtrip(item1, item2)
+
+
+ def testParseJSON(self):
+
+ def _doRoundtrip(caldata, jcaldata):
+ cal1 = Calendar.parseText(caldata)
+ test1 = cal1.getText()
+
+ cal2 = Calendar.parseJSONData(jcaldata)
+ test2 = cal2.getText()
+
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+ for item1, item2 in self.data:
+ _doRoundtrip(item1, item2)
+
+
+ def testjCalExample1(self):
+
+ jcaldata = """["vcalendar",
+ [
+ ["calscale", {}, "text", "GREGORIAN"],
+ ["prodid", {}, "text", "-//Example Inc.//Example Calendar//EN"],
+ ["version", {}, "text", "2.0"]
+ ],
+ [
+ ["vevent",
+ [
+ ["dtstamp", {}, "date-time", "2008-02-05T19:12:24Z"],
+ ["dtstart", {}, "date", "2008-10-06"],
+ ["summary", {}, "text", "Planning meeting"],
+ ["uid", {}, "text", "4088E990AD89CB3DBB484909"]
+ ],
+ []
+ ]
+ ]
+]
+"""
+
+ icaldata = """BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20080205T191224Z
+DTSTART;VALUE=DATE:20081006
+SUMMARY:Planning meeting
+UID:4088E990AD89CB3DBB484909
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ cal1 = Calendar.parseText(icaldata)
+ test1 = cal1.getText()
+
+ cal2 = Calendar.parseJSONData(jcaldata)
+ test2 = cal2.getText()
+
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+
+ def testjCalExample2(self):
+
+ jcaldata = """["vcalendar",
+ [
+ ["prodid", {}, "text", "-//Example Corp.//Example Client//EN"],
+ ["version", {}, "text", "2.0"]
+ ],
+ [
+ ["vtimezone",
+ [
+ ["last-modified", {}, "date-time", "2004-01-10T03:28:45Z"],
+ ["tzid", {}, "text", "US/Eastern"]
+ ],
+ [
+ ["daylight",
+ [
+ ["dtstart", {}, "date-time", "2000-04-04T02:00:00"],
+ ["rrule",
+ {},
+ "recur",
+ {
+ "freq": "YEARLY",
+ "byday": "1SU",
+ "bymonth": 4
+ }
+ ],
+ ["tzname", {}, "text", "EDT"],
+ ["tzoffsetfrom", {}, "utc-offset", "-05:00"],
+ ["tzoffsetto", {}, "utc-offset", "-04:00"]
+ ],
+ []
+ ],
+ ["standard",
+ [
+ ["dtstart", {}, "date-time", "2000-10-26T02:00:00"],
+ ["rrule",
+ {},
+ "recur",
+ {
+ "freq": "YEARLY",
+ "byday": "-1SU",
+ "bymonth": 10
+ }
+ ],
+ ["tzname", {}, "text", "EST"],
+ ["tzoffsetfrom", {}, "utc-offset", "-04:00:00"],
+ ["tzoffsetto", {}, "utc-offset", "-05:00:00"]
+ ],
+ []
+ ]
+ ]
+ ],
+ ["vevent",
+ [
+ ["dtstamp", {}, "date-time", "2006-02-06T00:11:21Z"],
+ ["dtstart",
+ { "tzid": "US/Eastern" },
+ "date-time",
+ "2006-01-02T12:00:00"
+ ],
+ ["duration", {}, "duration", "PT1H"],
+ ["rrule", {}, "recur", { "freq": "DAILY", "count": 5 } ],
+ ["rdate",
+ { "tzid": "US/Eastern" },
+ "period",
+ ["2006-01-02T15:00:00", "PT2H"]
+ ],
+ ["summary", {}, "text", "Event #2"],
+ ["description",
+ {},
+ "text",
+ "We are having a meeting all this week at 12 pm for one hour, with an additional meeting on the first day 2 hours long.\\nPlease bring your own lunch for the 12 pm meetings."
+ ],
+ ["uid", {}, "text", "00959BC664CA650E933C892C@example.com"]
+ ],
+ []
+ ],
+ ["vevent",
+ [
+ ["dtstamp", {}, "date-time", "2006-02-06T00:11:21Z"],
+ ["dtstart",
+ { "tzid": "US/Eastern" },
+ "date-time",
+ "2006-01-04T14:00:00"
+ ],
+ ["duration", {}, "duration", "PT1H"],
+ ["recurrence-id",
+ { "tzid": "US/Eastern" },
+ "date-time",
+ "2006-01-04T12:00:00"
+ ],
+ ["summary", {}, "text", "Event #2 bis"],
+ ["uid", {}, "text", "00959BC664CA650E933C892C@example.com"]
+ ],
+ []
+ ]
+ ]
+]
+"""
+
+ icaldata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Example Corp.//Example Client//EN
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART;TZID=US/Eastern:20060102T120000
+DURATION:PT1H
+RRULE:FREQ=DAILY;COUNT=5
+RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H
+SUMMARY:Event #2
+DESCRIPTION:We are having a meeting all this week at 12 pm fo
+ r one hour\\, with an additional meeting on the first day 2 h
+ ours long.\\nPlease bring your own lunch for the 12 pm meetin
+ gs.
+UID:00959BC664CA650E933C892C@example.com
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART;TZID=US/Eastern:20060104T140000
+DURATION:PT1H
+RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+SUMMARY:Event #2 bis
+UID:00959BC664CA650E933C892C@example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ cal1 = Calendar.parseText(icaldata)
+ test1 = cal1.getText()
+
+ cal2 = Calendar.parseJSONData(jcaldata)
+ test2 = cal2.getText()
+
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+
+
+class TestJSONProperty(unittest.TestCase):
+
+ test_data = (
+ # Different value types
+ ["attach", {}, "binary", "VGVzdA=="],
+ ["organizer", {}, "cal-address", "mailto:jdoe@example.com"],
+ ["dtstart", {"tzid": "US/Eastern"}, "date-time", "2006-02-26T12:00:00"],
+ ["dtstart", {}, "date", "2006-02-26"],
+ ["dtstart", {}, "date-time", "2006-02-26T13:00:00Z"],
+ ["x-foo", {}, "text", "BAR"],
+ ["duration", {}, "duration", "PT10M"],
+ ["sequence", {}, "integer", 1],
+ ["rdate", {}, "date-time", "2006-02-26T12:00:00Z", "2006-02-27T12:00:00Z"],
+ ["freebusy", {}, "period", ["2006-02-26T12:00:00Z", "2006-02-27T12:00:00Z"]],
+ ["rrule", {}, "recur", {"freq":"MONTHLY", "count": 3, "byday":["TU", "WE", "TH"], "bysetpos":[-1]}],
+ ["request-status", {}, "text", ["2.0", "Success"]],
+ ["geo", {}, "float", [-2.1, 3.2]],
+ ["uri", {}, "uri", "http://www.example.com"],
+ ["tzoffsetfrom", {}, "utc-offset", "-05:00"],
+ ["tzoffsetfrom", {}, "utc-offset", "-04:58:57"],
+ ["x-foo", {}, "float", -1.23],
+ ["x-test", {}, "text", "Some:, text."],
+ ["x-apple-structured-location", {}, "uri", "geo:123.123,123.123"],
+ ["rrule", {}, "recur", {"freq":"MONTHLY", "until": "2013-01-01T00:00:00Z"}],
+ ["categories", {}, "text", "A", "B"],
+
+ # Various parameters
+ ["dtstart", {"tzid": "Somewhere, else"}, "date-time", "2006-02-26T12:00:00"],
+ ["attendee", {"partstat": "ACCEPTED", "role": "CHAIR"}, "cal-address", "mailto:jdoe@example.com"],
+ ["x-foo", {"x-bar": "Some\\ntext"}, "text", "foobar"],
+
+ # Parameter escaping
+ ["attendee", {"cn": "My 'Test' Name", "role": "CHAIR"}, "cal-address", "mailto:jdoe@example.com"],
+ )
+
+
+ def testParseGenerate(self):
+
+ for data in TestJSONProperty.test_data:
+ prop = Property.parseJSON(data)
+ jobject = []
+ prop.writeJSON(jobject)
+ self.assertEqual(jobject[0], data, "Failed parse/generate: %s to %s" % (data, jobject[0],))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_propertypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_propertypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_property.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,181 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.parameter import Parameter
+from pycalendar.exceptions import InvalidProperty
+from pycalendar.icalendar.property import Property
+from pycalendar.parser import ParserContext
+from pycalendar.value import Value
+import unittest
+
+class TestProperty(unittest.TestCase):
+
+ test_data = (
+ # Different value types
+ "ATTACH;VALUE=BINARY:VGVzdA==",
+ "attach;VALUE=BINARY:VGVzdA==",
+ "ORGANIZER:mailto:jdoe@example.com",
+ "DTSTART;TZID=US/Eastern:20060226T120000",
+ "DTSTART;VALUE=DATE:20060226",
+ "DTSTART:20060226T130000Z",
+ "X-FOO:BAR",
+ "DURATION:PT10M",
+ "duraTION:PT10M",
+ "SEQUENCE:1",
+ "RDATE:20060226T120000Z,20060227T120000Z",
+ "FREEBUSY:20060226T120000Z/20060227T120000Z",
+ "SUMMARY:Some \\ntext",
+ "RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1",
+ "REQUEST-STATUS:2.0;Success",
+ "GEO:-2.1;3.2",
+ "URI:http://www.example.com",
+ "TZOFFSETFROM:-0500",
+ "TZOFFSETFROM:-045857",
+ "X-FOO;VALUE=FLOAT:-1.23",
+ "X-Test:Some\, text.",
+ "X-Test:Some:, text.",
+ "X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123",
+ "X-CALENDARSERVER-PRIVATE-COMMENT:This\\ntest\\nis\\, here.\\n",
+
+ # Various parameters
+ "DTSTART;TZID=\"Somewhere, else\":20060226T120000",
+ "ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:jdoe@example.com",
+ "X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-APPLE-ABUID=ab\\://Work;X-TITLE=\"10\\n XX S. XXX Dr.\\nSuite XXX\\nXX XX XXXXX\\nUnited States\":\"geo:11.111111,-11.111111\"",
+
+ # Parameter escaping
+ "ATTENDEE;CN=My ^'Test^' Name;ROLE=CHAIR:mailto:jdoe@example.com",
+ )
+
+
+ def testParseGenerate(self):
+
+ for data in TestProperty.test_data:
+ prop = Property.parseText(data)
+ propstr = str(prop).replace("\r\n ", "")
+ self.assertEqual(propstr[:-2], data, "Failed parse/generate: %s to %s" % (data, propstr,))
+
+
+ def testEquality(self):
+
+ for data in TestProperty.test_data:
+ prop1 = Property.parseText(data)
+ prop2 = Property.parseText(data)
+ self.assertEqual(prop1, prop2, "Failed equality: %s" % (data,))
+
+
+ def testParseBad(self):
+
+ test_bad_data = (
+ "DTSTART;TZID=US/Eastern:abc",
+ "DTSTART;VALUE=DATE:20060226T",
+ "DTSTART:20060226T120000A",
+ "X-FOO;:BAR",
+ "DURATION:A",
+ "SEQUENCE:b",
+ "RDATE:20060226T120000Z;20060227T120000Z",
+ "FREEBUSY:20060226T120000Z/ABC",
+ "SUMMARY:Some \\qtext",
+ "RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,VE;BYSETPOS=-1",
+ "TZOFFSETFROM:-050",
+ """ATTENDEE;CN="\\";CUTYPE=INDIVIDUAL;PARTSTAT=X-UNDELIVERABLE:invalid:nomai
+ l""",
+ )
+ save = ParserContext.INVALID_ESCAPE_SEQUENCES
+ for data in test_bad_data:
+ ParserContext.INVALID_ESCAPE_SEQUENCES = ParserContext.PARSER_RAISE
+ self.assertRaises(InvalidProperty, Property.parseText, data)
+ ParserContext.INVALID_ESCAPE_SEQUENCES = save
+
+
+ def testHash(self):
+
+ hashes = []
+ for item in TestProperty.test_data:
+ prop = Property.parseText(item)
+ hashes.append(hash(prop))
+ hashes.sort()
+ for i in range(1, len(hashes)):
+ self.assertNotEqual(hashes[i - 1], hashes[i])
+
+
+ def testDefaultValueCreate(self):
+
+ test_data = (
+ ("ATTENDEE", "mailto:attendee@example.com", "ATTENDEE:mailto:attendee@example.com\r\n"),
+ ("attendee", "mailto:attendee@example.com", "attendee:mailto:attendee@example.com\r\n"),
+ ("ORGANIZER", "mailto:organizer@example.com", "ORGANIZER:mailto:organizer@example.com\r\n"),
+ ("ORGANizer", "mailto:organizer@example.com", "ORGANizer:mailto:organizer@example.com\r\n"),
+ ("URL", "http://example.com/tz1", "URL:http://example.com/tz1\r\n"),
+ ("TZURL", "http://example.com/tz2", "TZURL:http://example.com/tz2\r\n"),
+ )
+ for propname, propvalue, result in test_data:
+ prop = Property(name=propname, value=propvalue)
+ self.assertEqual(str(prop), result)
+
+
+ def testGEOValueRoundtrip(self):
+
+ data = "GEO:123.456;789.101"
+ prop = Property.parseText(data)
+ self.assertEqual(str(prop), data + "\r\n")
+
+
+ def testUnknownValueRoundtrip(self):
+
+ data = "X-FOO:Text, not escaped"
+ prop = Property.parseText(data)
+ self.assertEqual(str(prop), data + "\r\n")
+
+ prop = Property("X-FOO", "Text, not escaped")
+ self.assertEqual(str(prop), data + "\r\n")
+
+ data = "X-FOO:Text\\, escaped\\n"
+ prop = Property.parseText(data)
+ self.assertEqual(str(prop), data + "\r\n")
+
+ prop = Property("X-FOO", "Text\\, escaped\\n")
+ self.assertEqual(str(prop), data + "\r\n")
+
+
+ def testNewRegistrationValueRoundtrip(self):
+
+ Property.registerDefaultValue("X-SPECIAL-REGISTRATION", Value.VALUETYPE_TEXT)
+
+ data = "X-SPECIAL-REGISTRATION:Text\\, escaped\\n"
+ prop = Property.parseText(data)
+ self.assertEqual(str(prop), "X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n")
+
+ prop = Property("X-SPECIAL-REGISTRATION", "Text, escaped\n")
+ self.assertEqual(str(prop), "X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n")
+
+
+ def testParameterEncodingDecoding(self):
+
+ prop = Property("X-FOO", "Test")
+ prop.addParameter(Parameter("X-BAR", "\"Check\""))
+ self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^':Test\r\n")
+
+ prop.addParameter(Parameter("X-BAR2", "Check\nThis\tOut\n"))
+ self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n")
+
+ data = "X-FOO;X-BAR=^'Check^':Test"
+ prop = Property.parseText(data)
+ self.assertEqual(prop.getParameterValue("X-BAR"), "\"Check\"")
+
+ data = "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test"
+ prop = Property.parseText(data)
+ self.assertEqual(prop.getParameterValue("X-BAR"), "\"Check\"")
+ self.assertEqual(prop.getParameterValue("X-BAR2"), "Check\nThis\tOut\n")
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_recurrencepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_recurrencepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_recurrence.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,160 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.period import Period
+from pycalendar.icalendar.recurrence import Recurrence
+import unittest
+
+class TestRecurrence(unittest.TestCase):
+
+ items = (
+ "FREQ=DAILY",
+ "FREQ=YEARLY;COUNT=400",
+ "FREQ=MONTHLY;UNTIL=20110102",
+ "FREQ=MONTHLY;UNTIL=20110102T090000",
+ "FREQ=MONTHLY;UNTIL=20110102T100000Z",
+ "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1",
+
+ # These are from RFC5545 examples
+ "FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
+ "FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4",
+ "FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4",
+ "FREQ=YEARLY;BYDAY=2SU;BYMONTH=3",
+ "FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10",
+ "FREQ=DAILY;INTERVAL=2",
+ "FREQ=DAILY;COUNT=5;INTERVAL=10",
+ "FREQ=DAILY;UNTIL=20000131T140000Z;BYMONTH=1",
+ "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
+ "FREQ=WEEKLY;UNTIL=19971007T000000Z;BYDAY=TU,TH;WKST=SU",
+ "FREQ=WEEKLY;COUNT=10;BYDAY=TU,TH;WKST=SU",
+ "FREQ=WEEKLY;UNTIL=19971224T000000Z;INTERVAL=2;BYDAY=MO,WE,FR;WKST=SU",
+ "FREQ=WEEKLY;COUNT=8;INTERVAL=2;BYDAY=TU,TH;WKST=SU",
+ "FREQ=MONTHLY;BYMONTHDAY=-3",
+ "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1",
+ "FREQ=MONTHLY;COUNT=10;INTERVAL=18;BYMONTHDAY=10,11,12,13,14,15",
+ "FREQ=YEARLY;COUNT=10;INTERVAL=3;BYYEARDAY=1,100,200",
+ "FREQ=YEARLY;BYDAY=MO;BYWEEKNO=20",
+ "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3",
+ "FREQ=DAILY;BYMINUTE=0,20,40;BYHOUR=9,10,11,12,13,14,15,16",
+ )
+
+
+ def testParse(self):
+
+ for item in TestRecurrence.items:
+ recur = Recurrence()
+ recur.parse(item)
+ self.assertEqual(recur.getText(), item, "Failed to parse and re-generate '%s'" % (item,))
+
+
+ def testParseInvalid(self):
+
+ items = (
+ "",
+ "FREQ=",
+ "FREQ=MICROSECONDLY",
+ "FREQ=YEARLY;COUNT=ABC",
+ "FREQ=YEARLY;COUNT=123;UNTIL=20110102",
+ "FREQ=MONTHLY;UNTIL=20110102T",
+ "FREQ=MONTHLY;UNTIL=20110102t090000",
+ "FREQ=MONTHLY;UNTIL=20110102T100000z",
+ "FREQ=MONTHLY;UNTIL=20110102TAABBCCz",
+ "FREQ=MONTHLY;BYDAY=A",
+ "FREQ=MONTHLY;BYDAY=+1,3MO",
+ "FREQ=MONTHLY;BYHOUR=A",
+ "FREQ=MONTHLY;BYHOUR=54",
+ )
+
+ for item in items:
+ self.assertRaises(ValueError, Recurrence().parse, item)
+
+
+ def testEquality(self):
+
+ recur1 = Recurrence()
+ recur1.parse("FREQ=YEARLY;COUNT=400")
+ recur2 = Recurrence()
+ recur2.parse("COUNT=400;FREQ=YEARLY")
+
+ self.assertEqual(recur1, recur2)
+
+
+ def testInequality(self):
+
+ recur1 = Recurrence()
+ recur1.parse("FREQ=YEARLY;COUNT=400")
+ recur2 = Recurrence()
+ recur2.parse("COUNT=400;FREQ=YEARLY;BYMONTH=1")
+
+ self.assertNotEqual(recur1, recur2)
+
+
+ def testHash(self):
+
+ hashes = []
+ for item in TestRecurrence.items:
+ recur = Recurrence()
+ recur.parse(item)
+ hashes.append(hash(recur))
+ hashes.sort()
+ for i in range(1, len(hashes)):
+ self.assertNotEqual(hashes[i - 1], hashes[i])
+
+
+ def testByWeekNoExpand(self):
+
+ recur = Recurrence()
+ recur.parse("FREQ=YEARLY;BYWEEKNO=1,2")
+ start = DateTime(2013, 1, 1, 0, 0, 0)
+ end = DateTime(2017, 1, 1, 0, 0, 0)
+ items = []
+ range = Period(start, end)
+ recur.expand(start, range, items)
+ self.assertEqual(
+ items,
+ [
+ DateTime(2013, 1, 1, 0, 0, 0),
+ DateTime(2013, 1, 8, 0, 0, 0),
+ DateTime(2014, 1, 1, 0, 0, 0),
+ DateTime(2014, 1, 8, 0, 0, 0),
+ DateTime(2015, 1, 1, 0, 0, 0),
+ DateTime(2015, 1, 8, 0, 0, 0),
+ DateTime(2016, 1, 8, 0, 0, 0),
+ DateTime(2016, 1, 15, 0, 0, 0),
+ ],
+ )
+
+
+ def testClearOnChange(self):
+
+ recur = Recurrence()
+ recur.parse("FREQ=DAILY")
+
+ start = DateTime(2013, 1, 1, 0, 0, 0)
+ end = DateTime(2017, 1, 1, 0, 0, 0)
+ range = Period(start, end)
+ items = []
+ recur.expand(start, range, items)
+ self.assertTrue(recur.mCached)
+ self.assertTrue(len(items) > 100)
+
+ recur.setUseCount(True)
+ recur.setCount(10)
+ self.assertFalse(recur.mCached)
+ items = []
+ recur.expand(start, range, items)
+ self.assertEqual(len(items), 10)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_requeststatuspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_requeststatuspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_requeststatus.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.parser import ParserContext
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.requeststatusvalue import RequestStatusValue
+import unittest
+
+class TestRequestStatus(unittest.TestCase):
+
+ def testParseValue(self):
+
+ items = (
+ "2.0;Success",
+ "2.0;Success\;here",
+ "2.0;Success;Extra",
+ "2.0;Success\;here;Extra",
+ "2.0;Success;Extra\;here",
+ "2.0;Success\;here;Extra\;here too",
+ )
+
+ for item in items:
+ req = RequestStatusValue()
+ req.parse(item, "icalendar")
+ self.assertEqual(req.getText(), item, "Failed to parse and re-generate '%s'" % (item,))
+
+
+ def testBadValue(self):
+
+ bad_value = "2.0\;Success"
+ ok_value = "2.0;Success"
+
+ # Fix the value
+ oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
+ ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
+ req = RequestStatusValue()
+ req.parse(bad_value, "icalendar")
+ self.assertEqual(req.getText(), ok_value, "Failed to parse and re-generate '%s'" % (bad_value,))
+
+ # Raise the value
+ ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
+ req = RequestStatusValue()
+ self.assertRaises(ValueError, req.parse, bad_value)
+
+ ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
+
+
+ def testTruncatedValue(self):
+
+ bad_value = "2.0"
+ ok_value = "2.0;"
+
+ # Fix the value
+ oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
+ ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
+ req = RequestStatusValue()
+ req.parse(bad_value, "icalendar")
+ self.assertEqual(req.getText(), ok_value, "Failed to parse and re-generate '%s'" % (bad_value,))
+
+ # Raise the value
+ ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
+ req = RequestStatusValue()
+ self.assertRaises(ValueError, req.parse, bad_value)
+
+ ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
+
+
+ def testParseProperty(self):
+
+ items = (
+ "REQUEST-STATUS:2.0;Success",
+ "REQUEST-STATUS:2.0;Success\;here",
+ "REQUEST-STATUS:2.0;Success;Extra",
+ "REQUEST-STATUS:2.0;Success\;here;Extra",
+ "REQUEST-STATUS:2.0;Success;Extra\;here",
+ "REQUEST-STATUS:2.0;Success\;here;Extra\;here too",
+ )
+
+ for item in items:
+ req = Property.parseText(item)
+ self.assertEqual(req.getText(), item + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_timezonepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_timezonepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_timezone.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,235 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.icalendar.calendar import Calendar
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+ def testOffsets(self):
+
+ data = (
+ ("""BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:STANDARD
+DTSTART:18831118T120358
+RDATE:18831118T120358
+TZNAME:EST
+TZOFFSETFROM:-045602
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19180331T020000
+RRULE:FREQ=YEARLY;UNTIL=19190330T070000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19181027T020000
+RRULE:FREQ=YEARLY;UNTIL=19191026T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19200101T000000
+RDATE:19200101T000000
+RDATE:19420101T000000
+RDATE:19460101T000000
+RDATE:19670101T000000
+TZNAME:EST
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19200328T020000
+RDATE:19200328T020000
+RDATE:19740106T020000
+RDATE:19750223T020000
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19201031T020000
+RDATE:19201031T020000
+RDATE:19450930T020000
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19210424T020000
+RRULE:FREQ=YEARLY;UNTIL=19410427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19210925T020000
+RRULE:FREQ=YEARLY;UNTIL=19410928T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19420209T020000
+RDATE:19420209T020000
+TZNAME:EWT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19450814T190000
+RDATE:19450814T190000
+TZNAME:EPT
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19460428T020000
+RRULE:FREQ=YEARLY;UNTIL=19660424T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19460929T020000
+RRULE:FREQ=YEARLY;UNTIL=19540926T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19551030T020000
+RRULE:FREQ=YEARLY;UNTIL=19661030T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19670430T020000
+RRULE:FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;UNTIL=20061029T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;UNTIL=19860427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+""",
+ (
+ (DateTime(1942, 2, 8), -5),
+ (DateTime(1942, 2, 10), -4),
+ (DateTime(2011, 1, 1), -5),
+ (DateTime(2011, 4, 1), -4),
+ (DateTime(2011, 10, 24), -4),
+ (DateTime(2011, 11, 8), -5),
+ (DateTime(2006, 1, 1), -5),
+ (DateTime(2006, 4, 1), -5),
+ (DateTime(2006, 5, 1), -4),
+ (DateTime(2006, 10, 1), -4),
+ (DateTime(2006, 10, 24), -4),
+ (DateTime(2006, 11, 8), -5),
+ )
+ ),
+ ("""BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+8
+X-LIC-LOCATION:Etc/GMT+8
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+8
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+""",
+ (
+ (DateTime(1942, 2, 8), -8),
+ (DateTime(1942, 2, 10), -8),
+ (DateTime(2011, 1, 1), -8),
+ (DateTime(2011, 4, 1), -8),
+ )
+ ),
+ )
+
+ for tzdata, offsets in data:
+
+ cal = Calendar.parseText(tzdata.replace("\n", "\r\n"))
+ tz = cal.getComponents()[0]
+
+ for dt, offset in offsets:
+ tzoffset = tz.getTimezoneOffsetSeconds(dt)
+ self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s with caching" % (tz.getID(), dt,))
+ for dt, offset in reversed(offsets):
+ tzoffset = tz.getTimezoneOffsetSeconds(dt)
+ self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s with caching, reversed" % (tz.getID(), dt,))
+
+ for dt, offset in offsets:
+ tz.mCachedExpandAllMax = None
+ tzoffset = tz.getTimezoneOffsetSeconds(dt)
+ self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s without caching" % (tz.getID(), dt,))
+ for dt, offset in reversed(offsets):
+ tz.mCachedExpandAllMax = None
+ tzoffset = tz.getTimezoneOffsetSeconds(dt)
+ self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s without caching, reversed" % (tz.getID(), dt,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_validationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,8 +14,8 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.exceptions import PyCalendarValidationError
</del><ins>+from pycalendar.exceptions import ValidationError
+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> import unittest
</span><span class="cx">
</span><span class="cx"> class TestValidation(unittest.TestCase):
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, item, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(item)
</del><ins>+ cal = Calendar.parseText(item)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=False)
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(unfixed), test_unfixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -216,7 +216,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=False, doRaise=False)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -367,7 +367,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True, doRaise=False)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -523,9 +523,9 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed, test_raises in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> if test_raises:
</span><del>- self.assertRaises(PyCalendarValidationError, cal.validate, doFix=False, doRaise=True)
</del><ins>+ self.assertRaises(ValidationError, cal.validate, doFix=False, doRaise=True)
</ins><span class="cx"> else:
</span><span class="cx"> try:
</span><span class="cx"> fixed, unfixed = cal.validate(doFix=False, doRaise=False)
</span><span class="lines">@@ -685,9 +685,9 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed, test_raises in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> if test_raises:
</span><del>- self.assertRaises(PyCalendarValidationError, cal.validate, doFix=False, doRaise=True)
</del><ins>+ self.assertRaises(ValidationError, cal.validate, doFix=False, doRaise=True)
</ins><span class="cx"> else:
</span><span class="cx"> try:
</span><span class="cx"> fixed, unfixed = cal.validate(doFix=True, doRaise=False)
</span><span class="lines">@@ -977,7 +977,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -1047,7 +1047,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -1115,7 +1115,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -1260,7 +1260,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -1482,7 +1482,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -1680,7 +1680,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -1874,7 +1874,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -2564,7 +2564,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -2713,7 +2713,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span><span class="lines">@@ -3182,7 +3182,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for title, test_old, test_new, test_doFix, test_fixed, test_unfixed in data:
</span><del>- cal = PyCalendar.parseText(test_old)
</del><ins>+ cal = Calendar.parseText(test_old)
</ins><span class="cx"> fixed, unfixed = cal.validate(doFix=test_doFix)
</span><span class="cx"> self.assertEqual(str(cal), test_new, msg="Failed test: %s" % (title,))
</span><span class="cx"> self.assertEqual(set(fixed), test_fixed, msg="Failed test: %s" % (title,))
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_vpollpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_vpollpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_vpoll.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,98 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import difflib
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+ data = (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VPOLL
+UID:A979D282-2CDB-484F-BD63-3972094DFFC0
+DTSTAMP:20020101T000000Z
+ORGANIZER:mailto:user01@example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+VOTER;CN=User 02:mailto:user02@example.com
+VOTER;CN=User 03:mailto:user03@example.com
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20130101
+DTEND;VALUE=DATE:20130102
+DTSTAMP:20020101T000000Z
+POLL-ITEM-ID:1
+SUMMARY:Party option #1
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20130201
+DTEND;VALUE=DATE:20130202
+DTSTAMP:20020101T000000Z
+POLL-ITEM-ID:2
+SUMMARY:Party option #2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+
+"""BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REPLY
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VPOLL
+UID:A979D282-2CDB-484F-BD63-3972094DFFC0
+DTSTAMP:20020101T000000Z
+ORGANIZER:mailto:user01@example.com
+POLL-ITEM-ID;PUBLIC-COMMENT=Not ideal;RESPONSE=50:1
+POLL-ITEM-ID;PUBLIC-COMMENT=Perfect;RESPONSE=100:2
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+VOTER;CN=User 02:mailto:user02@example.com
+END:VPOLL
+END:VCALENDAR
+""",
+
+)
+
+
+ def testRoundtrip(self):
+
+
+ def _doRoundtrip(caldata, resultdata=None):
+ test1 = resultdata if resultdata is not None else caldata
+
+ cal = Calendar()
+ cal.parse(StringIO.StringIO(caldata))
+
+ s = StringIO.StringIO()
+ cal.generate(s)
+ test2 = s.getvalue()
+
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+ for item in self.data:
+ _doRoundtrip(item.replace("\n", "\r\n"))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_xmlpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_xmlpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_xml.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,104 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import difflib
+import unittest
+
+class TestXML(unittest.TestCase):
+
+ data = (
+ (
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+X-TEST:Testing
+END:VCALENDAR
+""".replace("\n", "\r\n"),
+
+"""<?xml version="1.0" encoding="utf-8"?>
+<ns0:icalendar xmlns:ns0="urn:ietf:params:xml:ns:icalendar-2.0">
+ <ns0:vcalendar>
+ <ns0:properties>
+ <ns0:version>
+ <ns0:text>2.0</ns0:text>
+ </ns0:version>
+ <ns0:prodid>
+ <ns0:text>-//mulberrymail.com//Mulberry v4.0//EN</ns0:text>
+ </ns0:prodid>
+ <ns0:x-test>
+ <ns0:unknown>Testing</ns0:unknown>
+ </ns0:x-test>
+ </ns0:properties>
+ <ns0:components>
+ <ns0:vevent>
+ <ns0:properties>
+ <ns0:uid>
+ <ns0:text>12345-67890-3</ns0:text>
+ </ns0:uid>
+ <ns0:dtstart>
+ <ns0:date-time>2007-11-14T00:00:00Z</ns0:date-time>
+ </ns0:dtstart>
+ <ns0:attendee>
+ <ns0:cal-address>mailto:user2@example.com</ns0:cal-address>
+ </ns0:attendee>
+ <ns0:exdate>
+ <ns0:date-time>2008-11-14T00:00:00Z</ns0:date-time>
+ </ns0:exdate>
+ <ns0:organizer>
+ <ns0:cal-address>mailto:user1@example.com</ns0:cal-address>
+ </ns0:organizer>
+ <ns0:rrule>
+ <ns0:recur>
+ <ns0:freq>YEARLY</ns0:freq>
+ </ns0:recur>
+ </ns0:rrule>
+ </ns0:properties>
+ </ns0:vevent>
+ </ns0:components>
+ </ns0:vcalendar>
+</ns0:icalendar>
+""",
+ ),
+)
+
+ def testGenerateXML(self):
+
+ def _doRoundtrip(caldata, resultdata=None):
+ test1 = resultdata if resultdata is not None else caldata
+
+ cal = Calendar()
+ cal.parse(StringIO.StringIO(caldata))
+
+ test2 = cal.getTextXML()
+
+ self.assertEqual(
+ test1,
+ test2,
+ "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+ )
+
+ for item1, item2 in self.data:
+ _doRoundtrip(item1, item2)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvalarmpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvalarmpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/valarm.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/valarm.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/valarm.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/valarm.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,707 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.parameter import Parameter
+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.value import Value
+
+class VAlarm(Component):
+
+ sActionMap = {
+ definitions.cICalProperty_ACTION_AUDIO: definitions.eAction_VAlarm_Audio,
+ definitions.cICalProperty_ACTION_DISPLAY: definitions.eAction_VAlarm_Display,
+ definitions.cICalProperty_ACTION_EMAIL: definitions.eAction_VAlarm_Email,
+ definitions.cICalProperty_ACTION_PROCEDURE: definitions.eAction_VAlarm_Procedure,
+ definitions.cICalProperty_ACTION_URI: definitions.eAction_VAlarm_URI,
+ definitions.cICalProperty_ACTION_NONE: definitions.eAction_VAlarm_None,
+ }
+
+ sActionValueMap = {
+ definitions.eAction_VAlarm_Audio: definitions.cICalProperty_ACTION_AUDIO,
+ definitions.eAction_VAlarm_Display: definitions.cICalProperty_ACTION_DISPLAY,
+ definitions.eAction_VAlarm_Email: definitions.cICalProperty_ACTION_EMAIL,
+ definitions.eAction_VAlarm_Procedure: definitions.cICalProperty_ACTION_PROCEDURE,
+ definitions.eAction_VAlarm_URI: definitions.cICalProperty_ACTION_URI,
+ definitions.eAction_VAlarm_None: definitions.cICalProperty_ACTION_NONE,
+ }
+
+ # Classes for each action encapsulating action-specific data
+ class VAlarmAction(object):
+
+ propertyCardinality_1 = ()
+ propertyCardinality_1_Fix_Empty = ()
+ propertyCardinality_0_1 = ()
+ propertyCardinality_1_More = ()
+
+ def __init__(self, type):
+ self.mType = type
+
+ def duplicate(self):
+ return VAlarm.VAlarmAction(self.mType)
+
+ def load(self, valarm):
+ pass
+
+ def add(self, valarm):
+ pass
+
+ def remove(self, valarm):
+ pass
+
+ def getType(self):
+ return self.mType
+
+
+ class VAlarmAudio(VAlarmAction):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_ACTION,
+ definitions.cICalProperty_TRIGGER,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_REPEAT,
+ definitions.cICalProperty_ATTACH,
+ definitions.cICalProperty_ACKNOWLEDGED,
+ )
+
+ def __init__(self, speak=None):
+ super(VAlarm.VAlarmAudio, self).__init__(type=definitions.eAction_VAlarm_Audio)
+ self.mSpeakText = speak
+
+ def duplicate(self):
+ return VAlarm.VAlarmAudio(self.mSpeakText)
+
+ def load(self, valarm):
+ # Get properties
+ self.mSpeakText = valarm.loadValueString(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
+
+ def add(self, valarm):
+ # Delete existing then add
+ self.remove(valarm)
+
+ prop = Property(definitions.cICalProperty_ACTION_X_SPEAKTEXT, self.mSpeakText)
+ valarm.addProperty(prop)
+
+ def remove(self, valarm):
+ valarm.removeProperties(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
+
+ def isSpeakText(self):
+ return len(self.mSpeakText) != 0
+
+ def getSpeakText(self):
+ return self.mSpeakText
+
+
+ class VAlarmDisplay(VAlarmAction):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_ACTION,
+ definitions.cICalProperty_TRIGGER,
+ )
+
+ propertyCardinality_1_Fix_Empty = (
+ definitions.cICalProperty_DESCRIPTION,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_REPEAT,
+ definitions.cICalProperty_ACKNOWLEDGED,
+ )
+
+ def __init__(self, description=None):
+ super(VAlarm.VAlarmDisplay, self).__init__(type=definitions.eAction_VAlarm_Display)
+ self.mDescription = description
+
+ def duplicate(self):
+ return VAlarm.VAlarmDisplay(self.mDescription)
+
+ def load(self, valarm):
+ # Get properties
+ self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
+
+ def add(self, valarm):
+ # Delete existing then add
+ self.remove(valarm)
+
+ prop = Property(definitions.cICalProperty_DESCRIPTION, self.mDescription)
+ valarm.addProperty(prop)
+
+ def remove(self, valarm):
+ valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
+
+ def getDescription(self):
+ return self.mDescription
+
+
+ class VAlarmEmail(VAlarmAction):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_ACTION,
+ definitions.cICalProperty_TRIGGER,
+ )
+
+ propertyCardinality_1_Fix_Empty = (
+ definitions.cICalProperty_DESCRIPTION,
+ definitions.cICalProperty_SUMMARY,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_REPEAT,
+ definitions.cICalProperty_ACKNOWLEDGED,
+ )
+
+ propertyCardinality_1_More = (
+ definitions.cICalProperty_ATTENDEE,
+ )
+
+ def __init__(self, description=None, summary=None, attendees=None):
+ super(VAlarm.VAlarmEmail, self).__init__(type=definitions.eAction_VAlarm_Email)
+ self.mDescription = description
+ self.mSummary = summary
+ self.mAttendees = attendees
+
+ def duplicate(self):
+ return VAlarm.VAlarmEmail(self.mDescription, self.mSummary, self.mAttendees)
+
+ def load(self, valarm):
+ # Get properties
+ self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
+ self.mSummary = valarm.loadValueString(definitions.cICalProperty_SUMMARY)
+
+ self.mAttendees = []
+ if valarm.hasProperty(definitions.cICalProperty_ATTENDEE):
+ # Get each attendee
+ range = valarm.getProperties().get(definitions.cICalProperty_ATTENDEE, ())
+ for iter in range:
+ # Get the attendee value
+ attendee = iter.getCalAddressValue()
+ if attendee is not None:
+ self.mAttendees.append(attendee.getValue())
+
+ def add(self, valarm):
+ # Delete existing then add
+ self.remove(valarm)
+
+ prop = Property(definitions.cICalProperty_DESCRIPTION, self.mDescription)
+ valarm.addProperty(prop)
+
+ prop = Property(definitions.cICalProperty_SUMMARY, self.mSummary)
+ valarm.addProperty(prop)
+
+ for iter in self.mAttendees:
+ prop = Property(definitions.cICalProperty_ATTENDEE, iter, Value.VALUETYPE_CALADDRESS)
+ valarm.addProperty(prop)
+
+ def remove(self, valarm):
+ valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
+ valarm.removeProperties(definitions.cICalProperty_SUMMARY)
+ valarm.removeProperties(definitions.cICalProperty_ATTENDEE)
+
+ def getDescription(self):
+ return self.mDescription
+
+ def getSummary(self):
+ return self.mSummary
+
+ def getAttendees(self):
+ return self.mAttendees
+
+
+ class VAlarmUnknown(VAlarmAction):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_ACTION,
+ definitions.cICalProperty_TRIGGER,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_REPEAT,
+ definitions.cICalProperty_ACKNOWLEDGED,
+ )
+
+ def __init__(self):
+ super(VAlarm.VAlarmUnknown, self).__init__(type=definitions.eAction_VAlarm_Unknown)
+
+ def duplicate(self):
+ return VAlarm.VAlarmUnknown()
+
+
+ class VAlarmURI(VAlarmAction):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_ACTION,
+ definitions.cICalProperty_TRIGGER,
+ definitions.cICalProperty_URL,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_REPEAT,
+ definitions.cICalProperty_ACKNOWLEDGED,
+ )
+
+ def __init__(self, uri=None):
+ super(VAlarm.VAlarmURI, self).__init__(type=definitions.eAction_VAlarm_URI)
+ self.mURI = uri
+
+ def duplicate(self):
+ return VAlarm.VAlarmURI(self.mURI)
+
+ def load(self, valarm):
+ # Get properties
+ self.mURI = valarm.loadValueString(definitions.cICalProperty_URL)
+
+ def add(self, valarm):
+ # Delete existing then add
+ self.remove(valarm)
+
+ prop = Property(definitions.cICalProperty_URL, self.mURI)
+ valarm.addProperty(prop)
+
+ def remove(self, valarm):
+ valarm.removeProperties(definitions.cICalProperty_URL)
+
+ def getURI(self):
+ return self.mURI
+
+
+ class VAlarmNone(VAlarmAction):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_ACTION,
+ )
+
+ def __init__(self):
+ super(VAlarm.VAlarmNone, self).__init__(type=definitions.eAction_VAlarm_None)
+
+ def duplicate(self):
+ return VAlarm.VAlarmNone()
+
+
+ def getMimeComponentName(self):
+ # Cannot be sent as a separate MIME object
+ return None
+
+ sActionToAlarmMap = {
+ definitions.eAction_VAlarm_Audio: VAlarmAudio,
+ definitions.eAction_VAlarm_Display: VAlarmDisplay,
+ definitions.eAction_VAlarm_Email: VAlarmEmail,
+ definitions.eAction_VAlarm_URI: VAlarmURI,
+ definitions.eAction_VAlarm_None: VAlarmNone,
+ }
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+
+ super(VAlarm, self).__init__(parent=parent)
+
+ self.mAction = definitions.eAction_VAlarm_Display
+ self.mTriggerAbsolute = False
+ self.mTriggerOnStart = True
+ self.mTriggerOn = DateTime()
+
+ # Set duration default to 1 hour
+ self.mTriggerBy = Duration()
+ self.mTriggerBy.setDuration(60 * 60)
+
+ # Does not repeat by default
+ self.mRepeats = 0
+ self.mRepeatInterval = Duration()
+ self.mRepeatInterval.setDuration(5 * 60) # Five minutes
+
+ # Status
+ self.mStatusInit = False
+ self.mAlarmStatus = definitions.eAlarm_Status_Pending
+ self.mLastTrigger = DateTime()
+ self.mNextTrigger = DateTime()
+ self.mDoneCount = 0
+
+ # Create action data
+ self.mActionData = VAlarm.VAlarmDisplay("")
+
+
+ def duplicate(self, parent=None):
+ other = super(VAlarm, self).duplicate(parent=parent)
+ other.mAction = self.mAction
+ other.mTriggerAbsolute = self.mTriggerAbsolute
+ other.mTriggerOn = self.mTriggerOn.duplicate()
+ other.mTriggerBy = self.mTriggerBy.duplicate()
+ other.mTriggerOnStart = self.mTriggerOnStart
+
+ other.mRepeats = self.mRepeats
+ other.mRepeatInterval = self.mRepeatInterval.duplicate()
+
+ other.mAlarmStatus = self.mAlarmStatus
+ if self.mLastTrigger is not None:
+ other.mLastTrigger = self.mLastTrigger.duplicate()
+ if self.mNextTrigger is not None:
+ other.mNextTrigger = self.mNextTrigger.duplicate()
+ other.mDoneCount = self.mDoneCount
+
+ other.mActionData = self.mActionData.duplicate()
+ return other
+
+
+ def getType(self):
+ return definitions.cICalComponent_VALARM
+
+
+ def getAction(self):
+ return self.mAction
+
+
+ def getActionData(self):
+ return self.mActionData
+
+
+ def isTriggerAbsolute(self):
+ return self.mTriggerAbsolute
+
+
+ def getTriggerOn(self):
+ return self.mTriggerOn
+
+
+ def getTriggerDuration(self):
+ return self.mTriggerBy
+
+
+ def isTriggerOnStart(self):
+ return self.mTriggerOnStart
+
+
+ def getRepeats(self):
+ return self.mRepeats
+
+
+ def getInterval(self):
+ return self.mRepeatInterval
+
+
+ def added(self):
+ # Added to calendar so add to calendar notifier
+ # calstore::CCalendarNotifier::sCalendarNotifier.AddAlarm(this)
+
+ # Do inherited
+ super(VAlarm, self).added()
+
+
+ def removed(self):
+ # Removed from calendar so add to calendar notifier
+ # calstore::CCalendarNotifier::sCalendarNotifier.RemoveAlarm(this)
+
+ # Do inherited
+ super(VAlarm, self).removed()
+
+
+ def changed(self):
+ # Always force recalc of trigger status
+ self.mStatusInit = False
+
+ # Changed in calendar so change in calendar notifier
+ # calstore::CCalendarNotifier::sCalendarNotifier.ChangedAlarm(this)
+
+ # Do not do inherited as this is always a sub-component and we do not
+ # do top-level component changes
+ # super.changed()
+
+
+ def finalise(self):
+ # Do inherited
+ super(VAlarm, self).finalise()
+
+ # Get the ACTION
+ temp = self.loadValueString(definitions.cICalProperty_ACTION)
+ if temp is not None:
+ self.mAction = VAlarm.sActionMap.get(temp, definitions.eAction_VAlarm_Unknown)
+ self.loadAction()
+
+ # Get the trigger
+ if self.hasProperty(definitions.cICalProperty_TRIGGER):
+ # Determine the type of the value
+ temp1 = self.loadValueDateTime(definitions.cICalProperty_TRIGGER)
+ temp2 = self.loadValueDuration(definitions.cICalProperty_TRIGGER)
+ if temp1 is not None:
+ self.mTriggerAbsolute = True
+ self.mTriggerOn = temp1
+ elif temp2 is not None:
+ self.mTriggerAbsolute = False
+ self.mTriggerBy = temp2
+
+ # Get the property
+ prop = self.findFirstProperty(definitions.cICalProperty_TRIGGER)
+
+ # Look for RELATED parameter
+ if prop.hasParameter(definitions.cICalParameter_RELATED):
+ temp = prop.getParameterValue(definitions.cICalParameter_RELATED)
+ if temp == definitions.cICalParameter_RELATED_START:
+ self.mTriggerOnStart = True
+ elif temp == definitions.cICalParameter_RELATED_END:
+ self.mTriggerOnStart = False
+ else:
+ self.mTriggerOnStart = True
+
+ # Get repeat & interval
+ temp = self.loadValueInteger(definitions.cICalProperty_REPEAT)
+ if temp is not None:
+ self.mRepeats = temp
+ temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+ if temp is not None:
+ self.mRepeatInterval = temp
+
+ # Set a map key for sorting
+ self.mMapKey = "%s:%s" % (self.mAction, self.mTriggerOn if self.mTriggerAbsolute else self.mTriggerBy,)
+
+ # Alarm status - private to Mulberry
+ status = self.loadValueString(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
+ if status is not None:
+ if status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING:
+ self.mAlarmStatus = definitions.eAlarm_Status_Pending
+ elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED:
+ self.mAlarmStatus = definitions.eAlarm_Status_Completed
+ elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED:
+ self.mAlarmStatus = definitions.eAlarm_Status_Disabled
+ else:
+ self.mAlarmStatus = definitions.eAlarm_Status_Pending
+
+ # Last trigger time - private to Mulberry
+ temp = self.loadValueDateTime(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
+ if temp is not None:
+ self.mLastTrigger = temp
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems, else raise. If
+ loggedProblems is not None it must be a C{list} and problem descriptions are appended
+ to that.
+ """
+
+ # Validate using action specific constraints
+ self.propertyCardinality_1 = self.mActionData.propertyCardinality_1
+ self.propertyCardinality_1_Fix_Empty = self.mActionData.propertyCardinality_1_Fix_Empty
+ self.propertyCardinality_0_1 = self.mActionData.propertyCardinality_0_1
+ self.propertyCardinality_1_More = self.mActionData.propertyCardinality_1_More
+
+ fixed, unfixed = super(VAlarm, self).validate(doFix)
+
+ # Extra constraint: both DURATION and REPEAT must be present togethe
+ if self.hasProperty(definitions.cICalProperty_DURATION) ^ self.hasProperty(definitions.cICalProperty_REPEAT):
+ # Cannot fix this
+ logProblem = "[%s] Properties must be present together: %s, %s" % (
+ self.getType(),
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_REPEAT,
+ )
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ def editStatus(self, status):
+ # Remove existing
+ self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
+
+ # Updated cached values
+ self.mAlarmStatus = status
+
+ # Add new
+ status_txt = ""
+ if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
+ status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
+ elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
+ status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
+ elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
+ status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
+ self.addProperty(Property(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status_txt))
+
+
+ def editAction(self, action, data):
+ # Remove existing
+ self.removeProperties(definitions.cICalProperty_ACTION)
+ self.mActionData.remove(self)
+ self.mActionData = None
+
+ # Updated cached values
+ self.mAction = action
+ self.mActionData = data
+
+ # Add new properties to alarm
+ action_txt = VAlarm.sActionValueMap.get(self.mAction, definitions.cICalProperty_ACTION_PROCEDURE)
+
+ prop = Property(definitions.cICalProperty_ACTION, action_txt)
+ self.addProperty(prop)
+
+ self.mActionData.add(self)
+
+
+ def editTriggerOn(self, dt):
+ # Remove existing
+ self.removeProperties(definitions.cICalProperty_TRIGGER)
+
+ # Updated cached values
+ self.mTriggerAbsolute = True
+ self.mTriggerOn = dt
+
+ # Add new
+ prop = Property(definitions.cICalProperty_TRIGGER, dt)
+ self.addProperty(prop)
+
+
+ def editTriggerBy(self, duration, trigger_start):
+ # Remove existing
+ self.removeProperties(definitions.cICalProperty_TRIGGER)
+
+ # Updated cached values
+ self.mTriggerAbsolute = False
+ self.mTriggerBy = duration
+ self.mTriggerOnStart = trigger_start
+
+ # Add new (with parameter)
+ prop = Property(definitions.cICalProperty_TRIGGER, duration)
+ attr = Parameter(definitions.cICalParameter_RELATED,
+ (definitions.cICalParameter_RELATED_START,
+ definitions.cICalParameter_RELATED_END)[not trigger_start])
+ prop.addParameter(attr)
+ self.addProperty(prop)
+
+
+ def editRepeats(self, repeat, interval):
+ # Remove existing
+ self.removeProperties(definitions.cICalProperty_REPEAT)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+
+ # Updated cached values
+ self.mRepeats = repeat
+ self.mRepeatInterval = interval
+
+ # Add new
+ if self.mRepeats > 0:
+ self.addProperty(Property(definitions.cICalProperty_REPEAT, repeat))
+ self.addProperty(Property(definitions.cICalProperty_DURATION, interval))
+
+
+ def getAlarmStatus(self):
+ return self.mAlarmStatus
+
+
+ def getNextTrigger(self, dt):
+ if not self.mStatusInit:
+ self.initNextTrigger()
+ dt.copy(self.mNextTrigger)
+
+
+ def alarmTriggered(self, dt):
+ # Remove existing
+ self.removeProperties(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
+ self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
+
+ # Updated cached values
+ self.mLastTrigger.copy(dt)
+
+ if self.mDoneCount < self.mRepeats:
+ self.mNextTrigger = self.mLastTrigger + self.mRepeatInterval
+ dt.copy(self.mNextTrigger)
+ self.mDoneCount += 1
+ self.mAlarmStatus = definitions.eAlarm_Status_Pending
+ else:
+ self.mAlarmStatus = definitions.eAlarm_Status_Completed
+
+ # Add new
+ self.addProperty(Property(definitions.cICalProperty_ALARM_X_LASTTRIGGER, dt))
+ status = ""
+ if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
+ status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
+ elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
+ status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
+ elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
+ status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
+ self.addProperty(Property(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status))
+
+ # Now update dt to the next alarm time
+ return self.mAlarmStatus == definitions.eAlarm_Status_Pending
+
+
+ def loadAction(self):
+ # Delete current one
+ self.mActionData = None
+ self.mActionData = VAlarm.sActionToAlarmMap.get(self.mAction, VAlarm.VAlarmUnknown)()
+ self.mActionData.load(self)
+
+
+ def initNextTrigger(self):
+ # Do not bother if its completed
+ if self.mAlarmStatus == definitions.eAlarm_Status_Completed:
+ return
+ self.mStatusInit = True
+
+ # Look for trigger immediately preceeding or equal to utc now
+ nowutc = DateTime.getNowUTC()
+
+ # Init done counter
+ self.mDoneCount = 0
+
+ # Determine the first trigger
+ trigger = DateTime()
+ self.getFirstTrigger(trigger)
+
+ while self.mDoneCount < self.mRepeats:
+ # See if next trigger is later than now
+ next_trigger = trigger + self.mRepeatInterval
+ if next_trigger > nowutc:
+ break
+ self.mDoneCount += 1
+ trigger = next_trigger
+
+ # Check for completion
+ if trigger == self.mLastTrigger or (nowutc - trigger).getTotalSeconds() > 24 * 60 * 60:
+ if self.mDoneCount == self.mRepeats:
+ self.mAlarmStatus = definitions.eAlarm_Status_Completed
+ return
+ else:
+ trigger = trigger + self.mRepeatInterval
+ self.mDoneCount += 1
+
+ self.mNextTrigger = trigger
+
+
+ def getFirstTrigger(self, dt):
+ # If absolute trigger, use that
+ if self.isTriggerAbsolute():
+ # Get the trigger on
+ dt.copy(self.getTriggerOn())
+ else:
+ # Get the parent embedder class (must be CICalendarComponentRecur type)
+ owner = self.getEmbedder()
+ if owner is not None:
+ # Determine time at which alarm will trigger
+ trigger = (owner.getStart(), owner.getEnd())[not self.isTriggerOnStart()]
+
+ # Offset by duration
+ dt.copy(trigger + self.getTriggerDuration())
+
+Component.registerComponent(definitions.cICalComponent_VALARM, VAlarm)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvalidationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import definitions
</del><ins>+from pycalendar.icalendar import definitions
</ins><span class="cx"> from pycalendar.validation import partial, PropertyValueChecks
</span><span class="cx">
</span><span class="cx"> ICALENDAR_VALUE_CHECKS = {
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvavailabilitypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvavailabilitypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vavailability.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,109 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VAvailability(Component):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_UID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_BUSYTYPE,
+ definitions.cICalProperty_CLASS,
+ definitions.cICalProperty_CREATED,
+ definitions.cICalProperty_DESCRIPTION,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_ORGANIZER,
+ definitions.cICalProperty_SEQUENCE,
+ definitions.cICalProperty_SUMMARY,
+ definitions.cICalProperty_URL,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+ super(VAvailability, self).__init__(parent=parent)
+
+
+ def duplicate(self, parent=None):
+ return super(VAvailability, self).duplicate(parent=parent)
+
+
+ def getType(self):
+ return definitions.cICalComponent_VAVAILABILITY
+
+
+ def getMimeComponentName(self):
+ return itipdefinitions.cICalMIMEComponent_VAVAILABILITY
+
+
+ def finalise(self):
+ super(VAvailability, self).finalise()
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems, else raise. If
+ loggedProblems is not None it must be a C{list} and problem descriptions are appended
+ to that.
+ """
+
+ fixed, unfixed = super(VAvailability, self).validate(doFix)
+
+ # Extra constraint: only one of DTEND or DURATION
+ if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
+ # Fix by removing the DTEND
+ logProblem = "[%s] Properties must not both be present: %s, %s" % (
+ self.getType(),
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ )
+ if doFix:
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ fixed.append(logProblem)
+ else:
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ def addComponent(self, comp):
+ # We can embed the available components only
+ if comp.getType() == definitions.cICalComponent_AVAILABLE:
+ super(VAvailability, self).addComponent(comp)
+ else:
+ raise ValueError
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_DTEND,
+ )
+
+Component.registerComponent(definitions.cICalComponent_VAVAILABILITY, VAvailability)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarveventpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarveventpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vevent.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vevent.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vevent.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vevent.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,172 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VEvent(ComponentRecur):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_UID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_CLASS,
+ definitions.cICalProperty_CREATED,
+ definitions.cICalProperty_DESCRIPTION,
+ definitions.cICalProperty_GEO,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_LOCATION,
+ definitions.cICalProperty_ORGANIZER,
+ definitions.cICalProperty_PRIORITY,
+ definitions.cICalProperty_SEQUENCE,
+ # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
+ definitions.cICalProperty_SUMMARY,
+ definitions.cICalProperty_TRANSP,
+ definitions.cICalProperty_URL,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_RRULE,
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+ super(VEvent, self).__init__(parent=parent)
+ self.mStatus = definitions.eStatus_VEvent_None
+
+
+ def duplicate(self, parent=None):
+ other = super(VEvent, self).duplicate(parent=parent)
+ other.mStatus = self.mStatus
+ return other
+
+
+ def getType(self):
+ return definitions.cICalComponent_VEVENT
+
+
+ def getMimeComponentName(self):
+ return itipdefinitions.cICalMIMEComponent_VEVENT
+
+
+ def addComponent(self, comp):
+ # We can embed the alarm components only
+ if comp.getType() == definitions.cICalComponent_VALARM:
+ super(VEvent, self).addComponent(comp)
+ else:
+ raise ValueError
+
+
+ def getStatus(self):
+ return self.mStatus
+
+
+ def setStatus(self, status):
+ self.mStatus = status
+
+
+ def finalise(self):
+ # Do inherited
+ super(VEvent, self).finalise()
+
+ temp = self.loadValueString(definitions.cICalProperty_STATUS)
+ if temp is not None:
+ if temp == definitions.cICalProperty_STATUS_TENTATIVE:
+ self.mStatus = definitions.eStatus_VEvent_Tentative
+ elif temp == definitions.cICalProperty_STATUS_CONFIRMED:
+ self.mStatus = definitions.eStatus_VEvent_Confirmed
+ elif temp == definitions.cICalProperty_STATUS_CANCELLED:
+ self.mStatus = definitions.eStatus_VEvent_Cancelled
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems, else raise. If
+ loggedProblems is not None it must be a C{list} and problem descriptions are appended
+ to that.
+ """
+
+ fixed, unfixed = super(VEvent, self).validate(doFix)
+
+ # Extra constraint: if METHOD not present, DTSTART must be
+ if self.mParentComponent and not self.mParentComponent.hasProperty(definitions.cICalProperty_METHOD):
+ if not self.hasProperty(definitions.cICalProperty_DTSTART):
+ # Cannot fix a missing required property
+ logProblem = "[%s] Missing required property: %s" % (self.getType(), definitions.cICalProperty_DTSTART,)
+ unfixed.append(logProblem)
+
+ # Extra constraint: only one of DTEND or DURATION
+ if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
+ # Fix by removing the DTEND
+ logProblem = "[%s] Properties must not both be present: %s, %s" % (
+ self.getType(),
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ )
+ if doFix:
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ fixed.append(logProblem)
+ else:
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ # Editing
+ def editStatus(self, status):
+ # Only if it is different
+ if self.mStatus != status:
+ # Updated cached values
+ self.mStatus = status
+
+ # Remove existing STATUS items
+ self.removeProperties(definitions.cICalProperty_STATUS)
+
+ # Now create properties
+ value = None
+ if status == definitions.eStatus_VEvent_None:
+ pass
+ elif status == definitions.eStatus_VEvent_Tentative:
+ value = definitions.cICalProperty_STATUS_TENTATIVE
+ elif status == definitions.eStatus_VEvent_Confirmed:
+ value = definitions.cICalProperty_STATUS_CONFIRMED
+ elif status == definitions.eStatus_VEvent_Cancelled:
+ value = definitions.cICalProperty_STATUS_CANCELLED
+ else:
+ pass
+
+ if value is not None:
+ prop = Property(definitions.cICalProperty_STATUS, value)
+ self.addProperty(prop)
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_DTEND,
+ )
+
+Component.registerComponent(definitions.cICalComponent_VEVENT, VEvent)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvfreebusypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvfreebusypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vfreebusy.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,347 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.freebusy import FreeBusy
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.period import Period
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.value import Value
+
+class VFreeBusy(Component):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_UID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_CONTACT,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_ORGANIZER,
+ definitions.cICalProperty_URL,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+ super(VFreeBusy, self).__init__(parent=parent)
+ self.mStart = DateTime()
+ self.mHasStart = False
+ self.mEnd = DateTime()
+ self.mHasEnd = False
+ self.mDuration = False
+ self.mCachedBusyTime = False
+ self.mSpanPeriod = None
+ self.mBusyTime = None
+
+
+ def duplicate(self, parent=None):
+ other = super(VFreeBusy, self).duplicate(parent=parent)
+ other.mStart = self.mStart.duplicate()
+ other.mHasStart = self.mHasStart
+ other.mEnd = self.mEnd.duplicate()
+ other.mHasEnd = self.mHasEnd
+ other.mDuration = self.mDuration
+ other.mCachedBusyTime = False
+ other.mBusyTime = None
+ return other
+
+
+ def getType(self):
+ return definitions.cICalComponent_VFREEBUSY
+
+
+ def getMimeComponentName(self):
+ return itipdefinitions.cICalMIMEComponent_VFREEBUSY
+
+
+ def finalise(self):
+ # Do inherited
+ super(VFreeBusy, self).finalise()
+
+ # Get DTSTART
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
+ self.mHasStart = temp is not None
+ if self.mHasStart:
+ self.mStart = temp
+
+ # Get DTEND
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
+ if temp is None:
+ # Try DURATION instead
+ temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+ if temp is not None:
+ self.mEnd = self.mStart + temp
+ self.mDuration = True
+ else:
+ # Force end to start, which will then be fixed to sensible
+ # value later
+ self.mEnd = self.mStart
+ else:
+ self.mHasEnd = True
+ self.mDuration = False
+ self.mEnd = temp
+
+
+ def fixStartEnd(self):
+ # End is always greater than start if start exists
+ if self.mHasStart and self.mEnd <= self.mStart:
+ # Use the start
+ self.mEnd = self.mStart.duplicate()
+ self.mDuration = False
+
+ # Adjust to appropiate non-inclusive end point
+ if self.mStart.isDateOnly():
+ self.mEnd.offsetDay(1)
+
+ # For all day events it makes sense to use duration
+ self.mDuration = True
+ else:
+ # Use end of current day
+ self.mEnd.offsetDay(1)
+ self.mEnd.setHHMMSS(0, 0, 0)
+
+
+ def getStart(self):
+ return self.mStart
+
+
+ def hasStart(self):
+ return self.mHasStart
+
+
+ def getEnd(self):
+ return self.mEnd
+
+
+ def hasEnd(self):
+ return self.mHasEnd
+
+
+ def useDuration(self):
+ return self.mDuration
+
+
+ def getSpanPeriod(self):
+ return self.mSpanPeriod
+
+
+ def getBusyTime(self):
+ return self.mBusyTime
+
+
+ def editTiming(self):
+ # Updated cached values
+ self.mHasStart = False
+ self.mHasEnd = False
+ self.mDuration = False
+ self.mStart.setToday()
+ self.mEnd.setToday()
+
+ # Remove existing DTSTART & DTEND & DURATION & DUE items
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+
+
+ def editTimingStartEnd(self, start, end):
+ # Updated cached values
+ self.mHasStart = self.mHasEnd = True
+ self.mStart = start
+ self.mEnd = end
+ self.mDuration = False
+ self.fixStartEnd()
+
+ # Remove existing DTSTART & DTEND & DURATION & DUE items
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+
+ # Now create properties
+ prop = Property(definitions.cICalProperty_DTSTART, start)
+ self.addProperty(prop)
+
+ # If its an all day event and the end one day after the start, ignore it
+ temp = start.duplicate()
+ temp.offsetDay(1)
+ if not start.isDateOnly() or end != temp:
+ prop = Property(definitions.cICalProperty_DTEND, end)
+ self.addProperty(prop)
+
+
+ def editTimingStartDuration(self, start, duration):
+ # Updated cached values
+ self.mHasStart = True
+ self.mHasEnd = False
+ self.mStart = start
+ self.mEnd = start + duration
+ self.mDuration = True
+
+ # Remove existing DTSTART & DTEND & DURATION & DUE items
+ self.removeProperties(definitions.cICalProperty_DTSTART)
+ self.removeProperties(definitions.cICalProperty_DTEND)
+ self.removeProperties(definitions.cICalProperty_DURATION)
+ self.removeProperties(definitions.cICalProperty_DUE)
+
+ # Now create properties
+ prop = Property(definitions.cICalProperty_DTSTART, start)
+ self.addProperty(prop)
+
+ # If its an all day event and the duration is one day, ignore it
+ if (not start.isDateOnly() or (duration.getWeeks() != 0)
+ or (duration.getDays() > 1)):
+ prop = Property(definitions.cICalProperty_DURATION, duration)
+ self.addProperty(prop)
+
+
+ # Generating info
+ def expandPeriodComp(self, period, list):
+ # Cache the busy-time details if not done already
+ if not self.mCachedBusyTime:
+ self.cacheBusyTime()
+
+ # See if period intersects the busy time span range
+ if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
+ list.append(self)
+
+
+ def expandPeriodFB(self, period, list):
+ # Cache the busy-time details if not done already
+ if not self.mCachedBusyTime:
+ self.cacheBusyTime()
+
+ # See if period intersects the busy time span range
+ if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
+ for fb in self.mBusyTime:
+ list.append(FreeBusy(fb))
+
+
+ def cacheBusyTime(self):
+
+ # Clear out any existing cache
+ self.mBusyTime = []
+
+ # Get all FREEBUSY items and add those that are BUSY
+ min_start = DateTime()
+ max_end = DateTime()
+ props = self.getProperties()
+ result = props.get(definitions.cICalProperty_FREEBUSY, ())
+ for iter in result:
+
+ # Check the properties FBTYPE parameter
+ type = 0
+ is_busy = False
+ if iter.hasParameter(definitions.cICalParameter_FBTYPE):
+
+ fbyype = iter.getParameterValue(definitions.cICalParameter_FBTYPE)
+ if fbyype.upper() == definitions.cICalParameter_FBTYPE_BUSY:
+
+ is_busy = True
+ type = FreeBusy.BUSY
+
+ elif fbyype.upper() == definitions.cICalParameter_FBTYPE_BUSYUNAVAILABLE:
+
+ is_busy = True
+ type = FreeBusy.BUSYUNAVAILABLE
+
+ elif fbyype.upper() == definitions.cICalParameter_FBTYPE_BUSYTENTATIVE:
+
+ is_busy = True
+ type = FreeBusy.BUSYTENTATIVE
+
+ else:
+
+ is_busy = False
+ type = FreeBusy.FREE
+
+ else:
+
+ # Default is busy when no parameter
+ is_busy = True
+ type = FreeBusy.BUSY
+
+ # Add this period
+ if is_busy:
+
+ multi = iter.getMultiValue()
+ if (multi is not None) and (multi.getType() == Value.VALUETYPE_PERIOD):
+
+ for o in multi.getValues():
+
+ # Double-check type
+ period = None
+ if isinstance(o, PeriodValue):
+ period = o
+
+ # Double-check type
+ if period is not None:
+
+ self.mBusyTime.append(FreeBusy(type, period.getValue()))
+
+ if len(self.mBusyTime) == 1:
+
+ min_start = period.getValue().getStart()
+ max_end = period.getValue().getEnd()
+
+ else:
+
+ if min_start > period.getValue().getStart():
+ min_start = period.getValue().getStart()
+ if max_end < period.getValue().getEnd():
+ max_end = period.getValue().getEnd()
+
+ # If nothing present, empty the list
+ if len(self.mBusyTime) == 0:
+
+ self.mBusyTime = None
+
+ else:
+
+ # Sort the list by period
+ self.mBusyTime.sort(cmp=lambda x, y: x.getPeriod().getStart().compareDateTime(y.getPeriod().getStart()))
+
+ # Determine range
+ start = DateTime()
+ end = DateTime()
+ if self.mHasStart:
+ start = self.mStart
+ else:
+ start = min_start
+ if self.mHasEnd:
+ end = self.mEnd
+ else:
+ end = max_end
+
+ self.mSpanPeriod = Period(start, end)
+
+ self.mCachedBusyTime = True
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_DTEND,
+ )
+
+Component.registerComponent(definitions.cICalComponent_VFREEBUSY, VFreeBusy)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvjournalpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvjournalpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vjournal.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VJournal(ComponentRecur):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_UID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_CLASS,
+ definitions.cICalProperty_CREATED,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_ORGANIZER,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_SEQUENCE,
+ # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
+ definitions.cICalProperty_SUMMARY,
+ definitions.cICalProperty_URL,
+ definitions.cICalProperty_RRULE,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+ super(VJournal, self).__init__(parent=parent)
+
+
+ def duplicate(self, parent=None):
+ return super(VJournal, self).duplicate(parent=parent)
+
+
+ def getType(self):
+ return definitions.cICalComponent_VJOURNAL
+
+
+ def getMimeComponentName(self):
+ return itipdefinitions.cICalMIMEComponent_VJOURNAL
+
+
+ def finalise(self):
+ super(VJournal, self).finalise()
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_DTSTART,
+ )
+
+Component.registerComponent(definitions.cICalComponent_VJOURNAL, VJournal)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvpollpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvpollpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vpoll.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,79 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VPoll(Component):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_ORGANIZER,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_ACCEPT_RESPONSE,
+ definitions.cICalProperty_CLASS,
+ definitions.cICalProperty_CREATED,
+ definitions.cICalProperty_COMPLETED,
+ definitions.cICalProperty_DESCRIPTION,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DTEND,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_POLL_MODE,
+ definitions.cICalProperty_POLL_PROPERTIES,
+ definitions.cICalProperty_PRIORITY,
+ definitions.cICalProperty_SEQUENCE,
+ definitions.cICalProperty_STATUS,
+ definitions.cICalProperty_SUMMARY,
+ definitions.cICalProperty_URL,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def getType(self):
+ return definitions.cICalComponent_VPOLL
+
+
+ def getMimeComponentName(self):
+ return itipdefinitions.cICalMIMEComponent_VPOLL
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_DTEND,
+ )
+
+
+ def sortedComponents(self):
+ """
+ Also take POLL-ID into account
+ """
+
+ components = self.mComponents[:]
+
+ # Write out the remainder sorted by name, sortKey
+ return sorted(components, key=lambda x: (x.getType().upper(), x.loadValueString(definitions.cICalProperty_POLL_ITEM_ID),))
+
+
+Component.registerComponent(definitions.cICalComponent_VPOLL, VPoll)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezonepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezonepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezone.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,287 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VTimezone(Component):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_TZID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_TZURL,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ UTCOFFSET_CACHE_MAX_ENTRIES = 100000
+
+ sortSubComponents = False
+
+ def __init__(self, parent=None):
+ super(VTimezone, self).__init__(parent=parent)
+ self.mID = ""
+ self.mUTCOffsetSortKey = None
+ self.mCachedExpandAllMaxYear = None
+ self.mCachedOffsets = None
+
+
+ def duplicate(self, parent=None):
+ other = super(VTimezone, self).duplicate(parent=parent)
+ other.mID = self.mID
+ other.mUTCOffsetSortKey = self.mUTCOffsetSortKey
+ return other
+
+
+ def getType(self):
+ return definitions.cICalComponent_VTIMEZONE
+
+
+ def getMimeComponentName(self):
+ # Cannot be sent as a separate MIME object
+ return None
+
+
+ def addComponent(self, comp):
+ # We can embed the timezone components only
+ if ((comp.getType() == definitions.cICalComponent_STANDARD)
+ or (comp.getType() == definitions.cICalComponent_DAYLIGHT)):
+ super(VTimezone, self).addComponent(comp)
+ else:
+ raise ValueError
+
+
+ def getMapKey(self):
+ return self.mID
+
+
+ def finalise(self):
+ # Get TZID
+ temp = self.loadValueString(definitions.cICalProperty_TZID)
+ if temp is not None:
+ self.mID = temp
+
+ # Sort sub-components by DTSTART
+ self.mComponents.sort(key=lambda x: x.getStart())
+
+ # Do inherited
+ super(VTimezone, self).finalise()
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems, else raise. If
+ loggedProblems is not None it must be a C{list} and problem descriptions are appended
+ to that.
+ """
+
+ fixed, unfixed = super(VTimezone, self).validate(doFix)
+
+ # Must have at least one STANDARD or DAYLIGHT sub-component
+ for component in self.mComponents:
+ if component.getType() in (definitions.cICalComponent_STANDARD, definitions.cICalComponent_DAYLIGHT):
+ break
+ else:
+ # Cannot fix a missing required component
+ logProblem = "[%s] At least one component must be present: %s or %s" % (
+ self.getType(),
+ definitions.cICalComponent_STANDARD,
+ definitions.cICalComponent_DAYLIGHT,
+ )
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ def getID(self):
+ return self.mID
+
+
+ def getUTCOffsetSortKey(self):
+ if self.mUTCOffsetSortKey is None:
+ # Take time from first element
+ if len(self.mComponents) > 0:
+ # Initial offset provides the primary key
+ utc_offset1 = self.mComponents[0].getUTCOffset()
+
+ # Presence of secondary is the next key
+ utc_offset2 = utc_offset1
+ if len(self.mComponents) > 1:
+ utc_offset2 = self.mComponents[1].getUTCOffset()
+
+ # Create key
+ self.mUTCOffsetSortKey = (utc_offset1 + utc_offset2) / 2
+ else:
+ self.mUTCOffsetSortKey = 0
+
+ return self.mUTCOffsetSortKey
+
+
+ def getTimezoneOffsetSeconds(self, dt):
+ """
+ Caching implementation of expansion. We cache the entire set of transitions up to one year ahead
+ of the requested time.
+ """
+
+ # Need to make the incoming date-time relative to the DTSTART in the
+ # timezone component for proper comparison.
+ # This means making the incoming date-time a floating (no timezone)
+ # item
+ temp = dt.duplicate()
+ temp.setTimezoneID(None)
+
+ # Check whether we need to recache
+ if self.mCachedExpandAllMaxYear is None or temp.mYear >= self.mCachedExpandAllMaxYear:
+ cacheMax = temp.duplicate()
+ cacheMax.setHHMMSS(0, 0, 0)
+ cacheMax.offsetYear(2)
+ cacheMax.setMonth(1)
+ cacheMax.setDay(1)
+ self.mCachedExpandAll = self.expandAll(None, cacheMax)
+ self.mCachedExpandAllMaxYear = cacheMax.mYear
+ self.mCachedOffsets = {}
+
+ # Now search for the transition just below the time we want
+ if len(self.mCachedExpandAll):
+ cacheKey = (temp.mYear, temp.mMonth, temp.mDay, temp.mHours, temp.mMinutes,)
+ i = self.mCachedOffsets.get(cacheKey)
+ if i is None:
+ i = VTimezone.tuple_bisect_right(self.mCachedExpandAll, temp)
+ if len(self.mCachedOffsets) >= self.UTCOFFSET_CACHE_MAX_ENTRIES:
+ self.mCachedOffsets = {}
+ self.mCachedOffsets[cacheKey] = i
+ if i != 0:
+ return self.mCachedExpandAll[i - 1][2]
+
+ return 0
+
+
+ def getTimezoneDescriptor(self, dt):
+ result = ""
+
+ # Get the closet matching element to the time
+ found = self.findTimezoneElement(dt)
+
+ # Get it
+ if found is not None:
+ if len(found.getTZName()) == 0:
+ tzoffset = found.getUTCOffset()
+ negative = False
+ if tzoffset < 0:
+ tzoffset = -tzoffset
+ negative = True
+ result = ("+", "-")[negative]
+ hours_offset = tzoffset / (60 * 60)
+ if hours_offset < 10:
+ result += "0"
+ result += str(hours_offset)
+ mins_offset = (tzoffset / 60) % 60
+ if mins_offset < 10:
+ result += "0"
+ result += str(mins_offset)
+ else:
+ result = "("
+ result += found.getTZName()
+ result += ")"
+
+ return result
+
+
+ def mergeTimezone(self, tz):
+ pass
+
+
+ @staticmethod
+ def tuple_bisect_right(a, x):
+ """
+ Same as bisect_right except that the values being compared are the first elements
+ of a tuple.
+ """
+
+ lo = 0
+ hi = len(a)
+ while lo < hi:
+ mid = (lo + hi) // 2
+ if x < a[mid][0]:
+ hi = mid
+ else:
+ lo = mid + 1
+ return lo
+
+
+ def findTimezoneElement(self, dt):
+ # Need to make the incoming date-time relative to the DTSTART in the
+ # timezone component for proper comparison.
+ # This means making the incoming date-time a floating (no timezone)
+ # item
+ temp = dt.duplicate()
+ temp.setTimezoneID(None)
+
+ # Had to rework this because some VTIMEZONEs have sub-components where the DST instances are interleaved. That
+ # means we have to evaluate each and every sub-component to find the instance immediately less than the time we are checking.
+
+ # Now do the expansion for each one found and pick the lowest
+ found = None
+ dt_found = DateTime()
+
+ for item in self.mComponents:
+ dt_item = item.expandBelow(temp)
+ if temp >= dt_item:
+ if found is not None:
+ # Compare with the one previously cached and switch to this
+ # one if newer
+ if dt_item > dt_found:
+ found = item
+ dt_found = dt_item
+ else:
+ found = item
+ dt_found = dt_item
+
+ return found
+
+
+ def expandAll(self, start, end, with_name=False):
+ results = []
+ for item in self.mComponents:
+ results.extend(item.expandAll(start, end, with_name))
+ results = [x for x in set(results)]
+ results.sort(key=lambda x: x[0].getPosixTime())
+ return results
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_TZID,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_TZURL,
+ )
+
+
+ @staticmethod
+ def sortByUTCOffsetComparator(tz1, tz2):
+ sort1 = tz1.getUTCOffsetSortKey()
+ sort2 = tz2.getUTCOffsetSortKey()
+ if sort1 == sort2:
+ return tz1.getID().compareToIgnoreCase(tz2.getID())
+ else:
+ return (1, -1)[sort1 < sort2]
+
+Component.registerComponent(definitions.cICalComponent_VTIMEZONE, VTimezone)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezonedaylightpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezonedaylightpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezonedaylight.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.vtimezoneelement import VTimezoneElement
+
+class Daylight(VTimezoneElement):
+
+ def __init__(self, parent=None):
+ super(Daylight, self).__init__(parent=parent)
+
+
+ def duplicate(self, parent=None):
+ return super(Daylight, self).duplicate(parent=parent)
+
+
+ def getType(self):
+ return definitions.cICalComponent_DAYLIGHT
+
+Component.registerComponent(definitions.cICalComponent_DAYLIGHT, Daylight)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezoneelementpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezoneelementpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezoneelement.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,219 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 bisect import bisect_right
+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.recurrenceset import RecurrenceSet
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.period import Period
+from pycalendar.value import Value
+
+class VTimezoneElement(Component):
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_TZOFFSETTO,
+ definitions.cICalProperty_TZOFFSETFROM,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_RRULE,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None, dt=None, offset=None):
+ super(VTimezoneElement, self).__init__(parent=parent)
+ self.mStart = dt if dt is not None else DateTime()
+ self.mTZName = ""
+ self.mUTCOffset = offset if offset is not None else 0
+ self.mUTCOffsetFrom = 0
+ self.mRecurrences = RecurrenceSet()
+ self.mCachedExpandBelow = None
+ self.mCachedExpandBelowItems = None
+
+
+ def duplicate(self, parent=None):
+ other = super(VTimezoneElement, self).duplicate(parent=parent)
+ other.mStart = self.mStart.duplicate()
+ other.mTZName = self.mTZName
+ other.mUTCOffset = self.mUTCOffset
+ other.mUTCOffsetFrom = self.mUTCOffsetFrom
+ other.mRecurrences = self.mRecurrences.duplicate()
+ other.mCachedExpandBelow = None
+ other.mCachedExpandBelowItems = None
+ return other
+
+
+ def finalise(self):
+ # Get DTSTART
+ temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
+ if temp is not None:
+ self.mStart = temp
+
+ # Get TZOFFSETTO
+ temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, Value.VALUETYPE_UTC_OFFSET)
+ if temp is not None:
+ self.mUTCOffset = temp
+
+ # Get TZOFFSETFROM
+ temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, Value.VALUETYPE_UTC_OFFSET)
+ if temp is not None:
+ self.mUTCOffsetFrom = temp
+
+ # Get TZNAME
+ temps = self.loadValueString(definitions.cICalProperty_TZNAME)
+ if temps is not None:
+ self.mTZName = temps
+
+ # Get RRULEs
+ self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
+
+ # Get RDATEs
+ self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
+
+ # Do inherited
+ super(VTimezoneElement, self).finalise()
+
+
+ def getSortKey(self):
+ """
+ We do not want these components sorted.
+ """
+ return ""
+
+
+ def getStart(self):
+ return self.mStart
+
+
+ def getUTCOffset(self):
+ return self.mUTCOffset
+
+
+ def getUTCOffsetFrom(self):
+ return self.mUTCOffsetFrom
+
+
+ def getTZName(self):
+ return self.mTZName
+
+
+ def expandBelow(self, below):
+
+ # Look for recurrences
+ if not self.mRecurrences.hasRecurrence() or self.mStart > below:
+ # Return DTSTART even if it is newer
+ return self.mStart
+ else:
+ # We want to allow recurrence calculation caching to help us here
+ # as this method
+ # gets called a lot - most likely for ever increasing dt values
+ # (which will therefore
+ # invalidate the recurrence cache).
+ #
+ # What we will do is round up the date-time to the next year so
+ # that the recurrence
+ # cache is invalidated less frequently
+
+ temp = DateTime(below.getYear(), 1, 1, 0, 0, 0)
+
+ # Use cache of expansion
+ if self.mCachedExpandBelowItems is None:
+ self.mCachedExpandBelowItems = []
+ if self.mCachedExpandBelow is None:
+ self.mCachedExpandBelow = self.mStart.duplicate()
+ if temp > self.mCachedExpandBelow:
+ self.mCachedExpandBelowItems = []
+ period = Period(self.mStart, temp)
+ self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
+ self.mCachedExpandBelow = temp
+
+ if len(self.mCachedExpandBelowItems) != 0:
+ # List comes back sorted so we pick the element just less than
+ # the dt value we want
+ i = bisect_right(self.mCachedExpandBelowItems, below)
+ if i != 0:
+ return self.mCachedExpandBelowItems[i - 1]
+
+ # The first one in the list is the one we want
+ return self.mCachedExpandBelowItems[0]
+
+ return self.mStart
+
+
+ def expandAll(self, start, end, with_name):
+
+ if start is None:
+ start = self.mStart
+
+ # Ignore if there is no change in offset
+ offsetto = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, Value.VALUETYPE_UTC_OFFSET)
+ offsetfrom = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, Value.VALUETYPE_UTC_OFFSET)
+# if offsetto == offsetfrom:
+# return ()
+
+ # Look for recurrences
+ if self.mStart > end:
+ # Return nothing
+ return ()
+ elif not self.mRecurrences.hasRecurrence():
+ # Return DTSTART even if it is newer
+ if self.mStart >= start:
+ result = (self.mStart, offsetfrom, offsetto,)
+ if with_name:
+ result += (self.getTZName(),)
+ return (result,)
+ else:
+ return ()
+ else:
+ # We want to allow recurrence calculation caching to help us here
+ # as this method
+ # gets called a lot - most likely for ever increasing dt values
+ # (which will therefore
+ # invalidate the recurrence cache).
+ #
+ # What we will do is round up the date-time to the next year so
+ # that the recurrence
+ # cache is invalidated less frequently
+
+ temp = DateTime(end.getYear(), 1, 1, 0, 0, 0)
+
+ # Use cache of expansion
+ if self.mCachedExpandBelowItems is None:
+ self.mCachedExpandBelowItems = []
+ if self.mCachedExpandBelow is None:
+ self.mCachedExpandBelow = self.mStart.duplicate()
+ if temp > self.mCachedExpandBelow:
+ self.mCachedExpandBelowItems = []
+ period = Period(self.mStart, end)
+ self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
+ self.mCachedExpandBelow = temp
+
+ if len(self.mCachedExpandBelowItems) != 0:
+ # Return them all within the range
+ results = []
+ for dt in self.mCachedExpandBelowItems:
+ if dt >= start and dt < end:
+ result = (dt, offsetfrom, offsetto,)
+ if with_name:
+ result += (self.getTZName(),)
+ results.append(result)
+ return results
+
+ return ()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezonestandardpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezonestandardpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezonestandard.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.vtimezoneelement import VTimezoneElement
+
+class Standard(VTimezoneElement):
+
+ def __init__(self, parent=None):
+ super(Standard, self).__init__(parent=parent)
+
+
+ def duplicate(self, parent=None):
+ return super(Standard, self).duplicate(parent=parent)
+
+
+ def getType(self):
+ return definitions.cICalComponent_STANDARD
+
+Component.registerComponent(definitions.cICalComponent_STANDARD, Standard)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtodopyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtodopy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtodo.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,369 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+import cStringIO as StringIO
+
+class VToDo(ComponentRecur):
+
+ OVERDUE = 0
+ DUE_NOW = 1
+ DUE_LATER = 2
+ DONE = 3
+ CANCELLED = 4
+
+ @staticmethod
+ def sort_for_display(e1, e2):
+ s1 = e1.getMaster()
+ s2 = e2.getMaster()
+
+ # Check status first (convert None -> Needs action for tests)
+ status1 = s1.self.mStatus
+ status2 = s2.self.mStatus
+ if status1 == definitions.eStatus_VToDo_None:
+ status1 = definitions.eStatus_VToDo_NeedsAction
+ if status2 == definitions.eStatus_VToDo_None:
+ status2 = definitions.eStatus_VToDo_NeedsAction
+ if status1 != status2:
+ # More important ones at the top
+ return status1 < status2
+
+ # At this point the status of each is the same
+
+ # If status is cancelled sort by start time
+ if s1.self.mStatus == definitions.eStatus_VToDo_Cancelled:
+ # Older ones at the bottom
+ return s1.mStart > s2.mStart
+
+ # If status is completed sort by completion time
+ if s1.self.mStatus == definitions.eStatus_VToDo_Completed:
+ # Older ones at the bottom
+ return s1.self.mCompleted > s2.self.mCompleted
+
+ # Check due date exists
+ if s1.mHasEnd != s2.mHasEnd:
+ now = DateTime()
+ now.setToday()
+
+ # Ones with due dates after today below ones without due dates
+ if s1.hasEnd():
+ return s1.mEnd <= now
+ elif s2.hasEnd():
+ return now < s2.mEnd
+
+ # Check due dates if present
+ if s1.mHasEnd:
+ if s1.mEnd != s2.mEnd:
+ # Soonest dues dates above later ones
+ return s1.mEnd < s2.mEnd
+
+ # Check priority next
+ if s1.self.mPriority != s2.self.mPriority:
+ # Higher priority above lower ones
+ return s1.self.mPriority < s2.self.mPriority
+
+ # Just use start time - older ones at the top
+ return s1.mStart < s2.mStart
+
+ propertyCardinality_1 = (
+ definitions.cICalProperty_DTSTAMP,
+ definitions.cICalProperty_UID,
+ )
+
+ propertyCardinality_0_1 = (
+ definitions.cICalProperty_CLASS,
+ definitions.cICalProperty_COMPLETED,
+ definitions.cICalProperty_CREATED,
+ definitions.cICalProperty_DESCRIPTION,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_GEO,
+ definitions.cICalProperty_LAST_MODIFIED,
+ definitions.cICalProperty_LOCATION,
+ definitions.cICalProperty_ORGANIZER,
+ definitions.cICalProperty_PERCENT_COMPLETE,
+ definitions.cICalProperty_PRIORITY,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_SEQUENCE,
+ # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
+ definitions.cICalProperty_SUMMARY,
+ definitions.cICalProperty_URL,
+ definitions.cICalProperty_RRULE,
+ definitions.cICalProperty_DUE,
+ definitions.cICalProperty_DURATION,
+ )
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None):
+ super(VToDo, self).__init__(parent=parent)
+ self.mPriority = 0
+ self.mStatus = definitions.eStatus_VToDo_None
+ self.mPercentComplete = 0
+ self.mCompleted = DateTime()
+ self.mHasCompleted = False
+
+
+ def duplicate(self, parent=None):
+ other = super(VToDo, self).duplicate(parent=parent)
+ other.mPriority = self.mPriority
+ other.mStatus = self.mStatus
+ other.mPercentComplete = self.mPercentComplete
+ other.mCompleted = self.mCompleted.duplicate()
+ other.mHasCompleted = self.mHasCompleted
+ return other
+
+
+ def getType(self):
+ return definitions.cICalComponent_VTODO
+
+
+ def getMimeComponentName(self):
+ return itipdefinitions.cICalMIMEComponent_VTODO
+
+
+ def addComponent(self, comp):
+ # We can embed the alarm components only
+ if comp.getType() == definitions.cICalComponent_VALARM:
+ super(VToDo, self).addComponent(comp)
+ else:
+ raise ValueError
+
+
+ def getStatus(self):
+ return self.mStatus
+
+
+ def setStatus(self, status):
+ self.mStatus = status
+
+
+ def getStatusText(self):
+ sout = StringIO()
+
+ if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
+ if self.hasEnd():
+ # Check due date
+ today = DateTime()
+ today.setToday()
+ if self.getEnd() > today:
+ sout.append("Due: ")
+ whendue = self.getEnd() - today
+ if (whendue.getDays() > 0) and (whendue.getDays() <= 7):
+ sout.write(whendue.getDays())
+ sout.write(" days")
+ else:
+ sout.write(self.getEnd().getLocaleDate(DateTime.NUMERICDATE))
+ elif self.getEnd() == today:
+ sout.write("Due today")
+ else:
+ sout.write("Overdue: ")
+ overdue = today - self.getEnd()
+ if overdue.getWeeks() != 0:
+ sout.write(overdue.getWeeks())
+ sout.write(" weeks")
+ else:
+ sout.write(overdue.getDays() + 1)
+ sout.write(" days")
+ else:
+ sout.write("Not Completed")
+ elif self.mStatus == definitions.eStatus_VToDo_Completed:
+ if self.hasCompleted():
+ sout.write("Completed: ")
+ sout.write(self.getCompleted().getLocaleDate(DateTime.NUMERICDATE))
+ else:
+ sout.write("Completed")
+ elif definitions.eStatus_VToDo_Cancelled:
+ sout.write("Cancelled")
+
+ return sout.toString()
+
+
+ def getCompletionState(self):
+ if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
+ if self.hasEnd():
+ # Check due date
+ today = DateTime()
+ today.setToday()
+ if self.getEnd() > today:
+ return VToDo.DUE_LATER
+ elif self.getEnd() == today:
+ return VToDo.DUE_NOW
+ else:
+ return VToDo.OVERDUE
+ else:
+ return VToDo.DUE_NOW
+ elif self.mStatus == definitions.eStatus_VToDo_Completed:
+ return VToDo.DONE
+ elif self.mStatus == definitions.eStatus_VToDo_Cancelled:
+ return VToDo.CANCELLED
+
+
+ def getPriority(self):
+ return self.mPriority
+
+
+ def setPriority(self, priority):
+ self.mPriority = priority
+
+
+ def getCompleted(self):
+ return self.mCompleted
+
+
+ def hasCompleted(self):
+ return self.mHasCompleted
+
+
+ def finalise(self):
+ # Do inherited
+ super(VToDo, self).finalise()
+
+ # Get DUE
+ temp = self.loadValueDateTime(definitions.cICalProperty_DUE)
+ if temp is None:
+ # Try DURATION instead
+ temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+ if temp is not None:
+ self.mEnd = self.mStart + temp
+ self.mHasEnd = True
+ else:
+ self.mHasEnd = False
+ else:
+ self.mHasEnd = True
+ self.mEnd = temp
+
+ # Get PRIORITY
+ self.mPriority = self.loadValueInteger(definitions.cICalProperty_PRIORITY)
+
+ # Get STATUS
+ temp = self.loadValueString(definitions.cICalProperty_STATUS)
+ if temp is not None:
+ if temp == definitions.cICalProperty_STATUS_NEEDS_ACTION:
+ self.mStatus = definitions.eStatus_VToDo_NeedsAction
+ elif temp == definitions.cICalProperty_STATUS_COMPLETED:
+ self.mStatus = definitions.eStatus_VToDo_Completed
+ elif temp == definitions.cICalProperty_STATUS_IN_PROCESS:
+ self.mStatus = definitions.eStatus_VToDo_InProcess
+ elif temp == definitions.cICalProperty_STATUS_CANCELLED:
+ self.mStatus = definitions.eStatus_VToDo_Cancelled
+
+ # Get PERCENT-COMPLETE
+ self.mPercentComplete = self.loadValueInteger(definitions.cICalProperty_PERCENT_COMPLETE)
+
+ # Get COMPLETED
+ temp = self.loadValueDateTime(definitions.cICalProperty_COMPLETED)
+ self.mHasCompleted = temp is not None
+ if self.mHasCompleted:
+ self.mCompleted = temp
+
+
+ def validate(self, doFix=False):
+ """
+ Validate the data in this component and optionally fix any problems, else raise. If
+ loggedProblems is not None it must be a C{list} and problem descriptions are appended
+ to that.
+ """
+
+ fixed, unfixed = super(VToDo, self).validate(doFix)
+
+ # Extra constraint: only one of DUE or DURATION
+ if self.hasProperty(definitions.cICalProperty_DUE) and self.hasProperty(definitions.cICalProperty_DURATION):
+ # Fix by removing the DURATION
+ logProblem = "[%s] Properties must not both be present: %s, %s" % (
+ self.getType(),
+ definitions.cICalProperty_DUE,
+ definitions.cICalProperty_DURATION,
+ )
+ if doFix:
+ self.removeProperties(definitions.cICalProperty_DURATION)
+ fixed.append(logProblem)
+ else:
+ unfixed.append(logProblem)
+
+ # Extra constraint: DTSTART must be present if DURATION is present
+ if self.hasProperty(definitions.cICalProperty_DURATION) and not self.hasProperty(definitions.cICalProperty_DTSTART):
+ # Cannot fix this one
+ logProblem = "[%s] Property must be present: %s with %s" % (
+ self.getType(),
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ )
+ unfixed.append(logProblem)
+
+ return fixed, unfixed
+
+
+ # Editing
+ def editStatus(self, status):
+ # Only if it is different
+ if self.mStatus != status:
+ # Updated cached values
+ self.mStatus = status
+
+ # Remove existing STATUS & COMPLETED items
+ self.removeProperties(definitions.cICalProperty_STATUS)
+ self.removeProperties(definitions.cICalProperty_COMPLETED)
+ self.mHasCompleted = False
+
+ # Now create properties
+ value = None
+ if status == definitions.eStatus_VToDo_NeedsAction:
+ value = definitions.cICalProperty_STATUS_NEEDS_ACTION
+ if status == definitions.eStatus_VToDo_Completed:
+ value = definitions.cICalProperty_STATUS_COMPLETED
+ # Add the completed item
+ self.mCompleted.setNowUTC()
+ self.mHasCompleted = True
+ prop = Property(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
+ self.addProperty(prop)
+ elif status == definitions.eStatus_VToDo_InProcess:
+ value = definitions.cICalProperty_STATUS_IN_PROCESS
+ elif status == definitions.eStatus_VToDo_Cancelled:
+ value = definitions.cICalProperty_STATUS_CANCELLED
+ prop = Property(definitions.cICalProperty_STATUS, value)
+ self.addProperty(prop)
+
+
+ def editCompleted(self, completed):
+ # Remove existing COMPLETED item
+ self.removeProperties(definitions.cICalProperty_COMPLETED)
+ self.mHasCompleted = False
+
+ # Always UTC
+ self.mCompleted = completed.duplicate()
+ self.mCompleted.adjustToUTC()
+ self.mHasCompleted = True
+ prop = Property(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
+ self.addProperty(prop)
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ definitions.cICalProperty_RECURRENCE_ID,
+ definitions.cICalProperty_DTSTART,
+ definitions.cICalProperty_DURATION,
+ definitions.cICalProperty_DUE,
+ definitions.cICalProperty_COMPLETED,
+ )
+
+Component.registerComponent(definitions.cICalComponent_VTODO, VToDo)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvunknownpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvunknownpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vunknown.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+import uuid
+
+class UnknownComponent(Component):
+
+ propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+ def __init__(self, parent=None, comptype=""):
+ super(UnknownComponent, self).__init__(parent=parent)
+ self.mType = comptype
+ self.mMapKey = str(uuid.uuid4())
+
+
+ def duplicate(self, parent=None):
+ return super(UnknownComponent, self).duplicate(parent=parent, comptype=self.mType)
+
+
+ def getType(self):
+ return self.mType
+
+
+ def getBeginDelimiter(self):
+ return "BEGIN:" + self.mType
+
+
+ def getEndDelimiter(self):
+ return "END:" + self.mType
+
+
+ def getMimeComponentName(self):
+ return "unknown"
+
+
+ def getMapKey(self):
+ return self.mMapKey
+
+
+ def getSortKey(self):
+ """
+ We do not want unknown components sorted.
+ """
+ return ""
+
+
+ def sortedPropertyKeyOrder(self):
+ return (
+ definitions.cICalProperty_UID,
+ )
+
+Component.registerComponent(definitions.cICalComponent_UNKNOWN, UnknownComponent)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarxmldefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarxmldefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/xmldefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# iCalendar XML definitions
+
+iCalendar20_namespace = "urn:ietf:params:xml:ns:icalendar-2.0"
+
+icalendar = "icalendar"
+
+value_recur = "recur"
+
+recur_freq = "freq"
+recur_freq_secondly = "SECONDLY"
+recur_freq_minutely = "MINUTELY"
+recur_freq_hourly = "HOURLY"
+recur_freq_daily = "DAILY"
+recur_freq_weekly = "WEEKLY"
+recur_freq_monthly = "MONTHLY"
+recur_freq_yearly = "YEARLY"
+
+recur_count = "count"
+recur_until = "until"
+recur_interval = "interval"
+
+recur_bysecond = "bysecond"
+recur_byminute = "byminute"
+recur_byhour = "byhour"
+recur_byday = "byday"
+recur_bymonthday = "bymonthday"
+recur_byyearday = "byyearday"
+recur_byweekno = "byweekno"
+recur_bymonth = "bymonth"
+recur_bysetpos = "bysetpos"
+recur_wkst = "wkst"
+
+req_status = "request-status"
+req_status_code = "code"
+req_status_description = "description"
+req_status_data = "data"
+
+geo = "geo"
+geo_longitude = "longitude"
+geo_latitude = "latitude"
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarintegervaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/integervalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/integervalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/integervalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,24 +16,24 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarIntegerValue(PyCalendarValue):
</del><ins>+class IntegerValue(Value):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, value=None):
</span><span class="cx"> self.mValue = value if value is not None else 0
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- return PyCalendarIntegerValue(self.mValue)
</del><ins>+ return IntegerValue(self.mValue)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarValue.VALUETYPE_INTEGER
</del><ins>+ return Value.VALUETYPE_INTEGER
</ins><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, variant):
</ins><span class="cx"> self.mValue = int(data)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -50,6 +50,14 @@
</span><span class="cx"> value.text = str(self.mValue)
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parseJSONValue(self, jobject):
+ self.mValue = int(jobject)
+
+
+ def writeJSONValue(self, jobject):
+ jobject.append(self.mValue)
+
+
</ins><span class="cx"> def getValue(self):
</span><span class="cx"> return self.mValue
</span><span class="cx">
</span><span class="lines">@@ -57,4 +65,4 @@
</span><span class="cx"> def setValue(self, value):
</span><span class="cx"> self.mValue = value
</span><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_INTEGER, PyCalendarIntegerValue, xmldefs.value_integer)
</del><ins>+Value.registerType(Value.VALUETYPE_INTEGER, IntegerValue, xmldefinitions.value_integer)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaritipdefinitionspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/itipdefinitions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/itipdefinitions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/itipdefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,42 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# 2446 Section 3
-
-cICalMethod_PUBLISH = "PUBLISH"
-cICalMethod_REQUEST = "REQUEST"
-cICalMethod_REFRESH = "REFRESH"
-cICalMethod_CANCEL = "CANCEL"
-cICalMethod_ADD = "ADD"
-cICalMethod_REPLY = "REPLY"
-cICalMethod_COUNTER = "COUNTER"
-cICalMethod_DECLINECOUNTER = "DECLINECOUNTER"
-
-# 2447 Section 2.4
-cICalMIMEMethod_PUBLISH = "publish"
-cICalMIMEMethod_REQUEST = "request"
-cICalMIMEMethod_REFRESH = "refresh"
-cICalMIMEMethod_CANCEL = "cancel"
-cICalMIMEMethod_ADD = "add"
-cICalMIMEMethod_REPLY = "reply"
-cICalMIMEMethod_COUNTER = "counter"
-cICalMIMEMethod_DECLINECOUNTER = "declinecounter"
-
-cICalMIMEComponent_VEVENT = "vevent"
-cICalMIMEComponent_VTODO = "vtodo"
-cICalMIMEComponent_VJOURNAL = "vjournal"
-cICalMIMEComponent_VFREEBUSY = "vfreebusy"
-cICalMIMEComponent_VAVAILABILITY = "vavailability"
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarlocalepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/locale.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/locale.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/locale.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarmanagerpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/manager.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/manager.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/manager.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,14 +14,14 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.timezone import Timezone
</ins><span class="cx">
</span><del>-class PyCalendarManager(object):
</del><ins>+class CalendarManager(object):
</ins><span class="cx">
</span><span class="cx"> sICalendarManager = None
</span><span class="cx">
</span><span class="cx"> def __init__(self):
</span><del>- PyCalendarTimezone.sDefaultTimezone = PyCalendarTimezone()
</del><ins>+ Timezone.sDefaultTimezone = Timezone()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def initManager(self):
</span><span class="lines">@@ -29,31 +29,31 @@
</span><span class="cx">
</span><span class="cx"> # Eventually we need to read these from prefs - for now they are
</span><span class="cx"> # hard-coded to my personal prefs!
</span><del>- self.setDefaultTimezone(PyCalendarTimezone(utc=False, tzid="US/Eastern"))
</del><ins>+ self.setDefaultTimezone(Timezone(utc=False, tzid="US/Eastern"))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setDefaultTimezoneID(self, tzid):
</span><span class="cx"> # Check for UTC
</span><span class="cx"> if tzid == "UTC":
</span><del>- temp = PyCalendarTimezone(utc=True)
</del><ins>+ temp = Timezone(utc=True)
</ins><span class="cx"> self.setDefaultTimezone(temp)
</span><span class="cx"> else:
</span><del>- temp = PyCalendarTimezone(utc=False, tzid=tzid)
</del><ins>+ temp = Timezone(utc=False, tzid=tzid)
</ins><span class="cx"> self.setDefaultTimezone(temp)
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setDefaultTimezone(self, tzid):
</span><del>- PyCalendarTimezone.sDefaultTimezone = tzid
</del><ins>+ Timezone.sDefaultTimezone = tzid
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getDefaultTimezoneID(self):
</span><del>- if PyCalendarTimezone.sDefaultTimezone.getUTC():
</del><ins>+ if Timezone.sDefaultTimezone.getUTC():
</ins><span class="cx"> return "UTC"
</span><span class="cx"> else:
</span><del>- return PyCalendarTimezone.sDefaultTimezone.getTimezoneID()
</del><ins>+ return Timezone.sDefaultTimezone.getTimezoneID()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getDefaultTimezone(self):
</span><del>- return PyCalendarTimezone.sDefaultTimezone
</del><ins>+ return Timezone.sDefaultTimezone
</ins><span class="cx">
</span><del>-PyCalendarManager.sICalendarManager = PyCalendarManager()
</del><ins>+CalendarManager.sICalendarManager = CalendarManager()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarmultivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/multivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/multivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/multivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,9 +14,9 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarMultiValue(PyCalendarValue):
</del><ins>+class MultiValue(Value):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, type):
</span><span class="cx">
</span><span class="lines">@@ -29,7 +29,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- other = PyCalendarMultiValue(self.mType)
</del><ins>+ other = MultiValue(self.mType)
</ins><span class="cx"> other.mValues = [i.duplicate() for i in self.mValues]
</span><span class="cx"> return other
</span><span class="cx">
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getRealType(self):
</span><del>- return PyCalendarValue.VALUETYPE_MULTIVALUE
</del><ins>+ return Value.VALUETYPE_MULTIVALUE
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getValue(self):
</span><span class="lines">@@ -57,13 +57,13 @@
</span><span class="cx"> def setValue(self, value):
</span><span class="cx"> newValues = []
</span><span class="cx"> for v in value:
</span><del>- pyCalendarValue = PyCalendarValue.createFromType(self.mType)
- pyCalendarValue.setValue(v)
- newValues.append(pyCalendarValue)
</del><ins>+ val = Value.createFromType(self.mType)
+ val.setValue(v)
+ newValues.append(val)
</ins><span class="cx"> self.mValues = newValues
</span><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, variant):
</ins><span class="cx"> # Tokenize on comma
</span><span class="cx"> if "," in data:
</span><span class="cx"> tokens = data.split(",")
</span><span class="lines">@@ -71,8 +71,8 @@
</span><span class="cx"> tokens = (data,)
</span><span class="cx"> for token in tokens:
</span><span class="cx"> # Create single value, and parse data
</span><del>- value = PyCalendarValue.createFromType(self.mType)
- value.parse(token)
</del><ins>+ value = Value.createFromType(self.mType)
+ value.parse(token, variant)
</ins><span class="cx"> self.mValues.append(value)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -93,4 +93,16 @@
</span><span class="cx"> for iter in self.mValues:
</span><span class="cx"> iter.writeXML(node, namespace)
</span><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_MULTIVALUE, PyCalendarMultiValue, None)
</del><ins>+
+ def parseJSONValue(self, jobject):
+ for jvalue in jobject:
+ value = Value.createFromType(self.mType)
+ value.parseJSONValue(jvalue)
+ self.mValues.append(value)
+
+
+ def writeJSONValue(self, jobject):
+ for iter in self.mValues:
+ iter.writeJSONValue(jobject)
+
+Value.registerType(Value.VALUETYPE_MULTIVALUE, MultiValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarnpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/n.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/n.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,124 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# vCard ADR value
-
-from pycalendar import utils
-from pycalendar.valueutils import ValueMixin
-
-class N(ValueMixin):
- """
- mValue is a tuple of seven str or tuples of str
- """
-
- (
- LAST,
- FIRST,
- MIDDLE,
- PREFIX,
- SUFFIX,
- MAXITEMS
- ) = range(6)
-
- def __init__(self, last="", first="", middle="", prefix="", suffix=""):
- self.mValue = (last, first, middle, prefix, suffix)
-
-
- def duplicate(self):
- return N(*self.mValue)
-
-
- def __hash__(self):
- return hash(self.mValue)
-
-
- def __repr__(self):
- return "N %s" % (self.getText(),)
-
-
- def __eq__(self, comp):
- return self.mValue == comp.mValue
-
-
- def getFirst(self):
- return self.mValue[N.FIRST]
-
-
- def setFirst(self, value):
- self.mValue[N.FIRST] = value
-
-
- def getLast(self):
- return self.mValue[N.LAST]
-
-
- def setLast(self, value):
- self.mValue[N.LAST] = value
-
-
- def getMiddle(self):
- return self.mValue[N.MIDDLE]
-
-
- def setMiddle(self, value):
- self.mValue[N.MIDDLE] = value
-
-
- def getPrefix(self):
- return self.mValue[N.PREFIX]
-
-
- def setPrefix(self, value):
- self.mValue[N.PREFIX] = value
-
-
- def getSuffix(self):
- return self.mValue[N.SUFFIX]
-
-
- def setSuffix(self, value):
- self.mValue[N.SUFFIX] = value
-
-
- def getFullName(self):
-
-
- def _stringOrList(item):
- return item if isinstance(item, basestring) else " ".join(item)
-
- results = []
- for i in (N.PREFIX, N.FIRST, N.MIDDLE, N.LAST, N.SUFFIX):
- result = _stringOrList(self.mValue[i])
- if result:
- results.append(result)
-
- return " ".join(results)
-
-
- def parse(self, data):
- self.mValue = utils.parseDoubleNestedList(data, N.MAXITEMS)
-
-
- def generate(self, os):
- utils.generateDoubleNestedList(os, self.mValue)
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarnvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/nvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/nvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,51 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# vCard ADR value
-
-from pycalendar.n import N
-from pycalendar.value import PyCalendarValue
-
-class NValue(PyCalendarValue):
-
- def __init__(self, value=None):
- self.mValue = value if value is not None else N()
-
-
- def duplicate(self):
- return NValue(self.mValue.duplicate())
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_N
-
-
- def parse(self, data):
- self.mValue.parse(data)
-
-
- def generate(self, os):
- self.mValue.generate(os)
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_N, NValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarorgvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/orgvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/orgvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,54 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-# vCard ORG value
-
-from pycalendar import utils
-from pycalendar.value import PyCalendarValue
-
-class OrgValue(PyCalendarValue):
- """
- mValue is a str or tuple of str
- """
-
- def __init__(self, value=None):
- self.mValue = value
-
-
- def duplicate(self):
- return OrgValue(self.mValue)
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_ORG
-
-
- def parse(self, data):
- self.mValue = utils.parseTextList(data, ';')
-
-
- def generate(self, os):
- utils.generateTextList(os, self.mValue, ';')
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_ORG, OrgValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendaroutputfilterpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/outputfilter.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/outputfilter.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/outputfilter.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,7 +15,7 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx">
</span><del>-class PyCalendarOutputFilter(object):
</del><ins>+class OutputFilter(object):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, type):
</span><span class="cx"> self.mType = type
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarparameterpyfromrev11912PyCalendarbranchesjson2srcpycalendarparameterpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/parameter.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/parameter.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/parameter.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/parameter.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+"""
+ICalendar parameter.
+
+The parameter can consist of one or more values, all string.
+"""
+
+from pycalendar import xmldefinitions, xmlutils
+from pycalendar.utils import encodeParameterValue
+import xml.etree.cElementTree as XML
+
+class Parameter(object):
+
+ def __init__(self, name, value=None):
+ self.mName = name
+ if value is None:
+ self.mValues = []
+ elif isinstance(value, basestring):
+ self.mValues = [value]
+ else:
+ self.mValues = value
+
+
+ def duplicate(self):
+ other = Parameter(self.mName)
+ other.mValues = self.mValues[:]
+ return other
+
+
+ def __hash__(self):
+ return hash((self.mName.upper(), tuple(self.mValues)))
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+ def __eq__(self, other):
+ if not isinstance(other, Parameter):
+ return False
+ return self.mName.upper() == other.mName.upper() and self.mValues == other.mValues
+
+
+ def getName(self):
+ return self.mName
+
+
+ def setName(self, name):
+ self.mName = name
+
+
+ def getFirstValue(self):
+ return self.mValues[0]
+
+
+ def getValues(self):
+ return self.mValues
+
+
+ def setValues(self, values):
+ self.mValues = values
+
+
+ def addValue(self, value):
+ self.mValues.append(value)
+
+
+ def removeValue(self, value):
+ self.mValues.remove(value)
+ return len(self.mValues)
+
+
+ def generate(self, os):
+ try:
+ os.write(self.mName)
+
+ # To support vCard 2.1 syntax we allow parameters without values
+ if self.mValues:
+ os.write("=")
+
+ first = True
+ for s in self.mValues:
+ if first:
+ first = False
+ else:
+ os.write(",")
+
+ # Write with quotation if required
+ self.generateValue(os, s)
+
+ except:
+ # We ignore errors
+ pass
+
+
+ def generateValue(self, os, str):
+
+ # ^-escaping
+ str = encodeParameterValue(str)
+
+ # Look for quoting
+ if str.find(":") != -1 or str.find(";") != -1 or str.find(",") != -1:
+ os.write("\"%s\"" % (str,))
+ else:
+ os.write(str)
+
+
+ def writeXML(self, node, namespace):
+ param = XML.SubElement(node, xmlutils.makeTag(namespace, self.getName()))
+ for value in self.getValues():
+ # TODO: need to figure out proper value types
+ text = XML.SubElement(param, xmlutils.makeTag(namespace, xmldefinitions.value_text))
+ text.text = value
+
+
+ def writeJSON(self, jobject):
+ jobject[self.getName().lower()] = self.mValues if len(self.mValues) != 1 else self.mValues[0]
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarperiodpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/period.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/period.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/period.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,17 +14,17 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar import xmldefinitions, xmlutils
+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
</ins><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx">
</span><del>-class PyCalendarPeriod(ValueMixin):
</del><ins>+class Period(ValueMixin):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, start=None, end=None, duration=None):
</span><span class="cx">
</span><del>- self.mStart = start if start is not None else PyCalendarDateTime()
</del><ins>+ self.mStart = start if start is not None else DateTime()
</ins><span class="cx">
</span><span class="cx"> if end is not None:
</span><span class="cx"> self.mEnd = end
</span><span class="lines">@@ -36,12 +36,12 @@
</span><span class="cx"> self.mUseDuration = True
</span><span class="cx"> else:
</span><span class="cx"> self.mEnd = self.mStart.duplicate()
</span><del>- self.mDuration = PyCalendarDuration()
</del><ins>+ self.mDuration = Duration()
</ins><span class="cx"> self.mUseDuration = False
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- other = PyCalendarPeriod(start=self.mStart.duplicate(), end=self.mEnd.duplicate())
</del><ins>+ other = Period(start=self.mStart.duplicate(), end=self.mEnd.duplicate())
</ins><span class="cx"> other.mUseDuration = self.mUseDuration
</span><span class="cx"> return other
</span><span class="cx">
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __repr__(self):
</span><del>- return "PyCalendarPeriod %s" % (self.getText(),)
</del><ins>+ return "Period %s" % (self.getText(),)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __str__(self):
</span><span class="lines">@@ -78,19 +78,19 @@
</span><span class="cx"> return period
</span><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, fullISO=False):
</ins><span class="cx"> splits = data.split('/', 1)
</span><span class="cx"> if len(splits) == 2:
</span><span class="cx"> start = splits[0]
</span><span class="cx"> end = splits[1]
</span><span class="cx">
</span><del>- self.mStart.parse(start)
</del><ins>+ self.mStart.parse(start, fullISO)
</ins><span class="cx"> if end[0] == 'P':
</span><span class="cx"> self.mDuration.parse(end)
</span><span class="cx"> self.mUseDuration = True
</span><span class="cx"> self.mEnd = self.mStart + self.mDuration
</span><span class="cx"> else:
</span><del>- self.mEnd.parse(end)
</del><ins>+ self.mEnd.parse(end, fullISO)
</ins><span class="cx"> self.mUseDuration = False
</span><span class="cx"> self.mDuration = self.mEnd - self.mStart
</span><span class="cx"> else:
</span><span class="lines">@@ -110,17 +110,37 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def writeXML(self, node, namespace):
</span><del>- start = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.period_start))
</del><ins>+ start = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.period_start))
</ins><span class="cx"> start.text = self.mStart.getXMLText()
</span><span class="cx">
</span><span class="cx"> if self.mUseDuration:
</span><del>- duration = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.period_duration))
</del><ins>+ duration = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.period_duration))
</ins><span class="cx"> duration.text = self.mDuration.getText()
</span><span class="cx"> else:
</span><del>- end = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.period_end))
</del><ins>+ end = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.period_end))
</ins><span class="cx"> end.text = self.mEnd.getXMLText()
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parseJSON(self, jobject):
+ """
+ jCal encodes this as an array of two values. We convert back into a single "/"
+ separated string and parse as normal.
+ """
+ self.parse("%s/%s" % tuple(jobject), True)
+
+
+ def writeJSON(self, jobject):
+ """
+ jCal encodes this value as an array with two components.
+ """
+ value = [self.mStart.getXMLText(), ]
+ if self.mUseDuration:
+ value.append(self.mDuration.getText())
+ else:
+ value.append(self.mEnd.getXMLText())
+ jobject.append(value)
+
+
</ins><span class="cx"> def getStart(self):
</span><span class="cx"> return self.mStart
</span><span class="cx">
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarperiodvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/periodvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/periodvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/periodvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,42 +14,14 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.period import Period
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
</ins><span class="cx">
</span><del>-class PyCalendarPeriodValue(PyCalendarValue):
</del><ins>+class PeriodValue(WrapperValue, Value):
</ins><span class="cx">
</span><del>- def __init__(self, value=None):
- self.mValue = value if value is not None else PyCalendarPeriod()
</del><ins>+ _wrappedClass = Period
+ _wrappedType = Value.VALUETYPE_PERIOD
</ins><span class="cx">
</span><del>-
- def duplicate(self):
- return PyCalendarPeriodValue(self.mValue.duplicate())
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_PERIOD
-
-
- def parse(self, data):
- self.mValue.parse(data)
-
-
- def generate(self, os):
- self.mValue.generate(os)
-
-
- def writeXML(self, node, namespace):
- value = self.getXMLNode(node, namespace)
- value.text = self.mValue.writeXML()
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_PERIOD, PyCalendarPeriodValue, xmldefs.value_period)
</del><ins>+Value.registerType(Value.VALUETYPE_PERIOD, PeriodValue, xmldefinitions.value_period)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarplaintextvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/plaintextvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/plaintextvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/plaintextvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,11 +14,11 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-# iCalendar UTC Offset value
</del><ins>+# iCalendar generic text-like value
</ins><span class="cx">
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarPlainTextValue(PyCalendarValue):
</del><ins>+class PlainTextValue(Value):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, value=''):
</span><span class="cx"> self.mValue = value
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx"> return self.__class__(self.mValue)
</span><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, variant):
</ins><span class="cx"> # No decoding required
</span><span class="cx"> self.mValue = data
</span><span class="cx">
</span><span class="lines">@@ -47,6 +47,14 @@
</span><span class="cx"> value.text = self.mValue
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parseJSONValue(self, jobject):
+ self.mValue = str(jobject)
+
+
+ def writeJSONValue(self, jobject):
+ jobject.append(self.mValue)
+
+
</ins><span class="cx"> def getValue(self):
</span><span class="cx"> return self.mValue
</span><span class="cx">
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarpropertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,227 +14,60 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import definitions, xmldefs
-from pycalendar import stringutils
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.binaryvalue import PyCalendarBinaryValue
-from pycalendar.caladdressvalue import PyCalendarCalAddressValue
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.datetimevalue import PyCalendarDateTimeValue
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.durationvalue import PyCalendarDurationValue
-from pycalendar.exceptions import PyCalendarInvalidProperty
-from pycalendar.integervalue import PyCalendarIntegerValue
-from pycalendar.multivalue import PyCalendarMultiValue
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.periodvalue import PyCalendarPeriodValue
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.recurrence import PyCalendarRecurrence
-from pycalendar.recurrencevalue import PyCalendarRecurrenceValue
-from pycalendar.requeststatusvalue import PyCalendarRequestStatusValue
-from pycalendar.unknownvalue import PyCalendarUnknownValue
-from pycalendar.urivalue import PyCalendarURIValue
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar import stringutils, xmlutils, xmldefinitions
+from pycalendar.parameter import Parameter
+from pycalendar.binaryvalue import BinaryValue
+from pycalendar.caladdressvalue import CalAddressValue
+from pycalendar.datetimevalue import DateTimeValue
+from pycalendar.durationvalue import DurationValue
+from pycalendar.exceptions import InvalidProperty
+from pycalendar.integervalue import IntegerValue
+from pycalendar.multivalue import MultiValue
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.unknownvalue import UnknownValue
+from pycalendar.urivalue import URIValue
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> from pycalendar.utils import decodeParameterValue
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx">
</span><del>-class PyCalendarProperty(object):
</del><ins>+class PropertyBase(object):
</ins><span class="cx">
</span><del>- sDefaultValueTypeMap = {
</del><ins>+ # Mappings between various tokens and internal definitions
+ sDefaultValueTypeMap = {}
+ sValueTypeMap = {}
+ sTypeValueMap = {}
+ sMultiValues = set()
+ sSpecialVariants = {}
</ins><span class="cx">
</span><del>- # 5545 Section 3.7
- definitions.cICalProperty_CALSCALE : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_METHOD : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_PRODID : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_VERSION : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ sUsesGroup = False
</ins><span class="cx">
</span><del>- # 5545 Section 3.8.1
- definitions.cICalProperty_ATTACH : PyCalendarValue.VALUETYPE_URI,
- definitions.cICalProperty_CATEGORIES : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_CLASS : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_COMMENT : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_DESCRIPTION : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_GEO : PyCalendarValue.VALUETYPE_GEO,
- definitions.cICalProperty_LOCATION : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_PERCENT_COMPLETE : PyCalendarValue.VALUETYPE_INTEGER,
- definitions.cICalProperty_PRIORITY : PyCalendarValue.VALUETYPE_INTEGER,
- definitions.cICalProperty_RESOURCES : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_STATUS : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_SUMMARY : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ sVariant = "none" # Used to differentiate different forms of text parsing
</ins><span class="cx">
</span><del>- # 5545 Section 3.8.2
- definitions.cICalProperty_COMPLETED : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_DTEND : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_DUE : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_DTSTART : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_DURATION : PyCalendarValue.VALUETYPE_DURATION,
- definitions.cICalProperty_FREEBUSY : PyCalendarValue.VALUETYPE_PERIOD,
- definitions.cICalProperty_TRANSP : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ sValue = None
+ sText = None
</ins><span class="cx">
</span><del>- # 5545 Section 3.8.3
- definitions.cICalProperty_TZID : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_TZNAME : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_TZOFFSETFROM : PyCalendarValue.VALUETYPE_UTC_OFFSET,
- definitions.cICalProperty_TZOFFSETTO : PyCalendarValue.VALUETYPE_UTC_OFFSET,
- definitions.cICalProperty_TZURL : PyCalendarValue.VALUETYPE_URI,
</del><ins>+ @classmethod
+ def registerDefaultValue(cls, propname, valuetype):
+ if propname not in cls.sDefaultValueTypeMap:
+ cls.sDefaultValueTypeMap[propname] = valuetype
</ins><span class="cx">
</span><del>- # 5545 Section 3.8.4
- definitions.cICalProperty_ATTENDEE : PyCalendarValue.VALUETYPE_CALADDRESS,
- definitions.cICalProperty_CONTACT : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_ORGANIZER : PyCalendarValue.VALUETYPE_CALADDRESS,
- definitions.cICalProperty_RECURRENCE_ID : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_RELATED_TO : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_URL : PyCalendarValue.VALUETYPE_URI,
- definitions.cICalProperty_UID : PyCalendarValue.VALUETYPE_TEXT,
</del><span class="cx">
</span><del>- # 5545 Section 3.8.5
- definitions.cICalProperty_EXDATE : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_EXRULE : PyCalendarValue.VALUETYPE_RECUR, # 2445 only
- definitions.cICalProperty_RDATE : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_RRULE : PyCalendarValue.VALUETYPE_RECUR,
-
- # 5545 Section 3.8.6
- definitions.cICalProperty_ACTION : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_REPEAT : PyCalendarValue.VALUETYPE_INTEGER,
- definitions.cICalProperty_TRIGGER : PyCalendarValue.VALUETYPE_DURATION,
-
- # 5545 Section 3.8.7
- definitions.cICalProperty_CREATED : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_DTSTAMP : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_LAST_MODIFIED : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_SEQUENCE : PyCalendarValue.VALUETYPE_INTEGER,
-
- # 5545 Section 3.8.8
- definitions.cICalProperty_REQUEST_STATUS : PyCalendarValue.VALUETYPE_REQUEST_STATUS,
-
- # Extensions: draft-daboo-valarm-extensions-03
- definitions.cICalProperty_ACKNOWLEDGED : PyCalendarValue.VALUETYPE_DATETIME,
-
- # Apple Extensions
- definitions.cICalProperty_XWRCALNAME : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_XWRCALDESC : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_XWRALARMUID : PyCalendarValue.VALUETYPE_TEXT,
-
- # Mulberry extensions
- definitions.cICalProperty_ACTION_X_SPEAKTEXT : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalProperty_ALARM_X_LASTTRIGGER : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalProperty_ALARM_X_ALARMSTATUS : PyCalendarValue.VALUETYPE_TEXT,
- }
-
- sValueTypeMap = {
-
- # 5545 Section 3.3
- definitions.cICalValue_BINARY : PyCalendarValue.VALUETYPE_BINARY,
- definitions.cICalValue_BOOLEAN : PyCalendarValue.VALUETYPE_BOOLEAN,
- definitions.cICalValue_CAL_ADDRESS : PyCalendarValue.VALUETYPE_CALADDRESS,
- definitions.cICalValue_DATE : PyCalendarValue.VALUETYPE_DATE,
- definitions.cICalValue_DATE_TIME : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.cICalValue_DURATION : PyCalendarValue.VALUETYPE_DURATION,
- definitions.cICalValue_FLOAT : PyCalendarValue.VALUETYPE_FLOAT,
- definitions.cICalValue_INTEGER : PyCalendarValue.VALUETYPE_INTEGER,
- definitions.cICalValue_PERIOD : PyCalendarValue.VALUETYPE_PERIOD,
- definitions.cICalValue_RECUR : PyCalendarValue.VALUETYPE_RECUR,
- definitions.cICalValue_TEXT : PyCalendarValue.VALUETYPE_TEXT,
- definitions.cICalValue_TIME : PyCalendarValue.VALUETYPE_TIME,
- definitions.cICalValue_URI : PyCalendarValue.VALUETYPE_URI,
- definitions.cICalValue_UTC_OFFSET : PyCalendarValue.VALUETYPE_UTC_OFFSET,
- }
-
- sTypeValueMap = {
-
- # 5545 Section 3.3
- PyCalendarValue.VALUETYPE_BINARY : definitions.cICalValue_BINARY,
- PyCalendarValue.VALUETYPE_BOOLEAN : definitions.cICalValue_BOOLEAN,
- PyCalendarValue.VALUETYPE_CALADDRESS : definitions.cICalValue_CAL_ADDRESS,
- PyCalendarValue.VALUETYPE_DATE : definitions.cICalValue_DATE,
- PyCalendarValue.VALUETYPE_DATETIME : definitions.cICalValue_DATE_TIME,
- PyCalendarValue.VALUETYPE_DURATION : definitions.cICalValue_DURATION,
- PyCalendarValue.VALUETYPE_FLOAT : definitions.cICalValue_FLOAT,
- PyCalendarValue.VALUETYPE_GEO : definitions.cICalValue_FLOAT,
- PyCalendarValue.VALUETYPE_INTEGER : definitions.cICalValue_INTEGER,
- PyCalendarValue.VALUETYPE_PERIOD : definitions.cICalValue_PERIOD,
- PyCalendarValue.VALUETYPE_RECUR : definitions.cICalValue_RECUR,
- PyCalendarValue.VALUETYPE_TEXT : definitions.cICalValue_TEXT,
- PyCalendarValue.VALUETYPE_REQUEST_STATUS : definitions.cICalValue_TEXT,
- PyCalendarValue.VALUETYPE_TIME : definitions.cICalValue_TIME,
- PyCalendarValue.VALUETYPE_URI : definitions.cICalValue_URI,
- PyCalendarValue.VALUETYPE_UTC_OFFSET : definitions.cICalValue_UTC_OFFSET,
- }
-
- sMultiValues = set((
- definitions.cICalProperty_CATEGORIES,
- definitions.cICalProperty_RESOURCES,
- definitions.cICalProperty_FREEBUSY,
- definitions.cICalProperty_EXDATE,
- definitions.cICalProperty_RDATE,
- ))
-
- @staticmethod
- def registerDefaultValue(propname, valuetype):
- if propname not in PyCalendarProperty.sDefaultValueTypeMap:
- PyCalendarProperty.sDefaultValueTypeMap[propname] = valuetype
-
-
</del><span class="cx"> def __init__(self, name=None, value=None, valuetype=None):
</span><del>- self._init_PyCalendarProperty()
</del><ins>+
</ins><span class="cx"> self.mName = name if name is not None else ""
</span><ins>+ self.mParameters = {}
+ self.mValue = None
</ins><span class="cx">
</span><del>- # The None check speeds up .duplicate()
- if value is None:
- pass
</del><span class="cx">
</span><del>- # Order these based on most likely occurrence to speed up this method
- elif isinstance(value, str):
- self._init_attr_value_text(value, valuetype if valuetype else PyCalendarProperty.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_UNKNOWN))
-
- elif isinstance(value, PyCalendarDateTime):
- self._init_attr_value_datetime(value)
-
- elif isinstance(value, PyCalendarDuration):
- self._init_attr_value_duration(value)
-
- elif isinstance(value, PyCalendarRecurrence):
- self._init_attr_value_recur(value)
-
- elif isinstance(value, PyCalendarPeriod):
- self._init_attr_value_period(value)
-
- elif isinstance(value, int):
- self._init_attr_value_int(value)
-
- elif isinstance(value, list):
- if name.upper() == definitions.cICalProperty_REQUEST_STATUS:
- self._init_attr_value_requeststatus(value)
- else:
- period_list = False
- if len(value) != 0:
- period_list = isinstance(value[0], PyCalendarPeriod)
- if period_list:
- self._init_attr_value_periodlist(value)
- else:
- self._init_attr_value_datetimelist(value)
-
- elif isinstance(value, PyCalendarUTCOffsetValue):
- self._init_attr_value_utcoffset(value)
-
-
</del><span class="cx"> def duplicate(self):
</span><del>- other = PyCalendarProperty(self.mName)
- for attrname, attrs in self.mAttributes.items():
- other.mAttributes[attrname] = [i.duplicate() for i in attrs]
- other.mValue = self.mValue.duplicate()
</del><ins>+ raise NotImplementedError
</ins><span class="cx">
</span><del>- return other
</del><span class="cx">
</span><del>-
</del><span class="cx"> def __hash__(self):
</span><del>- return hash((
- self.mName,
- tuple([tuple(self.mAttributes[attrname]) for attrname in sorted(self.mAttributes.keys())]),
- self.mValue,
- ))
</del><ins>+ raise NotImplementedError
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __ne__(self, other):
</span><span class="lines">@@ -242,19 +75,26 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __eq__(self, other):
</span><del>- if not isinstance(other, PyCalendarProperty):
- return False
- return self.mName == other.mName and self.mValue == other.mValue and self.mAttributes == other.mAttributes
</del><ins>+ raise NotImplementedError
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __repr__(self):
</span><del>- return "PyCalendarProperty: %s" % (self.getText(),)
</del><ins>+ return "Property: %s" % (self.getText(),)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __str__(self):
</span><span class="cx"> return self.getText()
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def getGroup(self):
+ return self.mGroup if self.sUsesGroup else None
+
+
+ def setGroup(self, group):
+ if self.sUsesGroup:
+ self.mGroup = group
+
+
</ins><span class="cx"> def getName(self):
</span><span class="cx"> return self.mName
</span><span class="cx">
</span><span class="lines">@@ -263,33 +103,33 @@
</span><span class="cx"> self.mName = name
</span><span class="cx">
</span><span class="cx">
</span><del>- def getAttributes(self):
- return self.mAttributes
</del><ins>+ def getParameters(self):
+ return self.mParameters
</ins><span class="cx">
</span><span class="cx">
</span><del>- def setAttributes(self, attributes):
- self.mAttributes = dict([(k.upper(), v) for k, v in attributes.iteritems()])
</del><ins>+ def setParameters(self, parameters):
+ self.mParameters = dict([(k.upper(), v) for k, v in parameters.iteritems()])
</ins><span class="cx">
</span><span class="cx">
</span><del>- def hasAttribute(self, attr):
- return attr.upper() in self.mAttributes
</del><ins>+ def hasParameter(self, attr):
+ return attr.upper() in self.mParameters
</ins><span class="cx">
</span><span class="cx">
</span><del>- def getAttributeValue(self, attr):
- return self.mAttributes[attr.upper()][0].getFirstValue()
</del><ins>+ def getParameterValue(self, attr):
+ return self.mParameters[attr.upper()][0].getFirstValue()
</ins><span class="cx">
</span><span class="cx">
</span><del>- def addAttribute(self, attr):
- self.mAttributes.setdefault(attr.getName().upper(), []).append(attr)
</del><ins>+ def addParameter(self, attr):
+ self.mParameters.setdefault(attr.getName().upper(), []).append(attr)
</ins><span class="cx">
</span><span class="cx">
</span><del>- def replaceAttribute(self, attr):
- self.mAttributes[attr.getName().upper()] = [attr]
</del><ins>+ def replaceParameter(self, attr):
+ self.mParameters[attr.getName().upper()] = [attr]
</ins><span class="cx">
</span><span class="cx">
</span><del>- def removeAttributes(self, attr):
- if attr.upper() in self.mAttributes:
- del self.mAttributes[attr.upper()]
</del><ins>+ def removeParameters(self, attr):
+ if attr.upper() in self.mParameters:
+ del self.mParameters[attr.upper()]
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getValue(self):
</span><span class="lines">@@ -298,7 +138,7 @@
</span><span class="cx">
</span><span class="cx"> def getBinaryValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarBinaryValue):
</del><ins>+ if isinstance(self.mValue, BinaryValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -306,7 +146,7 @@
</span><span class="cx">
</span><span class="cx"> def getCalAddressValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarCalAddressValue):
</del><ins>+ if isinstance(self.mValue, CalAddressValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -314,7 +154,7 @@
</span><span class="cx">
</span><span class="cx"> def getDateTimeValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarDateTimeValue):
</del><ins>+ if isinstance(self.mValue, DateTimeValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -322,7 +162,7 @@
</span><span class="cx">
</span><span class="cx"> def getDurationValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarDurationValue):
</del><ins>+ if isinstance(self.mValue, DurationValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -330,7 +170,7 @@
</span><span class="cx">
</span><span class="cx"> def getIntegerValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarIntegerValue):
</del><ins>+ if isinstance(self.mValue, IntegerValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -338,7 +178,7 @@
</span><span class="cx">
</span><span class="cx"> def getMultiValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarMultiValue):
</del><ins>+ if isinstance(self.mValue, MultiValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -346,23 +186,15 @@
</span><span class="cx">
</span><span class="cx"> def getPeriodValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarPeriodValue):
</del><ins>+ if isinstance(self.mValue, PeriodValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="cx">
</span><span class="cx">
</span><del>- def getRecurrenceValue(self):
-
- if isinstance(self.mValue, PyCalendarRecurrenceValue):
- return self.mValue
- else:
- return None
-
-
</del><span class="cx"> def getTextValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarPlainTextValue):
</del><ins>+ if isinstance(self.mValue, PlainTextValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -370,7 +202,7 @@
</span><span class="cx">
</span><span class="cx"> def getURIValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarURIValue):
</del><ins>+ if isinstance(self.mValue, URIValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="lines">@@ -378,70 +210,113 @@
</span><span class="cx">
</span><span class="cx"> def getUTCOffsetValue(self):
</span><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarUTCOffsetValue):
</del><ins>+ if isinstance(self.mValue, UTCOffsetValue):
</ins><span class="cx"> return self.mValue
</span><span class="cx"> else:
</span><span class="cx"> return None
</span><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
- # Look for attribute or value delimiter
- prop_name, txt = stringutils.strduptokenstr(data, ";:")
- if not prop_name:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ @classmethod
+ def parseText(cls, data):
+ """
+ Parse the text format data and return a L{Property}
</ins><span class="cx">
</span><del>- # We have the name
- self.mName = prop_name
</del><ins>+ @param data: text data
+ @type data: C{str}
+ """
</ins><span class="cx">
</span><del>- # TODO: Try to use static string for the name
</del><ins>+ try:
+ prop = cls()
</ins><span class="cx">
</span><del>- # Now loop getting data
</del><ins>+ # Look for parameter or value delimiter
+ prop_name, txt = stringutils.strduptokenstr(data, ";:")
+ if not prop_name:
+ raise InvalidProperty("Invalid property", data)
+
+ # Get the name
+ if prop.sUsesGroup:
+ # Check for group prefix
+ splits = prop_name.split(".", 1)
+ if len(splits) == 2:
+ # We have both group and name
+ prop.mGroup = splits[0]
+ prop.mName = splits[1]
+ else:
+ # We have the name
+ prop.mName = prop_name
+ else:
+ prop.mName = prop_name
+
+ # Get the parameters
+ txt = prop.parseTextParameters(txt, data)
+
+ # Tidy first
+ prop.mValue = None
+
+ # Get value type from property name
+ value_type = prop.determineValueType()
+
+ # Check for multivalued
+ if prop.mName.upper() in prop.sMultiValues:
+ prop.mValue = MultiValue(value_type)
+ else:
+ # Create the type
+ prop.mValue = Value.createFromType(value_type)
+
+ # Now parse the data
+ prop.mValue.parse(txt, prop.sVariant)
+
+ prop._postCreateValue(value_type)
+
+ return prop
+
+ except Exception:
+ raise InvalidProperty("Invalid property", data)
+
+
+ def parseTextParameters(self, txt, data):
+ """
+ Parse parameters, return string point at value.
+ """
+
</ins><span class="cx"> try:
</span><span class="cx"> while txt:
</span><span class="cx"> if txt[0] == ';':
</span><del>- # Parse attribute
</del><ins>+ # Parse parameter
</ins><span class="cx">
</span><span class="cx"> # Move past delimiter
</span><span class="cx"> txt = txt[1:]
</span><span class="cx">
</span><span class="cx"> # Get quoted string or token
</span><del>- attribute_name, txt = stringutils.strduptokenstr(txt, "=")
- if attribute_name is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ parameter_name, txt = stringutils.strduptokenstr(txt, "=")
+ if parameter_name is None:
+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx"> txt = txt[1:]
</span><del>- attribute_value, txt = stringutils.strduptokenstr(txt, ":;,")
- if attribute_value is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ parameter_value, txt = stringutils.strduptokenstr(txt, ":;,")
+ if parameter_value is None:
+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx">
</span><del>- # Now add attribute value (decode ^-escpaing)
- attrvalue = PyCalendarAttribute(name=attribute_name, value=decodeParameterValue(attribute_value))
- self.mAttributes.setdefault(attribute_name.upper(), []).append(attrvalue)
</del><ins>+ # Now add parameter value (decode ^-escaping)
+ attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value))
+ self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue)
</ins><span class="cx">
</span><span class="cx"> # Look for additional values
</span><span class="cx"> while txt[0] == ',':
</span><span class="cx"> txt = txt[1:]
</span><del>- attribute_value2, txt = stringutils.strduptokenstr(txt, ":;,")
- if attribute_value2 is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
- attrvalue.addValue(decodeParameterValue(attribute_value2))
</del><ins>+ parameter_value2, txt = stringutils.strduptokenstr(txt, ":;,")
+ if parameter_value2 is None:
+ raise InvalidProperty("Invalid property", data)
+ attrvalue.addValue(decodeParameterValue(parameter_value2))
</ins><span class="cx"> elif txt[0] == ':':
</span><del>- txt = txt[1:]
- self.createValue(txt)
- txt = None
</del><ins>+ return txt[1:]
</ins><span class="cx"> else:
</span><span class="cx"> # We should never get here but if we do we need to terminate the loop
</span><del>- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx">
</span><span class="cx"> except IndexError:
</span><del>- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx">
</span><del>- # We must have a value of some kind
- if self.mValue is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><span class="cx">
</span><del>- return True
-
-
</del><span class="cx"> def getText(self):
</span><span class="cx"> os = StringIO.StringIO()
</span><span class="cx"> self.generate(os)
</span><span class="lines">@@ -465,15 +340,17 @@
</span><span class="cx"> # Write out the actual property, possibly skipping the value
</span><span class="cx"> def generateValue(self, os, novalue):
</span><span class="cx">
</span><del>- self.setupValueAttribute()
</del><ins>+ self.setupValueParameter()
</ins><span class="cx">
</span><span class="cx"> # Must write to temp buffer and then wrap
</span><span class="cx"> sout = StringIO.StringIO()
</span><ins>+ if self.sUsesGroup and self.mGroup:
+ sout.write(self.mGroup + ".")
</ins><span class="cx"> sout.write(self.mName)
</span><span class="cx">
</span><del>- # Write all attributes
- for key in sorted(self.mAttributes.keys()):
- for attr in self.mAttributes[key]:
</del><ins>+ # Write all parameters
+ for key in sorted(self.mParameters.keys()):
+ for attr in self.mParameters[key]:
</ins><span class="cx"> sout.write(";")
</span><span class="cx"> attr.generate(sout)
</span><span class="cx">
</span><span class="lines">@@ -493,9 +370,10 @@
</span><span class="cx"> # Look for valid utf8 range and write that out
</span><span class="cx"> start = 0
</span><span class="cx"> written = 0
</span><ins>+ lineWrap = 74
</ins><span class="cx"> while written < len(temp):
</span><span class="cx"> # Start 74 chars on from where we are
</span><del>- offset = start + 74
</del><ins>+ offset = start + lineWrap
</ins><span class="cx"> if offset >= len(temp):
</span><span class="cx"> line = temp[start:]
</span><span class="cx"> os.write(line)
</span><span class="lines">@@ -509,6 +387,7 @@
</span><span class="cx"> line = temp[start:offset]
</span><span class="cx"> os.write(line)
</span><span class="cx"> os.write("\r\n ")
</span><ins>+ lineWrap = 73 # We are now adding a space at the start
</ins><span class="cx"> written += offset - start
</span><span class="cx"> start = offset
</span><span class="cx">
</span><span class="lines">@@ -521,7 +400,7 @@
</span><span class="cx"> self.generateValueXML(node, namespace, False)
</span><span class="cx">
</span><span class="cx">
</span><del>- def generateFilteredXML(self, node, namespace, filter):
</del><ins>+ def writeXMLFiltered(self, node, namespace, filter):
</ins><span class="cx">
</span><span class="cx"> # Check for property in filter and whether value is written out
</span><span class="cx"> test, novalue = filter.testPropertyValue(self.mName.upper())
</span><span class="lines">@@ -532,14 +411,14 @@
</span><span class="cx"> # Write out the actual property, possibly skipping the value
</span><span class="cx"> def generateValueXML(self, node, namespace, novalue):
</span><span class="cx">
</span><del>- prop = XML.SubElement(node, xmldefs.makeTag(namespace, self.getName()))
</del><ins>+ prop = XML.SubElement(node, xmlutils.makeTag(namespace, self.getName()))
</ins><span class="cx">
</span><del>- # Write all attributes
- if len(self.mAttributes):
- params = XML.SubElement(prop, xmldefs.makeTag(namespace, xmldefs.parameters))
- for key in sorted(self.mAttributes.keys()):
- for attr in self.mAttributes[key]:
- if attr.getName() != "VALUE":
</del><ins>+ # Write all parameters
+ if len(self.mParameters):
+ params = XML.SubElement(prop, xmlutils.makeTag(namespace, xmldefinitions.parameters))
+ for key in sorted(self.mParameters.keys()):
+ for attr in self.mParameters[key]:
+ if attr.getName().lower() != "value":
</ins><span class="cx"> attr.writeXML(params, namespace)
</span><span class="cx">
</span><span class="cx"> # Write value
</span><span class="lines">@@ -547,90 +426,172 @@
</span><span class="cx"> self.mValue.writeXML(prop, namespace)
</span><span class="cx">
</span><span class="cx">
</span><del>- def _init_PyCalendarProperty(self):
- self.mName = ""
- self.mAttributes = {}
- self.mValue = None
</del><ins>+ @classmethod
+ def parseJSON(cls, jobject):
+ """
+ Parse a JSON property of the form:
</ins><span class="cx">
</span><ins>+ [name, attrs, type, value1, value2, ...]
</ins><span class="cx">
</span><ins>+ @param jobject: a JSON array
+ @type jobject: C{list}
+ """
+
+ try:
+ prop = cls()
+
+ # Get the name
+ prop.mName = jobject[0].upper()
+
+ # Get the parameters
+ if jobject[1]:
+ for name, value in jobject[1].items():
+ # Now add parameter value
+ name = name.upper()
+ attrvalue = Parameter(name=name, value=value)
+ prop.mParameters.setdefault(name, []).append(attrvalue)
+
+ # Get default value type from property name and insert a VALUE parameter if current value type is not default
+ value_type = cls.sValueTypeMap.get(jobject[2].upper(), Value.VALUETYPE_UNKNOWN)
+ default_type = cls.sDefaultValueTypeMap.get(prop.mName.upper(), Value.VALUETYPE_UNKNOWN)
+ if default_type != value_type:
+ attrvalue = Parameter(name=cls.sValue, value=jobject[2].upper())
+ prop.mParameters.setdefault(cls.sValue, []).append(attrvalue)
+
+ # Get value type from property name
+ value_type = prop.determineValueType()
+
+ # Check for multivalued
+ values = jobject[3:]
+ if prop.mName.upper() in cls.sMultiValues:
+ prop.mValue = MultiValue(value_type)
+ prop.mValue.parseJSONValue(values)
+ else:
+ # Create the type
+ prop.mValue = Value.createFromType(value_type)
+ prop.mValue.parseJSONValue(values[0])
+
+ # Special post-create for some types
+ prop._postCreateValue(value_type)
+
+ return prop
+
+ except Exception:
+ raise InvalidProperty("Invalid property", jobject)
+
+
+ def writeJSON(self, jobject):
+
+ # Write it out always with value
+ self.generateValueJSON(jobject, False)
+
+
+ def writeJSONFiltered(self, jobject, filter):
+
+ # Check for property in filter and whether value is written out
+ test, novalue = filter.testPropertyValue(self.mName.upper())
+ if test:
+ self.generateValueJSON(jobject, novalue)
+
+
+ def generateValueJSON(self, jobject, novalue):
+
+ prop = [
+ self.getName().lower(),
+ {},
+ ]
+ jobject.append(prop)
+
+ # Write all parameters
+ for key in sorted(self.mParameters.keys()):
+ for attr in self.mParameters[key]:
+ if attr.getName().lower() != "value":
+ attr.writeJSON(prop[1])
+
+ # Write value
+ if self.mValue and not novalue:
+ self.mValue.writeJSON(prop)
+
+
+ def determineValueType(self):
+ # Get value type from property name
+ value_type = self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN)
+
+ # Check whether custom value is set
+ if self.sValue in self.mParameters:
+ attr = self.getParameterValue(self.sValue)
+ value_type = self.sValueTypeMap.get(attr, value_type)
+
+ # Check for specials
+ if self.mName.upper() in self.sSpecialVariants:
+ # Make sure we have the default value for the special
+ if value_type == self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN):
+ value_type = self.sSpecialVariants[self.mName.upper()]
+
+ return value_type
+
+
</ins><span class="cx"> def createValue(self, data):
</span><span class="cx"> # Tidy first
</span><span class="cx"> self.mValue = None
</span><span class="cx">
</span><span class="cx"> # Get value type from property name
</span><del>- type = PyCalendarProperty.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_UNKNOWN)
</del><ins>+ value_type = self.determineValueType()
</ins><span class="cx">
</span><del>- # Check whether custom value is set
- if definitions.cICalAttribute_VALUE in self.mAttributes:
- type = PyCalendarProperty.sValueTypeMap.get(self.getAttributeValue(definitions.cICalAttribute_VALUE), type)
-
</del><span class="cx"> # Check for multivalued
</span><del>- if self.mName.upper() in PyCalendarProperty.sMultiValues:
- self.mValue = PyCalendarMultiValue(type)
</del><ins>+ if self.mName.upper() in self.sMultiValues:
+ self.mValue = MultiValue(value_type)
</ins><span class="cx"> else:
</span><span class="cx"> # Create the type
</span><del>- self.mValue = PyCalendarValue.createFromType(type)
</del><ins>+ self.mValue = Value.createFromType(value_type)
</ins><span class="cx">
</span><span class="cx"> # Now parse the data
</span><span class="cx"> try:
</span><del>- self.mValue.parse(data)
</del><ins>+ self.mValue.parse(data, self.sVariant)
</ins><span class="cx"> except ValueError:
</span><del>- raise PyCalendarInvalidProperty("Invalid property value", data)
</del><ins>+ raise InvalidProperty("Invalid property value", data)
</ins><span class="cx">
</span><del>- # Special post-create for some types
- if type in (PyCalendarValue.VALUETYPE_TIME, PyCalendarValue.VALUETYPE_DATETIME):
- # Look for TZID attribute
- tzid = None
- if (self.hasAttribute(definitions.cICalAttribute_TZID)):
- tzid = self.getAttributeValue(definitions.cICalAttribute_TZID)
</del><ins>+ self._postCreateValue(value_type)
</ins><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarDateTimeValue):
- self.mValue.getValue().setTimezoneID(tzid)
- elif isinstance(self.mValue, PyCalendarMultiValue):
- for item in self.mValue.getValues():
- if isinstance(item, PyCalendarDateTimeValue):
- item.getValue().setTimezoneID(tzid)
</del><span class="cx">
</span><ins>+ def _postCreateValue(self, value_type):
+ """
+ Do some extra work after creating a value in this property.
</ins><span class="cx">
</span><ins>+ @param value_type: the iCalendar VALUE type for this property
+ @type value_type: C{str}
+ """
+ pass
+
+
</ins><span class="cx"> def setValue(self, value):
</span><span class="cx"> # Tidy first
</span><span class="cx"> self.mValue = None
</span><span class="cx">
</span><span class="cx"> # Get value type from property name
</span><del>- type = PyCalendarProperty.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_TEXT)
</del><ins>+ value_type = self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_TEXT)
</ins><span class="cx">
</span><span class="cx"> # Check whether custom value is set
</span><del>- if definitions.cICalAttribute_VALUE in self.mAttributes:
- type = PyCalendarProperty.sValueTypeMap.get(self.getAttributeValue(definitions.cICalAttribute_VALUE), type)
</del><ins>+ if self.sValue in self.mParameters:
+ value_type = self.sValueTypeMap.get(self.getParameterValue(self.sValue), value_type)
</ins><span class="cx">
</span><span class="cx"> # Check for multivalued
</span><del>- if self.mName.upper() in PyCalendarProperty.sMultiValues:
- self.mValue = PyCalendarMultiValue(type)
</del><ins>+ if self.mName.upper() in self.sMultiValues:
+ self.mValue = MultiValue(value_type)
</ins><span class="cx"> else:
</span><span class="cx"> # Create the type
</span><del>- self.mValue = PyCalendarValue.createFromType(type)
</del><ins>+ self.mValue = Value.createFromType(value_type)
</ins><span class="cx">
</span><span class="cx"> self.mValue.setValue(value)
</span><span class="cx">
</span><span class="cx"> # Special post-create for some types
</span><del>- if type in (PyCalendarValue.VALUETYPE_TIME, PyCalendarValue.VALUETYPE_DATETIME):
- # Look for TZID attribute
- tzid = None
- if (self.hasAttribute(definitions.cICalAttribute_TZID)):
- tzid = self.getAttributeValue(definitions.cICalAttribute_TZID)
</del><ins>+ self._postCreateValue(value_type)
</ins><span class="cx">
</span><del>- if isinstance(self.mValue, PyCalendarDateTimeValue):
- self.mValue.getValue().setTimezoneID(tzid)
- elif isinstance(self.mValue, PyCalendarMultiValue):
- for item in self.mValue.getValues():
- if isinstance(item, PyCalendarDateTimeValue):
- item.getValue().setTimezoneID(tzid)
</del><span class="cx">
</span><ins>+ def setupValueParameter(self):
+ if self.sValue in self.mParameters:
+ del self.mParameters[self.sValue]
</ins><span class="cx">
</span><del>- def setupValueAttribute(self):
- if definitions.cICalAttribute_VALUE in self.mAttributes:
- del self.mAttributes[definitions.cICalAttribute_VALUE]
-
</del><span class="cx"> # Only if we have a value right now
</span><span class="cx"> if self.mValue is None:
</span><span class="cx"> return
</span><span class="lines">@@ -638,117 +599,47 @@
</span><span class="cx"> # See if current type is default for this property. If there is no mapping available,
</span><span class="cx"> # then always add VALUE if it is not TEXT.
</span><span class="cx"> default_type = self.sDefaultValueTypeMap.get(self.mName.upper())
</span><del>- actual_type = self.mValue.getType()
</del><ins>+ if self.mName.upper() in self.sSpecialVariants:
+ actual_type = default_type
+ else:
+ actual_type = self.mValue.getType()
</ins><span class="cx"> if default_type is None or default_type != actual_type:
</span><span class="cx"> actual_value = self.sTypeValueMap.get(actual_type)
</span><del>- if actual_value is not None and (default_type is not None or actual_type != PyCalendarValue.VALUETYPE_TEXT):
- self.mAttributes.setdefault(definitions.cICalAttribute_VALUE, []).append(PyCalendarAttribute(name=definitions.cICalAttribute_VALUE, value=actual_value))
</del><ins>+ if actual_value is not None and (default_type is not None or actual_type != Value.VALUETYPE_TEXT):
+ self.mParameters.setdefault(self.sValue, []).append(Parameter(name=self.sValue, value=actual_value))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> # Creation
</span><span class="cx"> def _init_attr_value_int(self, ival):
</span><span class="cx"> # Value
</span><del>- self.mValue = PyCalendarIntegerValue(value=ival)
</del><ins>+ self.mValue = IntegerValue(value=ival)
</ins><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def _init_attr_value_text(self, txt, value_type):
</span><span class="cx"> # Value
</span><del>- self.mValue = PyCalendarValue.createFromType(value_type)
- if isinstance(self.mValue, PyCalendarPlainTextValue) or isinstance(self.mValue, PyCalendarUnknownValue):
</del><ins>+ self.mValue = Value.createFromType(value_type)
+ if isinstance(self.mValue, PlainTextValue) or isinstance(self.mValue, UnknownValue):
</ins><span class="cx"> self.mValue.setValue(txt)
</span><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins><span class="cx">
</span><span class="cx">
</span><del>- def _init_attr_value_requeststatus(self, reqstatus):
- # Value
- self.mValue = PyCalendarRequestStatusValue(reqstatus)
-
- # Attributes
- self.setupValueAttribute()
-
-
</del><span class="cx"> def _init_attr_value_datetime(self, dt):
</span><span class="cx"> # Value
</span><del>- self.mValue = PyCalendarDateTimeValue(value=dt)
</del><ins>+ self.mValue = DateTimeValue(value=dt)
</ins><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins><span class="cx">
</span><del>- # Look for timezone
- if not dt.isDateOnly() and dt.local():
- if definitions.cICalAttribute_TZID in self.mAttributes:
- del self.mAttributes[definitions.cICalAttribute_TZID]
- self.mAttributes.setdefault(definitions.cICalAttribute_TZID, []).append(
- PyCalendarAttribute(name=definitions.cICalAttribute_TZID, value=dt.getTimezoneID()))
</del><span class="cx">
</span><del>-
- def _init_attr_value_datetimelist(self, dtl):
- # Value
- date_only = (len(dtl) > 0) and dtl[0].isDateOnly()
- if date_only:
- self.mValue = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_DATE)
- else:
- self.mValue = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_DATETIME)
-
- for dt in dtl:
- self.mValue.addValue(PyCalendarDateTimeValue(dt))
-
- # Attributes
- self.setupValueAttribute()
-
- # Look for timezone
- if ((len(dtl) > 0)
- and not dtl[0].isDateOnly()
- and dtl[0].local()):
- if definitions.cICalAttribute_TZID in self.mAttributes:
- del self.mAttributes[definitions.cICalAttribute_TZID]
- self.mAttributes.setdefault(definitions.cICalAttribute_TZID, []).append(
- PyCalendarAttribute(name=definitions.cICalAttribute_TZID, value=dtl[0].getTimezoneID()))
-
-
- def _init_attr_value_periodlist(self, periodlist):
- # Value
- self.mValue = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_PERIOD)
- for period in periodlist:
- self.mValue.addValue(PyCalendarPeriodValue(period))
-
- # Attributes
- self.setupValueAttribute()
-
-
- def _init_attr_value_duration(self, du):
- # Value
- self.mValue = PyCalendarDurationValue(value=du)
-
- # Attributes
- self.setupValueAttribute()
-
-
- def _init_attr_value_period(self, pe):
- # Value
- self.mValue = PyCalendarPeriodValue(value=pe)
-
- # Attributes
- self.setupValueAttribute()
-
-
- def _init_attr_value_recur(self, recur):
- # Value
- self.mValue = PyCalendarRecurrenceValue(value=recur)
-
- # Attributes
- self.setupValueAttribute()
-
-
</del><span class="cx"> def _init_attr_value_utcoffset(self, utcoffset):
</span><span class="cx"> # Value
</span><del>- self.mValue = PyCalendarUTCOffsetValue()
</del><ins>+ self.mValue = UTCOffsetValue()
</ins><span class="cx"> self.mValue.setValue(utcoffset.getValue())
</span><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrecurrencepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/recurrence.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/recurrence.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,1637 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import xmldefs
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.valueutils import ValueMixin
-import cStringIO as StringIO
-import xml.etree.cElementTree as XML
-
-def WeekDayNumCompare_compare(w1, w2):
-
- if w1[0] < w2[0]:
- return -1
- elif w1[0] > w2[0]:
- return 1
- elif w1[1] < w2[1]:
- return -1
- elif w1[1] > w2[1]:
- return 1
- else:
- return 0
-
-
-
-def WeekDayNumSort_less_than(w1, w2):
-
- return (w1[0] < w2[0]) or (w1[0] == w2[0]) and (w1[1] < w2[1])
-
-
-
-class PyCalendarRecurrence(ValueMixin):
-
- cFreqMap = {
- definitions.cICalValue_RECUR_SECONDLY : definitions.eRecurrence_SECONDLY,
- definitions.cICalValue_RECUR_MINUTELY : definitions.eRecurrence_MINUTELY,
- definitions.cICalValue_RECUR_HOURLY : definitions.eRecurrence_HOURLY,
- definitions.cICalValue_RECUR_DAILY : definitions.eRecurrence_DAILY,
- definitions.cICalValue_RECUR_WEEKLY : definitions.eRecurrence_WEEKLY,
- definitions.cICalValue_RECUR_MONTHLY : definitions.eRecurrence_MONTHLY,
- definitions.cICalValue_RECUR_YEARLY : definitions.eRecurrence_YEARLY,
- }
-
- cFreqToXMLMap = {
- definitions.eRecurrence_SECONDLY: xmldefs.recur_freq_secondly,
- definitions.eRecurrence_MINUTELY: xmldefs.recur_freq_minutely,
- definitions.eRecurrence_HOURLY: xmldefs.recur_freq_hourly,
- definitions.eRecurrence_DAILY: xmldefs.recur_freq_daily,
- definitions.eRecurrence_WEEKLY: xmldefs.recur_freq_weekly,
- definitions.eRecurrence_MONTHLY: xmldefs.recur_freq_monthly,
- definitions.eRecurrence_YEARLY: xmldefs.recur_freq_yearly,
- }
-
- cRecurMap = {
- definitions.cICalValue_RECUR_FREQ : definitions.eRecurrence_FREQ,
- definitions.cICalValue_RECUR_UNTIL : definitions.eRecurrence_UNTIL,
- definitions.cICalValue_RECUR_COUNT : definitions.eRecurrence_COUNT,
- definitions.cICalValue_RECUR_INTERVAL : definitions.eRecurrence_INTERVAL,
- definitions.cICalValue_RECUR_BYSECOND : definitions.eRecurrence_BYSECOND,
- definitions.cICalValue_RECUR_BYMINUTE : definitions.eRecurrence_BYMINUTE,
- definitions.cICalValue_RECUR_BYHOUR : definitions.eRecurrence_BYHOUR,
- definitions.cICalValue_RECUR_BYDAY : definitions.eRecurrence_BYDAY,
- definitions.cICalValue_RECUR_BYMONTHDAY : definitions.eRecurrence_BYMONTHDAY,
- definitions.cICalValue_RECUR_BYYEARDAY : definitions.eRecurrence_BYYEARDAY,
- definitions.cICalValue_RECUR_BYWEEKNO : definitions.eRecurrence_BYWEEKNO,
- definitions.cICalValue_RECUR_BYMONTH : definitions.eRecurrence_BYMONTH,
- definitions.cICalValue_RECUR_BYSETPOS : definitions.eRecurrence_BYSETPOS,
- definitions.cICalValue_RECUR_WKST : definitions.eRecurrence_WKST,
- }
-
- cWeekdayMap = {
- definitions.cICalValue_RECUR_WEEKDAY_SU : definitions.eRecurrence_WEEKDAY_SU,
- definitions.cICalValue_RECUR_WEEKDAY_MO : definitions.eRecurrence_WEEKDAY_MO,
- definitions.cICalValue_RECUR_WEEKDAY_TU : definitions.eRecurrence_WEEKDAY_TU,
- definitions.cICalValue_RECUR_WEEKDAY_WE : definitions.eRecurrence_WEEKDAY_WE,
- definitions.cICalValue_RECUR_WEEKDAY_TH : definitions.eRecurrence_WEEKDAY_TH,
- definitions.cICalValue_RECUR_WEEKDAY_FR : definitions.eRecurrence_WEEKDAY_FR,
- definitions.cICalValue_RECUR_WEEKDAY_SA : definitions.eRecurrence_WEEKDAY_SA,
- }
-
- cWeekdayRecurMap = dict([(v, k) for k, v in cWeekdayMap.items()])
-
- cUnknownIndex = -1
-
- def __init__(self):
- self.init_PyCalendarRecurrence()
-
-
- def duplicate(self):
- other = PyCalendarRecurrence()
-
- other.mFreq = self.mFreq
-
- other.mUseCount = self.mUseCount
- other.mCount = self.mCount
- other.mUseUntil = self.mUseUntil
- if other.mUseUntil:
- other.mUntil = self.mUntil.duplicate()
-
- other.mInterval = self.mInterval
- if self.mBySeconds is not None:
- other.mBySeconds = self.mBySeconds[:]
- if self.mByMinutes is not None:
- other.mByMinutes = self.mByMinutes[:]
- if self.mByHours is not None:
- other.mByHours = self.mByHours[:]
- if self.mByDay is not None:
- other.mByDay = self.mByDay[:]
- if self.mByMonthDay is not None:
- other.mByMonthDay = self.mByMonthDay[:]
- if self.mByYearDay is not None:
- other.mByYearDay = self.mByYearDay[:]
- if self.mByWeekNo is not None:
- other.mByWeekNo = self.mByWeekNo[:]
- if self.mByMonth is not None:
- other.mByMonth = self.mByMonth[:]
- if self.mBySetPos is not None:
- other.mBySetPos = self.mBySetPos[:]
- other.mWeekstart = self.mWeekstart
-
- other.mCached = self.mCached
- if self.mCacheStart:
- other.mCacheStart = self.mCacheStart.duplicate()
- if self.mCacheUpto:
- other.mCacheUpto = self.mCacheUpto.duplicate()
- other.mFullyCached = self.mFullyCached
- if self.mRecurrences:
- other.mRecurrences = self.mRecurrences[:]
-
- return other
-
-
- def init_PyCalendarRecurrence(self):
- self.mFreq = definitions.eRecurrence_YEARLY
-
- self.mUseCount = False
- self.mCount = 0
-
- self.mUseUntil = False
- self.mUntil = None
-
- self.mInterval = 1
- self.mBySeconds = None
- self.mByMinutes = None
- self.mByHours = None
- self.mByDay = None
- self.mByMonthDay = None
- self.mByYearDay = None
- self.mByWeekNo = None
- self.mByMonth = None
- self.mBySetPos = None
- self.mWeekstart = definitions.eRecurrence_WEEKDAY_MO
-
- self.mCached = False
- self.mCacheStart = None
- self.mCacheUpto = None
- self.mFullyCached = False
- self.mRecurrences = None
-
-
- def __hash__(self):
- return hash((
- self.mFreq,
- self.mUseCount,
- self.mCount,
- self.mUseUntil,
- self.mUntil,
- self.mInterval,
- tuple(self.mBySeconds) if self.mBySeconds else None,
- tuple(self.mByMinutes) if self.mByMinutes else None,
- tuple(self.mByHours) if self.mByHours else None,
- tuple(self.mByDay) if self.mByDay else None,
- tuple(self.mByMonthDay) if self.mByMonthDay else None,
- tuple(self.mByYearDay) if self.mByYearDay else None,
- tuple(self.mByWeekNo) if self.mByWeekNo else None,
- tuple(self.mByMonth) if self.mByMonth else None,
- tuple(self.mBySetPos) if self.mBySetPos else None,
- self.mWeekstart,
- ))
-
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
-
- def __eq__(self, other):
- if not isinstance(other, PyCalendarRecurrence):
- return False
- return self.equals(other)
-
-
- def equals(self, comp):
- return (self.mFreq == comp.mFreq) \
- and (self.mUseCount == comp.mUseCount) and (self.mCount == comp.mCount) \
- and (self.mUseUntil == comp.mUseUntil) and (self.mUntil == comp.mUntil) \
- and (self.mInterval == comp.mInterval) \
- and self.equalsNum(self.mBySeconds, comp.mBySeconds) \
- and self.equalsNum(self.mByMinutes, comp.mByMinutes) \
- and self.equalsNum(self.mByHours, comp.mByHours) \
- and self.equalsDayNum(self.mByDay, comp.mByDay) \
- and self.equalsNum(self.mByMonthDay, comp.mByMonthDay) \
- and self.equalsNum(self.mByYearDay, comp.mByYearDay) \
- and self.equalsNum(self.mByWeekNo, comp.mByWeekNo) \
- and self.equalsNum(self.mByMonth, comp.mByMonth) \
- and self.equalsNum(self.mBySetPos, comp.mBySetPos) \
- and (self.mWeekstart == comp.mWeekstart)
-
-
- def equalsNum(self, items1, items2):
- # Check sizes first
- if items1 is None:
- items1 = []
- if items2 is None:
- items2 = []
- if len(items1) != len(items2):
- return False
- elif len(items1) == 0:
- return True
-
- # Copy and sort each one for comparison
- temp1 = items1[:]
- temp2 = items2[:]
- temp1.sort()
- temp2.sort()
-
- for i in range(0, len(temp1)):
- if temp1[i] != temp2[i]:
- return False
- return True
-
-
- def equalsDayNum(self, items1, items2):
- # Check sizes first
- if items1 is None:
- items1 = []
- if items2 is None:
- items2 = []
- if len(items1) != len(items2):
- return False
- elif len(items1) == 0:
- return True
-
- # Copy and sort each one for comparison
- temp1 = items1[:]
- temp2 = items2[:]
- temp1.sort()
- temp2.sort()
-
- for i in range(0, len(temp1)):
- if temp1[i] != temp2[i]:
- return False
- return True
-
-
- def _setAndclearIfChanged(self, attr, value):
- if getattr(self, attr) != value:
- self.clear()
- setattr(self, attr, value)
-
-
- def getFreq(self):
- return self.mFreq
-
-
- def setFreq(self, freq):
- self._setAndclearIfChanged("mFreq", freq)
-
-
- def getUseUntil(self):
- return self.mUseUntil
-
-
- def setUseUntil(self, use_until):
- self._setAndclearIfChanged("mUseUntil", use_until)
-
-
- def getUntil(self):
- return self.mUntil
-
-
- def setUntil(self, until):
- self._setAndclearIfChanged("mUntil", until)
-
-
- def getUseCount(self):
- return self.mUseCount
-
-
- def setUseCount(self, use_count):
- self._setAndclearIfChanged("mUseCount", use_count)
-
-
- def getCount(self):
- return self.mCount
-
-
- def setCount(self, count):
- self._setAndclearIfChanged("mCount", count)
-
-
- def getInterval(self):
- return self.mInterval
-
-
- def setInterval(self, interval):
- self._setAndclearIfChanged("mInterval", interval)
-
-
- def getByMonth(self):
- return self.mByMonth
-
-
- def setByMonth(self, by):
- self._setAndclearIfChanged("mByMonth", by[:])
-
-
- def getByMonthDay(self):
- return self.mByMonthDay
-
-
- def setByMonthDay(self, by):
- self._setAndclearIfChanged("mByMonthDay", by[:])
-
-
- def getByYearDay(self):
- return self.mByYearDay
-
-
- def setByYearDay(self, by):
- self._setAndclearIfChanged("mByYearDay", by[:])
-
-
- def getByDay(self):
- return self.mByDay
-
-
- def setByDay(self, by):
- self._setAndclearIfChanged("mByDay", by[:])
-
-
- def getBySetPos(self):
- return self.mBySetPos
-
-
- def setBySetPos(self, by):
- self._setAndclearIfChanged("mBySetPos", by[:])
-
-
- def parse(self, data):
- self.init_PyCalendarRecurrence()
-
- # Tokenise using ''
- tokens = data.split(";")
- tokens.reverse()
-
- if len(tokens) == 0:
- raise ValueError("PyCalendarRecurrence: Invalid recurrence rule value")
-
- while len(tokens) != 0:
- # Get next token
- token = tokens.pop()
- try:
- tname, tvalue = token.split("=")
- except ValueError:
- raise ValueError("PyCalendarRecurrence: Invalid token '%s'" % (token,))
-
- # Determine token type
- index = PyCalendarRecurrence.cRecurMap.get(tname, PyCalendarRecurrence.cUnknownIndex)
- if index == PyCalendarRecurrence.cUnknownIndex:
- raise ValueError("PyCalendarRecurrence: Invalid token '%s'" % (tname,))
-
- # Parse remainder based on index
- if index == definitions.eRecurrence_FREQ:
- # Get the FREQ value
- index = PyCalendarRecurrence.cFreqMap.get(tvalue, PyCalendarRecurrence.cUnknownIndex)
- if index == PyCalendarRecurrence.cUnknownIndex:
- raise ValueError("PyCalendarRecurrence: Invalid FREQ value")
- self.mFreq = index
-
- elif index == definitions.eRecurrence_UNTIL:
- if self.mUseCount:
- raise ValueError("PyCalendarRecurrence: Can't have both UNTIL and COUNT")
- self.mUseUntil = True
- if self.mUntil is None:
- self.mUntil = PyCalendarDateTime()
- try:
- self.mUntil.parse(tvalue)
- except ValueError:
- raise ValueError("PyCalendarRecurrence: Invalid UNTIL value")
-
- elif index == definitions.eRecurrence_COUNT:
- if self.mUseUntil:
- raise ValueError("PyCalendarRecurrence: Can't have both UNTIL and COUNT")
- self.mUseCount = True
- try:
- self.mCount = int(tvalue)
- except ValueError:
- raise ValueError("PyCalendarRecurrence: Invalid COUNT value")
-
- # Must not be less than one
- if self.mCount < 1:
- raise ValueError("PyCalendarRecurrence: Invalid COUNT value")
-
- elif index == definitions.eRecurrence_INTERVAL:
- try:
- self.mInterval = int(tvalue)
- except ValueError:
- raise ValueError("PyCalendarRecurrence: Invalid INTERVAL value")
-
- # Must NOT be less than one
- if self.mInterval < 1:
- raise ValueError("PyCalendarRecurrence: Invalid INTERVAL value")
-
- elif index == definitions.eRecurrence_BYSECOND:
- if self.mBySeconds is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYSECOND allowed")
- self.mBySeconds = []
- self.parseList(tvalue, self.mBySeconds, 0, 60, errmsg="PyCalendarRecurrence: Invalid BYSECOND value")
-
- elif index == definitions.eRecurrence_BYMINUTE:
- if self.mByMinutes is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYMINUTE allowed")
- self.mByMinutes = []
- self.parseList(tvalue, self.mByMinutes, 0, 59, errmsg="PyCalendarRecurrence: Invalid BYMINUTE value")
-
- elif index == definitions.eRecurrence_BYHOUR:
- if self.mByHours is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYHOUR allowed")
- self.mByHours = []
- self.parseList(tvalue, self.mByHours, 0, 23, errmsg="PyCalendarRecurrence: Invalid BYHOUR value")
-
- elif index == definitions.eRecurrence_BYDAY:
- if self.mByDay is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYDAY allowed")
- self.mByDay = []
- self.parseListDW(tvalue, self.mByDay, errmsg="PyCalendarRecurrence: Invalid BYDAY value")
-
- elif index == definitions.eRecurrence_BYMONTHDAY:
- if self.mByMonthDay is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYMONTHDAY allowed")
- self.mByMonthDay = []
- self.parseList(tvalue, self.mByMonthDay, 1, 31, True, errmsg="PyCalendarRecurrence: Invalid BYMONTHDAY value")
-
- elif index == definitions.eRecurrence_BYYEARDAY:
- if self.mByYearDay is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYYEARDAY allowed")
- self.mByYearDay = []
- self.parseList(tvalue, self.mByYearDay, 1, 366, True, errmsg="PyCalendarRecurrence: Invalid BYYEARDAY value")
-
- elif index == definitions.eRecurrence_BYWEEKNO:
- if self.mByWeekNo is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYWEEKNO allowed")
- self.mByWeekNo = []
- self.parseList(tvalue, self.mByWeekNo, 1, 53, True, errmsg="PyCalendarRecurrence: Invalid BYWEEKNO value")
-
- elif index == definitions.eRecurrence_BYMONTH:
- if self.mByMonth is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYMONTH allowed")
- self.mByMonth = []
- self.parseList(tvalue, self.mByMonth, 1, 12, errmsg="PyCalendarRecurrence: Invalid BYMONTH value")
-
- elif index == definitions.eRecurrence_BYSETPOS:
- if self.mBySetPos is not None:
- raise ValueError("PyCalendarRecurrence: Only one BYSETPOS allowed")
- self.mBySetPos = []
- self.parseList(tvalue, self.mBySetPos, allowNegative=True, errmsg="PyCalendarRecurrence: Invalid BYSETPOS value")
-
- elif index == definitions.eRecurrence_WKST:
- index = PyCalendarRecurrence.cWeekdayMap.get(tvalue, PyCalendarRecurrence.cUnknownIndex)
- if (index == PyCalendarRecurrence.cUnknownIndex):
- raise ValueError("PyCalendarRecurrence: Invalid WKST value")
- self.mWeekstart = index
-
-
- def parseList(self, txt, list, min=None, max=None, allowNegative=False, errmsg=""):
-
- if "," in txt:
- tokens = txt.split(",")
- else:
- tokens = (txt,)
-
- for token in tokens:
- value = int(token)
- if not allowNegative and value < 0:
- raise ValueError(errmsg)
- avalue = abs(value)
- if min is not None and avalue < min:
- raise ValueError(errmsg)
- if max is not None and avalue > max:
- raise ValueError(errmsg)
- list.append(value)
-
-
- def parseListDW(self, txt, list, errmsg=""):
-
- if "," in txt:
- tokens = txt.split(",")
- else:
- tokens = (txt,)
-
- for token in tokens:
- # Get number if present
- num = 0
- if (len(token) > 0) and token[0] in "+-1234567890":
- offset = 0
- while (offset < len(token)) and token[offset] in "+-1234567890":
- offset += 1
-
- num = int(token[0:offset])
- token = token[offset:]
-
- anum = abs(num)
- if anum < 1:
- raise ValueError(errmsg)
- if anum > 53:
- raise ValueError(errmsg)
-
- # Get day
- index = PyCalendarRecurrence.cWeekdayMap.get(token, PyCalendarRecurrence.cUnknownIndex)
- if (index == PyCalendarRecurrence.cUnknownIndex):
- raise ValueError(errmsg)
- wday = index
-
- list.append((num, wday))
-
-
- def generate(self, os):
- try:
- os.write(definitions.cICalValue_RECUR_FREQ)
- os.write("=")
-
- if self.mFreq == definitions.eRecurrence_SECONDLY:
- os.write(definitions.cICalValue_RECUR_SECONDLY)
-
- elif self.mFreq == definitions.eRecurrence_MINUTELY:
- os.write(definitions.cICalValue_RECUR_MINUTELY)
-
- elif self.mFreq == definitions.eRecurrence_HOURLY:
- os.write(definitions.cICalValue_RECUR_HOURLY)
-
- elif self.mFreq == definitions.eRecurrence_DAILY:
- os.write(definitions.cICalValue_RECUR_DAILY)
-
- elif self.mFreq == definitions.eRecurrence_WEEKLY:
- os.write(definitions.cICalValue_RECUR_WEEKLY)
-
- elif self.mFreq == definitions.eRecurrence_MONTHLY:
- os.write(definitions.cICalValue_RECUR_MONTHLY)
-
- elif self.mFreq == definitions.eRecurrence_YEARLY:
- os.write(definitions.cICalValue_RECUR_YEARLY)
-
- if self.mUseCount:
- os.write(";")
- os.write(definitions.cICalValue_RECUR_COUNT)
- os.write("=")
- os.write(str(self.mCount))
- elif self.mUseUntil:
- os.write(";")
- os.write(definitions.cICalValue_RECUR_UNTIL)
- os.write("=")
- self.mUntil.generate(os)
-
- if self.mInterval > 1:
- os.write(";")
- os.write(definitions.cICalValue_RECUR_INTERVAL)
- os.write("=")
- os.write(str(self.mInterval))
-
- self.generateList(os, definitions.cICalValue_RECUR_BYSECOND, self.mBySeconds)
- self.generateList(os, definitions.cICalValue_RECUR_BYMINUTE, self.mByMinutes)
- self.generateList(os, definitions.cICalValue_RECUR_BYHOUR, self.mByHours)
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- os.write(";")
- os.write(definitions.cICalValue_RECUR_BYDAY)
- os.write("=")
- comma = False
- for iter in self.mByDay:
- if comma:
- os.write(",")
- comma = True
-
- if iter[0] != 0:
- os.write(str(iter[0]))
-
- if iter[1] == definitions.eRecurrence_WEEKDAY_SU:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
-
- elif iter[1] == definitions.eRecurrence_WEEKDAY_MO:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
-
- elif iter[1] == definitions.eRecurrence_WEEKDAY_TU:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
-
- elif iter[1] == definitions.eRecurrence_WEEKDAY_WE:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
-
- elif iter[1] == definitions.eRecurrence_WEEKDAY_TH:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
-
- elif iter[1] == definitions.eRecurrence_WEEKDAY_FR:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
-
- elif iter[1] == definitions.eRecurrence_WEEKDAY_SA:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
-
- self.generateList(os, definitions.cICalValue_RECUR_BYMONTHDAY, self.mByMonthDay)
- self.generateList(os, definitions.cICalValue_RECUR_BYYEARDAY, self.mByYearDay)
- self.generateList(os, definitions.cICalValue_RECUR_BYWEEKNO, self.mByWeekNo)
- self.generateList(os, definitions.cICalValue_RECUR_BYMONTH, self.mByMonth)
- self.generateList(os, definitions.cICalValue_RECUR_BYSETPOS, self.mBySetPos)
-
- # MO is the default so we do not need it
- if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
- os.write(";")
- os.write(definitions.cICalValue_RECUR_WKST)
- os.write("=")
-
- if self.mWeekstart == definitions.eRecurrence_WEEKDAY_SU:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
-
- elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_MO:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
-
- elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TU:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
-
- elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_WE:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
-
- elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TH:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
-
- elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_FR:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
-
- elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_SA:
- os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
-
- except:
- pass
-
-
- def generateList(self, os, title, items):
-
- if (items is not None) and (len(items) != 0):
- os.write(";")
- os.write(title)
- os.write("=")
- comma = False
- for e in items:
- if comma:
- os.write(",")
- comma = True
- os.write(str(e))
-
-
- def writeXML(self, node, namespace):
-
- recur = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.value_recur))
-
- freq = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_freq))
- freq.text = self.cFreqToXMLMap[self.mFreq]
-
- if self.mUseCount:
- count = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_count))
- count.text = str(self.mCount)
- elif self.mUseUntil:
- until = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_until))
- self.mUntil.writeXML(until, namespace)
-
- if self.mInterval > 1:
- interval = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_interval))
- interval.text = str(self.mInterval)
-
- self.writeXMLList(recur, namespace, xmldefs.recur_bysecond, self.mBySeconds)
- self.writeXMLList(recur, namespace, xmldefs.recur_byminute, self.mByMinutes)
- self.writeXMLList(recur, namespace, xmldefs.recur_byhour, self.mByHours)
-
- if self.mByDay is not None and len(self.mByDay) != 0:
- for iter in self.mByDay:
- byday = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_byday))
- data = ""
- if iter[0] != 0:
- data = str(iter[0])
- data += self.cWeekdayRecurMap.get(iter[1], "")
- byday.text = data
-
- self.writeXMLList(recur, namespace, xmldefs.recur_bymonthday, self.mByMonthDay)
- self.writeXMLList(recur, namespace, xmldefs.recur_byyearday, self.mByYearDay)
- self.writeXMLList(recur, namespace, xmldefs.recur_byweekno, self.mByWeekNo)
- self.writeXMLList(recur, namespace, xmldefs.recur_bymonth, self.mByMonth)
- self.writeXMLList(recur, namespace, xmldefs.recur_bysetpos, self.mBySetPos)
-
- # MO is the default so we do not need it
- if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
- wkst = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_wkst))
- wkst.text = self.cWeekdayRecurMap.get(self.mWeekstart, definitions.cICalValue_RECUR_WEEKDAY_MO)
-
-
- def writeXMLList(self, node, namespace, name, items):
- if items is not None and len(items) != 0:
- for item in items:
- child = XML.SubElement(node, xmldefs.makeTag(namespace, name))
- child.text = str(item)
-
-
- def hasBy(self):
- return (self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
- or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
- or (self.mByHours is not None) and (len(self.mByHours) != 0) \
- or (self.mByDay is not None) and (len(self.mByDay) != 0) \
- or (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0) \
- or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
- or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0) \
- or (self.mByMonth is not None) and (len(self.mByMonth) != 0) \
- or (self.mBySetPos is not None) and (len(self.mBySetPos) != 0)
-
-
- def isSimpleRule(self):
- # One that has no BYxxx rules
- return not self.hasBy()
-
-
- def isAdvancedRule(self):
- # One that has BYMONTH,
- # BYMONTHDAY (with no negative value),
- # BYDAY (with multiple unnumbered, or numbered with all the same number
- # (1..4, -2, -1)
- # BYSETPOS with +1, or -1 only
- # no others
-
- # First checks the ones we do not handle at all
- if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
- or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
- or (self.mByHours is not None) and (len(self.mByHours) != 0) \
- or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
- or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0)):
- return False
-
- # Check BYMONTHDAY numbers (we can handle -7...-1, 1..31)
- if self.mByMonthDay is not None:
- for iter in self.mByMonthDay:
- if (iter < -7) or (iter > 31) or (iter == 0):
- return False
-
- # Check BYDAY numbers
- if self.mByDay is not None:
- number = 0
- first = True
- for iter in self.mByDay:
-
- # Get the first number
- if (first):
- number = iter[0]
- first = False
-
- # Check number range
- if (number > 4) or (number < -2):
- return False
-
- # If current differs from last, then we have an error
- elif number != iter[0]:
- return False
-
- # Check BYSETPOS numbers
- if self.mBySetPos is not None:
- if len(self.mBySetPos) > 1:
- return False
- if (len(self.mBySetPos) == 1) and (self.mBySetPos[0] != -1) and (self.mBySetPos[0] != 1):
- return False
-
- # If we get here it must be OK
- return True
-
-
- def getUIDescription(self):
- try:
- # For now just use iCal item
- sout = StringIO()
- self.generate(sout)
- result = sout.getvalue()
- except:
- result = ""
-
- return result
-
-
- def expand(self, start, range, items, float_offset=0):
-
- # Must have recurrence list at this point
- if self.mRecurrences is None:
- self.mRecurrences = []
-
- # Wipe cache if start is different
- if self.mCached and (start != self.mCacheStart):
- self.mCached = False
- self.mFullyCached = False
- self.mRecurrences = []
-
- # Is the current cache complete or does it extend past the requested
- # range end
- if not self.mCached or not self.mFullyCached \
- and (self.mCacheUpto is None or self.mCacheUpto < range.getEnd()):
- cache_range = range.duplicate()
-
- # If partially cached just cache from previous cache end up to new
- # end
- if self.mCached:
- cache_range = PyCalendarPeriod(self.mCacheUpto, range.getEnd())
-
- # Simple expansion is one where there is no BYXXX rule part
- if not self.hasBy():
- self.mFullyCached = self.simpleExpand(start, cache_range, self.mRecurrences, float_offset)
- else:
- self.mFullyCached = self.complexExpand(start, cache_range, self.mRecurrences, float_offset)
-
- # Set cache values
- self.mCached = True
- self.mCacheStart = start
- self.mCacheUpto = range.getEnd()
-
- # Just return the cached items in the requested range
- limited = not self.mFullyCached
- for iter in self.mRecurrences:
- if range.isDateWithinPeriod(iter):
- items.append(iter)
- else:
- limited = True
- return limited
-
-
- def simpleExpand(self, start, range, items, float_offset):
- start_iter = start.duplicate()
- ctr = 0
-
- if self.mUseUntil:
- float_until = self.mUntil.duplicate()
- if start.floating():
- float_until.setTimezoneID(0)
- float_until.offsetSeconds(float_offset)
-
- while True:
- # Exit if after period we want
- if range.isDateAfterPeriod(start_iter):
- return False
-
- # Add current one to list
- items.append(start_iter.duplicate())
-
- # Get next item
- start_iter.recur(self.mFreq, self.mInterval)
-
- # Check limits
- if self.mUseCount:
- # Bump counter and exit if over
- ctr += 1
- if ctr >= self.mCount:
- return True
- elif self.mUseUntil:
- # Exit if next item is after until (its OK if its the same as
- # UNTIL as UNTIL is inclusive)
- if start_iter > float_until:
- return True
-
-
- def complexExpand(self, start, range, items, float_offset):
- start_iter = start.duplicate()
- ctr = 0
-
- if self.mUseUntil:
- float_until = self.mUntil.duplicate()
- if start.floating():
- float_until.setTimezoneID(None)
- float_until.offsetSeconds(float_offset)
-
- # Always add the initial instance DTSTART
- if self.mUseCount:
- # Bump counter and exit if over
- ctr += 1
- if ctr >= self.mCount:
- return True
-
- # Need to re-initialise start based on BYxxx rules
- while True:
- # Behaviour is based on frequency
- set_items = []
-
- if self.mFreq == definitions.eRecurrence_SECONDLY:
- self.generateSecondlySet(start_iter, set_items)
-
- elif self.mFreq == definitions.eRecurrence_MINUTELY:
- self.generateMinutelySet(start_iter, set_items)
-
- elif self.mFreq == definitions.eRecurrence_HOURLY:
- self.generateHourlySet(start_iter, set_items)
-
- elif self.mFreq == definitions.eRecurrence_DAILY:
- self.generateDailySet(start_iter, set_items)
-
- elif self.mFreq == definitions.eRecurrence_WEEKLY:
- self.generateWeeklySet(start_iter, set_items)
-
- elif self.mFreq == definitions.eRecurrence_MONTHLY:
- self.generateMonthlySet(start_iter, set_items)
-
- elif self.mFreq == definitions.eRecurrence_YEARLY:
- self.generateYearlySet(start_iter, set_items)
-
- # Always sort the set as BYxxx rules may not be sorted
- #set_items.sort(cmp=PyCalendarDateTime.sort)
- set_items.sort(key=lambda x: x.getPosixTime())
-
- # Process each one in the generated set
- for iter in set_items:
-
- # Ignore if it is before the actual start - we need this
- # because the expansion
- # can go back in time from the real start, but we must exclude
- # those when counting
- # even if they are not within the requested range
- if iter < start:
- continue
-
- # Exit if after period we want
- if range.isDateAfterPeriod(iter):
- return False
-
- # Exit if beyond the UNTIL limit
- if self.mUseUntil:
- # Exit if next item is after until (its OK if its the same
- # as UNTIL as UNTIL is inclusive)
- if iter > float_until:
- return True
-
- # Special for start instance
- if (ctr == 1) and (start == iter):
- continue
-
- # Add current one to list
- items.append(iter)
-
- # Check limits
- if self.mUseCount:
- # Bump counter and exit if over
- ctr += 1
- if ctr >= self.mCount:
- return True
-
- # Exit if after period we want
- if range.isDateAfterPeriod(start_iter):
- return False
-
- # Get next item
- start_iter.recur(self.mFreq, self.mInterval)
-
-
- def clear(self):
- self.mCached = False
- self.mFullyCached = False
- if self.mRecurrences is not None:
- self.mRecurrences = []
-
-
- # IMPORTANT ExcludeFutureRecurrence assumes mCacheStart is setup with the
- # owning VEVENT's DTSTART
- # Currently this method is only called when a recurrence is being removed
- # so
- # the recurrence data should be cached
-
- # Exclude dates on or after the chosen one
- def excludeFutureRecurrence(self, exclude):
- # Expand the rule up to the exclude date
- items = []
- period = PyCalendarPeriod()
- period.init(self.mCacheStart, exclude)
- self.expand(self.mCacheStart, period, items)
-
- # Adjust UNTIL or add one if no COUNT
- if self.getUseUntil() or not self.getUseCount():
- # The last one is just less than the exclude date
- if len(items) != 0:
- # Now use the data as the UNTIL
- self.mUseUntil = True
- self.mUntil = items[-1]
-
- # Adjust COUNT
- elif self.getUseCount():
- # The last one is just less than the exclude date
- self.mUseCount = True
- self.mCount = len(items)
-
- # Now clear out the cached set after making changes
- self.clear()
-
-
- def generateYearlySet(self, start, items):
- # All possible BYxxx are valid, though some combinations are not
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- items[:] = self.byMonthExpand(items)
-
- if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byWeekNoExpand(items)
-
- if (self.mByYearDay is not None) and (len(self.mByYearDay) != 0):
- items[:] = self.byYearDayExpand(items)
-
- if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
- items[:] = self.byMonthDayExpand(items)
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- # BYDAY is complicated:
- # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
- # contracts the recurrence set
- # else it expands it, but the expansion depends on the frequency
- # and other BYxxx periodicities
-
- if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
- or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
- items[:] = self.byDayLimit(items)
- elif (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byDayExpandWeekly(items)
- elif (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- items[:] = self.byDayExpandMonthly(items)
- else:
- items[:] = self.byDayExpandYearly(items)
-
- if (self.mByHours is not None) and (len(self.mByHours) != 0):
- items[:] = self.byHourExpand(items)
-
- if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
- items[:] = self.byMinuteExpand(items)
-
- if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
- items[:] = self.bySecondExpand(items)
-
- if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
- items[:] = self.bySetPosLimit(items)
-
-
- def generateMonthlySet(self, start, items):
- # Cannot have BYYEARDAY and BYWEEKNO
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- # BYMONTH limits the range of possible values
- items[:] = self.byMonthLimit(items)
- if (len(items) == 0):
- return
-
- # No BYWEEKNO
-
- # No BYYEARDAY
-
- if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
- items[:] = self.byMonthDayExpand(items)
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- # BYDAY is complicated:
- # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
- # contracts the recurrence set
- # else it expands it, but the expansion depends on the frequency
- # and other BYxxx periodicities
-
- if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
- or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
- items[:] = self.byDayLimit(items)
- else:
- items[:] = self.byDayExpandMonthly(items)
-
- if ((self.mByHours is not None) and (len(self.mByHours) != 0)):
- items[:] = self.byHourExpand(items)
-
- if ((self.mByMinutes is not None) and (len(self.mByMinutes) != 0)):
- items[:] = self.byMinuteExpand(items)
-
- if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0)):
- items[:] = self.bySecondExpand(items)
-
- if ((self.mBySetPos is not None) and (len(self.mBySetPos) != 0)):
- items[:] = self.bySetPosLimit(items)
-
-
- def generateWeeklySet(self, start, items):
- # Cannot have BYYEARDAY and BYMONTHDAY
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- # BYMONTH limits the range of possible values
- items[:] = self.byMonthLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byWeekNoLimit(items)
- if (len(items) == 0):
- return
-
- # No BYYEARDAY
-
- # No BYMONTHDAY
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- items[:] = self.byDayExpandWeekly(items)
-
- if (self.mByHours is not None) and (len(self.mByHours) != 0):
- items[:] = self.byHourExpand(items)
-
- if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
- items[:] = self.byMinuteExpand(items)
-
- if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
- items[:] = self.bySecondExpand(items)
-
- if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
- items[:] = self.bySetPosLimit(items)
-
-
- def generateDailySet(self, start, items):
- # Cannot have BYYEARDAY
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- # BYMONTH limits the range of possible values
- items[:] = self.byMonthLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byWeekNoLimit(items)
- if (len(items) == 0):
- return
-
- # No BYYEARDAY
-
- if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
- items[:] = self.byMonthDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- items[:] = self.byDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByHours is not None) and (len(self.mByHours) != 0):
- items[:] = self.byHourExpand(items)
-
- if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
- items[:] = self.byMinuteExpand(items)
-
- if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
- items[:] = self.bySecondExpand(items)
-
- if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
- items[:] = self.bySetPosLimit(items)
-
-
- def generateHourlySet(self, start, items):
- # Cannot have BYYEARDAY
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- # BYMONTH limits the range of possible values
- items[:] = self.byMonthLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byWeekNoLimit(items)
- if (len(items) == 0):
- return
-
- # No BYYEARDAY
-
- if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
- items[:] = self.byMonthDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- items[:] = self.byDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByHours is not None) and (len(self.mByHours) != 0):
- items[:] = self.byHourLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
- items[:] = self.byMinuteExpand(items)
-
- if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
- items[:] = self.bySecondExpand(items)
-
- if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
- items[:] = self.bySetPosLimit(items)
-
-
- def generateMinutelySet(self, start, items):
- # Cannot have BYYEARDAY
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- # BYMONTH limits the range of possible values
- items[:] = self.byMonthLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byWeekNoLimit(items)
- if (len(items) == 0):
- return
-
- # No BYYEARDAY
-
- if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
- items[:] = self.byMonthDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- items[:] = self.byDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByHours is not None) and (len(self.mByHours) != 0):
- items[:] = self.byHourLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
- items[:] = self.byMinuteLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
- items[:] = self.bySecondExpand(items)
-
- if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
- items[:] = self.bySetPosLimit(items)
-
-
- def generateSecondlySet(self, start, items):
- # Cannot have BYYEARDAY
-
- # Start with initial date-time
- items.append(start.duplicate())
-
- if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
- # BYMONTH limits the range of possible values
- items[:] = self.byMonthLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
- items[:] = self.byWeekNoLimit(items)
- if (len(items) == 0):
- return
-
- # No BYYEARDAY
-
- if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
- items[:] = self.byMonthDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByDay is not None) and (len(self.mByDay) != 0):
- items[:] = self.byDayLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByHours is not None) and (len(self.mByHours) != 0):
- items[:] = self.byHourLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
- items[:] = self.byMinuteLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
- items[:] = self.bySecondLimit(items)
- if (len(items) == 0):
- return
-
- if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
- items[:] = self.bySetPosLimit(items)
-
-
- def byMonthExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYMONTH and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByMonth:
- temp = iter1.duplicate()
- temp.setMonth(iter2)
- output.append(temp)
-
- return output
-
-
- def byWeekNoExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYWEEKNO and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByWeekNo:
- temp = iter1.duplicate()
- temp.setWeekNo(iter2)
- output.append(temp)
-
- return output
-
-
- def byYearDayExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYYEARDAY and generating a new date-time for it
- # and insert into output
- for iter2 in self.mByYearDay:
- temp = iter1.duplicate()
- temp.setYearDay(iter2)
- output.append(temp)
-
- return output
-
-
- def byMonthDayExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYMONTHDAY and generating a new date-time for it
- # and insert into output
- for iter2 in self.mByMonthDay:
- temp = iter1.duplicate()
- temp.setMonthDay(iter2)
- output.append(temp)
-
- return output
-
-
- def byDayExpandYearly(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYDAY and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByDay:
- # Numeric value means specific instance
- if iter2[0] != 0:
- temp = iter1.duplicate()
- temp.setDayOfWeekInYear(iter2[0], iter2[1])
- output.append(temp)
- else:
- # Every matching day in the year
- for i in range(1, 54):
- temp = iter1.duplicate()
- temp.setDayOfWeekInYear(i, iter2[1])
- if temp.getYear() == (iter1).getYear():
- output.append(temp)
-
- return output
-
-
- def byDayExpandMonthly(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYDAY and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByDay:
- # Numeric value means specific instance
- if iter2[0] != 0:
- temp = iter1.duplicate()
- temp.setDayOfWeekInMonth(iter2[0], iter2[1])
- output.append(temp)
- else:
- # Every matching day in the month
- for i in range(1, 7):
- temp = iter1.duplicate()
- temp.setDayOfWeekInMonth(i, iter2[1])
- if temp.getMonth() == iter1.getMonth():
- output.append(temp)
-
- return output
-
-
- def byDayExpandWeekly(self, dates):
- # Must take into account the WKST value
-
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYDAY and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByDay:
- # Numeric values are meaningless so ignore them
- if iter2[0] == 0:
- temp = iter1.duplicate()
-
- # Determine amount of offset to apply to temp to shift it
- # to the start of the week (backwards)
- week_start_offset = self.mWeekstart - temp.getDayOfWeek()
- if week_start_offset > 0:
- week_start_offset -= 7
-
- # Determine amount of offset from the start of the week to
- # the day we want (forwards)
- day_in_week_offset = iter2[1] - self.mWeekstart
- if day_in_week_offset < 0:
- day_in_week_offset += 7
-
- # Apply offsets
- temp.offsetDay(week_start_offset + day_in_week_offset)
- output.append(temp)
-
- return output
-
-
- def byHourExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYHOUR and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByHours:
- temp = iter1.duplicate()
- temp.setHours(iter2)
- output.append(temp)
-
- return output
-
-
- def byMinuteExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYMINUTE and generating a new date-time for it and
- # insert into output
- for iter2 in self.mByMinutes:
- temp = iter1.duplicate()
- temp.setMinutes(iter2)
- output.append(temp)
-
- return output
-
-
- def bySecondExpand(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYSECOND and generating a new date-time for it and
- # insert into output
- for iter2 in self.mBySeconds:
- temp = iter1.duplicate()
- temp.setSeconds(iter2)
- output.append(temp)
-
- return output
-
-
- def byMonthLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYMONTH and indicate keep if input month matches
- keep = False
- for iter2 in self.mByMonth:
- keep = (iter1.getMonth() == iter2)
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def byWeekNoLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYWEEKNO and indicate keep if input month matches
- keep = False
- for iter2 in self.mByWeekNo:
- keep = iter1.isWeekNo(iter2)
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def byMonthDayLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYMONTHDAY and indicate keep if input month
- # matches
- keep = False
- for iter2 in self.mByMonthDay:
- keep = iter1.isMonthDay(iter2)
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def byDayLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYDAY and indicate keep if input month matches
- keep = False
- for iter2 in self.mByDay:
- keep = iter1.isDayOfWeekInMonth(iter2[0], iter2[1])
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def byHourLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYHOUR and indicate keep if input hour matches
- keep = False
- for iter2 in self.mByHours:
- keep = (iter1.getHours() == iter2)
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def byMinuteLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYMINUTE and indicate keep if input minute matches
- keep = False
- for iter2 in self.mByMinutes:
- keep = (iter1.getMinutes() == iter2)
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def bySecondLimit(self, dates):
- # Loop over all input items
- output = []
- for iter1 in dates:
- # Loop over each BYSECOND and indicate keep if input second matches
- keep = False
- for iter2 in self.mBySeconds:
- keep = (iter1.getSeconds() == iter2)
- if keep:
- break
-
- if keep:
- output.append(iter1)
-
- return output
-
-
- def bySetPosLimit(self, dates):
- # The input dates MUST be sorted in order for this to work properly
- #dates.sort(cmp=PyCalendarDateTime.sort)
- dates.sort(key=lambda x: x.getPosixTime())
-
- # Loop over each BYSETPOS and extract the relevant component from the
- # input array and add to the output
- output = []
- input_size = len(dates)
- for iter in self.mBySetPos:
- if iter > 0:
- # Positive values are offset from the start
- if iter <= input_size:
- output.append(dates[iter - 1])
- elif iter < 0:
- # Negative values are offset from the end
- if -iter <= input_size:
- output.append(dates[input_size + iter])
-
- return output
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrecurrencesetpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/recurrenceset.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/recurrenceset.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/recurrenceset.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,312 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.utils import set_difference
-
-class PyCalendarRecurrenceSet(object):
-
- def __init__(self):
- self.mRrules = []
- self.mExrules = []
- self.mRdates = []
- self.mExdates = []
- self.mRperiods = []
- self.mExperiods = []
-
-
- def duplicate(self):
- other = PyCalendarRecurrenceSet()
- other.mRrules = [i.duplicate() for i in self.mRrules]
- other.mExrules = [i.duplicate() for i in self.mExrules]
- other.mRdates = [i.duplicate() for i in self.mRdates]
- other.mExdates = [i.duplicate() for i in self.mExdates]
- other.mRperiods = [i.duplicate() for i in self.mRperiods]
- other.mExperiods = [i.duplicate() for i in self.mExperiods]
- return other
-
-
- def hasRecurrence(self):
- return ((len(self.mRrules) != 0) or (len(self.mRdates) != 0) or (len(self.mRperiods) != 0)
- or (len(self.mExrules) != 0) or (len(self.mExdates) != 0)
- or (len(self.mExperiods) != 0))
-
-
- def equals(self, comp):
- # Look at RRULEs
- if not self.equalsRules(self.mRrules, comp.self.mRrules):
- return False
-
- # Look at EXRULEs
- if not self.equalsRules(self.mExrules, comp.self.mExrules):
- return False
-
- # Look at RDATEs
- if not self.equalsDates(self.mRdates, comp.self.mRdates):
- return False
- if not self.equalsPeriods(self.mRperiods, comp.self.mRperiods):
- return False
-
- # Look at EXDATEs
- if not self.equalsDates(self.mExdates, comp.self.mExdates):
- return False
- if not self.equalsPeriods(self.mExperiods, comp.self.mExperiods):
- return False
-
- # If we get here they match
- return True
-
-
- def equalsRules(self, rules1, rules2):
- # Check sizes first
- if len(rules1) != len(rules2):
- return False
- elif len(rules1) == 0:
- return True
-
- # Do sledge hammer O(n^2) approach as its not easy to sort these things
- # for a smarter test.
- # In most cases there will only be one rule anyway, so this should not
- # be too painful.
-
- temp2 = rules2[:]
-
- for r1 in rules1:
- found = False
- for r2 in temp2:
- if r1.equals(r2):
- # Remove the one found so it is not tested again
- temp2.remove(r2)
- found = True
- break
-
- if not found:
- return False
-
- return True
-
-
- def equalsDates(self, dates1, dates2):
- # Check sizes first
- if len(dates1) != len(dates2):
- return False
- elif len(dates1) == 0:
- return True
-
- # Copy each and sort for comparison
- dt1 = dates1[:]
- dt2 = dates2[:]
-
- dt1.sort(key=lambda x: x.getPosixTime())
- dt2.sort(key=lambda x: x.getPosixTime())
-
- return dt1.equal(dt2)
-
-
- def equalsPeriods(self, periods1, periods2):
- # Check sizes first
- if len(periods1) != len(periods2):
- return False
- elif len(periods1) == 0:
- return True
-
- # Copy each and sort for comparison
- p1 = periods1[:]
- p2 = periods2[:]
-
- p1.sort()
- p2.sort()
-
- return p1.equal(p2)
-
-
- def addRule(self, rule):
- self.mRrules.append(rule)
-
-
- def subtractRule(self, rule):
- self.mExrules.append(rule)
-
-
- def addDT(self, dt):
- self.mRdates.append(dt)
-
-
- def subtractDT(self, dt):
- self.mExdates.append(dt)
-
-
- def addPeriod(self, p):
- self.mRperiods.append(p)
-
-
- def subtractPeriod(self, p):
- self.mExperiods.append(p)
-
-
- def getRules(self):
- return self.mRrules
-
-
- def getExrules(self):
- return self.mExrules
-
-
- def getDates(self):
- return self.mRdates
-
-
- def getExdates(self):
- return self.mExdates
-
-
- def getPeriods(self):
- return self.mRperiods
-
-
- def getExperiods(self):
- return self.mExperiods
-
-
- def expand(self, start, range, items, float_offset=0):
- # Need to return whether the limit was applied or not
- limited = False
-
- # Now create list of items to include
- include = []
-
- # Always include the initial DTSTART if within the range
- if range.isDateWithinPeriod(start):
- include.append(start)
- else:
- limited = True
-
- # RRULES
- for iter in self.mRrules:
- if iter.expand(start, range, include, float_offset=float_offset):
- limited = True
-
- # RDATES
- for iter in self.mRdates:
- if range.isDateWithinPeriod(iter):
- include.append(iter)
- else:
- limited = True
- for iter in self.mRperiods:
- if range.isPeriodOverlap(iter):
- include.append(iter.getStart())
- else:
- limited = True
-
- # Make sure the list is unique
- include = [x for x in set(include)]
- include.sort(key=lambda x: x.getPosixTime())
-
- # Now create list of items to exclude
- exclude = []
-
- # EXRULES
- for iter in self.mExrules:
- iter.expand(start, range, exclude, float_offset=float_offset)
-
- # EXDATES
- for iter in self.mExdates:
- if range.isDateWithinPeriod(iter):
- exclude.append(iter)
- for iter in self.mExperiods:
- if range.isPeriodOverlap(iter):
- exclude.append(iter.getStart())
-
- # Make sure the list is unique
- exclude = [x for x in set(exclude)]
- exclude.sort(key=lambda x: x.getPosixTime())
-
- # Add difference between to the two sets (include - exclude) to the
- # results
- items.extend(set_difference(include, exclude))
- return limited
-
-
- def changed(self):
- # RRULES
- for iter in self.mRrules:
- iter.clear()
-
- # EXRULES
- for iter in self.mExrules:
- iter.clear()
-
-
- def excludeFutureRecurrence(self, exclude):
- # Adjust RRULES to end before start
- for iter in self.mRrules:
- iter.excludeFutureRecurrence(exclude)
-
- # Remove RDATES on or after start
- self.mRdates.removeOnOrAfter(exclude)
- for iter in self.mRperiods:
- if iter > exclude:
- self.mRperiods.remove(iter)
-
-
- # UI operations
- def isSimpleUI(self):
- # Right now the Event dialog only handles a single RRULE (but we allow
- # any number of EXDATES as deleted
- # instances will appear as EXDATES)
- if ((len(self.mRrules) > 1) or (len(self.mExrules) > 0)
- or (len(self.mRdates) > 0) or (len(self.mRperiods) > 0)):
- return False
-
- # Also, check the rule iteself
- elif len(self.mRrules) == 1:
- return self.mRrules.firstElement().isSimpleRule()
- else:
- return True
-
-
- def isAdvancedUI(self):
- # Right now the Event dialog only handles a single RRULE
- if ((len(self.mRrules) > 1) or (len(self.mExrules) > 0)
- or (len(self.mRdates) > 0) or (len(self.mRperiods) > 0)):
- return False
-
- # Also, check the rule iteself
- elif len(self.mRrules) == 1:
- return self.mRrules.firstElement().isAdvancedRule()
- else:
- return True
-
-
- def getUIRecurrence(self):
- if len(self.mRrules) == 1:
- return self.mRrules[0]
- else:
- return None
-
-
- def getUIDescription(self):
- # Check for anything
- if not self.hasRecurrence():
- return "No Recurrence"
-
- # Look for a single RRULE and return its descriptor
- if ((len(self.mRrules) == 1) and (len(self.mExrules) == 0) and (len(self.mRdates) == 0)
- and (len(self.mExdates) == 0) and (len(self.mRperiods) == 0)
- and (len(self.mExperiods) == 0)):
- return self.mRrules.firstElement().getUIDescription()
-
- # Indicate some form of complex recurrence
- return "Multiple recurrence rules, dates or exclusions"
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrecurrencevaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/recurrencevalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/recurrencevalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/recurrencevalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,54 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import xmldefs
-from pycalendar.recurrence import PyCalendarRecurrence
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarRecurrenceValue(PyCalendarValue):
-
- def __init__(self, value=None):
- self.mValue = value if value is not None else PyCalendarRecurrence()
-
-
- def duplicate(self):
- return PyCalendarRecurrenceValue(self.mValue.duplicate())
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_RECUR
-
-
- def parse(self, data):
- self.mValue.parse(data)
-
-
- def generate(self, os):
- self.mValue.generate(os)
-
-
- def writeXML(self, node, namespace):
- self.mValue.writeXML(node, namespace)
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_RECUR, PyCalendarRecurrenceValue, xmldefs.value_recur)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrequeststatusvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/requeststatusvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/requeststatusvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/requeststatusvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,102 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2013 Cyrus Daboo. 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.
-##
-
-# iCalendar REQUEST-STATUS value
-
-from pycalendar import utils, xmldefs
-from pycalendar.parser import ParserContext
-from pycalendar.value import PyCalendarValue
-import xml.etree.cElementTree as XML
-
-class PyCalendarRequestStatusValue(PyCalendarValue):
- """
- The value is a list of strings (either 2 or 3 items)
- """
-
- def __init__(self, value=None):
- self.mValue = value if value is not None else ["2.0", "Success"]
-
-
- def __hash__(self):
- return hash(tuple(self.mValue))
-
-
- def duplicate(self):
- return PyCalendarRequestStatusValue(self.mValue[:])
-
-
- def getType(self):
- return PyCalendarValue.VALUETYPE_REQUEST_STATUS
-
-
- def parse(self, data):
-
- result = utils.parseTextList(data, always_list=True)
- if len(result) == 1:
- if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
- if ";" in result[0]:
- code, desc = result[0].split(";", 1)
- else:
- code = result[0]
- desc = ""
- rest = None
- else:
- raise ValueError
- elif len(result) == 2:
- code, desc = result
- rest = None
- elif len(result) == 3:
- code, desc, rest = result
- else:
- if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
- code, desc, rest = result[:3]
- else:
- raise ValueError
-
- if "\\" in code and ParserContext.INVALID_REQUEST_STATUS_VALUE in (ParserContext.PARSER_IGNORE, ParserContext.PARSER_FIX):
- code = code.replace("\\", "")
- elif ParserContext.INVALID_REQUEST_STATUS_VALUE == ParserContext.PARSER_RAISE:
- raise ValueError
-
- # Decoding required
- self.mValue = [code, desc, rest, ] if rest else [code, desc, ]
-
-
- # os - StringIO object
- def generate(self, os):
- utils.generateTextList(os, self.mValue if len(self.mValue) < 3 or self.mValue[2] else self.mValue[:2])
-
-
- def writeXML(self, node, namespace):
- code = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.req_status_code))
- code.text = self.mValue[0]
-
- description = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.req_status_description))
- description.text = self.mValue[1]
-
- if len(self.mValue) == 3 and self.mValue[2]:
- data = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.req_status_data))
- data.text = self.mValue[1]
-
-
- def getValue(self):
- return self.mValue
-
-
- def setValue(self, value):
- self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_REQUEST_STATUS, PyCalendarRequestStatusValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarstringutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/stringutils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/stringutils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/stringutils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendartests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_adrpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_adr.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_adr.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,50 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar.adr import Adr
-import unittest
-
-class TestAdrValue(unittest.TestCase):
-
- def testInit(self):
- data = (
- (
- ("pobox", "extended", "street", "locality", "region", "postalcode", "country"),
- "pobox;extended;street;locality;region;postalcode;country",
- ),
- (
- (("pobox",), ("extended",), ("street1", "street2",), "locality", "region", (), "country"),
- "pobox;extended;street1,street2;locality;region;;country",
- ),
- )
-
- for args, result in data:
- a = Adr(*args)
-
- self.assertEqual(
- a.getValue(),
- args,
- )
-
- self.assertEqual(
- a.getText(),
- result,
- )
-
- self.assertEqual(
- a.duplicate().getText(),
- result,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_adrvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,62 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar.adrvalue import AdrValue
-from pycalendar.vcard.property import Property
-import unittest
-
-class TestAdrValue(unittest.TestCase):
-
- def testParseValue(self):
-
- items = (
- ("", ";;;;;;"),
- (";", ";;;;;;"),
- (";;;;;;", ";;;;;;"),
- (";;123 Main Street;Any Town;CA;91921-1234", ";;123 Main Street;Any Town;CA;91921-1234;"),
- (";;;;;;USA", ";;;;;;USA"),
- ("POB1", "POB1;;;;;;"),
- (";EXT", ";EXT;;;;;"),
- (";;123 Main Street,The Cards;Any Town;CA;91921-1234", ";;123 Main Street,The Cards;Any Town;CA;91921-1234;"),
- (";;123 Main\, Street,The Cards;Any Town;CA;91921-1234", ";;123 Main\, Street,The Cards;Any Town;CA;91921-1234;"),
- (";;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234", ";;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234;"),
- )
-
- for item, result in items:
- req = AdrValue()
- req.parse(item)
- test = req.getText()
- self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
-
-
- def testParseProperty(self):
-
- items = (
- ("ADR:", "ADR:;;;;;;"),
- ("ADR:;", "ADR:;;;;;;"),
- ("ADR:;;;;;;", "ADR:;;;;;;"),
- ("ADR:;;123 Main Street;Any Town;CA;91921-1234", "ADR:;;123 Main Street;Any Town;CA;91921-1234;"),
- ("ADR:;;;;;;USA", "ADR:;;;;;;USA"),
- ("ADR:POB1", "ADR:POB1;;;;;;"),
- ("ADR:;EXT", "ADR:;EXT;;;;;"),
- ("ADR;VALUE=TEXT:;;123 Main Street;Any Town;CA;91921-1234", "ADR:;;123 Main Street;Any Town;CA;91921-1234;"),
- )
-
- for item, result in items:
- prop = Property()
- prop.parse(item)
- test = prop.getText()
- self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_calendarpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_calendar.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_calendar.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,854 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.exceptions import PyCalendarInvalidData
-from pycalendar.parser import ParserContext
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.property import PyCalendarProperty
-import cStringIO as StringIO
-import difflib
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
- data = (
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-X-WR-CALNAME:PayDay
-BEGIN:VTIMEZONE
-TZID:US/Eastern
-LAST-MODIFIED:20040110T032845Z
-BEGIN:DAYLIGHT
-DTSTART:20000404T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20001026T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:DC3D0301C7790B38631F1FBB@ninevah.local
-DTSTART;VALUE=DATE:20040227
-DTSTAMP:20050211T173501Z
-RRULE:FREQ=MONTHLY;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR;BYSETPOS=-1
-SUMMARY:PAY DAY
-BEGIN:VALARM
-ACTION:DISPLAY
-DESCRIPTION:Alarm for Organizer!
-TRIGGER;RELATED=START:-PT15M
-END:VALARM
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH:http://example.com/test.jpg
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH;ENCODING=BASE64;VALUE=BINARY:dGVzdA==
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Example Inc.//Example Calendar//EN
-BEGIN:VTIMEZONE
-TZID:America/Montreal
-LAST-MODIFIED:20040110T032845Z
-BEGIN:DAYLIGHT
-DTSTART:20000404T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20001026T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VAVAILABILITY
-UID:20061005T133225Z-00001-availability@example.com
-DTSTART;TZID=America/Montreal:20060101T000000
-DTEND;TZID=America/Montreal:20060108T000000
-DTSTAMP:20061005T133225Z
-ORGANIZER:mailto:bernard@example.com
-BEGIN:AVAILABLE
-UID:20061005T133225Z-00001-A-availability@example.com
-DTSTART;TZID=America/Montreal:20060102T090000
-DTEND;TZID=America/Montreal:20060102T120000
-DTSTAMP:20061005T133225Z
-RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
-SUMMARY:Monday\\, Wednesday and Friday from 9:00 to 12:00
-END:AVAILABLE
-BEGIN:AVAILABLE
-UID:20061005T133225Z-00001-A-availability@example.com
-RECURRENCE-ID;TZID=America/Montreal:20060106T090000
-DTSTART;TZID=America/Montreal:20060106T120000
-DTEND;TZID=America/Montreal:20060106T170000
-DTSTAMP:20061005T133225Z
-SUMMARY:Friday override from 12:00 to 17:00
-END:AVAILABLE
-END:VAVAILABILITY
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Example Inc.//Example Calendar//EN
-BEGIN:VTODO
-UID:event1@ninevah.local
-CREATED:20060101T150000Z
-DTSTAMP:20051222T205953Z
-SUMMARY:event 1
-END:VTODO
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:X-COMPONENT
-UID:1234
-END:X-COMPONENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Apple Inc.//iCal 4.0.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;BYDAY=1SU;BYMONTH=11
-TZNAME:PST
-TZOFFSETFROM:-0700
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:uid4
-DTSTART;TZID=US/Pacific:20100207T170000
-DTEND;TZID=US/Pacific:20100207T173000
-CREATED:20100203T013849Z
-DTSTAMP:20100203T013909Z
-SEQUENCE:3
-SUMMARY:New Event
-TRANSP:OPAQUE
-BEGIN:VALARM
-ACTION:AUDIO
-ATTACH:Basso
-TRIGGER:-PT20M
-X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1
-END:VALARM
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH:http://example.com/test.jpg
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-X-APPLE-STRUCTURED-LOCATION:geo:123.123,123.123
-X-Test:Some\, text.
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH:http://example.com/test.jpg
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123
-X-Test:Some\, text.
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-)
- data2 = (
- (
-"""BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-X-TEST:Testing
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-X-TEST:Testing
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- ),
-)
-
-
- def testRoundtrip(self):
-
-
- def _doRoundtrip(caldata, resultdata=None):
- test1 = resultdata if resultdata is not None else caldata
-
- cal = PyCalendar()
- cal.parse(StringIO.StringIO(caldata))
-
- s = StringIO.StringIO()
- cal.generate(s)
- test2 = s.getvalue()
-
- self.assertEqual(
- test1,
- test2,
- "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
- )
-
- for item in self.data:
- _doRoundtrip(item)
-
- for item1, item2 in self.data2:
- _doRoundtrip(item1, item2)
-
-
- def testRoundtripDuplicate(self):
-
-
- def _doDuplicateRoundtrip(caldata):
- cal = PyCalendar()
- cal.parse(StringIO.StringIO(caldata))
- cal = cal.duplicate()
-
- s = StringIO.StringIO()
- cal.generate(s)
- self.assertEqual(caldata, s.getvalue())
-
- for item in self.data:
- _doDuplicateRoundtrip(item)
-
-
- def testEquality(self):
-
-
- def _doEquality(caldata):
- cal1 = PyCalendar()
- cal1.parse(StringIO.StringIO(caldata))
-
- cal2 = PyCalendar()
- cal2.parse(StringIO.StringIO(caldata))
-
- self.assertEqual(cal1, cal2, "%s\n\n%s" % (cal1, cal2,))
-
-
- def _doNonEquality(caldata):
- cal1 = PyCalendar()
- cal1.parse(StringIO.StringIO(caldata))
-
- cal2 = PyCalendar()
- cal2.parse(StringIO.StringIO(caldata))
- cal2.addProperty(PyCalendarProperty("X-FOO", "BAR"))
-
- self.assertNotEqual(cal1, cal2)
-
- for item in self.data:
- _doEquality(item)
- _doNonEquality(item)
-
-
- def testParseComponent(self):
-
- data1 = """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n")
-
- data2 = """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Example Inc.//Example Calendar//EN
-BEGIN:VTIMEZONE
-TZID:America/Montreal
-LAST-MODIFIED:20040110T032845Z
-BEGIN:DAYLIGHT
-DTSTART:20000404T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20001026T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-END:VTIMEZONE
-END:VCALENDAR
-""".replace("\n", "\r\n")
-
- result = """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VTIMEZONE
-TZID:America/Montreal
-LAST-MODIFIED:20040110T032845Z
-BEGIN:DAYLIGHT
-DTSTART:20000404T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20001026T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n")
-
- cal = PyCalendar()
- cal.parse(StringIO.StringIO(data1))
- cal.parseComponent(StringIO.StringIO(data2))
- self.assertEqual(str(cal), result)
-
-
- def testParseFail(self):
-
- data = (
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCARD
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-VERSION:2.0
-END:VCARD
-""".replace("\n", "\r\n"),
-
-"""BOGUS
-BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BOGUS
-
-BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-BOGUS
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-
-BOGUS
-""".replace("\n", "\r\n"),
-
- )
-
- for item in data:
- self.assertRaises(PyCalendarInvalidData, PyCalendar.parseText, item)
-
-
- def testParseBlank(self):
-
- data = (
-"""
-BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""
-
-BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-
-
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-
-
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- )
-
- save = ParserContext.BLANK_LINES_IN_DATA
- for item in data:
- ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_RAISE
- self.assertRaises(PyCalendarInvalidData, PyCalendar.parseText, item)
-
- ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_IGNORE
- lines = item.split("\r\n")
- result = "\r\n".join([line for line in lines if line]) + "\r\n"
- self.assertEqual(str(PyCalendar.parseText(item)), result)
-
- ParserContext.BLANK_LINES_IN_DATA = save
-
-
- def testGetVEvents(self):
-
- data = (
- (
- "Non-recurring match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20110601
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (PyCalendarDateTime(2011, 6, 1),),
- ),
- (
- "Non-recurring no-match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20110501
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (),
- ),
- (
- "Recurring match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20110601
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (
- PyCalendarDateTime(2011, 6, 1),
- PyCalendarDateTime(2011, 6, 2),
- ),
- ),
- (
- "Recurring no match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20110501
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (),
- ),
- (
- "Recurring with override match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART:20110601T120000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-RECURRENCE-ID;VALUE=DATE:20110602T120000
-DTSTART;VALUE=DATE:20110602T130000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (
- PyCalendarDateTime(2011, 6, 1, 12, 0, 0),
- PyCalendarDateTime(2011, 6, 2, 13, 0, 0),
- ),
- ),
- (
- "Recurring with override no match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART:20110501T120000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-RECURRENCE-ID;VALUE=DATE:20110502T120000
-DTSTART;VALUE=DATE:20110502T130000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (),
- ),
- (
- "Recurring partial match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20110531
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (
- PyCalendarDateTime(2011, 6, 1),
- ),
- ),
- (
- "Recurring with override partial match",
- """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART:20110531T120000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-RECURRENCE-ID;VALUE=DATE:20110601T120000
-DTSTART;VALUE=DATE:20110601T130000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
- (
- PyCalendarDateTime(2011, 6, 1, 13, 0, 0),
- ),
- ),
- )
-
- for title, caldata, result in data:
- calendar = PyCalendar.parseText(caldata)
- instances = []
- calendar.getVEvents(
- PyCalendarPeriod(
- start=PyCalendarDateTime(2011, 6, 1),
- end=PyCalendarDateTime(2011, 7, 1),
- ),
- instances
- )
- instances = tuple([instance.getInstanceStart() for instance in instances])
- self.assertEqual(instances, result, "Failed in %s: got %s, expected %s" % (title, instances, result))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_componentrecurpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,66 +0,0 @@
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.calendar import PyCalendar
-import cStringIO as StringIO
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
- def testDuplicateWithRecurrenceChange(self):
-
- data = (
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;COUNT=400
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-)
-
- cal1 = PyCalendar()
- cal1.parse(StringIO.StringIO(data[0]))
- cal2 = cal1.duplicate()
- vevent = cal2.getComponents()[0]
- rrules = vevent.getRecurrenceSet()
- for rrule in rrules.getRules():
- rrule.setUseCount(True)
- rrule.setCount(400)
- rrules.changed()
-
- self.assertEqual(data[0], str(cal1))
- self.assertEqual(data[1], str(cal2))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_datetimepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_datetime.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_datetime.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_datetime.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,9 +14,9 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.timezone import Timezone
</ins><span class="cx"> import unittest
</span><span class="cx">
</span><span class="cx"> class TestDateTime(unittest.TestCase):
</span><span class="lines">@@ -25,16 +25,16 @@
</span><span class="cx">
</span><span class="cx"> items = (
</span><span class="cx"> (
</span><del>- PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
- PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+ DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+ DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx"> ),
</span><span class="cx"> (
</span><del>- PyCalendarDateTime(2011, 1, 1, 0, 0, 0),
- PyCalendarDateTime(2011, 1, 1, 0, 0, 0),
</del><ins>+ DateTime(2011, 1, 1, 0, 0, 0),
+ DateTime(2011, 1, 1, 0, 0, 0),
</ins><span class="cx"> ),
</span><span class="cx"> (
</span><del>- PyCalendarDateTime(2011, 1, 1),
- PyCalendarDateTime(2011, 1, 1),
</del><ins>+ DateTime(2011, 1, 1),
+ DateTime(2011, 1, 1),
</ins><span class="cx"> )
</span><span class="cx"> )
</span><span class="cx">
</span><span class="lines">@@ -47,13 +47,13 @@
</span><span class="cx">
</span><span class="cx"> s = set(
</span><span class="cx"> (
</span><del>- PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
- PyCalendarDateTime(2011, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+ DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+ DateTime(2011, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx"> )
</span><span class="cx"> )
</span><span class="cx">
</span><del>- self.assertTrue(PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)) in s)
- self.assertFalse(PyCalendarDateTime(2011, 1, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)) in s)
</del><ins>+ self.assertTrue(DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) in s)
+ self.assertFalse(DateTime(2011, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)) in s)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def testRoundtrip(self):
</span><span class="lines">@@ -85,11 +85,11 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item in data1:
</span><del>- dt = PyCalendarDateTime.parseText(item, False)
</del><ins>+ dt = DateTime.parseText(item, False)
</ins><span class="cx"> self.assertEqual(dt.getText(), item, "Failed on: %s" % (item,))
</span><span class="cx">
</span><span class="cx"> for item, result in data2:
</span><del>- dt = PyCalendarDateTime.parseText(item, True)
</del><ins>+ dt = DateTime.parseText(item, True)
</ins><span class="cx"> self.assertEqual(dt.getText(), result, "Failed on: %s" % (item,))
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -122,16 +122,16 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item in data1:
</span><del>- self.assertRaises(ValueError, PyCalendarDateTime.parseText, item, False)
</del><ins>+ self.assertRaises(ValueError, DateTime.parseText, item, False)
</ins><span class="cx">
</span><span class="cx"> for item in data2:
</span><del>- self.assertRaises(ValueError, PyCalendarDateTime.parseText, item, False)
</del><ins>+ self.assertRaises(ValueError, DateTime.parseText, item, False)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def testCachePreserveOnAdjustment(self):
</span><span class="cx">
</span><span class="cx"> # UTC first
</span><del>- dt = PyCalendarDateTime(2012, 6, 7, 12, 0, 0, PyCalendarTimezone(tzid="utc"))
</del><ins>+ dt = DateTime(2012, 6, 7, 12, 0, 0, Timezone(tzid="utc"))
</ins><span class="cx"> dt.getPosixTime()
</span><span class="cx">
</span><span class="cx"> # check existing cache is complete
</span><span class="lines">@@ -301,9 +301,9 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> """.replace("\n", "\r\n")
</span><span class="cx">
</span><del>- PyCalendar.parseText(tzdata)
</del><ins>+ Calendar.parseText(tzdata)
</ins><span class="cx">
</span><del>- dt = PyCalendarDateTime(2012, 6, 7, 12, 0, 0, PyCalendarTimezone(tzid="America/Pittsburgh"))
</del><ins>+ dt = DateTime(2012, 6, 7, 12, 0, 0, Timezone(tzid="America/Pittsburgh"))
</ins><span class="cx"> dt.getPosixTime()
</span><span class="cx">
</span><span class="cx"> # check existing cache is complete
</span><span class="lines">@@ -326,47 +326,47 @@
</span><span class="cx">
</span><span class="cx"> def testSetWeekNo(self):
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> dt.setWeekNo(1)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> dt.setWeekNo(2)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2013, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2013, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2013, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2013, 1, 8, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx"> dt.setWeekNo(1)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2014, 1, 7, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2014, 1, 7, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx"> dt.setWeekNo(1)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2013, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2013, 12, 31, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2012, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2012, 12, 31, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> dt.setWeekNo(1)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2012, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2012, 12, 31, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2016, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2016, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 53)
</span><span class="cx"> dt.setWeekNo(1)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2016, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> dt.setWeekNo(2)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2016, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2016, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+ dt = DateTime(2016, 1, 8, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> dt.setWeekNo(1)
</span><del>- self.assertEqual(dt, PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+ self.assertEqual(dt, DateTime(2016, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> self.assertEqual(dt.getWeekNo(), 1)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_durationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_duration.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_duration.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_duration.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,7 +15,7 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.duration import Duration
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> import unittest
</span><span class="cx">
</span><span class="lines">@@ -56,13 +56,13 @@
</span><span class="cx"> self.assertEqual(os.getvalue(), result)
</span><span class="cx">
</span><span class="cx"> for seconds, result in TestDuration.test_data:
</span><del>- _doTest(PyCalendarDuration(duration=seconds), result)
</del><ins>+ _doTest(Duration(duration=seconds), result)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def testParse(self):
</span><span class="cx">
</span><span class="cx"> for seconds, result in TestDuration.test_data:
</span><del>- duration = PyCalendarDuration().parseText(result)
</del><ins>+ duration = Duration().parseText(result)
</ins><span class="cx"> self.assertEqual(duration.getTotalSeconds(), seconds)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx"> "P12DT1SA",
</span><span class="cx"> )
</span><span class="cx"> for data in test_bad_data:
</span><del>- self.assertRaises(ValueError, PyCalendarDuration.parseText, data)
</del><ins>+ self.assertRaises(ValueError, Duration.parseText, data)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def testRelaxedBad(self):
</span><span class="lines">@@ -94,8 +94,8 @@
</span><span class="cx"> for text, seconds, result in test_relaxed_data:
</span><span class="cx">
</span><span class="cx"> ParserContext.INVALID_DURATION_VALUE = ParserContext.PARSER_FIX
</span><del>- self.assertEqual(PyCalendarDuration.parseText(text).getTotalSeconds(), seconds)
- self.assertEqual(PyCalendarDuration.parseText(text).getText(), result)
</del><ins>+ self.assertEqual(Duration.parseText(text).getTotalSeconds(), seconds)
+ self.assertEqual(Duration.parseText(text).getText(), result)
</ins><span class="cx">
</span><span class="cx"> ParserContext.INVALID_DURATION_VALUE = ParserContext.PARSER_RAISE
</span><del>- self.assertRaises(ValueError, PyCalendarDuration.parseText, text)
</del><ins>+ self.assertRaises(ValueError, Duration.parseText, text)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_i18npy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_i18n.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_i18n.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_i18n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,74 +0,0 @@
</span><del>-# coding: utf-8
-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.attribute import PyCalendarAttribute
-from pycalendar.calendar import PyCalendar
-import cStringIO as StringIO
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
- def testAddCN(self):
-
- data = (
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-ORGANIZER:user01@example.com
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
- "まだ",
-
-"""BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-ORGANIZER;CN=まだ:user01@example.com
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
- )
-
- cal1 = PyCalendar()
- cal1.parse(StringIO.StringIO(data[0]))
-
- vevent = cal1.getComponents("VEVENT")[0]
- organizer = vevent.getProperties("ORGANIZER")[0]
- organizer.addAttribute(PyCalendarAttribute("CN", data[1]))
-
- cal2 = PyCalendar()
- cal2.parse(StringIO.StringIO(data[2]))
-
- self.assertEqual(str(cal1), str(cal2))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_multivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,8 +15,8 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> import unittest
</span><del>-from pycalendar.multivalue import PyCalendarMultiValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.multivalue import MultiValue
+from pycalendar.value import Value
</ins><span class="cx">
</span><span class="cx"> class TestMultiValue(unittest.TestCase):
</span><span class="cx">
</span><span class="lines">@@ -29,8 +29,8 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item, result, count in items:
</span><del>- req = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_TEXT)
- req.parse(item)
</del><ins>+ req = MultiValue(Value.VALUETYPE_TEXT)
+ req.parse(item, "icalendar")
</ins><span class="cx"> test = req.getText()
</span><span class="cx"> self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
</span><span class="cx"> self.assertEqual(len(req.mValues), count, "Failed to parse and re-generate '%s'" % (item,))
</span><span class="lines">@@ -38,8 +38,8 @@
</span><span class="cx">
</span><span class="cx"> def testSetValue(self):
</span><span class="cx">
</span><del>- req = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_TEXT)
- req.parse("Example1, Example2")
</del><ins>+ req = MultiValue(Value.VALUETYPE_TEXT)
+ req.parse("Example1, Example2", "icalendar")
</ins><span class="cx"> req.setValue(("Example3", "Example4",))
</span><span class="cx"> test = req.getText()
</span><span class="cx"> self.assertEqual(test, "Example3,Example4")
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_npy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_n.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_n.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,92 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar.n import N
-import unittest
-
-class TestAdrValue(unittest.TestCase):
-
- def testInit(self):
-
- data = (
- (
- ("last", "first", "middle", "prefix", "suffix"),
- "last;first;middle;prefix;suffix",
- "prefix first middle last suffix",
- ),
- (
- ("last", ("first",), ("middle1", "middle2",), (), ("suffix",)),
- "last;first;middle1,middle2;;suffix",
- "first middle1 middle2 last suffix",
- ),
- )
-
- for args, result, fullName in data:
- n = N(*args)
-
- self.assertEqual(
- n.getValue(),
- args,
- )
-
- self.assertEqual(
- n.getText(),
- result,
- )
-
- self.assertEqual(
- n.getFullName(),
- fullName,
- )
-
- self.assertEqual(
- n.duplicate().getText(),
- result,
- )
-
-
- def testInitWithKeywords(self):
-
- data = (
- (
- {"first": "first", "last": "last", "middle": "middle", "prefix": "prefix", "suffix": "suffix"},
- "last;first;middle;prefix;suffix",
- "prefix first middle last suffix",
- ),
- (
- {"first": ("first",), "last": "last", "middle": ("middle1", "middle2",), "prefix": (), "suffix": ("suffix",)},
- "last;first;middle1,middle2;;suffix",
- "first middle1 middle2 last suffix",
- ),
- )
-
- for kwargs, result, fullName in data:
- n = N(**kwargs)
-
- self.assertEqual(
- n.getText(),
- result,
- )
-
- self.assertEqual(
- n.getFullName(),
- fullName,
- )
-
- self.assertEqual(
- n.duplicate().getText(),
- result,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_nvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,59 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar.nvalue import NValue
-from pycalendar.vcard.property import Property
-import unittest
-
-class TestNValue(unittest.TestCase):
-
- def testParseValue(self):
-
- items = (
- ("", ";;;;"),
- (";", ";;;;"),
- (";;;;", ";;;;"),
- ("Cyrus;Daboo;;Dr.", "Cyrus;Daboo;;Dr.;"),
- (";;;;PhD.", ";;;;PhD."),
- ("Cyrus", "Cyrus;;;;"),
- (";Daboo", ";Daboo;;;"),
- )
-
- for item, result in items:
- req = NValue()
- req.parse(item)
- test = req.getText()
- self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
-
-
- def testParseProperty(self):
-
- items = (
- ("N:", "N:;;;;"),
- ("N:;", "N:;;;;"),
- ("N:;;;;", "N:;;;;"),
- ("N:Cyrus;Daboo;;Dr.", "N:Cyrus;Daboo;;Dr.;"),
- ("N:;;;;PhD.", "N:;;;;PhD."),
- ("N:Cyrus", "N:Cyrus;;;;"),
- ("N:;Daboo", "N:;Daboo;;;"),
- ("N;VALUE=TEXT:Cyrus;Daboo;;Dr.", "N:Cyrus;Daboo;;Dr.;"),
- )
-
- for item, result in items:
- prop = Property()
- prop.parse(item)
- test = prop.getText()
- self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_orgvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,53 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar.orgvalue import OrgValue
-from pycalendar.vcard.property import Property
-import unittest
-
-class TestNValue(unittest.TestCase):
-
- def testParseValue(self):
-
- items = (
- ("", ""),
- ("Example", "Example"),
- ("Example\, Inc.", "Example\, Inc."),
- ("Example\; Inc;Dept. of Silly Walks", "Example\; Inc;Dept. of Silly Walks"),
- )
-
- for item, result in items:
- req = OrgValue()
- req.parse(item)
- test = req.getText()
- self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
-
-
- def testParseProperty(self):
-
- items = (
- ("ORG:", "ORG:"),
- ("ORG:Example", "ORG:Example"),
- ("ORG:Example\, Inc.", "ORG:Example\, Inc."),
- ("ORG:Example\; Inc;Dept. of Silly Walks", "ORG:Example\; Inc;Dept. of Silly Walks"),
- ("ORG;VALUE=TEXT:Example", "ORG:Example"),
- )
-
- for item, result in items:
- prop = Property()
- prop.parse(item)
- test = prop.getText()
- self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_propertypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,189 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2013 Cyrus Daboo. 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 pycalendar.attribute import PyCalendarAttribute
-from pycalendar.exceptions import PyCalendarInvalidProperty
-from pycalendar.parser import ParserContext
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
-import unittest
-
-class TestProperty(unittest.TestCase):
-
- test_data = (
- # Different value types
- "ATTACH;VALUE=BINARY:VGVzdA==",
- "attach;VALUE=BINARY:VGVzdA==",
- "ORGANIZER:mailto:jdoe@example.com",
- "DTSTART;TZID=US/Eastern:20060226T120000",
- "DTSTART;VALUE=DATE:20060226",
- "DTSTART:20060226T130000Z",
- "X-FOO:BAR",
- "DURATION:PT10M",
- "duraTION:PT10M",
- "SEQUENCE:1",
- "RDATE:20060226T120000Z,20060227T120000Z",
- "FREEBUSY:20060226T120000Z/20060227T120000Z",
- "SUMMARY:Some \\ntext",
- "RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1",
- "REQUEST-STATUS:2.0;Success",
- "URI:http://www.example.com",
- "TZOFFSETFROM:-0500",
- "X-Test:Some\, text.",
- "X-Test:Some:, text.",
- "X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123",
- "X-CALENDARSERVER-PRIVATE-COMMENT:This\\ntest\\nis\\, here.\\n",
-
- # Various parameters
- "DTSTART;TZID=\"Somewhere, else\":20060226T120000",
- "ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:jdoe@example.com",
- "X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-APPLE-ABUID=ab\\://Work;X-TITLE=\"10\\n XX S. XXX Dr.\\nSuite XXX\\nXX XX XXXXX\\nUnited States\":\"geo:11.111111,-11.111111\"",
-
- # Parameter escaping
- "ATTENDEE;CN=My ^'Test^' Name;ROLE=CHAIR:mailto:jdoe@example.com",
- )
-
-
- def testParseGenerate(self):
-
- for data in TestProperty.test_data:
- prop = PyCalendarProperty()
- prop.parse(data)
- propstr = str(prop).replace("\r\n ", "")
- self.assertEqual(propstr[:-2], data, "Failed parse/generate: %s to %s" % (data, propstr,))
-
-
- def testEquality(self):
-
- for data in TestProperty.test_data:
- prop1 = PyCalendarProperty()
- prop1.parse(data)
- prop2 = PyCalendarProperty()
- prop2.parse(data)
- self.assertEqual(prop1, prop2, "Failed equality: %s" % (data,))
-
-
- def testParseBad(self):
-
- test_bad_data = (
- "DTSTART;TZID=US/Eastern:abc",
- "DTSTART;VALUE=DATE:20060226T",
- "DTSTART:20060226T120000A",
- "X-FOO;:BAR",
- "DURATION:A",
- "SEQUENCE:b",
- "RDATE:20060226T120000Z;20060227T120000Z",
- "FREEBUSY:20060226T120000Z/ABC",
- "SUMMARY:Some \\qtext",
- "RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,VE;BYSETPOS=-1",
- "TZOFFSETFROM:-050",
- """ATTENDEE;CN="\\";CUTYPE=INDIVIDUAL;PARTSTAT=X-UNDELIVERABLE:invalid:nomai
- l""",
- )
- save = ParserContext.INVALID_ESCAPE_SEQUENCES
- for data in test_bad_data:
- ParserContext.INVALID_ESCAPE_SEQUENCES = ParserContext.PARSER_RAISE
- prop = PyCalendarProperty()
- self.assertRaises(PyCalendarInvalidProperty, prop.parse, data)
- ParserContext.INVALID_ESCAPE_SEQUENCES = save
-
-
- def testHash(self):
-
- hashes = []
- for item in TestProperty.test_data:
- prop = PyCalendarProperty()
- prop.parse(item)
- hashes.append(hash(prop))
- hashes.sort()
- for i in range(1, len(hashes)):
- self.assertNotEqual(hashes[i - 1], hashes[i])
-
-
- def testDefaultValueCreate(self):
-
- test_data = (
- ("ATTENDEE", "mailto:attendee@example.com", "ATTENDEE:mailto:attendee@example.com\r\n"),
- ("attendee", "mailto:attendee@example.com", "attendee:mailto:attendee@example.com\r\n"),
- ("ORGANIZER", "mailto:organizer@example.com", "ORGANIZER:mailto:organizer@example.com\r\n"),
- ("ORGANizer", "mailto:organizer@example.com", "ORGANizer:mailto:organizer@example.com\r\n"),
- ("URL", "http://example.com/tz1", "URL:http://example.com/tz1\r\n"),
- ("TZURL", "http://example.com/tz2", "TZURL:http://example.com/tz2\r\n"),
- )
- for propname, propvalue, result in test_data:
- prop = PyCalendarProperty(name=propname, value=propvalue)
- self.assertEqual(str(prop), result)
-
-
- def testGEOValueRoundtrip(self):
-
- data = "GEO:123.456,789.101"
- prop = PyCalendarProperty()
- prop.parse(data)
- self.assertEqual(str(prop), data + "\r\n")
-
-
- def testUnknownValueRoundtrip(self):
-
- data = "X-FOO:Text, not escaped"
- prop = PyCalendarProperty()
- prop.parse(data)
- self.assertEqual(str(prop), data + "\r\n")
-
- prop = PyCalendarProperty("X-FOO", "Text, not escaped")
- self.assertEqual(str(prop), data + "\r\n")
-
- data = "X-FOO:Text\\, escaped\\n"
- prop = PyCalendarProperty()
- prop.parse(data)
- self.assertEqual(str(prop), data + "\r\n")
-
- prop = PyCalendarProperty("X-FOO", "Text\\, escaped\\n")
- self.assertEqual(str(prop), data + "\r\n")
-
-
- def testNewRegistrationValueRoundtrip(self):
-
- PyCalendarProperty.registerDefaultValue("X-SPECIAL-REGISTRATION", PyCalendarValue.VALUETYPE_TEXT)
-
- data = "X-SPECIAL-REGISTRATION:Text\\, escaped\\n"
- prop = PyCalendarProperty()
- prop.parse(data)
- self.assertEqual(str(prop), "X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n")
-
- prop = PyCalendarProperty("X-SPECIAL-REGISTRATION", "Text, escaped\n")
- self.assertEqual(str(prop), "X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n")
-
-
- def testParameterEncodingDecoding(self):
-
- prop = PyCalendarProperty("X-FOO", "Test")
- prop.addAttribute(PyCalendarAttribute("X-BAR", "\"Check\""))
- self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^':Test\r\n")
-
- prop.addAttribute(PyCalendarAttribute("X-BAR2", "Check\nThis\tOut\n"))
- self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n")
-
- data = "X-FOO;X-BAR=^'Check^':Test"
- prop = PyCalendarProperty()
- prop.parse(data)
- self.assertEqual(prop.getAttributeValue("X-BAR"), "\"Check\"")
-
- data = "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test"
- prop = PyCalendarProperty()
- prop.parse(data)
- self.assertEqual(prop.getAttributeValue("X-BAR"), "\"Check\"")
- self.assertEqual(prop.getAttributeValue("X-BAR2"), "Check\nThis\tOut\n")
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_recurrencepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,161 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar.datetime import PyCalendarDateTime
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.recurrence import PyCalendarRecurrence
-import unittest
-
-class TestRecurrence(unittest.TestCase):
-
- items = (
- "FREQ=DAILY",
- "FREQ=YEARLY;COUNT=400",
- "FREQ=MONTHLY;UNTIL=20110102",
- "FREQ=MONTHLY;UNTIL=20110102T090000",
- "FREQ=MONTHLY;UNTIL=20110102T100000Z",
- "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1",
-
- # These are from RFC5545 examples
- "FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
- "FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4",
- "FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4",
- "FREQ=YEARLY;BYDAY=2SU;BYMONTH=3",
- "FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10",
- "FREQ=DAILY;INTERVAL=2",
- "FREQ=DAILY;COUNT=5;INTERVAL=10",
- "FREQ=DAILY;UNTIL=20000131T140000Z;BYMONTH=1",
- "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
- "FREQ=WEEKLY;UNTIL=19971007T000000Z;BYDAY=TU,TH;WKST=SU",
- "FREQ=WEEKLY;COUNT=10;BYDAY=TU,TH;WKST=SU",
- "FREQ=WEEKLY;UNTIL=19971224T000000Z;INTERVAL=2;BYDAY=MO,WE,FR;WKST=SU",
- "FREQ=WEEKLY;COUNT=8;INTERVAL=2;BYDAY=TU,TH;WKST=SU",
- "FREQ=MONTHLY;BYMONTHDAY=-3",
- "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1",
- "FREQ=MONTHLY;COUNT=10;INTERVAL=18;BYMONTHDAY=10,11,12,13,14,15",
- "FREQ=YEARLY;COUNT=10;INTERVAL=3;BYYEARDAY=1,100,200",
- "FREQ=YEARLY;BYDAY=MO;BYWEEKNO=20",
- "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3",
- "FREQ=DAILY;BYMINUTE=0,20,40;BYHOUR=9,10,11,12,13,14,15,16",
- )
-
-
- def testParse(self):
-
- for item in TestRecurrence.items:
- recur = PyCalendarRecurrence()
- recur.parse(item)
- self.assertEqual(recur.getText(), item, "Failed to parse and re-generate '%s'" % (item,))
-
-
- def testParseInvalid(self):
-
- items = (
- "",
- "FREQ=",
- "FREQ=MICROSECONDLY",
- "FREQ=YEARLY;COUNT=ABC",
- "FREQ=YEARLY;COUNT=123;UNTIL=20110102",
- "FREQ=MONTHLY;UNTIL=20110102T",
- "FREQ=MONTHLY;UNTIL=20110102t090000",
- "FREQ=MONTHLY;UNTIL=20110102T100000z",
- "FREQ=MONTHLY;UNTIL=20110102TAABBCCz",
- "FREQ=MONTHLY;BYDAY=A",
- "FREQ=MONTHLY;BYDAY=+1,3MO",
- "FREQ=MONTHLY;BYHOUR=A",
- "FREQ=MONTHLY;BYHOUR=54",
- )
-
- for item in items:
- self.assertRaises(ValueError, PyCalendarRecurrence().parse, item)
-
-
- def testEquality(self):
-
- recur1 = PyCalendarRecurrence()
- recur1.parse("FREQ=YEARLY;COUNT=400")
- recur2 = PyCalendarRecurrence()
- recur2.parse("COUNT=400;FREQ=YEARLY")
-
- self.assertEqual(recur1, recur2)
-
-
- def testInequality(self):
-
- recur1 = PyCalendarRecurrence()
- recur1.parse("FREQ=YEARLY;COUNT=400")
- recur2 = PyCalendarRecurrence()
- recur2.parse("COUNT=400;FREQ=YEARLY;BYMONTH=1")
-
- self.assertNotEqual(recur1, recur2)
-
-
- def testHash(self):
-
- hashes = []
- for item in TestRecurrence.items:
- recur = PyCalendarRecurrence()
- recur.parse(item)
- hashes.append(hash(recur))
- hashes.sort()
- for i in range(1, len(hashes)):
- self.assertNotEqual(hashes[i - 1], hashes[i])
-
-
- def testByWeekNoExpand(self):
-
- recur = PyCalendarRecurrence()
- recur.parse("FREQ=YEARLY;BYWEEKNO=1,2")
- start = PyCalendarDateTime(2013, 1, 1, 0, 0, 0)
- end = PyCalendarDateTime(2017, 1, 1, 0, 0, 0)
- items = []
- range = PyCalendarPeriod(start, end)
- recur.expand(start, range, items)
- self.assertEqual(
- items,
- [
- PyCalendarDateTime(2013, 1, 1, 0, 0, 0),
- PyCalendarDateTime(2013, 1, 8, 0, 0, 0),
- PyCalendarDateTime(2014, 1, 1, 0, 0, 0),
- PyCalendarDateTime(2014, 1, 8, 0, 0, 0),
- PyCalendarDateTime(2015, 1, 1, 0, 0, 0),
- PyCalendarDateTime(2015, 1, 8, 0, 0, 0),
- PyCalendarDateTime(2016, 1, 8, 0, 0, 0),
- PyCalendarDateTime(2016, 1, 15, 0, 0, 0),
- ],
- )
- print items
-
-
- def testClearOnChange(self):
-
- recur = PyCalendarRecurrence()
- recur.parse("FREQ=DAILY")
-
- start = PyCalendarDateTime(2013, 1, 1, 0, 0, 0)
- end = PyCalendarDateTime(2017, 1, 1, 0, 0, 0)
- range = PyCalendarPeriod(start, end)
- items = []
- recur.expand(start, range, items)
- self.assertTrue(recur.mCached)
- self.assertTrue(len(items) > 100)
-
- recur.setUseCount(True)
- recur.setCount(10)
- self.assertFalse(recur.mCached)
- items = []
- recur.expand(start, range, items)
- self.assertEqual(len(items), 10)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_requeststatuspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,95 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.parser import ParserContext
-from pycalendar.property import PyCalendarProperty
-from pycalendar.requeststatusvalue import PyCalendarRequestStatusValue
-import unittest
-
-class TestRequestStatus(unittest.TestCase):
-
- def testParseValue(self):
-
- items = (
- "2.0;Success",
- "2.0;Success\;here",
- "2.0;Success;Extra",
- "2.0;Success\;here;Extra",
- "2.0;Success;Extra\;here",
- "2.0;Success\;here;Extra\;here too",
- )
-
- for item in items:
- req = PyCalendarRequestStatusValue()
- req.parse(item)
- self.assertEqual(req.getText(), item, "Failed to parse and re-generate '%s'" % (item,))
-
-
- def testBadValue(self):
-
- bad_value = "2.0\;Success"
- ok_value = "2.0;Success"
-
- # Fix the value
- oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
- ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
- req = PyCalendarRequestStatusValue()
- req.parse(bad_value)
- self.assertEqual(req.getText(), ok_value, "Failed to parse and re-generate '%s'" % (bad_value,))
-
- # Raise the value
- ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
- req = PyCalendarRequestStatusValue()
- self.assertRaises(ValueError, req.parse, bad_value)
-
- ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
-
-
- def testTruncatedValue(self):
-
- bad_value = "2.0"
- ok_value = "2.0;"
-
- # Fix the value
- oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
- ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
- req = PyCalendarRequestStatusValue()
- req.parse(bad_value)
- self.assertEqual(req.getText(), ok_value, "Failed to parse and re-generate '%s'" % (bad_value,))
-
- # Raise the value
- ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
- req = PyCalendarRequestStatusValue()
- self.assertRaises(ValueError, req.parse, bad_value)
-
- ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
-
-
- def testParseProperty(self):
-
- items = (
- "REQUEST-STATUS:2.0;Success",
- "REQUEST-STATUS:2.0;Success\;here",
- "REQUEST-STATUS:2.0;Success;Extra",
- "REQUEST-STATUS:2.0;Success\;here;Extra",
- "REQUEST-STATUS:2.0;Success;Extra\;here",
- "REQUEST-STATUS:2.0;Success\;here;Extra\;here too",
- )
-
- for item in items:
- req = PyCalendarProperty()
- req.parse(item)
- self.assertEqual(req.getText(), item + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_timezonepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_timezone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_timezone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_timezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,235 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
- def testOffsets(self):
-
- data = (
- ("""BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-PRODID:-//calendarserver.org//Zonal//EN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:America/New_York
-X-LIC-LOCATION:America/New_York
-BEGIN:STANDARD
-DTSTART:18831118T120358
-RDATE:18831118T120358
-TZNAME:EST
-TZOFFSETFROM:-045602
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19180331T020000
-RRULE:FREQ=YEARLY;UNTIL=19190330T070000Z;BYDAY=-1SU;BYMONTH=3
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19181027T020000
-RRULE:FREQ=YEARLY;UNTIL=19191026T060000Z;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:STANDARD
-DTSTART:19200101T000000
-RDATE:19200101T000000
-RDATE:19420101T000000
-RDATE:19460101T000000
-RDATE:19670101T000000
-TZNAME:EST
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19200328T020000
-RDATE:19200328T020000
-RDATE:19740106T020000
-RDATE:19750223T020000
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19201031T020000
-RDATE:19201031T020000
-RDATE:19450930T020000
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19210424T020000
-RRULE:FREQ=YEARLY;UNTIL=19410427T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19210925T020000
-RRULE:FREQ=YEARLY;UNTIL=19410928T060000Z;BYDAY=-1SU;BYMONTH=9
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19420209T020000
-RDATE:19420209T020000
-TZNAME:EWT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:19450814T190000
-RDATE:19450814T190000
-TZNAME:EPT
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:19460428T020000
-RRULE:FREQ=YEARLY;UNTIL=19660424T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19460929T020000
-RRULE:FREQ=YEARLY;UNTIL=19540926T060000Z;BYDAY=-1SU;BYMONTH=9
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:STANDARD
-DTSTART:19551030T020000
-RRULE:FREQ=YEARLY;UNTIL=19661030T060000Z;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19670430T020000
-RRULE:FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19671029T020000
-RRULE:FREQ=YEARLY;UNTIL=20061029T060000Z;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19760425T020000
-RRULE:FREQ=YEARLY;UNTIL=19860427T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:19870405T020000
-RRULE:FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-END:VTIMEZONE
-END:VCALENDAR
-""",
- (
- (PyCalendarDateTime(1942, 2, 8), -5),
- (PyCalendarDateTime(1942, 2, 10), -4),
- (PyCalendarDateTime(2011, 1, 1), -5),
- (PyCalendarDateTime(2011, 4, 1), -4),
- (PyCalendarDateTime(2011, 10, 24), -4),
- (PyCalendarDateTime(2011, 11, 8), -5),
- (PyCalendarDateTime(2006, 1, 1), -5),
- (PyCalendarDateTime(2006, 4, 1), -5),
- (PyCalendarDateTime(2006, 5, 1), -4),
- (PyCalendarDateTime(2006, 10, 1), -4),
- (PyCalendarDateTime(2006, 10, 24), -4),
- (PyCalendarDateTime(2006, 11, 8), -5),
- )
- ),
- ("""BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-PRODID:-//calendarserver.org//Zonal//EN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:Etc/GMT+8
-X-LIC-LOCATION:Etc/GMT+8
-BEGIN:STANDARD
-DTSTART:18000101T000000
-RDATE:18000101T000000
-TZNAME:GMT+8
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-END:VCALENDAR
-""",
- (
- (PyCalendarDateTime(1942, 2, 8), -8),
- (PyCalendarDateTime(1942, 2, 10), -8),
- (PyCalendarDateTime(2011, 1, 1), -8),
- (PyCalendarDateTime(2011, 4, 1), -8),
- )
- ),
- )
-
- for tzdata, offsets in data:
-
- cal = PyCalendar.parseText(tzdata.replace("\n", "\r\n"))
- tz = cal.getComponents()[0]
-
- for dt, offset in offsets:
- tzoffset = tz.getTimezoneOffsetSeconds(dt)
- self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s with caching" % (tz.getID(), dt,))
- for dt, offset in reversed(offsets):
- tzoffset = tz.getTimezoneOffsetSeconds(dt)
- self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s with caching, reversed" % (tz.getID(), dt,))
-
- for dt, offset in offsets:
- tz.mCachedExpandAllMax = None
- tzoffset = tz.getTimezoneOffsetSeconds(dt)
- self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s without caching" % (tz.getID(), dt,))
- for dt, offset in reversed(offsets):
- tz.mCachedExpandAllMax = None
- tzoffset = tz.getTimezoneOffsetSeconds(dt)
- self.assertEqual(tzoffset, offset * 60 * 60, "Failed to match offset for %s at %s without caching, reversed" % (tz.getID(), dt,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_urivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2012-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,11 +15,11 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> from pycalendar.parser import ParserContext
</span><del>-from pycalendar.urivalue import PyCalendarURIValue
-from pycalendar.vcard.property import Property
</del><ins>+from pycalendar.urivalue import URIValue
+from pycalendar.icalendar.property import Property
</ins><span class="cx"> import unittest
</span><span class="cx">
</span><del>-class TestNValue(unittest.TestCase):
</del><ins>+class TestURIValue(unittest.TestCase):
</ins><span class="cx">
</span><span class="cx"> def testParseValue(self):
</span><span class="cx">
</span><span class="lines">@@ -35,8 +35,8 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item, result in items:
</span><del>- req = PyCalendarURIValue()
- req.parse(item)
</del><ins>+ req = URIValue()
+ req.parse(item, "icalendar")
</ins><span class="cx"> test = req.getText()
</span><span class="cx"> self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
</span><span class="cx">
</span><span class="lines">@@ -48,8 +48,8 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item, result in items:
</span><del>- req = PyCalendarURIValue()
- req.parse(item)
</del><ins>+ req = URIValue()
+ req.parse(item, "icalendar")
</ins><span class="cx"> test = req.getText()
</span><span class="cx"> self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
</span><span class="cx">
</span><span class="lines">@@ -68,8 +68,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item, result in items:
</span><del>- prop = Property()
- prop.parse(item)
</del><ins>+ prop = Property.parseText(item)
</ins><span class="cx"> test = prop.getText()
</span><span class="cx"> self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</span><span class="cx">
</span><span class="lines">@@ -81,7 +80,6 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item, result in items:
</span><del>- prop = Property()
- prop.parse(item)
</del><ins>+ prop = Property.parseText(item)
</ins><span class="cx"> test = prop.getText()
</span><span class="cx"> self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_utilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_utils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_utils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_utils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2012-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_validationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.property import PyCalendarProperty
</del><ins>+from pycalendar.icalendar.property import Property
</ins><span class="cx"> from pycalendar.validation import partial, PropertyValueChecks
</span><span class="cx"> import unittest
</span><span class="cx">
</span><span class="lines">@@ -40,8 +40,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for prop, test, result in props:
</span><del>- property = PyCalendarProperty()
- property.parse(prop)
</del><ins>+ property = Property.parseText(prop)
</ins><span class="cx"> self.assertEqual(PropertyValueChecks.stringValue(test, property), result)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -55,8 +54,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for prop, result in props:
</span><del>- property = PyCalendarProperty()
- property.parse(prop)
</del><ins>+ property = Property.parseText(prop)
</ins><span class="cx"> self.assertEqual(PropertyValueChecks.alwaysUTC(property), result)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -72,8 +70,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for prop, low, high, result in props:
</span><del>- property = PyCalendarProperty()
- property.parse(prop)
</del><ins>+ property = Property.parseText(prop)
</ins><span class="cx"> self.assertEqual(PropertyValueChecks.numericRange(low, high, property), result)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -87,6 +84,5 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for prop, result in props:
</span><del>- property = PyCalendarProperty()
- property.parse(prop)
</del><ins>+ property = Property.parseText(prop)
</ins><span class="cx"> self.assertEqual(PropertyValueChecks.positiveIntegerOrZero(property), result)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_xmlpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_xml.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_xml.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_xml.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,104 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar.calendar import PyCalendar
-import cStringIO as StringIO
-import difflib
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
- data = (
- (
-"""BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-X-TEST:Testing
-END:VCALENDAR
-""".replace("\n", "\r\n"),
-
-"""<?xml version="1.0" encoding="utf-8"?>
-<ns0:icalendar xmlns:ns0="urn:ietf:params:xml:ns:icalendar-2.0">
- <ns0:vcalendar>
- <ns0:properties>
- <ns0:version>
- <ns0:text>2.0</ns0:text>
- </ns0:version>
- <ns0:prodid>
- <ns0:text>-//mulberrymail.com//Mulberry v4.0//EN</ns0:text>
- </ns0:prodid>
- <ns0:x-test>
- <ns0:unknown>Testing</ns0:unknown>
- </ns0:x-test>
- </ns0:properties>
- <ns0:components>
- <ns0:vevent>
- <ns0:properties>
- <ns0:uid>
- <ns0:text>12345-67890-3</ns0:text>
- </ns0:uid>
- <ns0:dtstart>
- <ns0:date-time>2007-11-14T00:00:00Z</ns0:date-time>
- </ns0:dtstart>
- <ns0:attendee>
- <ns0:cal-address>mailto:user2@example.com</ns0:cal-address>
- </ns0:attendee>
- <ns0:exdate>
- <ns0:date-time>2008-11-14T00:00:00Z</ns0:date-time>
- </ns0:exdate>
- <ns0:organizer>
- <ns0:cal-address>mailto:user1@example.com</ns0:cal-address>
- </ns0:organizer>
- <ns0:rrule>
- <ns0:recur>
- <ns0:freq>YEARLY</ns0:freq>
- </ns0:recur>
- </ns0:rrule>
- </ns0:properties>
- </ns0:vevent>
- </ns0:components>
- </ns0:vcalendar>
-</ns0:icalendar>
-""",
- ),
-)
-
- def testGenerateXML(self):
-
- def _doRoundtrip(caldata, resultdata=None):
- test1 = resultdata if resultdata is not None else caldata
-
- cal = PyCalendar()
- cal.parse(StringIO.StringIO(caldata))
-
- test2 = cal.getTextXML()
-
- self.assertEqual(
- test1,
- test2,
- "\n".join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
- )
-
- for item1, item2 in self.data:
- _doRoundtrip(item1, item2)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendartextvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/textvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/textvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/textvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,17 +16,17 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx">
</span><del>-from pycalendar import utils, xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import utils, xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarTextValue(PyCalendarPlainTextValue):
</del><ins>+class TextValue(PlainTextValue):
</ins><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarValue.VALUETYPE_TEXT
</del><ins>+ return Value.VALUETYPE_TEXT
</ins><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, variant):
</ins><span class="cx"> # Decoding required
</span><span class="cx"> self.mValue = utils.decodeTextValue(data)
</span><span class="cx">
</span><span class="lines">@@ -39,4 +39,4 @@
</span><span class="cx"> except:
</span><span class="cx"> pass
</span><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_TEXT, PyCalendarTextValue, xmldefs.value_text)
</del><ins>+Value.registerType(Value.VALUETYPE_TEXT, TextValue, xmldefinitions.value_text)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendartimezonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/timezone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/timezone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/timezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,9 +15,9 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> from pycalendar import stringutils
</span><del>-from pycalendar.timezonedb import PyCalendarTimezoneDatabase
</del><ins>+from pycalendar.timezonedb import TimezoneDatabase
</ins><span class="cx">
</span><del>-class PyCalendarTimezone(object):
</del><ins>+class Timezone(object):
</ins><span class="cx"> """
</span><span class="cx"> Wrapper around a timezone specification. There are three options:
</span><span class="cx">
</span><span class="lines">@@ -41,13 +41,13 @@
</span><span class="cx"> self.mTimezone = None
</span><span class="cx">
</span><span class="cx"> # Copy default timezone if it exists
</span><del>- if PyCalendarTimezone.sDefaultTimezone is not None:
- self.mUTC = PyCalendarTimezone.sDefaultTimezone.mUTC
- self.mTimezone = PyCalendarTimezone.sDefaultTimezone.mTimezone
</del><ins>+ if Timezone.sDefaultTimezone is not None:
+ self.mUTC = Timezone.sDefaultTimezone.mUTC
+ self.mTimezone = Timezone.sDefaultTimezone.mTimezone
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- return PyCalendarTimezone(self.mUTC, self.mTimezone)
</del><ins>+ return Timezone(self.mUTC, self.mTimezone)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def equals(self, comp):
</span><span class="lines">@@ -63,7 +63,7 @@
</span><span class="cx"> @staticmethod
</span><span class="cx"> def same(utc1, tzid1, utc2, tzid2):
</span><span class="cx"> # Always match if any one of them is 'floating'
</span><del>- if PyCalendarTimezone.is_float(utc1, tzid1) or PyCalendarTimezone.is_float(utc2, tzid2):
</del><ins>+ if Timezone.is_float(utc1, tzid1) or Timezone.is_float(utc2, tzid2):
</ins><span class="cx"> return True
</span><span class="cx"> elif utc1 != utc2:
</span><span class="cx"> return False
</span><span class="lines">@@ -104,19 +104,19 @@
</span><span class="cx"> if self.mUTC:
</span><span class="cx"> return 0
</span><span class="cx"> elif self.mTimezone is None:
</span><del>- return PyCalendarTimezoneDatabase.getTimezoneOffsetSeconds(PyCalendarTimezone.sDefaultTimezone.getTimezoneID(), dt)
</del><ins>+ return TimezoneDatabase.getTimezoneOffsetSeconds(Timezone.sDefaultTimezone.getTimezoneID(), dt)
</ins><span class="cx"> elif isinstance(self.mTimezone, int):
</span><span class="cx"> return self.mTimezone
</span><span class="cx"> else:
</span><span class="cx"> # Look up timezone and resolve date using default timezones
</span><del>- return PyCalendarTimezoneDatabase.getTimezoneOffsetSeconds(self.mTimezone, dt)
</del><ins>+ return TimezoneDatabase.getTimezoneOffsetSeconds(self.mTimezone, dt)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def timeZoneDescriptor(self, dt):
</span><span class="cx"> if self.mUTC:
</span><span class="cx"> return "(UTC)"
</span><span class="cx"> elif self.mTimezone is None:
</span><del>- return PyCalendarTimezoneDatabase.getTimezoneDescriptor(PyCalendarTimezone.sDefaultTimezone.getTimezoneID(), dt)
</del><ins>+ return TimezoneDatabase.getTimezoneDescriptor(Timezone.sDefaultTimezone.getTimezoneID(), dt)
</ins><span class="cx"> elif isinstance(self.mTimezone, int):
</span><span class="cx"> sign = "-" if self.mTimezone < 0 else "+"
</span><span class="cx"> hours = abs(self.mTimezone) / 3600
</span><span class="lines">@@ -124,6 +124,6 @@
</span><span class="cx"> return "%s%02d%02d" % (sign, hours, minutes,)
</span><span class="cx"> else:
</span><span class="cx"> # Look up timezone and resolve date using default timezones
</span><del>- return PyCalendarTimezoneDatabase.getTimezoneDescriptor(self.mTimezone, dt)
</del><ins>+ return TimezoneDatabase.getTimezoneDescriptor(self.mTimezone, dt)
</ins><span class="cx">
</span><del>-PyCalendarTimezone.sDefaultTimezone = PyCalendarTimezone()
</del><ins>+Timezone.sDefaultTimezone = Timezone()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendartimezonedbpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/timezonedb.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/timezonedb.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/timezonedb.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,11 +14,11 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.exceptions import PyCalendarNoTimezoneInDatabase, \
- PyCalendarInvalidData
</del><ins>+from pycalendar.exceptions import NoTimezoneInDatabase, \
+ InvalidData
</ins><span class="cx"> import os
</span><span class="cx">
</span><del>-class PyCalendarTimezoneDatabase(object):
</del><ins>+class TimezoneDatabase(object):
</ins><span class="cx"> """
</span><span class="cx"> On demand timezone database cache. This scans a TZdb directory for .ics files matching a
</span><span class="cx"> TZID and caches the component data in a calendar from whence the actual component is returned.
</span><span class="lines">@@ -29,20 +29,20 @@
</span><span class="cx">
</span><span class="cx"> @staticmethod
</span><span class="cx"> def createTimezoneDatabase(dbpath):
</span><del>- PyCalendarTimezoneDatabase.sTimezoneDatabase = PyCalendarTimezoneDatabase()
- PyCalendarTimezoneDatabase.sTimezoneDatabase.setPath(dbpath)
</del><ins>+ TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
+ TimezoneDatabase.sTimezoneDatabase.setPath(dbpath)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @staticmethod
</span><span class="cx"> def clearTimezoneDatabase():
</span><del>- if PyCalendarTimezoneDatabase.sTimezoneDatabase is not None:
- PyCalendarTimezoneDatabase.sTimezoneDatabase.clear()
</del><ins>+ if TimezoneDatabase.sTimezoneDatabase is not None:
+ TimezoneDatabase.sTimezoneDatabase.clear()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __init__(self):
</span><del>- from pycalendar.calendar import PyCalendar
</del><ins>+ from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> self.dbpath = None
</span><del>- self.calendar = PyCalendar()
</del><ins>+ self.calendar = Calendar()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def setPath(self, dbpath):
</span><span class="lines">@@ -50,27 +50,27 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def clear(self):
</span><del>- from pycalendar.calendar import PyCalendar
- self.calendar = PyCalendar()
</del><ins>+ from pycalendar.icalendar.calendar import Calendar
+ self.calendar = Calendar()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @staticmethod
</span><span class="cx"> def getTimezoneDatabase():
</span><del>- if PyCalendarTimezoneDatabase.sTimezoneDatabase is None:
- PyCalendarTimezoneDatabase.sTimezoneDatabase = PyCalendarTimezoneDatabase()
- return PyCalendarTimezoneDatabase.sTimezoneDatabase
</del><ins>+ if TimezoneDatabase.sTimezoneDatabase is None:
+ TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
+ return TimezoneDatabase.sTimezoneDatabase
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @staticmethod
</span><span class="cx"> def getTimezone(tzid):
</span><span class="cx">
</span><span class="cx"> # Check whether current cached
</span><del>- tzdb = PyCalendarTimezoneDatabase.getTimezoneDatabase()
</del><ins>+ tzdb = TimezoneDatabase.getTimezoneDatabase()
</ins><span class="cx"> tz = tzdb.calendar.getTimezone(tzid)
</span><span class="cx"> if tz is None:
</span><span class="cx"> try:
</span><span class="cx"> tzdb.cacheTimezone(tzid)
</span><del>- except PyCalendarNoTimezoneInDatabase:
</del><ins>+ except NoTimezoneInDatabase:
</ins><span class="cx"> pass
</span><span class="cx"> tz = tzdb.calendar.getTimezone(tzid)
</span><span class="cx">
</span><span class="lines">@@ -83,10 +83,10 @@
</span><span class="cx"> Return a VTIMEZONE inside a valid VCALENDAR
</span><span class="cx"> """
</span><span class="cx">
</span><del>- tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
</del><ins>+ tz = TimezoneDatabase.getTimezone(tzid)
</ins><span class="cx"> if tz is not None:
</span><del>- from pycalendar.calendar import PyCalendar
- cal = PyCalendar()
</del><ins>+ from pycalendar.icalendar.calendar import Calendar
+ cal = Calendar()
</ins><span class="cx"> cal.addComponent(tz.duplicate(cal))
</span><span class="cx"> return cal
</span><span class="cx"> else:
</span><span class="lines">@@ -96,7 +96,7 @@
</span><span class="cx"> @staticmethod
</span><span class="cx"> def getTimezoneOffsetSeconds(tzid, dt):
</span><span class="cx"> # Cache it first
</span><del>- tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
</del><ins>+ tz = TimezoneDatabase.getTimezone(tzid)
</ins><span class="cx"> if tz is not None:
</span><span class="cx"> return tz.getTimezoneOffsetSeconds(dt)
</span><span class="cx"> else:
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx"> @staticmethod
</span><span class="cx"> def getTimezoneDescriptor(tzid, dt):
</span><span class="cx"> # Cache it first
</span><del>- tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
</del><ins>+ tz = TimezoneDatabase.getTimezone(tzid)
</ins><span class="cx"> if tz is not None:
</span><span class="cx"> return tz.getTimezoneDescriptor(dt)
</span><span class="cx"> else:
</span><span class="lines">@@ -123,10 +123,10 @@
</span><span class="cx"> if tzpath.startswith(self.dbpath) and os.path.isfile(tzpath):
</span><span class="cx"> try:
</span><span class="cx"> self.calendar.parseComponent(open(tzpath))
</span><del>- except (IOError, PyCalendarInvalidData):
- raise PyCalendarNoTimezoneInDatabase(self.dbpath, tzid)
</del><ins>+ except (IOError, InvalidData):
+ raise NoTimezoneInDatabase(self.dbpath, tzid)
</ins><span class="cx"> else:
</span><del>- raise PyCalendarNoTimezoneInDatabase(self.dbpath, tzid)
</del><ins>+ raise NoTimezoneInDatabase(self.dbpath, tzid)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def addTimezone(self, tz):
</span><span class="lines">@@ -140,7 +140,7 @@
</span><span class="cx"> Merge each timezone from other calendar.
</span><span class="cx"> """
</span><span class="cx">
</span><del>- tzdb = PyCalendarTimezoneDatabase.getTimezoneDatabase()
</del><ins>+ tzdb = TimezoneDatabase.getTimezoneDatabase()
</ins><span class="cx">
</span><span class="cx"> # Not if our own calendar
</span><span class="cx"> if cal is tzdb.calendar:
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarunknownvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/unknownvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/unknownvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/unknownvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,13 +16,13 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar Unknown value - one whose default type we don't know about
</span><span class="cx">
</span><del>-from pycalendar import xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarUnknownValue(PyCalendarPlainTextValue):
</del><ins>+class UnknownValue(PlainTextValue):
</ins><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarUnknownValue.VALUETYPE_UNKNOWN
</del><ins>+ return UnknownValue.VALUETYPE_UNKNOWN
</ins><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_UNKNOWN, PyCalendarUnknownValue, xmldefs.value_unknown)
</del><ins>+Value.registerType(Value.VALUETYPE_UNKNOWN, UnknownValue, xmldefinitions.value_unknown)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarurivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/urivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/urivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/urivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -16,18 +16,18 @@
</span><span class="cx">
</span><span class="cx"> # iCalendar URI value
</span><span class="cx">
</span><del>-from pycalendar import xmldefs, utils
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions, utils
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx">
</span><del>-class PyCalendarURIValue(PyCalendarPlainTextValue):
</del><ins>+class URIValue(PlainTextValue):
</ins><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarURIValue.VALUETYPE_URI
</del><ins>+ return URIValue.VALUETYPE_URI
</ins><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, variant):
</ins><span class="cx">
</span><span class="cx"> if ParserContext.BACKSLASH_IN_URI_VALUE == ParserContext.PARSER_FIX:
</span><span class="cx"> # Decoding required
</span><span class="lines">@@ -50,6 +50,6 @@
</span><span class="cx"> except:
</span><span class="cx"> pass
</span><span class="cx"> else:
</span><del>- super(PyCalendarURIValue, self).generate(os)
</del><ins>+ super(URIValue, self).generate(os)
</ins><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_URI, PyCalendarURIValue, xmldefs.value_uri)
</del><ins>+Value.registerType(Value.VALUETYPE_URI, URIValue, xmldefinitions.value_uri)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarutcoffsetvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -17,27 +17,30 @@
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx">
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar import xmldefs
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.value import Value
</ins><span class="cx">
</span><del>-class PyCalendarUTCOffsetValue(PyCalendarValue):
</del><ins>+class UTCOffsetValue(Value):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, value=0):
</span><span class="cx"> self.mValue = value
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><del>- return PyCalendarUTCOffsetValue(self.mValue)
</del><ins>+ return UTCOffsetValue(self.mValue)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getType(self):
</span><del>- return PyCalendarValue.VALUETYPE_UTC_OFFSET
</del><ins>+ return Value.VALUETYPE_UTC_OFFSET
</ins><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, data):
</del><ins>+ def parse(self, data, variant):
+
+ fullISO = (variant == "vcard")
+
</ins><span class="cx"> # Must be of specific lengths
</span><span class="cx"> datalen = len(data)
</span><del>- if datalen not in (5, 7):
</del><ins>+ if datalen not in ((6, 9,) if fullISO else (5, 7,)):
</ins><span class="cx"> self.mValue = 0
</span><span class="cx"> raise ValueError
</span><span class="cx">
</span><span class="lines">@@ -50,12 +53,14 @@
</span><span class="cx"> hours = int(data[1:3])
</span><span class="cx">
</span><span class="cx"> # Get minutes
</span><del>- mins = int(data[3:5])
</del><ins>+ index = 4 if fullISO else 3
+ mins = int(data[index:index + 2])
</ins><span class="cx">
</span><span class="cx"> # Get seconds if present
</span><span class="cx"> secs = 0
</span><del>- if datalen == 7 :
- secs = int(data[5:])
</del><ins>+ if datalen > 6:
+ index = 7 if fullISO else 5
+ secs = int(data[index:])
</ins><span class="cx">
</span><span class="cx"> self.mValue = ((hours * 60) + mins) * 60 + secs
</span><span class="cx"> if not plus:
</span><span class="lines">@@ -63,36 +68,31 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> # os - StringIO object
</span><del>- def generate(self, os):
</del><ins>+ def generate(self, os, fullISO=False):
</ins><span class="cx"> try:
</span><span class="cx"> abs_value = self.mValue
</span><del>- if self.mValue < 0 :
- os.write("-")
</del><ins>+ if abs_value < 0 :
+ sign = "-"
</ins><span class="cx"> abs_value = -self.mValue
</span><span class="cx"> else:
</span><del>- os.write("+")
</del><ins>+ sign = "+"
</ins><span class="cx">
</span><span class="cx"> secs = abs_value % 60
</span><span class="cx"> mins = (abs_value / 60) % 60
</span><span class="cx"> hours = abs_value / (60 * 60)
</span><span class="cx">
</span><del>- if (hours < 10):
- os.write("0")
- os.write(str(hours))
- if (mins < 10):
- os.write("0")
- os.write(str(mins))
</del><ins>+ s = ("%s%02d:%02d" if fullISO else "%s%02d%02d") % (sign, hours, mins,)
</ins><span class="cx"> if (secs != 0):
</span><del>- if (secs < 10):
- os.write("0")
- os.write(str(secs))
</del><ins>+ s = ("%s:%02d" if fullISO else "%s%02d") % (s, secs,)
+
+ os.write(s)
</ins><span class="cx"> except:
</span><span class="cx"> pass
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx">
</span><del>- os = StringIO.StringIO()
</del><ins>+ os = StringIO()
</ins><span class="cx"> self.generate(os)
</span><span class="cx"> text = os.getvalue()
</span><span class="cx"> text = text[:-2] + ":" + text[-2:]
</span><span class="lines">@@ -101,6 +101,18 @@
</span><span class="cx"> value.text = text
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parseJSONValue(self, jobject):
+ self.parse(str(jobject), variant="vcard")
+
+
+ def writeJSONValue(self, jobject):
+
+ os = StringIO()
+ self.generate(os, fullISO=True)
+ text = os.getvalue()
+ jobject.append(text)
+
+
</ins><span class="cx"> def getValue(self):
</span><span class="cx"> return self.mValue
</span><span class="cx">
</span><span class="lines">@@ -108,4 +120,4 @@
</span><span class="cx"> def setValue(self, value):
</span><span class="cx"> self.mValue = value
</span><span class="cx">
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_UTC_OFFSET, PyCalendarUTCOffsetValue, xmldefs.value_utc_offset)
</del><ins>+Value.registerType(Value.VALUETYPE_UTC_OFFSET, UTCOffsetValue, xmldefinitions.value_utc_offset)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/utils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/utils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/utils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -438,17 +438,17 @@
</span><span class="cx">
</span><span class="cx"> # Display elements
</span><span class="cx"> def getMonthTable(month, year, weekstart, table, today_index):
</span><del>- from pycalendar.datetime import PyCalendarDateTime
</del><ins>+ from pycalendar.datetime import DateTime
</ins><span class="cx">
</span><span class="cx"> # Get today
</span><del>- today = PyCalendarDateTime.getToday(None)
</del><ins>+ today = DateTime.getToday(None)
</ins><span class="cx"> today_index = [-1, -1]
</span><span class="cx">
</span><span class="cx"> # Start with empty table
</span><span class="cx"> table = []
</span><span class="cx">
</span><span class="cx"> # Determine first weekday in month
</span><del>- temp = PyCalendarDateTime(year, month, 1, 0)
</del><ins>+ temp = DateTime(year, month, 1, 0)
</ins><span class="cx"> row = -1
</span><span class="cx"> initial_col = temp.getDayOfWeek() - weekstart
</span><span class="cx"> if initial_col < 0:
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalarmpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/valarm.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/valarm.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/valarm.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,705 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarVAlarm(PyCalendarComponent):
-
- sActionMap = {
- definitions.cICalProperty_ACTION_AUDIO: definitions.eAction_VAlarm_Audio,
- definitions.cICalProperty_ACTION_DISPLAY: definitions.eAction_VAlarm_Display,
- definitions.cICalProperty_ACTION_EMAIL: definitions.eAction_VAlarm_Email,
- definitions.cICalProperty_ACTION_PROCEDURE: definitions.eAction_VAlarm_Procedure,
- definitions.cICalProperty_ACTION_URI: definitions.eAction_VAlarm_URI,
- definitions.cICalProperty_ACTION_NONE: definitions.eAction_VAlarm_None,
- }
-
- sActionValueMap = {
- definitions.eAction_VAlarm_Audio: definitions.cICalProperty_ACTION_AUDIO,
- definitions.eAction_VAlarm_Display: definitions.cICalProperty_ACTION_DISPLAY,
- definitions.eAction_VAlarm_Email: definitions.cICalProperty_ACTION_EMAIL,
- definitions.eAction_VAlarm_Procedure: definitions.cICalProperty_ACTION_PROCEDURE,
- definitions.eAction_VAlarm_URI: definitions.cICalProperty_ACTION_URI,
- definitions.eAction_VAlarm_None: definitions.cICalProperty_ACTION_NONE,
- }
-
- # Classes for each action encapsulating action-specific data
- class PyCalendarVAlarmAction(object):
-
- propertyCardinality_1 = ()
- propertyCardinality_1_Fix_Empty = ()
- propertyCardinality_0_1 = ()
- propertyCardinality_1_More = ()
-
- def __init__(self, type):
- self.mType = type
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmAction(self.mType)
-
- def load(self, valarm):
- pass
-
- def add(self, valarm):
- pass
-
- def remove(self, valarm):
- pass
-
- def getType(self):
- return self.mType
-
-
- class PyCalendarVAlarmAudio(PyCalendarVAlarmAction):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_ACTION,
- definitions.cICalProperty_TRIGGER,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_REPEAT,
- definitions.cICalProperty_ATTACH,
- definitions.cICalProperty_ACKNOWLEDGED,
- )
-
- def __init__(self, speak=None):
- super(PyCalendarVAlarm.PyCalendarVAlarmAudio, self).__init__(type=definitions.eAction_VAlarm_Audio)
- self.mSpeakText = speak
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmAudio(self.mSpeakText)
-
- def load(self, valarm):
- # Get properties
- self.mSpeakText = valarm.loadValueString(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
-
- def add(self, valarm):
- # Delete existing then add
- self.remove(valarm)
-
- prop = PyCalendarProperty(definitions.cICalProperty_ACTION_X_SPEAKTEXT, self.mSpeakText)
- valarm.addProperty(prop)
-
- def remove(self, valarm):
- valarm.removeProperties(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
-
- def isSpeakText(self):
- return len(self.mSpeakText) != 0
-
- def getSpeakText(self):
- return self.mSpeakText
-
-
- class PyCalendarVAlarmDisplay(PyCalendarVAlarmAction):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_ACTION,
- definitions.cICalProperty_TRIGGER,
- )
-
- propertyCardinality_1_Fix_Empty = (
- definitions.cICalProperty_DESCRIPTION,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_REPEAT,
- definitions.cICalProperty_ACKNOWLEDGED,
- )
-
- def __init__(self, description=None):
- super(PyCalendarVAlarm.PyCalendarVAlarmDisplay, self).__init__(type=definitions.eAction_VAlarm_Display)
- self.mDescription = description
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmDisplay(self.mDescription)
-
- def load(self, valarm):
- # Get properties
- self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
-
- def add(self, valarm):
- # Delete existing then add
- self.remove(valarm)
-
- prop = PyCalendarProperty(definitions.cICalProperty_DESCRIPTION, self.mDescription)
- valarm.addProperty(prop)
-
- def remove(self, valarm):
- valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
-
- def getDescription(self):
- return self.mDescription
-
-
- class PyCalendarVAlarmEmail(PyCalendarVAlarmAction):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_ACTION,
- definitions.cICalProperty_TRIGGER,
- )
-
- propertyCardinality_1_Fix_Empty = (
- definitions.cICalProperty_DESCRIPTION,
- definitions.cICalProperty_SUMMARY,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_REPEAT,
- definitions.cICalProperty_ACKNOWLEDGED,
- )
-
- propertyCardinality_1_More = (
- definitions.cICalProperty_ATTENDEE,
- )
-
- def __init__(self, description=None, summary=None, attendees=None):
- super(PyCalendarVAlarm.PyCalendarVAlarmEmail, self).__init__(type=definitions.eAction_VAlarm_Email)
- self.mDescription = description
- self.mSummary = summary
- self.mAttendees = attendees
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmEmail(self.mDescription, self.mSummary, self.mAttendees)
-
- def load(self, valarm):
- # Get properties
- self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
- self.mSummary = valarm.loadValueString(definitions.cICalProperty_SUMMARY)
-
- self.mAttendees = []
- if valarm.hasProperty(definitions.cICalProperty_ATTENDEE):
- # Get each attendee
- range = valarm.getProperties().get(definitions.cICalProperty_ATTENDEE, ())
- for iter in range:
- # Get the attendee value
- attendee = iter.getCalAddressValue()
- if attendee is not None:
- self.mAttendees.append(attendee.getValue())
-
- def add(self, valarm):
- # Delete existing then add
- self.remove(valarm)
-
- prop = PyCalendarProperty(definitions.cICalProperty_DESCRIPTION, self.mDescription)
- valarm.addProperty(prop)
-
- prop = PyCalendarProperty(definitions.cICalProperty_SUMMARY, self.mSummary)
- valarm.addProperty(prop)
-
- for iter in self.mAttendees:
- prop = PyCalendarProperty(definitions.cICalProperty_ATTENDEE, iter, PyCalendarValue.VALUETYPE_CALADDRESS)
- valarm.addProperty(prop)
-
- def remove(self, valarm):
- valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
- valarm.removeProperties(definitions.cICalProperty_SUMMARY)
- valarm.removeProperties(definitions.cICalProperty_ATTENDEE)
-
- def getDescription(self):
- return self.mDescription
-
- def getSummary(self):
- return self.mSummary
-
- def getAttendees(self):
- return self.mAttendees
-
-
- class PyCalendarVAlarmUnknown(PyCalendarVAlarmAction):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_ACTION,
- definitions.cICalProperty_TRIGGER,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_REPEAT,
- definitions.cICalProperty_ACKNOWLEDGED,
- )
-
- def __init__(self):
- super(PyCalendarVAlarm.PyCalendarVAlarmUnknown, self).__init__(type=definitions.eAction_VAlarm_Unknown)
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmUnknown()
-
-
- class PyCalendarVAlarmURI(PyCalendarVAlarmAction):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_ACTION,
- definitions.cICalProperty_TRIGGER,
- definitions.cICalProperty_URL,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_REPEAT,
- definitions.cICalProperty_ACKNOWLEDGED,
- )
-
- def __init__(self, uri=None):
- super(PyCalendarVAlarm.PyCalendarVAlarmURI, self).__init__(type=definitions.eAction_VAlarm_URI)
- self.mURI = uri
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmURI(self.mURI)
-
- def load(self, valarm):
- # Get properties
- self.mURI = valarm.loadValueString(definitions.cICalProperty_URL)
-
- def add(self, valarm):
- # Delete existing then add
- self.remove(valarm)
-
- prop = PyCalendarProperty(definitions.cICalProperty_URL, self.mURI)
- valarm.addProperty(prop)
-
- def remove(self, valarm):
- valarm.removeProperties(definitions.cICalProperty_URL)
-
- def getURI(self):
- return self.mURI
-
-
- class PyCalendarVAlarmNone(PyCalendarVAlarmAction):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_ACTION,
- )
-
- def __init__(self):
- super(PyCalendarVAlarm.PyCalendarVAlarmNone, self).__init__(type=definitions.eAction_VAlarm_None)
-
- def duplicate(self):
- return PyCalendarVAlarm.PyCalendarVAlarmNone()
-
-
- def getMimeComponentName(self):
- # Cannot be sent as a separate MIME object
- return None
-
- sActionToAlarmMap = {
- definitions.eAction_VAlarm_Audio: PyCalendarVAlarmAudio,
- definitions.eAction_VAlarm_Display: PyCalendarVAlarmDisplay,
- definitions.eAction_VAlarm_Email: PyCalendarVAlarmEmail,
- definitions.eAction_VAlarm_URI: PyCalendarVAlarmURI,
- definitions.eAction_VAlarm_None: PyCalendarVAlarmNone,
- }
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
-
- super(PyCalendarVAlarm, self).__init__(parent=parent)
-
- self.mAction = definitions.eAction_VAlarm_Display
- self.mTriggerAbsolute = False
- self.mTriggerOnStart = True
- self.mTriggerOn = PyCalendarDateTime()
-
- # Set duration default to 1 hour
- self.mTriggerBy = PyCalendarDuration()
- self.mTriggerBy.setDuration(60 * 60)
-
- # Does not repeat by default
- self.mRepeats = 0
- self.mRepeatInterval = PyCalendarDuration()
- self.mRepeatInterval.setDuration(5 * 60) # Five minutes
-
- # Status
- self.mStatusInit = False
- self.mAlarmStatus = definitions.eAlarm_Status_Pending
- self.mLastTrigger = PyCalendarDateTime()
- self.mNextTrigger = PyCalendarDateTime()
- self.mDoneCount = 0
-
- # Create action data
- self.mActionData = PyCalendarVAlarm.PyCalendarVAlarmDisplay("")
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarVAlarm, self).duplicate(parent=parent)
- other.mAction = self.mAction
- other.mTriggerAbsolute = self.mTriggerAbsolute
- other.mTriggerOn = self.mTriggerOn.duplicate()
- other.mTriggerBy = self.mTriggerBy.duplicate()
- other.mTriggerOnStart = self.mTriggerOnStart
-
- other.mRepeats = self.mRepeats
- other.mRepeatInterval = self.mRepeatInterval.duplicate()
-
- other.mAlarmStatus = self.mAlarmStatus
- if self.mLastTrigger is not None:
- other.mLastTrigger = self.mLastTrigger.duplicate()
- if self.mNextTrigger is not None:
- other.mNextTrigger = self.mNextTrigger.duplicate()
- other.mDoneCount = self.mDoneCount
-
- other.mActionData = self.mActionData.duplicate()
- return other
-
-
- def getType(self):
- return definitions.cICalComponent_VALARM
-
-
- def getAction(self):
- return self.mAction
-
-
- def getActionData(self):
- return self.mActionData
-
-
- def isTriggerAbsolute(self):
- return self.mTriggerAbsolute
-
-
- def getTriggerOn(self):
- return self.mTriggerOn
-
-
- def getTriggerDuration(self):
- return self.mTriggerBy
-
-
- def isTriggerOnStart(self):
- return self.mTriggerOnStart
-
-
- def getRepeats(self):
- return self.mRepeats
-
-
- def getInterval(self):
- return self.mRepeatInterval
-
-
- def added(self):
- # Added to calendar so add to calendar notifier
- # calstore::CCalendarNotifier::sCalendarNotifier.AddAlarm(this)
-
- # Do inherited
- super(PyCalendarVAlarm, self).added()
-
-
- def removed(self):
- # Removed from calendar so add to calendar notifier
- # calstore::CCalendarNotifier::sCalendarNotifier.RemoveAlarm(this)
-
- # Do inherited
- super(PyCalendarVAlarm, self).removed()
-
-
- def changed(self):
- # Always force recalc of trigger status
- self.mStatusInit = False
-
- # Changed in calendar so change in calendar notifier
- # calstore::CCalendarNotifier::sCalendarNotifier.ChangedAlarm(this)
-
- # Do not do inherited as this is always a sub-component and we do not
- # do top-level component changes
- # super.changed()
-
-
- def finalise(self):
- # Do inherited
- super(PyCalendarVAlarm, self).finalise()
-
- # Get the ACTION
- temp = self.loadValueString(definitions.cICalProperty_ACTION)
- if temp is not None:
- self.mAction = PyCalendarVAlarm.sActionMap.get(temp, definitions.eAction_VAlarm_Unknown)
- self.loadAction()
-
- # Get the trigger
- if self.hasProperty(definitions.cICalProperty_TRIGGER):
- # Determine the type of the value
- temp1 = self.loadValueDateTime(definitions.cICalProperty_TRIGGER)
- temp2 = self.loadValueDuration(definitions.cICalProperty_TRIGGER)
- if temp1 is not None:
- self.mTriggerAbsolute = True
- self.mTriggerOn = temp1
- elif temp2 is not None:
- self.mTriggerAbsolute = False
- self.mTriggerBy = temp2
-
- # Get the property
- prop = self.findFirstProperty(definitions.cICalProperty_TRIGGER)
-
- # Look for RELATED attribute
- if prop.hasAttribute(definitions.cICalAttribute_RELATED):
- temp = prop.getAttributeValue(definitions.cICalAttribute_RELATED)
- if temp == definitions.cICalAttribute_RELATED_START:
- self.mTriggerOnStart = True
- elif temp == definitions.cICalAttribute_RELATED_END:
- self.mTriggerOnStart = False
- else:
- self.mTriggerOnStart = True
-
- # Get repeat & interval
- temp = self.loadValueInteger(definitions.cICalProperty_REPEAT)
- if temp is not None:
- self.mRepeats = temp
- temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
- if temp is not None:
- self.mRepeatInterval = temp
-
- # Set a map key for sorting
- self.mMapKey = "%s:%s" % (self.mAction, self.mTriggerOn if self.mTriggerAbsolute else self.mTriggerBy,)
-
- # Alarm status - private to Mulberry
- status = self.loadValueString(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
- if status is not None:
- if status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING:
- self.mAlarmStatus = definitions.eAlarm_Status_Pending
- elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED:
- self.mAlarmStatus = definitions.eAlarm_Status_Completed
- elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED:
- self.mAlarmStatus = definitions.eAlarm_Status_Disabled
- else:
- self.mAlarmStatus = definitions.eAlarm_Status_Pending
-
- # Last trigger time - private to Mulberry
- temp = self.loadValueDateTime(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
- if temp is not None:
- self.mLastTrigger = temp
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems, else raise. If
- loggedProblems is not None it must be a C{list} and problem descriptions are appended
- to that.
- """
-
- # Validate using action specific constraints
- self.propertyCardinality_1 = self.mActionData.propertyCardinality_1
- self.propertyCardinality_1_Fix_Empty = self.mActionData.propertyCardinality_1_Fix_Empty
- self.propertyCardinality_0_1 = self.mActionData.propertyCardinality_0_1
- self.propertyCardinality_1_More = self.mActionData.propertyCardinality_1_More
-
- fixed, unfixed = super(PyCalendarVAlarm, self).validate(doFix)
-
- # Extra constraint: both DURATION and REPEAT must be present togethe
- if self.hasProperty(definitions.cICalProperty_DURATION) ^ self.hasProperty(definitions.cICalProperty_REPEAT):
- # Cannot fix this
- logProblem = "[%s] Properties must be present together: %s, %s" % (
- self.getType(),
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_REPEAT,
- )
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- def editStatus(self, status):
- # Remove existing
- self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
-
- # Updated cached values
- self.mAlarmStatus = status
-
- # Add new
- status_txt = ""
- if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
- status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
- elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
- status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
- elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
- status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status_txt))
-
-
- def editAction(self, action, data):
- # Remove existing
- self.removeProperties(definitions.cICalProperty_ACTION)
- self.mActionData.remove(self)
- self.mActionData = None
-
- # Updated cached values
- self.mAction = action
- self.mActionData = data
-
- # Add new properties to alarm
- action_txt = PyCalendarVAlarm.sActionValueMap.get(self.mAction, definitions.cICalProperty_ACTION_PROCEDURE)
-
- prop = PyCalendarProperty(definitions.cICalProperty_ACTION, action_txt)
- self.addProperty(prop)
-
- self.mActionData.add(self)
-
-
- def editTriggerOn(self, dt):
- # Remove existing
- self.removeProperties(definitions.cICalProperty_TRIGGER)
-
- # Updated cached values
- self.mTriggerAbsolute = True
- self.mTriggerOn = dt
-
- # Add new
- prop = PyCalendarProperty(definitions.cICalProperty_TRIGGER, dt)
- self.addProperty(prop)
-
-
- def editTriggerBy(self, duration, trigger_start):
- # Remove existing
- self.removeProperties(definitions.cICalProperty_TRIGGER)
-
- # Updated cached values
- self.mTriggerAbsolute = False
- self.mTriggerBy = duration
- self.mTriggerOnStart = trigger_start
-
- # Add new (with attribute)
- prop = PyCalendarProperty(definitions.cICalProperty_TRIGGER, duration)
- attr = PyCalendarAttribute(definitions.cICalAttribute_RELATED,
- (definitions.cICalAttribute_RELATED_START,
- definitions.cICalAttribute_RELATED_END)[not trigger_start])
- prop.addAttribute(attr)
- self.addProperty(prop)
-
-
- def editRepeats(self, repeat, interval):
- # Remove existing
- self.removeProperties(definitions.cICalProperty_REPEAT)
- self.removeProperties(definitions.cICalProperty_DURATION)
-
- # Updated cached values
- self.mRepeats = repeat
- self.mRepeatInterval = interval
-
- # Add new
- if self.mRepeats > 0:
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_REPEAT, repeat))
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_DURATION, interval))
-
-
- def getAlarmStatus(self):
- return self.mAlarmStatus
-
-
- def getNextTrigger(self, dt):
- if not self.mStatusInit:
- self.initNextTrigger()
- dt.copy(self.mNextTrigger)
-
-
- def alarmTriggered(self, dt):
- # Remove existing
- self.removeProperties(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
- self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
-
- # Updated cached values
- self.mLastTrigger.copy(dt)
-
- if self.mDoneCount < self.mRepeats:
- self.mNextTrigger = self.mLastTrigger + self.mRepeatInterval
- dt.copy(self.mNextTrigger)
- self.mDoneCount += 1
- self.mAlarmStatus = definitions.eAlarm_Status_Pending
- else:
- self.mAlarmStatus = definitions.eAlarm_Status_Completed
-
- # Add new
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_ALARM_X_LASTTRIGGER, dt))
- status = ""
- if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
- status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
- elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
- status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
- elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
- status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
- self.addProperty(PyCalendarProperty(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status))
-
- # Now update dt to the next alarm time
- return self.mAlarmStatus == definitions.eAlarm_Status_Pending
-
-
- def loadAction(self):
- # Delete current one
- self.mActionData = None
- self.mActionData = PyCalendarVAlarm.sActionToAlarmMap.get(self.mAction, PyCalendarVAlarm.PyCalendarVAlarmUnknown)()
- self.mActionData.load(self)
-
-
- def initNextTrigger(self):
- # Do not bother if its completed
- if self.mAlarmStatus == definitions.eAlarm_Status_Completed:
- return
- self.mStatusInit = True
-
- # Look for trigger immediately preceeding or equal to utc now
- nowutc = PyCalendarDateTime.getNowUTC()
-
- # Init done counter
- self.mDoneCount = 0
-
- # Determine the first trigger
- trigger = PyCalendarDateTime()
- self.getFirstTrigger(trigger)
-
- while self.mDoneCount < self.mRepeats:
- # See if next trigger is later than now
- next_trigger = trigger + self.mRepeatInterval
- if next_trigger > nowutc:
- break
- self.mDoneCount += 1
- trigger = next_trigger
-
- # Check for completion
- if trigger == self.mLastTrigger or (nowutc - trigger).getTotalSeconds() > 24 * 60 * 60:
- if self.mDoneCount == self.mRepeats:
- self.mAlarmStatus = definitions.eAlarm_Status_Completed
- return
- else:
- trigger = trigger + self.mRepeatInterval
- self.mDoneCount += 1
-
- self.mNextTrigger = trigger
-
-
- def getFirstTrigger(self, dt):
- # If absolute trigger, use that
- if self.isTriggerAbsolute():
- # Get the trigger on
- dt.copy(self.getTriggerOn())
- else:
- # Get the parent embedder class (must be CICalendarComponentRecur type)
- owner = self.getEmbedder()
- if owner is not None:
- # Determine time at which alarm will trigger
- trigger = (owner.getStart(), owner.getEnd())[not self.isTriggerOnStart()]
-
- # Offset by duration
- dt.copy(trigger + self.getTriggerDuration())
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalidationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
</del><ins>+from pycalendar.plaintextvalue import PlainTextValue
</ins><span class="cx">
</span><span class="cx"> # Grabbed from http://docs.python.org/library/functools.html since we need to support Python 2.5
</span><span class="cx"> def partial(func, *args, **keywords):
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> def stringValue(text, property):
</span><span class="cx">
</span><span class="cx"> value = property.getValue()
</span><del>- if value and isinstance(value, PyCalendarPlainTextValue):
</del><ins>+ if value and isinstance(value, PlainTextValue):
</ins><span class="cx"> value = value.getValue()
</span><span class="cx"> return value.lower() == text.lower()
</span><span class="cx">
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalidatorpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/validator.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/validator.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/validator.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2012-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,8 +15,8 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.exceptions import PyCalendarError
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.exceptions import ErrorBase
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> import os
</span><span class="lines">@@ -33,14 +33,14 @@
</span><span class="cx">
</span><span class="cx"> if data.find("BEGIN:VCALENDAR") != -1:
</span><span class="cx"> try:
</span><del>- cal = PyCalendar.parseText(data)
- except PyCalendarError, e:
</del><ins>+ cal = Calendar.parseText(data)
+ except ErrorBase, e:
</ins><span class="cx"> print "Failed to parse iCalendar: %r" % (e,)
</span><span class="cx"> sys.exit(1)
</span><span class="cx"> elif data.find("BEGIN:VCARD") != -1:
</span><span class="cx"> try:
</span><span class="cx"> cal = Card.parseText(data)
</span><del>- except PyCalendarError, e:
</del><ins>+ except ErrorBase, e:
</ins><span class="cx"> print "Failed to parse vCard: %r" % (e,)
</span><span class="cx"> sys.exit(1)
</span><span class="cx"> else:
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/value.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/value.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/value.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,11 +16,11 @@
</span><span class="cx">
</span><span class="cx"> # ICalendar Value class
</span><span class="cx">
</span><ins>+from pycalendar import xmlutils
</ins><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><del>-from pycalendar import xmldefs
</del><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx">
</span><del>-class PyCalendarValue(ValueMixin):
</del><ins>+class Value(ValueMixin):
</ins><span class="cx">
</span><span class="cx"> (
</span><span class="cx"> VALUETYPE_ADR,
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx">
</span><span class="cx"> _typeMap = {}
</span><span class="cx"> _xmlMap = {}
</span><ins>+ _jsonMap = {}
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __hash__(self):
</span><span class="lines">@@ -61,25 +62,26 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def __eq__(self, other):
</span><del>- if not isinstance(other, PyCalendarValue):
</del><ins>+ if not isinstance(other, Value):
</ins><span class="cx"> return False
</span><span class="cx"> return self.getType() == other.getType() and self.getValue() == other.getValue()
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @classmethod
</span><del>- def registerType(clz, type, cls, xmlNode):
</del><ins>+ def registerType(clz, type, cls, xmlNode, jsonNode=None):
</ins><span class="cx"> clz._typeMap[type] = cls
</span><span class="cx"> clz._xmlMap[type] = xmlNode
</span><ins>+ clz._jsonMap[type] = xmlNode if jsonNode is None else jsonNode
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @classmethod
</span><del>- def createFromType(clz, type):
- # Create the type
- created = clz._typeMap.get(type, None)
</del><ins>+ def createFromType(clz, value_type):
+ # Create the value type
+ created = clz._typeMap.get(value_type, None)
</ins><span class="cx"> if created:
</span><span class="cx"> return created()
</span><span class="cx"> else:
</span><del>- return clz._typeMap.get(PyCalendarValue.VALUETYPE_UNKNOWN)(type)
</del><ins>+ return clz._typeMap.get(Value.VALUETYPE_UNKNOWN)(value_type)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def getType(self):
</span><span class="lines">@@ -98,9 +100,26 @@
</span><span class="cx"> raise NotImplementedError
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parse(self, data, variant):
+ raise NotImplementedError
+
+
</ins><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx"> raise NotImplementedError
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def parseJSONValue(self, jobject):
+ raise NotImplementedError
+
+
+ def writeJSON(self, jobject):
+ jobject.append(self._jsonMap[self.getType()])
+ self.writeJSONValue(jobject)
+
+
+ def writeJSONValue(self, jobject):
+ raise NotImplementedError
+
+
</ins><span class="cx"> def getXMLNode(self, node, namespace):
</span><del>- return XML.SubElement(node, xmldefs.makeTag(namespace, self._xmlMap[self.getType()]))
</del><ins>+ return XML.SubElement(node, xmlutils.makeTag(namespace, self._xmlMap[self.getType()]))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalueutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/valueutils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/valueutils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/valueutils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -19,6 +19,9 @@
</span><span class="cx"> from cStringIO import StringIO
</span><span class="cx">
</span><span class="cx"> class ValueMixin(object):
</span><ins>+ """
+ Mix-in for operations common to Value's and value-specific classes.
+ """
</ins><span class="cx">
</span><span class="cx"> def __str__(self):
</span><span class="cx"> return self.getText()
</span><span class="lines">@@ -47,3 +50,61 @@
</span><span class="cx">
</span><span class="cx"> def writeXML(self, node, namespace):
</span><span class="cx"> raise NotImplementedError
</span><ins>+
+
+ def parseJSON(self, jobject):
+ raise NotImplementedError
+
+
+ def writeJSON(self, jobject):
+ raise NotImplementedError
+
+
+
+class WrapperValue(object):
+ """
+ Mix-in for Value derived classes that wrap a value-specific class.
+ """
+
+ _wrappedClass = None
+ _wrappedType = None
+
+ def __init__(self, value=None):
+ self.mValue = value if value is not None else self._wrappedClass()
+
+
+ def getType(self):
+ return self._wrappedType
+
+
+ def duplicate(self):
+ return self.__class__(self.mValue.duplicate())
+
+
+ def parse(self, data, variant):
+ self.mValue.parse(data)
+
+
+ def generate(self, os):
+ self.mValue.generate(os)
+
+
+ def writeXML(self, node, namespace):
+ value = self.getXMLNode(node, namespace)
+ value.text = self.mValue.writeXML()
+
+
+ def parseJSONValue(self, jobject):
+ self.mValue.parseJSON(jobject)
+
+
+ def writeJSONValue(self, jobject):
+ self.mValue.writeJSON(jobject)
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvavailabilitypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vavailability.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vavailability.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vavailability.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,107 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import itipdefinitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarVAvailability(PyCalendarComponent):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTAMP,
- definitions.cICalProperty_UID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_BUSYTYPE,
- definitions.cICalProperty_CLASS,
- definitions.cICalProperty_CREATED,
- definitions.cICalProperty_DESCRIPTION,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_ORGANIZER,
- definitions.cICalProperty_SEQUENCE,
- definitions.cICalProperty_SUMMARY,
- definitions.cICalProperty_URL,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_DURATION,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
- super(PyCalendarVAvailability, self).__init__(parent=parent)
-
-
- def duplicate(self, parent=None):
- return super(PyCalendarVAvailability, self).duplicate(parent=parent)
-
-
- def getType(self):
- return definitions.cICalComponent_VAVAILABILITY
-
-
- def getMimeComponentName(self):
- return itipdefinitions.cICalMIMEComponent_VAVAILABILITY
-
-
- def finalise(self):
- super(PyCalendarVAvailability, self).finalise()
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems, else raise. If
- loggedProblems is not None it must be a C{list} and problem descriptions are appended
- to that.
- """
-
- fixed, unfixed = super(PyCalendarVAvailability, self).validate(doFix)
-
- # Extra constraint: only one of DTEND or DURATION
- if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
- # Fix by removing the DTEND
- logProblem = "[%s] Properties must not both be present: %s, %s" % (
- self.getType(),
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_DURATION,
- )
- if doFix:
- self.removeProperties(definitions.cICalProperty_DTEND)
- fixed.append(logProblem)
- else:
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- def addComponent(self, comp):
- # We can embed the available components only
- if comp.getType() == definitions.cICalComponent_AVAILABLE:
- super(PyCalendarVAvailability, self).addComponent(comp)
- else:
- raise ValueError
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_DTEND,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcard__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardadrpyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardadrpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/adr.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/adr.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/adr.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,135 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# vCard ADR value
+
+from pycalendar import utils
+from pycalendar.valueutils import ValueMixin
+
+class Adr(ValueMixin):
+ """
+ mValue is a tuple of seven str or tuples of str
+ """
+
+ (
+ POBOX,
+ EXTENDED,
+ STREET,
+ LOCALITY,
+ REGION,
+ POSTALCODE,
+ COUNTRY,
+ MAXITEMS
+ ) = range(8)
+
+ def __init__(self, pobox="", extended="", street="", locality="", region="", postalcode="", country=""):
+ self.mValue = (pobox, extended, street, locality, region, postalcode, country)
+
+
+ def duplicate(self):
+ return Adr(*self.mValue)
+
+
+ def __hash__(self):
+ return hash(self.mValue)
+
+
+ def __repr__(self):
+ return "ADR %s" % (self.getText(),)
+
+
+ def __eq__(self, comp):
+ return self.mValue == comp.mValue
+
+
+ def getPobox(self):
+ return self.mValue[Adr.POBOX]
+
+
+ def setPobox(self, value):
+ self.mValue[Adr.POBOX] = value
+
+
+ def getExtended(self):
+ return self.mValue[Adr.EXTENDED]
+
+
+ def setExtended(self, value):
+ self.mValue[Adr.EXTENDED] = value
+
+
+ def getStreet(self):
+ return self.mValue[Adr.STREET]
+
+
+ def setStreet(self, value):
+ self.mValue[Adr.STREET] = value
+
+
+ def getLocality(self):
+ return self.mValue[Adr.LOCALITY]
+
+
+ def setLocality(self, value):
+ self.mValue[Adr.LOCALITY] = value
+
+
+ def getRegion(self):
+ return self.mValue[Adr.REGION]
+
+
+ def setRegion(self, value):
+ self.mValue[Adr.REGION] = value
+
+
+ def getPostalCode(self):
+ return self.mValue[Adr.POSTALCODE]
+
+
+ def setPostalCode(self, value):
+ self.mValue[Adr.POSTALCODE] = value
+
+
+ def getCountry(self):
+ return self.mValue[Adr.COUNTRY]
+
+
+ def setCountry(self, value):
+ self.mValue[Adr.COUNTRY] = value
+
+
+ def parse(self, data):
+ self.mValue = utils.parseDoubleNestedList(data, Adr.MAXITEMS)
+
+
+ def generate(self, os):
+ utils.generateDoubleNestedList(os, self.mValue)
+
+
+ def parseJSON(self, jobject):
+ self.mValue = tuple(jobject)
+
+
+ def writeJSON(self, jobject):
+ jobject.append(list(self.mValue))
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardadrvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardadrvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/adrvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# vCard ADR value
+
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
+from pycalendar.vcard.adr import Adr
+
+class AdrValue(WrapperValue, Value):
+
+ _wrappedClass = Adr
+ _wrappedType = Value.VALUETYPE_ADR
+
+Value.registerType(Value.VALUETYPE_ADR, AdrValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardcardpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/card.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/card.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/card.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,9 +15,8 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.exceptions import PyCalendarInvalidData, \
- PyCalendarValidationError
</del><ins>+from pycalendar.containerbase import ContainerBase
+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.utils import readFoldedLine
</span><span class="cx"> from pycalendar.vcard import definitions
</span><span class="lines">@@ -25,21 +24,17 @@
</span><span class="cx"> Property_PRODID, Property_UID
</span><span class="cx"> from pycalendar.vcard.property import Property
</span><span class="cx"> from pycalendar.vcard.validation import VCARD_VALUE_CHECKS
</span><ins>+import json
</ins><span class="cx">
</span><del>-class Card(PyCalendarComponentBase):
</del><ins>+class Card(ContainerBase):
</ins><span class="cx">
</span><del>- sProdID = "-//mulberrymail.com//Mulberry v4.0//EN"
- sDomain = "mulberrymail.com"
</del><ins>+ sContainerDescriptor = "vCard"
+ sComponentType = None
+ sPropertyType = Property
</ins><span class="cx">
</span><del>- @staticmethod
- def setPRODID(prodid):
- Card.sProdID = prodid
</del><ins>+ sFormatText = "text/vcard"
+ sFormatJSON = "application/vcard+json"
</ins><span class="cx">
</span><del>-
- @staticmethod
- def setDomain(domain):
- Card.sDomain = domain
-
</del><span class="cx"> propertyCardinality_1 = (
</span><span class="cx"> definitions.Property_VERSION,
</span><span class="cx"> definitions.Property_N,
</span><span class="lines">@@ -58,13 +53,6 @@
</span><span class="cx">
</span><span class="cx"> propertyValueChecks = VCARD_VALUE_CHECKS
</span><span class="cx">
</span><del>- def __init__(self, add_defaults=True):
- super(Card, self).__init__()
-
- if add_defaults:
- self.addDefaultProperties()
-
-
</del><span class="cx"> def duplicate(self):
</span><span class="cx"> return super(Card, self).duplicate()
</span><span class="cx">
</span><span class="lines">@@ -73,25 +61,6 @@
</span><span class="cx"> return VCARD
</span><span class="cx">
</span><span class="cx">
</span><del>- def finalise(self):
- pass
-
-
- def validate(self, doFix=False, doRaise=False):
- """
- Validate the data in this component and optionally fix any problems. Return
- a tuple containing two lists: the first describes problems that were fixed, the
- second problems that were not fixed. Caller can then decide what to do with unfixed
- issues.
- """
-
- # Optional raise behavior
- fixed, unfixed = super(Card, self).validate(doFix)
- if doRaise and unfixed:
- raise PyCalendarValidationError(";".join(unfixed))
- return fixed, unfixed
-
-
</del><span class="cx"> def sortedPropertyKeyOrder(self):
</span><span class="cx"> return (
</span><span class="cx"> Property_VERSION,
</span><span class="lines">@@ -100,12 +69,24 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx">
</span><del>- @staticmethod
- def parseMultiple(ins):
</del><ins>+ @classmethod
+ def parseMultipleData(cls, data, format):
</ins><span class="cx">
</span><ins>+ if format == cls.sFormatText:
+ return cls.parseMultipleTextData(data)
+ elif format == cls.sFormatJSON:
+ return cls.parseMultipleJSONData(data)
+
+
+ @classmethod
+ def parseMultipleTextData(cls, ins):
+
+ if isinstance(ins, str):
+ ins = StringIO(ins)
+
</ins><span class="cx"> results = []
</span><span class="cx">
</span><del>- card = Card(add_defaults=False)
</del><ins>+ card = cls(add_defaults=False)
</ins><span class="cx">
</span><span class="cx"> LOOK_FOR_VCARD = 0
</span><span class="cx"> GET_PROPERTY = 1
</span><span class="lines">@@ -129,11 +110,11 @@
</span><span class="cx"> elif len(line) == 0:
</span><span class="cx"> # Raise if requested, otherwise just ignore
</span><span class="cx"> if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
</span><del>- raise PyCalendarInvalidData("vCard data has blank lines")
</del><ins>+ raise InvalidData("vCard data has blank lines")
</ins><span class="cx">
</span><span class="cx"> # Unrecognized data
</span><span class="cx"> else:
</span><del>- raise PyCalendarInvalidData("vCard data not recognized", line)
</del><ins>+ raise InvalidData("vCard data not recognized", line)
</ins><span class="cx">
</span><span class="cx"> elif state == GET_PROPERTY:
</span><span class="cx">
</span><span class="lines">@@ -145,7 +126,7 @@
</span><span class="cx">
</span><span class="cx"> # Validate some things
</span><span class="cx"> if not card.hasProperty("VERSION"):
</span><del>- raise PyCalendarInvalidData("vCard missing VERSION", "")
</del><ins>+ raise InvalidData("vCard missing VERSION", "")
</ins><span class="cx">
</span><span class="cx"> results.append(card)
</span><span class="cx">
</span><span class="lines">@@ -157,119 +138,42 @@
</span><span class="cx"> elif len(line) == 0:
</span><span class="cx"> # Raise if requested, otherwise just ignore
</span><span class="cx"> if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
</span><del>- raise PyCalendarInvalidData("vCard data has blank lines")
</del><ins>+ raise InvalidData("vCard data has blank lines")
</ins><span class="cx">
</span><span class="cx"> # Must be a property
</span><span class="cx"> else:
</span><span class="cx">
</span><del>- # Parse attribute/value for top-level calendar item
- prop = Property()
- if prop.parse(line):
</del><ins>+ # Parse parameter/value for top-level calendar item
+ prop = Property.parseText(line)
</ins><span class="cx">
</span><del>- # Check for valid property
- if not card.validProperty(prop):
- raise PyCalendarInvalidData("Invalid property", str(prop))
- else:
- card.addProperty(prop)
</del><ins>+ # Check for valid property
+ if not card.validProperty(prop):
+ raise InvalidData("Invalid property", str(prop))
+ else:
+ card.addProperty(prop)
</ins><span class="cx">
</span><span class="cx"> # Check for truncated data
</span><span class="cx"> if state != LOOK_FOR_VCARD:
</span><del>- raise PyCalendarInvalidData("vCard data not complete")
</del><ins>+ raise InvalidData("vCard data not complete")
</ins><span class="cx">
</span><span class="cx"> return results
</span><span class="cx">
</span><span class="cx">
</span><del>- @staticmethod
- def parseText(data):
</del><ins>+ @classmethod
+ def parseMultipleJSONData(cls, data):
</ins><span class="cx">
</span><del>- cal = Card(add_defaults=False)
- if cal.parse(StringIO(data)):
- return cal
- else:
- return None
</del><ins>+ if not isinstance(data, str):
+ data = data.read()
+ try:
+ jobjects = json.loads(data)
+ except ValueError, e:
+ raise InvalidData(e, data)
+ results = []
+ for jobject in jobjects:
+ results.append(cls.parseJSON(jobject, None, cls(add_defaults=False)))
+ return results
</ins><span class="cx">
</span><span class="cx">
</span><del>- def parse(self, ins):
-
- result = False
-
- self.setProperties({})
-
- LOOK_FOR_VCARD = 0
- GET_PROPERTY = 1
-
- state = LOOK_FOR_VCARD
-
- # Get lines looking for start of calendar
- lines = [None, None]
-
- while readFoldedLine(ins, lines):
-
- line = lines[0]
- if state == LOOK_FOR_VCARD:
-
- # Look for start
- if line == self.getBeginDelimiter():
- # Next state
- state = GET_PROPERTY
-
- # Indicate success at this point
- result = True
-
- # Handle blank line
- elif len(line) == 0:
- # Raise if requested, otherwise just ignore
- if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
- raise PyCalendarInvalidData("vCard data has blank lines")
-
- # Unrecognized data
- else:
- raise PyCalendarInvalidData("vCard data not recognized", line)
-
- elif state == GET_PROPERTY:
-
- # Look for end of object
- if line == self.getEndDelimiter():
-
- # Finalise the current calendar
- self.finalise()
-
- # Change state
- state = LOOK_FOR_VCARD
-
- # Blank line
- elif len(line) == 0:
- # Raise if requested, otherwise just ignore
- if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
- raise PyCalendarInvalidData("vCard data has blank lines")
-
- # Must be a property
- else:
-
- # Parse attribute/value for top-level calendar item
- prop = Property()
- try:
- if prop.parse(line):
-
- # Check for valid property
- if not self.validProperty(prop):
- raise PyCalendarInvalidData("Invalid property", str(prop))
- else:
- self.addProperty(prop)
- except IndexError:
- print line
-
- # Check for truncated data
- if state != LOOK_FOR_VCARD:
- raise PyCalendarInvalidData("vCard data not complete", "")
-
- # Validate some things
- if result and not self.hasProperty("VERSION"):
- raise PyCalendarInvalidData("vCard missing VERSION", "")
-
- return result
-
-
</del><span class="cx"> def addDefaultProperties(self):
</span><span class="cx"> self.addProperty(Property(definitions.Property_PRODID, Card.sProdID))
</span><span class="cx"> self.addProperty(Property(definitions.Property_VERSION, "3.0"))
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcarddefinitionspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/definitions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/definitions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/definitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardnpyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardnpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/n.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/n.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/n.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# vCard ADR value
+
+from pycalendar import utils
+from pycalendar.valueutils import ValueMixin
+
+class N(ValueMixin):
+ """
+ mValue is a tuple of seven str or tuples of str
+ """
+
+ (
+ LAST,
+ FIRST,
+ MIDDLE,
+ PREFIX,
+ SUFFIX,
+ MAXITEMS
+ ) = range(6)
+
+ def __init__(self, last="", first="", middle="", prefix="", suffix=""):
+ self.mValue = (last, first, middle, prefix, suffix)
+
+
+ def duplicate(self):
+ return N(*self.mValue)
+
+
+ def __hash__(self):
+ return hash(self.mValue)
+
+
+ def __repr__(self):
+ return "N %s" % (self.getText(),)
+
+
+ def __eq__(self, comp):
+ return self.mValue == comp.mValue
+
+
+ def getFirst(self):
+ return self.mValue[N.FIRST]
+
+
+ def setFirst(self, value):
+ self.mValue[N.FIRST] = value
+
+
+ def getLast(self):
+ return self.mValue[N.LAST]
+
+
+ def setLast(self, value):
+ self.mValue[N.LAST] = value
+
+
+ def getMiddle(self):
+ return self.mValue[N.MIDDLE]
+
+
+ def setMiddle(self, value):
+ self.mValue[N.MIDDLE] = value
+
+
+ def getPrefix(self):
+ return self.mValue[N.PREFIX]
+
+
+ def setPrefix(self, value):
+ self.mValue[N.PREFIX] = value
+
+
+ def getSuffix(self):
+ return self.mValue[N.SUFFIX]
+
+
+ def setSuffix(self, value):
+ self.mValue[N.SUFFIX] = value
+
+
+ def getFullName(self):
+
+
+ def _stringOrList(item):
+ return item if isinstance(item, basestring) else " ".join(item)
+
+ results = []
+ for i in (N.PREFIX, N.FIRST, N.MIDDLE, N.LAST, N.SUFFIX):
+ result = _stringOrList(self.mValue[i])
+ if result:
+ results.append(result)
+
+ return " ".join(results)
+
+
+ def parse(self, data):
+ self.mValue = utils.parseDoubleNestedList(data, N.MAXITEMS)
+
+
+ def generate(self, os):
+ utils.generateDoubleNestedList(os, self.mValue)
+
+
+ def parseJSON(self, jobject):
+ self.mValue = tuple(jobject)
+
+
+ def writeJSON(self, jobject):
+ jobject.append(list(self.mValue))
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardnvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardnvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/nvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/nvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/nvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# vCard N value
+
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
+from pycalendar.vcard.n import N
+
+class NValue(WrapperValue, Value):
+
+ _wrappedClass = N
+ _wrappedType = Value.VALUETYPE_N
+
+Value.registerType(Value.VALUETYPE_N, NValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardorgvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardorgvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/orgvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# vCard ORG value
+
+from pycalendar import utils
+from pycalendar.value import Value
+
+class OrgValue(Value):
+ """
+ mValue is a str or tuple of str
+ """
+
+ def __init__(self, value=None):
+ self.mValue = value
+
+
+ def duplicate(self):
+ return OrgValue(self.mValue)
+
+
+ def getType(self):
+ return Value.VALUETYPE_ORG
+
+
+ def parse(self, data, variant="vcard"):
+ self.mValue = utils.parseTextList(data, ';')
+
+
+ def generate(self, os):
+ utils.generateTextList(os, self.mValue, ';')
+
+
+ def parseJSONValue(self, jobject):
+ self.mValue = tuple(jobject)
+
+
+ def writeJSONValue(self, jobject):
+ jobject.append(list(self.mValue))
+
+
+ def getValue(self):
+ return self.mValue
+
+
+ def setValue(self, value):
+ self.mValue = value
+
+Value.registerType(Value.VALUETYPE_ORG, OrgValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardpropertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,113 +15,109 @@
</span><span class="cx"> ##
</span><span class="cx">
</span><span class="cx"> from pycalendar import stringutils
</span><del>-from pycalendar.adr import Adr
-from pycalendar.adrvalue import AdrValue
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.datetimevalue import PyCalendarDateTimeValue
-from pycalendar.exceptions import PyCalendarInvalidProperty
-from pycalendar.integervalue import PyCalendarIntegerValue
-from pycalendar.multivalue import PyCalendarMultiValue
-from pycalendar.n import N
-from pycalendar.nvalue import NValue
-from pycalendar.orgvalue import OrgValue
</del><ins>+from pycalendar.parameter import Parameter
+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidProperty
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><del>-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.unknownvalue import PyCalendarUnknownValue
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar.property import PropertyBase
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> from pycalendar.utils import decodeParameterValue
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> from pycalendar.vcard import definitions
</span><ins>+from pycalendar.vcard.adr import Adr
+from pycalendar.vcard.adrvalue import AdrValue
+from pycalendar.vcard.n import N
+from pycalendar.vcard.nvalue import NValue
+from pycalendar.vcard.orgvalue import OrgValue
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx">
</span><span class="cx"> handleOptions = ("allow", "ignore", "fix", "raise")
</span><span class="cx"> missingParameterValues = "fix"
</span><span class="cx">
</span><del>-class Property(object):
</del><ins>+class Property(PropertyBase):
</ins><span class="cx">
</span><span class="cx"> sDefaultValueTypeMap = {
</span><span class="cx">
</span><span class="cx"> # 2425 Properties
</span><del>- definitions.Property_SOURCE : PyCalendarValue.VALUETYPE_URI,
- definitions.Property_NAME : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_PROFILE : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ definitions.Property_SOURCE : Value.VALUETYPE_URI,
+ definitions.Property_NAME : Value.VALUETYPE_TEXT,
+ definitions.Property_PROFILE : Value.VALUETYPE_TEXT,
</ins><span class="cx">
</span><span class="cx"> # 2426 vCard Properties
</span><span class="cx">
</span><span class="cx"> # 2426 Section 3.1
</span><del>- definitions.Property_FN : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_N : PyCalendarValue.VALUETYPE_N,
- definitions.Property_NICKNAME : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_PHOTO : PyCalendarValue.VALUETYPE_BINARY,
- definitions.Property_BDAY : PyCalendarValue.VALUETYPE_DATE,
</del><ins>+ definitions.Property_FN : Value.VALUETYPE_TEXT,
+ definitions.Property_N : Value.VALUETYPE_TEXT,
+ definitions.Property_NICKNAME : Value.VALUETYPE_TEXT,
+ definitions.Property_PHOTO : Value.VALUETYPE_BINARY,
+ definitions.Property_BDAY : Value.VALUETYPE_DATE,
</ins><span class="cx">
</span><span class="cx"> # 2426 Section 3.2
</span><del>- definitions.Property_ADR : PyCalendarValue.VALUETYPE_ADR,
- definitions.Property_LABEL : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ definitions.Property_ADR : Value.VALUETYPE_TEXT,
+ definitions.Property_LABEL : Value.VALUETYPE_TEXT,
</ins><span class="cx">
</span><span class="cx"> # 2426 Section 3.3
</span><del>- definitions.Property_TEL : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_EMAIL : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_MAILER : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ definitions.Property_TEL : Value.VALUETYPE_TEXT,
+ definitions.Property_EMAIL : Value.VALUETYPE_TEXT,
+ definitions.Property_MAILER : Value.VALUETYPE_TEXT,
</ins><span class="cx">
</span><span class="cx"> # 2426 Section 3.4
</span><del>- definitions.Property_TZ : PyCalendarValue.VALUETYPE_UTC_OFFSET,
- definitions.Property_GEO : PyCalendarValue.VALUETYPE_GEO,
</del><ins>+ definitions.Property_TZ : Value.VALUETYPE_UTC_OFFSET,
+ definitions.Property_GEO : Value.VALUETYPE_FLOAT,
</ins><span class="cx">
</span><span class="cx"> # 2426 Section 3.5
</span><del>- definitions.Property_TITLE : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_ROLE : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_LOGO : PyCalendarValue.VALUETYPE_BINARY,
- definitions.Property_AGENT : PyCalendarValue.VALUETYPE_VCARD,
- definitions.Property_ORG : PyCalendarValue.VALUETYPE_ORG,
</del><ins>+ definitions.Property_TITLE : Value.VALUETYPE_TEXT,
+ definitions.Property_ROLE : Value.VALUETYPE_TEXT,
+ definitions.Property_LOGO : Value.VALUETYPE_BINARY,
+ definitions.Property_AGENT : Value.VALUETYPE_VCARD,
+ definitions.Property_ORG : Value.VALUETYPE_TEXT,
</ins><span class="cx">
</span><span class="cx"> # 2426 Section 3.6
</span><del>- definitions.Property_CATEGORIES : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_NOTE : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_PRODID : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_REV : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.Property_SORT_STRING : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_SOUND : PyCalendarValue.VALUETYPE_BINARY,
- definitions.Property_UID : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_URL : PyCalendarValue.VALUETYPE_URI,
- definitions.Property_VERSION : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+ definitions.Property_CATEGORIES : Value.VALUETYPE_TEXT,
+ definitions.Property_NOTE : Value.VALUETYPE_TEXT,
+ definitions.Property_PRODID : Value.VALUETYPE_TEXT,
+ definitions.Property_REV : Value.VALUETYPE_DATETIME,
+ definitions.Property_SORT_STRING : Value.VALUETYPE_TEXT,
+ definitions.Property_SOUND : Value.VALUETYPE_BINARY,
+ definitions.Property_UID : Value.VALUETYPE_TEXT,
+ definitions.Property_URL : Value.VALUETYPE_URI,
+ definitions.Property_VERSION : Value.VALUETYPE_TEXT,
</ins><span class="cx">
</span><span class="cx"> # 2426 Section 3.7
</span><del>- definitions.Property_CLASS : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Property_KEY : PyCalendarValue.VALUETYPE_BINARY,
</del><ins>+ definitions.Property_CLASS : Value.VALUETYPE_TEXT,
+ definitions.Property_KEY : Value.VALUETYPE_BINARY,
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> sValueTypeMap = {
</span><del>- definitions.Value_BINARY : PyCalendarValue.VALUETYPE_BINARY,
- definitions.Value_BOOLEAN : PyCalendarValue.VALUETYPE_BOOLEAN,
- definitions.Value_DATE : PyCalendarValue.VALUETYPE_DATE,
- definitions.Value_DATE_TIME : PyCalendarValue.VALUETYPE_DATETIME,
- definitions.Value_FLOAT : PyCalendarValue.VALUETYPE_FLOAT,
- definitions.Value_INTEGER : PyCalendarValue.VALUETYPE_INTEGER,
- definitions.Value_TEXT : PyCalendarValue.VALUETYPE_TEXT,
- definitions.Value_TIME : PyCalendarValue.VALUETYPE_TIME,
- definitions.Value_URI : PyCalendarValue.VALUETYPE_URI,
- definitions.Value_UTCOFFSET : PyCalendarValue.VALUETYPE_UTC_OFFSET,
- definitions.Value_VCARD : PyCalendarValue.VALUETYPE_VCARD,
</del><ins>+ definitions.Value_BINARY : Value.VALUETYPE_BINARY,
+ definitions.Value_BOOLEAN : Value.VALUETYPE_BOOLEAN,
+ definitions.Value_DATE : Value.VALUETYPE_DATE,
+ definitions.Value_DATE_TIME : Value.VALUETYPE_DATETIME,
+ definitions.Value_FLOAT : Value.VALUETYPE_FLOAT,
+ definitions.Value_INTEGER : Value.VALUETYPE_INTEGER,
+ definitions.Value_TEXT : Value.VALUETYPE_TEXT,
+ definitions.Value_TIME : Value.VALUETYPE_TIME,
+ definitions.Value_URI : Value.VALUETYPE_URI,
+ definitions.Value_UTCOFFSET : Value.VALUETYPE_UTC_OFFSET,
+ definitions.Value_VCARD : Value.VALUETYPE_VCARD,
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> sTypeValueMap = {
</span><del>- PyCalendarValue.VALUETYPE_ADR : definitions.Value_TEXT,
- PyCalendarValue.VALUETYPE_BINARY : definitions.Value_BINARY,
- PyCalendarValue.VALUETYPE_BOOLEAN : definitions.Value_BOOLEAN,
- PyCalendarValue.VALUETYPE_DATE : definitions.Value_DATE,
- PyCalendarValue.VALUETYPE_DATETIME : definitions.Value_DATE_TIME,
- PyCalendarValue.VALUETYPE_FLOAT : definitions.Value_FLOAT,
- PyCalendarValue.VALUETYPE_GEO : definitions.Value_FLOAT,
- PyCalendarValue.VALUETYPE_INTEGER : definitions.Value_INTEGER,
- PyCalendarValue.VALUETYPE_N : definitions.Value_TEXT,
- PyCalendarValue.VALUETYPE_ORG : definitions.Value_TEXT,
- PyCalendarValue.VALUETYPE_TEXT : definitions.Value_TEXT,
- PyCalendarValue.VALUETYPE_TIME : definitions.Value_TIME,
- PyCalendarValue.VALUETYPE_URI : definitions.Value_URI,
- PyCalendarValue.VALUETYPE_UTC_OFFSET : definitions.Value_UTCOFFSET,
- PyCalendarValue.VALUETYPE_VCARD : definitions.Value_VCARD,
</del><ins>+ Value.VALUETYPE_ADR : definitions.Value_TEXT,
+ Value.VALUETYPE_BINARY : definitions.Value_BINARY,
+ Value.VALUETYPE_BOOLEAN : definitions.Value_BOOLEAN,
+ Value.VALUETYPE_DATE : definitions.Value_DATE,
+ Value.VALUETYPE_DATETIME : definitions.Value_DATE_TIME,
+ Value.VALUETYPE_FLOAT : definitions.Value_FLOAT,
+ Value.VALUETYPE_GEO : definitions.Value_FLOAT,
+ Value.VALUETYPE_INTEGER : definitions.Value_INTEGER,
+ Value.VALUETYPE_N : definitions.Value_TEXT,
+ Value.VALUETYPE_ORG : definitions.Value_TEXT,
+ Value.VALUETYPE_TEXT : definitions.Value_TEXT,
+ Value.VALUETYPE_TIME : definitions.Value_TIME,
+ Value.VALUETYPE_URI : definitions.Value_URI,
+ Value.VALUETYPE_UTC_OFFSET : definitions.Value_UTCOFFSET,
+ Value.VALUETYPE_VCARD : definitions.Value_VCARD,
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> sMultiValues = set((
</span><span class="lines">@@ -129,26 +125,37 @@
</span><span class="cx"> definitions.Property_CATEGORIES,
</span><span class="cx"> ))
</span><span class="cx">
</span><del>- sTextVariants = set((
- definitions.Property_ADR,
- definitions.Property_N,
- definitions.Property_ORG,
- ))
</del><ins>+ sSpecialVariants = {
+ definitions.Property_ADR : Value.VALUETYPE_ADR,
+ definitions.Property_GEO : Value.VALUETYPE_GEO,
+ definitions.Property_N: Value.VALUETYPE_N,
+ definitions.Property_ORG: Value.VALUETYPE_ORG,
+ }
</ins><span class="cx">
</span><ins>+ sUsesGroup = True
+
+ sVariant = "vcard"
+
+ sValue = definitions.Parameter_VALUE
+ sText = definitions.Value_TEXT
+
</ins><span class="cx"> def __init__(self, group=None, name=None, value=None, valuetype=None):
</span><del>- self._init_PyCalendarProperty()
</del><span class="cx">
</span><ins>+ super(Property, self).__init__(name, value, valuetype)
+
</ins><span class="cx"> self.mGroup = group
</span><span class="cx">
</span><del>- self.mName = name if name is not None else ""
</del><ins>+ # The None check speeds up .duplicate()
+ if value is None:
+ pass
</ins><span class="cx">
</span><span class="cx"> if isinstance(value, int):
</span><span class="cx"> self._init_attr_value_int(value)
</span><span class="cx">
</span><span class="cx"> elif isinstance(value, str):
</span><del>- self._init_attr_value_text(value, valuetype if valuetype else Property.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_TEXT))
</del><ins>+ self._init_attr_value_text(value, valuetype if valuetype else self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_TEXT))
</ins><span class="cx">
</span><del>- elif isinstance(value, PyCalendarDateTime):
</del><ins>+ elif isinstance(value, DateTime):
</ins><span class="cx"> self._init_attr_value_datetime(value)
</span><span class="cx">
</span><span class="cx"> elif isinstance(value, Adr):
</span><span class="lines">@@ -166,14 +173,14 @@
</span><span class="cx"> # Assume everything else is a text list
</span><span class="cx"> self._init_attr_value_text_list(value)
</span><span class="cx">
</span><del>- elif isinstance(value, PyCalendarUTCOffsetValue):
</del><ins>+ elif isinstance(value, UTCOffsetValue):
</ins><span class="cx"> self._init_attr_value_utcoffset(value)
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def duplicate(self):
</span><span class="cx"> other = Property(self.mGroup, self.mName)
</span><del>- for attrname, attrs in self.mAttributes.items():
- other.mAttributes[attrname] = [i.duplicate() for i in attrs]
</del><ins>+ for attrname, attrs in self.mParameters.items():
+ other.mParameters[attrname] = [i.duplicate() for i in attrs]
</ins><span class="cx"> other.mValue = self.mValue.duplicate()
</span><span class="cx">
</span><span class="cx"> return other
</span><span class="lines">@@ -181,16 +188,13 @@
</span><span class="cx">
</span><span class="cx"> def __hash__(self):
</span><span class="cx"> return hash((
</span><ins>+ self.mGroup,
</ins><span class="cx"> self.mName,
</span><del>- tuple([tuple(self.mAttributes[attrname]) for attrname in sorted(self.mAttributes.keys())]),
</del><ins>+ tuple([tuple(self.mParameters[attrname]) for attrname in sorted(self.mParameters.keys())]),
</ins><span class="cx"> self.mValue,
</span><span class="cx"> ))
</span><span class="cx">
</span><span class="cx">
</span><del>- def __ne__(self, other):
- return not self.__eq__(other)
-
-
</del><span class="cx"> def __eq__(self, other):
</span><span class="cx"> if not isinstance(other, Property):
</span><span class="cx"> return False
</span><span class="lines">@@ -198,89 +202,20 @@
</span><span class="cx"> self.mGroup == self.mGroup and
</span><span class="cx"> self.mName == other.mName and
</span><span class="cx"> self.mValue == other.mValue and
</span><del>- self.mAttributes == other.mAttributes
</del><ins>+ self.mParameters == other.mParameters
</ins><span class="cx"> )
</span><span class="cx">
</span><span class="cx">
</span><del>- def __repr__(self):
- return "vCard Property: %s" % (self.getText(),)
</del><ins>+ def parseTextParameters(self, txt, data):
+ """
+ Parse parameters, return string point at value.
+ """
</ins><span class="cx">
</span><del>-
- def __str__(self):
- return self.getText()
-
-
- def getGroup(self):
- return self.mGroup
-
-
- def setGroup(self, group):
- self.mGroup = group
-
-
- def getName(self):
- return self.mName
-
-
- def setName(self, name):
- self.mName = name
-
-
- def getAttributes(self):
- return self.mAttributes
-
-
- def setAttributes(self, attributes):
- self.mAttributes = dict([(k.upper(), v) for k, v in attributes.iteritems()])
-
-
- def hasAttribute(self, attr):
- return attr.upper() in self.mAttributes
-
-
- def getAttributeValue(self, attr):
- return self.mAttributes[attr.upper()][0].getFirstValue()
-
-
- def addAttribute(self, attr):
- self.mAttributes.setdefault(attr.getName().upper(), []).append(attr)
-
-
- def replaceAttribute(self, attr):
- self.mAttributes[attr.getName().upper()] = [attr]
-
-
- def removeAttributes(self, attr):
- if attr.upper() in self.mAttributes:
- del self.mAttributes[attr.upper()]
-
-
- def getValue(self):
- return self.mValue
-
-
- def parse(self, data):
- # Look for attribute or value delimiter
- prop_name, txt = stringutils.strduptokenstr(data, ";:")
- if not prop_name:
- raise PyCalendarInvalidProperty("Invalid property", data)
-
- # Check for group prefix
- splits = prop_name.split(".", 1)
- if len(splits) == 2:
- # We have both group and name
- self.mGroup = splits[0]
- self.mName = splits[1]
- else:
- # We have the name
- self.mName = prop_name
-
- # Now loop getting data
</del><span class="cx"> try:
</span><span class="cx"> stripValueSpaces = False # Fix for AB.app base PHOTO properties that use two spaces at start of line
</span><span class="cx"> while txt:
</span><span class="cx"> if txt[0] == ';':
</span><del>- # Parse attribute
</del><ins>+ # Parse parameter
</ins><span class="cx">
</span><span class="cx"> # Move past delimiter
</span><span class="cx"> txt = txt[1:]
</span><span class="lines">@@ -288,99 +223,72 @@
</span><span class="cx"> # Get quoted string or token - in iCalendar we only look for "=" here
</span><span class="cx"> # but for "broken" vCard BASE64 property we need to also terminate on
</span><span class="cx"> # ":;"
</span><del>- attribute_name, txt = stringutils.strduptokenstr(txt, "=:;")
- if attribute_name is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ parameter_name, txt = stringutils.strduptokenstr(txt, "=:;")
+ if parameter_name is None:
+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx">
</span><span class="cx"> if txt[0] != "=":
</span><span class="cx"> # Deal with parameters without values
</span><span class="cx"> if ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_RAISE:
</span><del>- raise PyCalendarInvalidProperty("Invalid property parameter", data)
</del><ins>+ raise InvalidProperty("Invalid property parameter", data)
</ins><span class="cx"> elif ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_ALLOW:
</span><del>- attribute_value = None
</del><ins>+ parameter_value = None
</ins><span class="cx"> else: # PARSER_IGNORE and PARSER_FIX
</span><del>- attribute_name = None
</del><ins>+ parameter_name = None
</ins><span class="cx">
</span><del>- if attribute_name.upper() == "BASE64" and ParserContext.VCARD_2_BASE64 == ParserContext.PARSER_FIX:
- attribute_name = definitions.Parameter_ENCODING
- attribute_value = definitions.Parameter_Value_ENCODING_B
</del><ins>+ if parameter_name.upper() == "BASE64" and ParserContext.VCARD_2_BASE64 == ParserContext.PARSER_FIX:
+ parameter_name = definitions.Parameter_ENCODING
+ parameter_value = definitions.Parameter_Value_ENCODING_B
</ins><span class="cx"> stripValueSpaces = True
</span><span class="cx"> else:
</span><span class="cx"> txt = txt[1:]
</span><del>- attribute_value, txt = stringutils.strduptokenstr(txt, ":;,")
- if attribute_value is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ parameter_value, txt = stringutils.strduptokenstr(txt, ":;,")
+ if parameter_value is None:
+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx">
</span><del>- # Now add attribute value (decode ^-escaping)
- if attribute_name is not None:
- attrvalue = PyCalendarAttribute(name=attribute_name, value=decodeParameterValue(attribute_value))
- self.mAttributes.setdefault(attribute_name.upper(), []).append(attrvalue)
</del><ins>+ # Now add parameter value (decode ^-escaping)
+ if parameter_name is not None:
+ attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value))
+ self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue)
</ins><span class="cx">
</span><span class="cx"> # Look for additional values
</span><span class="cx"> while txt[0] == ',':
</span><span class="cx"> txt = txt[1:]
</span><del>- attribute_value2, txt = stringutils.strduptokenstr(txt, ":;,")
- if attribute_value2 is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
- attrvalue.addValue(decodeParameterValue(attribute_value2))
</del><ins>+ parameter_value2, txt = stringutils.strduptokenstr(txt, ":;,")
+ if parameter_value2 is None:
+ raise InvalidProperty("Invalid property", data)
+ attrvalue.addValue(decodeParameterValue(parameter_value2))
</ins><span class="cx"> elif txt[0] == ':':
</span><span class="cx"> txt = txt[1:]
</span><span class="cx"> if stripValueSpaces:
</span><span class="cx"> txt = txt.replace(" ", "")
</span><del>- self.createValue(txt)
- txt = None
</del><ins>+ return txt
</ins><span class="cx">
</span><span class="cx"> except IndexError:
</span><del>- raise PyCalendarInvalidProperty("Invalid property", data)
</del><ins>+ raise InvalidProperty("Invalid property", data)
</ins><span class="cx">
</span><del>- # We must have a value of some kind
- if self.mValue is None:
- raise PyCalendarInvalidProperty("Invalid property", data)
</del><span class="cx">
</span><del>- return True
-
-
- def getText(self):
- os = StringIO.StringIO()
- self.generate(os)
- return os.getvalue()
-
-
- def generate(self, os):
-
- # Write it out always with value
- self.generateValue(os, False)
-
-
- def generateFiltered(self, os, filter):
-
- # Check for property in filter and whether value is written out
- test, novalue = filter.testPropertyValue(self.mName.upper())
- if test:
- self.generateValue(os, novalue)
-
-
</del><span class="cx"> # Write out the actual property, possibly skipping the value
</span><span class="cx"> def generateValue(self, os, novalue):
</span><span class="cx">
</span><del>- self.setupValueAttribute()
</del><ins>+ # Special case AB.app PHOTO values
+ if self.mName.upper() == "PHOTO" and self.mValue.getType() == Value.VALUETYPE_BINARY:
+ self.setupValueParameter()
</ins><span class="cx">
</span><del>- # Must write to temp buffer and then wrap
- sout = StringIO.StringIO()
- if self.mGroup:
- sout.write(self.mGroup + ".")
- sout.write(self.mName)
</del><ins>+ # Must write to temp buffer and then wrap
+ sout = StringIO.StringIO()
+ if self.mGroup:
+ sout.write(self.mGroup + ".")
+ sout.write(self.mName)
</ins><span class="cx">
</span><del>- # Write all attributes
- for key in sorted(self.mAttributes.keys()):
- for attr in self.mAttributes[key]:
- sout.write(";")
- attr.generate(sout)
</del><ins>+ # Write all parameters
+ for key in sorted(self.mParameters.keys()):
+ for attr in self.mParameters[key]:
+ sout.write(";")
+ attr.generate(sout)
</ins><span class="cx">
</span><del>- # Write value
- sout.write(":")
- if self.mName.upper() == "PHOTO" and self.mValue.getType() == PyCalendarValue.VALUETYPE_BINARY:
- # Handle AB.app PHOTO values
</del><ins>+ # Write value
+ sout.write(":")
</ins><span class="cx"> sout.write("\r\n")
</span><span class="cx">
</span><span class="cx"> value = self.mValue.getText()
</span><span class="lines">@@ -395,179 +303,31 @@
</span><span class="cx"> sout.write(" ")
</span><span class="cx"> sout.write(value[offset:])
</span><span class="cx"> os.write(sout.getvalue())
</span><ins>+ os.write("\r\n")
</ins><span class="cx"> else:
</span><del>- if self.mValue and not novalue:
- self.mValue.generate(sout)
</del><ins>+ super(Property, self).generateValue(os, novalue)
</ins><span class="cx">
</span><del>- # Get string text
- temp = sout.getvalue()
- sout.close()
</del><span class="cx">
</span><del>- # Look for line length exceed
- if len(temp) < 75:
- os.write(temp)
- else:
- # Look for valid utf8 range and write that out
- start = 0
- written = 0
- lineWrap = 74
- while written < len(temp):
- # Start 74 chars on from where we are
- offset = start + lineWrap
- if offset >= len(temp):
- line = temp[start:]
- os.write(line)
- written = len(temp)
- else:
- # Check whether next char is valid utf8 lead byte
- while (temp[offset] > 0x7F) and ((ord(temp[offset]) & 0xC0) == 0x80):
- # Step back until we have a valid char
- offset -= 1
-
- line = temp[start:offset]
- os.write(line)
- os.write("\r\n ")
- lineWrap = 73 # We are now adding a space at the start
- written += offset - start
- start = offset
-
- os.write("\r\n")
-
-
- def _init_PyCalendarProperty(self):
- self.mGroup = None
- self.mName = ""
- self.mAttributes = {}
- self.mValue = None
-
-
- def createValue(self, data):
- # Tidy first
- self.mValue = None
-
- # Get value type from property name
- valueType = Property.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_TEXT)
-
- # Check whether custom value is set
- if definitions.Parameter_VALUE in self.mAttributes:
- attr = self.getAttributeValue(definitions.Parameter_VALUE)
- if attr != definitions.Value_TEXT or self.mName.upper() not in Property.sTextVariants:
- valueType = Property.sValueTypeMap.get(attr, valueType)
-
- # Check for multivalued
- if self.mName.upper() in Property.sMultiValues:
- self.mValue = PyCalendarMultiValue(valueType)
- else:
- # Create the type
- self.mValue = PyCalendarValue.createFromType(valueType)
-
- # Now parse the data
- try:
- if valueType in (PyCalendarValue.VALUETYPE_DATE, PyCalendarValue.VALUETYPE_DATETIME):
- # vCard supports a slightly different, expanded form, of date
- self.mValue.parse(data, fullISO=True)
- else:
- self.mValue.parse(data)
- except ValueError:
- raise PyCalendarInvalidProperty("Invalid property value", data)
-
-
- def setValue(self, value):
- # Tidy first
- self.mValue = None
-
- # Get value type from property name
- valueType = Property.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarUnknownValue)
-
- # Check whether custom value is set
- if definitions.Parameter_VALUE in self.mAttributes:
- attr = self.getAttributeValue(definitions.Parameter_VALUE)
- if attr != definitions.Value_TEXT or self.mName.upper() not in Property.sTextVariants:
- valueType = Property.sValueTypeMap.get(attr, valueType)
-
- # Check for multivalued
- if self.mName.upper() in Property.sMultiValues:
- self.mValue = PyCalendarMultiValue(valueType)
- else:
- # Create the type
- self.mValue = PyCalendarValue.createFromType(valueType)
-
- self.mValue.setValue(value)
-
-
- def setupValueAttribute(self):
- if definitions.Parameter_VALUE in self.mAttributes:
- del self.mAttributes[definitions.Parameter_VALUE]
-
- # Only if we have a value right now
- if self.mValue is None:
- return
-
- # See if current type is default for this property. If there is no mapping available,
- # then always add VALUE if it is not TEXT.
- default_type = Property.sDefaultValueTypeMap.get(self.mName.upper())
- actual_type = self.mValue.getType()
- if default_type is None or default_type != actual_type:
- actual_value = self.sTypeValueMap.get(actual_type)
- if actual_value is not None and (default_type is not None or actual_type != PyCalendarValue.VALUETYPE_TEXT):
- self.mAttributes.setdefault(definitions.Parameter_VALUE, []).append(PyCalendarAttribute(name=definitions.Parameter_VALUE, value=actual_value))
-
-
</del><span class="cx"> # Creation
</span><del>- def _init_attr_value_int(self, ival):
- # Value
- self.mValue = PyCalendarIntegerValue(value=ival)
-
- # Attributes
- self.setupValueAttribute()
-
-
- def _init_attr_value_text(self, txt, value_type):
- # Value
- self.mValue = PyCalendarValue.createFromType(value_type)
- if isinstance(self.mValue, PyCalendarPlainTextValue) or isinstance(self.mValue, PyCalendarUnknownValue):
- self.mValue.setValue(txt)
-
- # Attributes
- self.setupValueAttribute()
-
-
</del><span class="cx"> def _init_attr_value_adr(self, reqstatus):
</span><span class="cx"> # Value
</span><span class="cx"> self.mValue = AdrValue(reqstatus)
</span><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def _init_attr_value_n(self, reqstatus):
</span><span class="cx"> # Value
</span><span class="cx"> self.mValue = NValue(reqstatus)
</span><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def _init_attr_value_org(self, reqstatus):
</span><span class="cx"> # Value
</span><span class="cx"> self.mValue = OrgValue(reqstatus)
</span><span class="cx">
</span><del>- # Attributes
- self.setupValueAttribute()
-
-
- def _init_attr_value_datetime(self, dt):
- # Value
- self.mValue = PyCalendarDateTimeValue(value=dt)
-
- # Attributes
- self.setupValueAttribute()
-
-
- def _init_attr_value_utcoffset(self, utcoffset):
- # Value
- self.mValue = PyCalendarUTCOffsetValue()
- self.mValue.setValue(utcoffset.getValue())
-
- # Attributes
- self.setupValueAttribute()
</del><ins>+ # Parameters
+ self.setupValueParameter()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardtests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_adrpyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_adrpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_adr.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.vcard.adr import Adr
+import unittest
+
+class TestAdrValue(unittest.TestCase):
+
+ def testInit(self):
+ data = (
+ (
+ ("pobox", "extended", "street", "locality", "region", "postalcode", "country"),
+ "pobox;extended;street;locality;region;postalcode;country",
+ ),
+ (
+ (("pobox",), ("extended",), ("street1", "street2",), "locality", "region", (), "country"),
+ "pobox;extended;street1,street2;locality;region;;country",
+ ),
+ )
+
+ for args, result in data:
+ a = Adr(*args)
+
+ self.assertEqual(
+ a.getValue(),
+ args,
+ )
+
+ self.assertEqual(
+ a.getText(),
+ result,
+ )
+
+ self.assertEqual(
+ a.duplicate().getText(),
+ result,
+ )
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_adrvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_adrvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_adrvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.vcard.adrvalue import AdrValue
+from pycalendar.vcard.property import Property
+import unittest
+
+class TestAdrValue(unittest.TestCase):
+
+ def testParseValue(self):
+
+ items = (
+ ("", ";;;;;;"),
+ (";", ";;;;;;"),
+ (";;;;;;", ";;;;;;"),
+ (";;123 Main Street;Any Town;CA;91921-1234", ";;123 Main Street;Any Town;CA;91921-1234;"),
+ (";;;;;;USA", ";;;;;;USA"),
+ ("POB1", "POB1;;;;;;"),
+ (";EXT", ";EXT;;;;;"),
+ (";;123 Main Street,The Cards;Any Town;CA;91921-1234", ";;123 Main Street,The Cards;Any Town;CA;91921-1234;"),
+ (";;123 Main\, Street,The Cards;Any Town;CA;91921-1234", ";;123 Main\, Street,The Cards;Any Town;CA;91921-1234;"),
+ (";;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234", ";;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234;"),
+ )
+
+ for item, result in items:
+ req = AdrValue()
+ req.parse(item, "vcard")
+ test = req.getText()
+ self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
+
+
+ def testParseProperty(self):
+
+ items = (
+ ("ADR:", "ADR:;;;;;;"),
+ ("ADR:;", "ADR:;;;;;;"),
+ ("ADR:;;;;;;", "ADR:;;;;;;"),
+ ("ADR:;;123 Main Street;Any Town;CA;91921-1234", "ADR:;;123 Main Street;Any Town;CA;91921-1234;"),
+ ("ADR:;;;;;;USA", "ADR:;;;;;;USA"),
+ ("ADR:POB1", "ADR:POB1;;;;;;"),
+ ("ADR:;EXT", "ADR:;EXT;;;;;"),
+ ("ADR;VALUE=TEXT:;;123 Main Street;Any Town;CA;91921-1234", "ADR:;;123 Main Street;Any Town;CA;91921-1234;"),
+ )
+
+ for item, result in items:
+ prop = Property.parseText(item)
+ test = prop.getText()
+ self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_cardpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.exceptions import PyCalendarInvalidData
</del><ins>+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> from pycalendar.vcard.property import Property
</span><span class="lines">@@ -343,7 +343,7 @@
</span><span class="cx">
</span><span class="cx"> for item, results in data:
</span><span class="cx">
</span><del>- cards = Card.parseMultiple(StringIO.StringIO(item))
</del><ins>+ cards = Card.parseMultipleTextData(StringIO.StringIO(item))
</ins><span class="cx"> self.assertEqual(len(cards), len(results))
</span><span class="cx"> for card, result in zip(cards, results):
</span><span class="cx"> self.assertEqual(str(card), result, "\n".join(difflib.unified_diff(str(card).splitlines(), result.splitlines())))
</span><span class="lines">@@ -383,7 +383,7 @@
</span><span class="cx"> REV:20110323T202004Z
</span><span class="cx"> TEL;type=WORK;type=pref:555-1212
</span><span class="cx"> TEL;type=HOME:532-1234
</span><del>-X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43:ABPerson
</del><ins>+X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43\:ABPerson
</ins><span class="cx"> END:VCARD
</span><span class="cx"> """.replace("\n", "\r\n")
</span><span class="cx">
</span><span class="lines">@@ -473,7 +473,7 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for item in data:
</span><del>- self.assertRaises(PyCalendarInvalidData, Card.parseText, item)
</del><ins>+ self.assertRaises(InvalidData, Card.parseText, item)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def testParseBlank(self):
</span><span class="lines">@@ -561,7 +561,7 @@
</span><span class="cx"> save = ParserContext.BLANK_LINES_IN_DATA
</span><span class="cx"> for item in data:
</span><span class="cx"> ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_RAISE
</span><del>- self.assertRaises(PyCalendarInvalidData, Card.parseText, item)
</del><ins>+ self.assertRaises(InvalidData, Card.parseText, item)
</ins><span class="cx">
</span><span class="cx"> ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_IGNORE
</span><span class="cx"> lines = item.split("\r\n")
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_npyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_npy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_n.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.vcard.n import N
+import unittest
+
+class TestAdrValue(unittest.TestCase):
+
+ def testInit(self):
+
+ data = (
+ (
+ ("last", "first", "middle", "prefix", "suffix"),
+ "last;first;middle;prefix;suffix",
+ "prefix first middle last suffix",
+ ),
+ (
+ ("last", ("first",), ("middle1", "middle2",), (), ("suffix",)),
+ "last;first;middle1,middle2;;suffix",
+ "first middle1 middle2 last suffix",
+ ),
+ )
+
+ for args, result, fullName in data:
+ n = N(*args)
+
+ self.assertEqual(
+ n.getValue(),
+ args,
+ )
+
+ self.assertEqual(
+ n.getText(),
+ result,
+ )
+
+ self.assertEqual(
+ n.getFullName(),
+ fullName,
+ )
+
+ self.assertEqual(
+ n.duplicate().getText(),
+ result,
+ )
+
+
+ def testInitWithKeywords(self):
+
+ data = (
+ (
+ {"first": "first", "last": "last", "middle": "middle", "prefix": "prefix", "suffix": "suffix"},
+ "last;first;middle;prefix;suffix",
+ "prefix first middle last suffix",
+ ),
+ (
+ {"first": ("first",), "last": "last", "middle": ("middle1", "middle2",), "prefix": (), "suffix": ("suffix",)},
+ "last;first;middle1,middle2;;suffix",
+ "first middle1 middle2 last suffix",
+ ),
+ )
+
+ for kwargs, result, fullName in data:
+ n = N(**kwargs)
+
+ self.assertEqual(
+ n.getText(),
+ result,
+ )
+
+ self.assertEqual(
+ n.getFullName(),
+ fullName,
+ )
+
+ self.assertEqual(
+ n.duplicate().getText(),
+ result,
+ )
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_nvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_nvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_nvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.vcard.nvalue import NValue
+from pycalendar.vcard.property import Property
+import unittest
+
+class TestNValue(unittest.TestCase):
+
+ def testParseValue(self):
+
+ items = (
+ ("", ";;;;"),
+ (";", ";;;;"),
+ (";;;;", ";;;;"),
+ ("Cyrus;Daboo;;Dr.", "Cyrus;Daboo;;Dr.;"),
+ (";;;;PhD.", ";;;;PhD."),
+ ("Cyrus", "Cyrus;;;;"),
+ (";Daboo", ";Daboo;;;"),
+ )
+
+ for item, result in items:
+ req = NValue()
+ req.parse(item, "vcard")
+ test = req.getText()
+ self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
+
+
+ def testParseProperty(self):
+
+ items = (
+ ("N:", "N:;;;;"),
+ ("N:;", "N:;;;;"),
+ ("N:;;;;", "N:;;;;"),
+ ("N:Cyrus;Daboo;;Dr.", "N:Cyrus;Daboo;;Dr.;"),
+ ("N:;;;;PhD.", "N:;;;;PhD."),
+ ("N:Cyrus", "N:Cyrus;;;;"),
+ ("N:;Daboo", "N:;Daboo;;;"),
+ ("N;VALUE=TEXT:Cyrus;Daboo;;Dr.", "N:Cyrus;Daboo;;Dr.;"),
+ )
+
+ for item, result in items:
+ prop = Property.parseText(item)
+ test = prop.getText()
+ self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_orgvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_orgvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_orgvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+##
+# Copyright (c) 2011-2013 Cyrus Daboo. 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 pycalendar.vcard.orgvalue import OrgValue
+from pycalendar.vcard.property import Property
+import unittest
+
+class TestNValue(unittest.TestCase):
+
+ def testParseValue(self):
+
+ items = (
+ ("", ""),
+ ("Example", "Example"),
+ ("Example\, Inc.", "Example\, Inc."),
+ ("Example\; Inc;Dept. of Silly Walks", "Example\; Inc;Dept. of Silly Walks"),
+ )
+
+ for item, result in items:
+ req = OrgValue()
+ req.parse(item, "vcard")
+ test = req.getText()
+ self.assertEqual(test, result, "Failed to parse and re-generate '%s'" % (item,))
+
+
+ def testParseProperty(self):
+
+ items = (
+ ("ORG:", "ORG:"),
+ ("ORG:Example", "ORG:Example"),
+ ("ORG:Example\, Inc.", "ORG:Example\, Inc."),
+ ("ORG:Example\; Inc;Dept. of Silly Walks", "ORG:Example\; Inc;Dept. of Silly Walks"),
+ ("ORG;VALUE=TEXT:Example", "ORG:Example"),
+ )
+
+ for item, result in items:
+ prop = Property.parseText(item)
+ test = prop.getText()
+ self.assertEqual(test, result + "\r\n", "Failed to parse and re-generate '%s'" % (item,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_propertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,8 +14,8 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.exceptions import PyCalendarInvalidProperty
</del><ins>+from pycalendar.parameter import Parameter
+from pycalendar.exceptions import InvalidProperty
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.vcard.property import Property
</span><span class="cx"> import unittest
</span><span class="lines">@@ -34,13 +34,14 @@
</span><span class="cx"> "item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;CA;11111;USA",
</span><span class="cx"> "X-Test:Some\, text.",
</span><span class="cx"> "X-Test;VALUE=URI:geio:123.123,123.123",
</span><ins>+ "X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43\\:ABPerson",
+ "X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43:ABPerson",
</ins><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> def testParseGenerate(self):
</span><span class="cx">
</span><span class="cx"> for data in TestProperty.test_data:
</span><del>- prop = Property()
- prop.parse(data)
</del><ins>+ prop = Property.parseText(data)
</ins><span class="cx"> propstr = str(prop)
</span><span class="cx"> self.assertEqual(propstr[:-2], data, "Failed parse/generate: %s to %s" % (data, propstr,))
</span><span class="cx">
</span><span class="lines">@@ -48,10 +49,8 @@
</span><span class="cx"> def testEquality(self):
</span><span class="cx">
</span><span class="cx"> for data in TestProperty.test_data:
</span><del>- prop1 = Property()
- prop1.parse(data)
- prop2 = Property()
- prop2.parse(data)
</del><ins>+ prop1 = Property.parseText(data)
+ prop2 = Property.parseText(data)
</ins><span class="cx"> self.assertEqual(prop1, prop2, "Failed equality: %s" % (data,))
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -64,8 +63,7 @@
</span><span class="cx"> save = ParserContext.INVALID_ESCAPE_SEQUENCES
</span><span class="cx"> for data in test_bad_data:
</span><span class="cx"> ParserContext.INVALID_ESCAPE_SEQUENCES = ParserContext.PARSER_RAISE
</span><del>- prop = Property()
- self.assertRaises(PyCalendarInvalidProperty, prop.parse, data)
</del><ins>+ self.assertRaises(InvalidProperty, Property.parseText, data)
</ins><span class="cx"> ParserContext.INVALID_ESCAPE_SEQUENCES = save
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -73,8 +71,7 @@
</span><span class="cx">
</span><span class="cx"> hashes = []
</span><span class="cx"> for item in TestProperty.test_data:
</span><del>- prop = Property()
- prop.parse(item)
</del><ins>+ prop = Property.parseText(item)
</ins><span class="cx"> hashes.append(hash(prop))
</span><span class="cx"> hashes.sort()
</span><span class="cx"> for i in range(1, len(hashes)):
</span><span class="lines">@@ -98,19 +95,17 @@
</span><span class="cx"> def testParameterEncodingDecoding(self):
</span><span class="cx">
</span><span class="cx"> prop = Property(name="X-FOO", value="Test")
</span><del>- prop.addAttribute(PyCalendarAttribute("X-BAR", "\"Check\""))
</del><ins>+ prop.addParameter(Parameter("X-BAR", "\"Check\""))
</ins><span class="cx"> self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^':Test\r\n")
</span><span class="cx">
</span><del>- prop.addAttribute(PyCalendarAttribute("X-BAR2", "Check\nThis\tOut\n"))
</del><ins>+ prop.addParameter(Parameter("X-BAR2", "Check\nThis\tOut\n"))
</ins><span class="cx"> self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n")
</span><span class="cx">
</span><span class="cx"> data = "X-FOO;X-BAR=^'Check^':Test"
</span><del>- prop = Property()
- prop.parse(data)
- self.assertEqual(prop.getAttributeValue("X-BAR"), "\"Check\"")
</del><ins>+ prop = Property.parseText(data)
+ self.assertEqual(prop.getParameterValue("X-BAR"), "\"Check\"")
</ins><span class="cx">
</span><span class="cx"> data = "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test"
</span><del>- prop = Property()
- prop.parse(data)
- self.assertEqual(prop.getAttributeValue("X-BAR"), "\"Check\"")
- self.assertEqual(prop.getAttributeValue("X-BAR2"), "Check\nThis\tOut\n")
</del><ins>+ prop = Property.parseText(data)
+ self.assertEqual(prop.getParameterValue("X-BAR"), "\"Check\"")
+ self.assertEqual(prop.getParameterValue("X-BAR2"), "Check\nThis\tOut\n")
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_validationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.exceptions import PyCalendarValidationError
</del><ins>+from pycalendar.exceptions import ValidationError
</ins><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> import unittest
</span><span class="cx">
</span><span class="lines">@@ -210,7 +210,7 @@
</span><span class="cx"> for title, test_old, test_new, test_fixed, test_unfixed, test_raises in data:
</span><span class="cx"> card = Card.parseText(test_old)
</span><span class="cx"> if test_raises:
</span><del>- self.assertRaises(PyCalendarValidationError, card.validate, doFix=False, doRaise=True)
</del><ins>+ self.assertRaises(ValidationError, card.validate, doFix=False, doRaise=True)
</ins><span class="cx"> else:
</span><span class="cx"> try:
</span><span class="cx"> fixed, unfixed = card.validate(doFix=False, doRaise=False)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardvalidationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2011-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardxmldefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardxmldefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/xmldefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# vCard XML definitions
+
+vCard40_namespace = "urn:ietf:params:xml:ns:vcard-4.0"
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarveventpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vevent.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vevent.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vevent.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,169 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import itipdefinitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.property import PyCalendarProperty
-
-class PyCalendarVEvent(PyCalendarComponentRecur):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTAMP,
- definitions.cICalProperty_UID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_CLASS,
- definitions.cICalProperty_CREATED,
- definitions.cICalProperty_DESCRIPTION,
- definitions.cICalProperty_GEO,
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_LOCATION,
- definitions.cICalProperty_ORGANIZER,
- definitions.cICalProperty_PRIORITY,
- definitions.cICalProperty_SEQUENCE,
- # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
- definitions.cICalProperty_SUMMARY,
- definitions.cICalProperty_TRANSP,
- definitions.cICalProperty_URL,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_RRULE,
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_DURATION,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
- super(PyCalendarVEvent, self).__init__(parent=parent)
- self.mStatus = definitions.eStatus_VEvent_None
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarVEvent, self).duplicate(parent=parent)
- other.mStatus = self.mStatus
- return other
-
-
- def getType(self):
- return definitions.cICalComponent_VEVENT
-
-
- def getMimeComponentName(self):
- return itipdefinitions.cICalMIMEComponent_VEVENT
-
-
- def addComponent(self, comp):
- # We can embed the alarm components only
- if comp.getType() == definitions.cICalComponent_VALARM:
- super(PyCalendarVEvent, self).addComponent(comp)
- else:
- raise ValueError
-
-
- def getStatus(self):
- return self.mStatus
-
-
- def setStatus(self, status):
- self.mStatus = status
-
-
- def finalise(self):
- # Do inherited
- super(PyCalendarVEvent, self).finalise()
-
- temp = self.loadValueString(definitions.cICalProperty_STATUS)
- if temp is not None:
- if temp == definitions.cICalProperty_STATUS_TENTATIVE:
- self.mStatus = definitions.eStatus_VEvent_Tentative
- elif temp == definitions.cICalProperty_STATUS_CONFIRMED:
- self.mStatus = definitions.eStatus_VEvent_Confirmed
- elif temp == definitions.cICalProperty_STATUS_CANCELLED:
- self.mStatus = definitions.eStatus_VEvent_Cancelled
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems, else raise. If
- loggedProblems is not None it must be a C{list} and problem descriptions are appended
- to that.
- """
-
- fixed, unfixed = super(PyCalendarVEvent, self).validate(doFix)
-
- # Extra constraint: if METHOD not present, DTSTART must be
- if self.mParentComponent and not self.mParentComponent.hasProperty(definitions.cICalProperty_METHOD):
- if not self.hasProperty(definitions.cICalProperty_DTSTART):
- # Cannot fix a missing required property
- logProblem = "[%s] Missing required property: %s" % (self.getType(), definitions.cICalProperty_DTSTART,)
- unfixed.append(logProblem)
-
- # Extra constraint: only one of DTEND or DURATION
- if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
- # Fix by removing the DTEND
- logProblem = "[%s] Properties must not both be present: %s, %s" % (
- self.getType(),
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_DURATION,
- )
- if doFix:
- self.removeProperties(definitions.cICalProperty_DTEND)
- fixed.append(logProblem)
- else:
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- # Editing
- def editStatus(self, status):
- # Only if it is different
- if self.mStatus != status:
- # Updated cached values
- self.mStatus = status
-
- # Remove existing STATUS items
- self.removeProperties(definitions.cICalProperty_STATUS)
-
- # Now create properties
- value = None
- if status == definitions.eStatus_VEvent_None:
- pass
- elif status == definitions.eStatus_VEvent_Tentative:
- value = definitions.cICalProperty_STATUS_TENTATIVE
- elif status == definitions.eStatus_VEvent_Confirmed:
- value = definitions.cICalProperty_STATUS_CONFIRMED
- elif status == definitions.eStatus_VEvent_Cancelled:
- value = definitions.cICalProperty_STATUS_CANCELLED
- else:
- pass
-
- if value is not None:
- prop = PyCalendarProperty(definitions.cICalProperty_STATUS, value)
- self.addProperty(prop)
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_DTEND,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvfreebusypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vfreebusy.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vfreebusy.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vfreebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,345 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import itipdefinitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.freebusy import PyCalendarFreeBusy
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.periodvalue import PyCalendarPeriodValue
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarVFreeBusy(PyCalendarComponent):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTAMP,
- definitions.cICalProperty_UID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_CONTACT,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DTEND,
- definitions.cICalProperty_ORGANIZER,
- definitions.cICalProperty_URL,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
- super(PyCalendarVFreeBusy, self).__init__(parent=parent)
- self.mStart = PyCalendarDateTime()
- self.mHasStart = False
- self.mEnd = PyCalendarDateTime()
- self.mHasEnd = False
- self.mDuration = False
- self.mCachedBusyTime = False
- self.mSpanPeriod = None
- self.mBusyTime = None
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarVFreeBusy, self).duplicate(parent=parent)
- other.mStart = self.mStart.duplicate()
- other.mHasStart = self.mHasStart
- other.mEnd = self.mEnd.duplicate()
- other.mHasEnd = self.mHasEnd
- other.mDuration = self.mDuration
- other.mCachedBusyTime = False
- other.mBusyTime = None
- return other
-
-
- def getType(self):
- return definitions.cICalComponent_VFREEBUSY
-
-
- def getMimeComponentName(self):
- return itipdefinitions.cICalMIMEComponent_VFREEBUSY
-
-
- def finalise(self):
- # Do inherited
- super(PyCalendarVFreeBusy, self).finalise()
-
- # Get DTSTART
- temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
- self.mHasStart = temp is not None
- if self.mHasStart:
- self.mStart = temp
-
- # Get DTEND
- temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
- if temp is None:
- # Try DURATION instead
- temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
- if temp is not None:
- self.mEnd = self.mStart + temp
- self.mDuration = True
- else:
- # Force end to start, which will then be fixed to sensible
- # value later
- self.mEnd = self.mStart
- else:
- self.mHasEnd = True
- self.mDuration = False
- self.mEnd = temp
-
-
- def fixStartEnd(self):
- # End is always greater than start if start exists
- if self.mHasStart and self.mEnd <= self.mStart:
- # Use the start
- self.mEnd = self.mStart.duplicate()
- self.mDuration = False
-
- # Adjust to appropiate non-inclusive end point
- if self.mStart.isDateOnly():
- self.mEnd.offsetDay(1)
-
- # For all day events it makes sense to use duration
- self.mDuration = True
- else:
- # Use end of current day
- self.mEnd.offsetDay(1)
- self.mEnd.setHHMMSS(0, 0, 0)
-
-
- def getStart(self):
- return self.mStart
-
-
- def hasStart(self):
- return self.mHasStart
-
-
- def getEnd(self):
- return self.mEnd
-
-
- def hasEnd(self):
- return self.mHasEnd
-
-
- def useDuration(self):
- return self.mDuration
-
-
- def getSpanPeriod(self):
- return self.mSpanPeriod
-
-
- def getBusyTime(self):
- return self.mBusyTime
-
-
- def editTiming(self):
- # Updated cached values
- self.mHasStart = False
- self.mHasEnd = False
- self.mDuration = False
- self.mStart.setToday()
- self.mEnd.setToday()
-
- # Remove existing DTSTART & DTEND & DURATION & DUE items
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
-
-
- def editTimingStartEnd(self, start, end):
- # Updated cached values
- self.mHasStart = self.mHasEnd = True
- self.mStart = start
- self.mEnd = end
- self.mDuration = False
- self.fixStartEnd()
-
- # Remove existing DTSTART & DTEND & DURATION & DUE items
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
-
- # Now create properties
- prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
- self.addProperty(prop)
-
- # If its an all day event and the end one day after the start, ignore it
- temp = start.duplicate()
- temp.offsetDay(1)
- if not start.isDateOnly() or end != temp:
- prop = PyCalendarProperty(definitions.cICalProperty_DTEND, end)
- self.addProperty(prop)
-
-
- def editTimingStartDuration(self, start, duration):
- # Updated cached values
- self.mHasStart = True
- self.mHasEnd = False
- self.mStart = start
- self.mEnd = start + duration
- self.mDuration = True
-
- # Remove existing DTSTART & DTEND & DURATION & DUE items
- self.removeProperties(definitions.cICalProperty_DTSTART)
- self.removeProperties(definitions.cICalProperty_DTEND)
- self.removeProperties(definitions.cICalProperty_DURATION)
- self.removeProperties(definitions.cICalProperty_DUE)
-
- # Now create properties
- prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
- self.addProperty(prop)
-
- # If its an all day event and the duration is one day, ignore it
- if (not start.isDateOnly() or (duration.getWeeks() != 0)
- or (duration.getDays() > 1)):
- prop = PyCalendarProperty(definitions.cICalProperty_DURATION, duration)
- self.addProperty(prop)
-
-
- # Generating info
- def expandPeriodComp(self, period, list):
- # Cache the busy-time details if not done already
- if not self.mCachedBusyTime:
- self.cacheBusyTime()
-
- # See if period intersects the busy time span range
- if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
- list.append(self)
-
-
- def expandPeriodFB(self, period, list):
- # Cache the busy-time details if not done already
- if not self.mCachedBusyTime:
- self.cacheBusyTime()
-
- # See if period intersects the busy time span range
- if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
- for fb in self.mBusyTime:
- list.append(PyCalendarFreeBusy(fb))
-
-
- def cacheBusyTime(self):
-
- # Clear out any existing cache
- self.mBusyTime = []
-
- # Get all FREEBUSY items and add those that are BUSY
- min_start = PyCalendarDateTime()
- max_end = PyCalendarDateTime()
- props = self.getProperties()
- result = props.get(definitions.cICalProperty_FREEBUSY, ())
- for iter in result:
-
- # Check the properties FBTYPE attribute
- type = 0
- is_busy = False
- if iter.hasAttribute(definitions.cICalAttribute_FBTYPE):
-
- fbyype = iter.getAttributeValue(definitions.cICalAttribute_FBTYPE)
- if fbyype.upper() == definitions.cICalAttribute_FBTYPE_BUSY:
-
- is_busy = True
- type = PyCalendarFreeBusy.BUSY
-
- elif fbyype.upper() == definitions.cICalAttribute_FBTYPE_BUSYUNAVAILABLE:
-
- is_busy = True
- type = PyCalendarFreeBusy.BUSYUNAVAILABLE
-
- elif fbyype.upper() == definitions.cICalAttribute_FBTYPE_BUSYTENTATIVE:
-
- is_busy = True
- type = PyCalendarFreeBusy.BUSYTENTATIVE
-
- else:
-
- is_busy = False
- type = PyCalendarFreeBusy.FREE
-
- else:
-
- # Default is busy when no attribute
- is_busy = True
- type = PyCalendarFreeBusy.BUSY
-
- # Add this period
- if is_busy:
-
- multi = iter.getMultiValue()
- if (multi is not None) and (multi.getType() == PyCalendarValue.VALUETYPE_PERIOD):
-
- for o in multi.getValues():
-
- # Double-check type
- period = None
- if isinstance(o, PyCalendarPeriodValue):
- period = o
-
- # Double-check type
- if period is not None:
-
- self.mBusyTime.append(PyCalendarFreeBusy(type, period.getValue()))
-
- if len(self.mBusyTime) == 1:
-
- min_start = period.getValue().getStart()
- max_end = period.getValue().getEnd()
-
- else:
-
- if min_start > period.getValue().getStart():
- min_start = period.getValue().getStart()
- if max_end < period.getValue().getEnd():
- max_end = period.getValue().getEnd()
-
- # If nothing present, empty the list
- if len(self.mBusyTime) == 0:
-
- self.mBusyTime = None
-
- else:
-
- # Sort the list by period
- self.mBusyTime.sort(cmp=lambda x, y: x.getPeriod().getStart().compareDateTime(y.getPeriod().getStart()))
-
- # Determine range
- start = PyCalendarDateTime()
- end = PyCalendarDateTime()
- if self.mHasStart:
- start = self.mStart
- else:
- start = min_start
- if self.mHasEnd:
- end = self.mEnd
- else:
- end = max_end
-
- self.mSpanPeriod = PyCalendarPeriod(start, end)
-
- self.mCachedBusyTime = True
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_DTEND,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvjournalpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vjournal.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vjournal.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vjournal.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,70 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import itipdefinitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarVJournal(PyCalendarComponentRecur):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTAMP,
- definitions.cICalProperty_UID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_CLASS,
- definitions.cICalProperty_CREATED,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_ORGANIZER,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_SEQUENCE,
- # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
- definitions.cICalProperty_SUMMARY,
- definitions.cICalProperty_URL,
- definitions.cICalProperty_RRULE,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
- super(PyCalendarVJournal, self).__init__(parent=parent)
-
-
- def duplicate(self, parent=None):
- return super(PyCalendarVJournal, self).duplicate(parent=parent)
-
-
- def getType(self):
- return definitions.cICalComponent_VJOURNAL
-
-
- def getMimeComponentName(self):
- return itipdefinitions.cICalMIMEComponent_VJOURNAL
-
-
- def finalise(self):
- super(PyCalendarVJournal, self).finalise()
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_DTSTART,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezonepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,285 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarVTimezone(PyCalendarComponent):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_TZID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_TZURL,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- UTCOFFSET_CACHE_MAX_ENTRIES = 100000
-
- sortSubComponents = False
-
- def __init__(self, parent=None):
- super(PyCalendarVTimezone, self).__init__(parent=parent)
- self.mID = ""
- self.mUTCOffsetSortKey = None
- self.mCachedExpandAllMaxYear = None
- self.mCachedOffsets = None
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarVTimezone, self).duplicate(parent=parent)
- other.mID = self.mID
- other.mUTCOffsetSortKey = self.mUTCOffsetSortKey
- return other
-
-
- def getType(self):
- return definitions.cICalComponent_VTIMEZONE
-
-
- def getMimeComponentName(self):
- # Cannot be sent as a separate MIME object
- return None
-
-
- def addComponent(self, comp):
- # We can embed the timezone components only
- if ((comp.getType() == definitions.cICalComponent_STANDARD)
- or (comp.getType() == definitions.cICalComponent_DAYLIGHT)):
- super(PyCalendarVTimezone, self).addComponent(comp)
- else:
- raise ValueError
-
-
- def getMapKey(self):
- return self.mID
-
-
- def finalise(self):
- # Get TZID
- temp = self.loadValueString(definitions.cICalProperty_TZID)
- if temp is not None:
- self.mID = temp
-
- # Sort sub-components by DTSTART
- self.mComponents.sort(key=lambda x: x.getStart())
-
- # Do inherited
- super(PyCalendarVTimezone, self).finalise()
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems, else raise. If
- loggedProblems is not None it must be a C{list} and problem descriptions are appended
- to that.
- """
-
- fixed, unfixed = super(PyCalendarVTimezone, self).validate(doFix)
-
- # Must have at least one STANDARD or DAYLIGHT sub-component
- for component in self.mComponents:
- if component.getType() in (definitions.cICalComponent_STANDARD, definitions.cICalComponent_DAYLIGHT):
- break
- else:
- # Cannot fix a missing required component
- logProblem = "[%s] At least one component must be present: %s or %s" % (
- self.getType(),
- definitions.cICalComponent_STANDARD,
- definitions.cICalComponent_DAYLIGHT,
- )
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- def getID(self):
- return self.mID
-
-
- def getUTCOffsetSortKey(self):
- if self.mUTCOffsetSortKey is None:
- # Take time from first element
- if len(self.mComponents) > 0:
- # Initial offset provides the primary key
- utc_offset1 = self.mComponents[0].getUTCOffset()
-
- # Presence of secondary is the next key
- utc_offset2 = utc_offset1
- if len(self.mComponents) > 1:
- utc_offset2 = self.mComponents[1].getUTCOffset()
-
- # Create key
- self.mUTCOffsetSortKey = (utc_offset1 + utc_offset2) / 2
- else:
- self.mUTCOffsetSortKey = 0
-
- return self.mUTCOffsetSortKey
-
-
- def getTimezoneOffsetSeconds(self, dt):
- """
- Caching implementation of expansion. We cache the entire set of transitions up to one year ahead
- of the requested time.
- """
-
- # Need to make the incoming date-time relative to the DTSTART in the
- # timezone component for proper comparison.
- # This means making the incoming date-time a floating (no timezone)
- # item
- temp = dt.duplicate()
- temp.setTimezoneID(None)
-
- # Check whether we need to recache
- if self.mCachedExpandAllMaxYear is None or temp.mYear >= self.mCachedExpandAllMaxYear:
- cacheMax = temp.duplicate()
- cacheMax.setHHMMSS(0, 0, 0)
- cacheMax.offsetYear(2)
- cacheMax.setMonth(1)
- cacheMax.setDay(1)
- self.mCachedExpandAll = self.expandAll(None, cacheMax)
- self.mCachedExpandAllMaxYear = cacheMax.mYear
- self.mCachedOffsets = {}
-
- # Now search for the transition just below the time we want
- if len(self.mCachedExpandAll):
- cacheKey = (temp.mYear, temp.mMonth, temp.mDay, temp.mHours, temp.mMinutes,)
- i = self.mCachedOffsets.get(cacheKey)
- if i is None:
- i = PyCalendarVTimezone.tuple_bisect_right(self.mCachedExpandAll, temp)
- if len(self.mCachedOffsets) >= self.UTCOFFSET_CACHE_MAX_ENTRIES:
- self.mCachedOffsets = {}
- self.mCachedOffsets[cacheKey] = i
- if i != 0:
- return self.mCachedExpandAll[i - 1][2]
-
- return 0
-
-
- def getTimezoneDescriptor(self, dt):
- result = ""
-
- # Get the closet matching element to the time
- found = self.findTimezoneElement(dt)
-
- # Get it
- if found is not None:
- if len(found.getTZName()) == 0:
- tzoffset = found.getUTCOffset()
- negative = False
- if tzoffset < 0:
- tzoffset = -tzoffset
- negative = True
- result = ("+", "-")[negative]
- hours_offset = tzoffset / (60 * 60)
- if hours_offset < 10:
- result += "0"
- result += str(hours_offset)
- mins_offset = (tzoffset / 60) % 60
- if mins_offset < 10:
- result += "0"
- result += str(mins_offset)
- else:
- result = "("
- result += found.getTZName()
- result += ")"
-
- return result
-
-
- def mergeTimezone(self, tz):
- pass
-
-
- @staticmethod
- def tuple_bisect_right(a, x):
- """
- Same as bisect_right except that the values being compared are the first elements
- of a tuple.
- """
-
- lo = 0
- hi = len(a)
- while lo < hi:
- mid = (lo + hi) // 2
- if x < a[mid][0]:
- hi = mid
- else:
- lo = mid + 1
- return lo
-
-
- def findTimezoneElement(self, dt):
- # Need to make the incoming date-time relative to the DTSTART in the
- # timezone component for proper comparison.
- # This means making the incoming date-time a floating (no timezone)
- # item
- temp = dt.duplicate()
- temp.setTimezoneID(None)
-
- # Had to rework this because some VTIMEZONEs have sub-components where the DST instances are interleaved. That
- # means we have to evaluate each and every sub-component to find the instance immediately less than the time we are checking.
-
- # Now do the expansion for each one found and pick the lowest
- found = None
- dt_found = PyCalendarDateTime()
-
- for item in self.mComponents:
- dt_item = item.expandBelow(temp)
- if temp >= dt_item:
- if found is not None:
- # Compare with the one previously cached and switch to this
- # one if newer
- if dt_item > dt_found:
- found = item
- dt_found = dt_item
- else:
- found = item
- dt_found = dt_item
-
- return found
-
-
- def expandAll(self, start, end, with_name=False):
- results = []
- for item in self.mComponents:
- results.extend(item.expandAll(start, end, with_name))
- results = [x for x in set(results)]
- results.sort(key=lambda x: x[0].getPosixTime())
- return results
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_TZID,
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_TZURL,
- )
-
-
- @staticmethod
- def sortByUTCOffsetComparator(tz1, tz2):
- sort1 = tz1.getUTCOffsetSortKey()
- sort2 = tz2.getUTCOffsetSortKey()
- if sort1 == sort2:
- return tz1.getID().compareToIgnoreCase(tz2.getID())
- else:
- return (1, -1)[sort1 < sort2]
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezonedaylightpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,31 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from vtimezoneelement import PyCalendarVTimezoneElement
-
-class PyCalendarVTimezoneDaylight(PyCalendarVTimezoneElement):
-
- def __init__(self, parent=None):
- super(PyCalendarVTimezoneDaylight, self).__init__(parent=parent)
-
-
- def duplicate(self, parent=None):
- return super(PyCalendarVTimezoneDaylight, self).duplicate(parent=parent)
-
-
- def getType(self):
- return definitions.cICalComponent_DAYLIGHT
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezoneelementpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezoneelement.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezoneelement.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezoneelement.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,219 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 bisect import bisect_right
-from pycalendar import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.recurrenceset import PyCalendarRecurrenceSet
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarVTimezoneElement(PyCalendarComponent):
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_TZOFFSETTO,
- definitions.cICalProperty_TZOFFSETFROM,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_RRULE,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None, dt=None, offset=None):
- super(PyCalendarVTimezoneElement, self).__init__(parent=parent)
- self.mStart = dt if dt is not None else PyCalendarDateTime()
- self.mTZName = ""
- self.mUTCOffset = offset if offset is not None else 0
- self.mUTCOffsetFrom = 0
- self.mRecurrences = PyCalendarRecurrenceSet()
- self.mCachedExpandBelow = None
- self.mCachedExpandBelowItems = None
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarVTimezoneElement, self).duplicate(parent=parent)
- other.mStart = self.mStart.duplicate()
- other.mTZName = self.mTZName
- other.mUTCOffset = self.mUTCOffset
- other.mUTCOffsetFrom = self.mUTCOffsetFrom
- other.mRecurrences = self.mRecurrences.duplicate()
- other.mCachedExpandBelow = None
- other.mCachedExpandBelowItems = None
- return other
-
-
- def finalise(self):
- # Get DTSTART
- temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
- if temp is not None:
- self.mStart = temp
-
- # Get TZOFFSETTO
- temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, PyCalendarValue.VALUETYPE_UTC_OFFSET)
- if temp is not None:
- self.mUTCOffset = temp
-
- # Get TZOFFSETFROM
- temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, PyCalendarValue.VALUETYPE_UTC_OFFSET)
- if temp is not None:
- self.mUTCOffsetFrom = temp
-
- # Get TZNAME
- temps = self.loadValueString(definitions.cICalProperty_TZNAME)
- if temps is not None:
- self.mTZName = temps
-
- # Get RRULEs
- self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
-
- # Get RDATEs
- self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
-
- # Do inherited
- super(PyCalendarVTimezoneElement, self).finalise()
-
-
- def getSortKey(self):
- """
- We do not want these components sorted.
- """
- return ""
-
-
- def getStart(self):
- return self.mStart
-
-
- def getUTCOffset(self):
- return self.mUTCOffset
-
-
- def getUTCOffsetFrom(self):
- return self.mUTCOffsetFrom
-
-
- def getTZName(self):
- return self.mTZName
-
-
- def expandBelow(self, below):
-
- # Look for recurrences
- if not self.mRecurrences.hasRecurrence() or self.mStart > below:
- # Return DTSTART even if it is newer
- return self.mStart
- else:
- # We want to allow recurrence calculation caching to help us here
- # as this method
- # gets called a lot - most likely for ever increasing dt values
- # (which will therefore
- # invalidate the recurrence cache).
- #
- # What we will do is round up the date-time to the next year so
- # that the recurrence
- # cache is invalidated less frequently
-
- temp = PyCalendarDateTime(below.getYear(), 1, 1, 0, 0, 0)
-
- # Use cache of expansion
- if self.mCachedExpandBelowItems is None:
- self.mCachedExpandBelowItems = []
- if self.mCachedExpandBelow is None:
- self.mCachedExpandBelow = self.mStart.duplicate()
- if temp > self.mCachedExpandBelow:
- self.mCachedExpandBelowItems = []
- period = PyCalendarPeriod(self.mStart, temp)
- self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
- self.mCachedExpandBelow = temp
-
- if len(self.mCachedExpandBelowItems) != 0:
- # List comes back sorted so we pick the element just less than
- # the dt value we want
- i = bisect_right(self.mCachedExpandBelowItems, below)
- if i != 0:
- return self.mCachedExpandBelowItems[i - 1]
-
- # The first one in the list is the one we want
- return self.mCachedExpandBelowItems[0]
-
- return self.mStart
-
-
- def expandAll(self, start, end, with_name):
-
- if start is None:
- start = self.mStart
-
- # Ignore if there is no change in offset
- offsetto = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, PyCalendarValue.VALUETYPE_UTC_OFFSET)
- offsetfrom = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, PyCalendarValue.VALUETYPE_UTC_OFFSET)
-# if offsetto == offsetfrom:
-# return ()
-
- # Look for recurrences
- if self.mStart > end:
- # Return nothing
- return ()
- elif not self.mRecurrences.hasRecurrence():
- # Return DTSTART even if it is newer
- if self.mStart >= start:
- result = (self.mStart, offsetfrom, offsetto,)
- if with_name:
- result += (self.getTZName(),)
- return (result,)
- else:
- return ()
- else:
- # We want to allow recurrence calculation caching to help us here
- # as this method
- # gets called a lot - most likely for ever increasing dt values
- # (which will therefore
- # invalidate the recurrence cache).
- #
- # What we will do is round up the date-time to the next year so
- # that the recurrence
- # cache is invalidated less frequently
-
- temp = PyCalendarDateTime(end.getYear(), 1, 1, 0, 0, 0)
-
- # Use cache of expansion
- if self.mCachedExpandBelowItems is None:
- self.mCachedExpandBelowItems = []
- if self.mCachedExpandBelow is None:
- self.mCachedExpandBelow = self.mStart.duplicate()
- if temp > self.mCachedExpandBelow:
- self.mCachedExpandBelowItems = []
- period = PyCalendarPeriod(self.mStart, end)
- self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
- self.mCachedExpandBelow = temp
-
- if len(self.mCachedExpandBelowItems) != 0:
- # Return them all within the range
- results = []
- for dt in self.mCachedExpandBelowItems:
- if dt >= start and dt < end:
- result = (dt, offsetfrom, offsetto,)
- if with_name:
- result += (self.getTZName(),)
- results.append(result)
- return results
-
- return ()
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezonestandardpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezonestandard.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezonestandard.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezonestandard.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,31 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar.vtimezoneelement import PyCalendarVTimezoneElement
-
-class PyCalendarVTimezoneStandard(PyCalendarVTimezoneElement):
-
- def __init__(self, parent=None):
- super(PyCalendarVTimezoneStandard, self).__init__(parent=parent)
-
-
- def duplicate(self, parent=None):
- return super(PyCalendarVTimezoneStandard, self).duplicate(parent=parent)
-
-
- def getType(self):
- return definitions.cICalComponent_STANDARD
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtodopy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtodo.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtodo.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtodo.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,366 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar import itipdefinitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.property import PyCalendarProperty
-import cStringIO as StringIO
-
-class PyCalendarVToDo(PyCalendarComponentRecur):
-
- OVERDUE = 0
- DUE_NOW = 1
- DUE_LATER = 2
- DONE = 3
- CANCELLED = 4
-
- @staticmethod
- def sort_for_display(e1, e2):
- s1 = e1.getMaster()
- s2 = e2.getMaster()
-
- # Check status first (convert None -> Needs action for tests)
- status1 = s1.self.mStatus
- status2 = s2.self.mStatus
- if status1 == definitions.eStatus_VToDo_None:
- status1 = definitions.eStatus_VToDo_NeedsAction
- if status2 == definitions.eStatus_VToDo_None:
- status2 = definitions.eStatus_VToDo_NeedsAction
- if status1 != status2:
- # More important ones at the top
- return status1 < status2
-
- # At this point the status of each is the same
-
- # If status is cancelled sort by start time
- if s1.self.mStatus == definitions.eStatus_VToDo_Cancelled:
- # Older ones at the bottom
- return s1.mStart > s2.mStart
-
- # If status is completed sort by completion time
- if s1.self.mStatus == definitions.eStatus_VToDo_Completed:
- # Older ones at the bottom
- return s1.self.mCompleted > s2.self.mCompleted
-
- # Check due date exists
- if s1.mHasEnd != s2.mHasEnd:
- now = PyCalendarDateTime()
- now.setToday()
-
- # Ones with due dates after today below ones without due dates
- if s1.hasEnd():
- return s1.mEnd <= now
- elif s2.hasEnd():
- return now < s2.mEnd
-
- # Check due dates if present
- if s1.mHasEnd:
- if s1.mEnd != s2.mEnd:
- # Soonest dues dates above later ones
- return s1.mEnd < s2.mEnd
-
- # Check priority next
- if s1.self.mPriority != s2.self.mPriority:
- # Higher priority above lower ones
- return s1.self.mPriority < s2.self.mPriority
-
- # Just use start time - older ones at the top
- return s1.mStart < s2.mStart
-
- propertyCardinality_1 = (
- definitions.cICalProperty_DTSTAMP,
- definitions.cICalProperty_UID,
- )
-
- propertyCardinality_0_1 = (
- definitions.cICalProperty_CLASS,
- definitions.cICalProperty_COMPLETED,
- definitions.cICalProperty_CREATED,
- definitions.cICalProperty_DESCRIPTION,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_GEO,
- definitions.cICalProperty_LAST_MODIFIED,
- definitions.cICalProperty_LOCATION,
- definitions.cICalProperty_ORGANIZER,
- definitions.cICalProperty_PERCENT_COMPLETE,
- definitions.cICalProperty_PRIORITY,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_SEQUENCE,
- # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
- definitions.cICalProperty_SUMMARY,
- definitions.cICalProperty_URL,
- definitions.cICalProperty_RRULE,
- definitions.cICalProperty_DUE,
- definitions.cICalProperty_DURATION,
- )
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None):
- super(PyCalendarVToDo, self).__init__(parent=parent)
- self.mPriority = 0
- self.mStatus = definitions.eStatus_VToDo_None
- self.mPercentComplete = 0
- self.mCompleted = PyCalendarDateTime()
- self.mHasCompleted = False
-
-
- def duplicate(self, parent=None):
- other = super(PyCalendarVToDo, self).duplicate(parent=parent)
- other.mPriority = self.mPriority
- other.mStatus = self.mStatus
- other.mPercentComplete = self.mPercentComplete
- other.mCompleted = self.mCompleted.duplicate()
- other.mHasCompleted = self.mHasCompleted
- return other
-
-
- def getType(self):
- return definitions.cICalComponent_VTODO
-
-
- def getMimeComponentName(self):
- return itipdefinitions.cICalMIMEComponent_VTODO
-
-
- def addComponent(self, comp):
- # We can embed the alarm components only
- if comp.getType() == definitions.cICalComponent_VALARM:
- super(PyCalendarVToDo, self).addComponent(comp)
- else:
- raise ValueError
-
-
- def getStatus(self):
- return self.mStatus
-
-
- def setStatus(self, status):
- self.mStatus = status
-
-
- def getStatusText(self):
- sout = StringIO()
-
- if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
- if self.hasEnd():
- # Check due date
- today = PyCalendarDateTime()
- today.setToday()
- if self.getEnd() > today:
- sout.append("Due: ")
- whendue = self.getEnd() - today
- if (whendue.getDays() > 0) and (whendue.getDays() <= 7):
- sout.write(whendue.getDays())
- sout.write(" days")
- else:
- sout.write(self.getEnd().getLocaleDate(PyCalendarDateTime.NUMERICDATE))
- elif self.getEnd() == today:
- sout.write("Due today")
- else:
- sout.write("Overdue: ")
- overdue = today - self.getEnd()
- if overdue.getWeeks() != 0:
- sout.write(overdue.getWeeks())
- sout.write(" weeks")
- else:
- sout.write(overdue.getDays() + 1)
- sout.write(" days")
- else:
- sout.write("Not Completed")
- elif self.mStatus == definitions.eStatus_VToDo_Completed:
- if self.hasCompleted():
- sout.write("Completed: ")
- sout.write(self.getCompleted().getLocaleDate(PyCalendarDateTime.NUMERICDATE))
- else:
- sout.write("Completed")
- elif definitions.eStatus_VToDo_Cancelled:
- sout.write("Cancelled")
-
- return sout.toString()
-
-
- def getCompletionState(self):
- if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
- if self.hasEnd():
- # Check due date
- today = PyCalendarDateTime()
- today.setToday()
- if self.getEnd() > today:
- return PyCalendarVToDo.DUE_LATER
- elif self.getEnd() == today:
- return PyCalendarVToDo.DUE_NOW
- else:
- return PyCalendarVToDo.OVERDUE
- else:
- return PyCalendarVToDo.DUE_NOW
- elif self.mStatus == definitions.eStatus_VToDo_Completed:
- return PyCalendarVToDo.DONE
- elif self.mStatus == definitions.eStatus_VToDo_Cancelled:
- return PyCalendarVToDo.CANCELLED
-
-
- def getPriority(self):
- return self.mPriority
-
-
- def setPriority(self, priority):
- self.mPriority = priority
-
-
- def getCompleted(self):
- return self.mCompleted
-
-
- def hasCompleted(self):
- return self.mHasCompleted
-
-
- def finalise(self):
- # Do inherited
- super(PyCalendarVToDo, self).finalise()
-
- # Get DUE
- temp = self.loadValueDateTime(definitions.cICalProperty_DUE)
- if temp is None:
- # Try DURATION instead
- temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
- if temp is not None:
- self.mEnd = self.mStart + temp
- self.mHasEnd = True
- else:
- self.mHasEnd = False
- else:
- self.mHasEnd = True
- self.mEnd = temp
-
- # Get PRIORITY
- self.mPriority = self.loadValueInteger(definitions.cICalProperty_PRIORITY)
-
- # Get STATUS
- temp = self.loadValueString(definitions.cICalProperty_STATUS)
- if temp is not None:
- if temp == definitions.cICalProperty_STATUS_NEEDS_ACTION:
- self.mStatus = definitions.eStatus_VToDo_NeedsAction
- elif temp == definitions.cICalProperty_STATUS_COMPLETED:
- self.mStatus = definitions.eStatus_VToDo_Completed
- elif temp == definitions.cICalProperty_STATUS_IN_PROCESS:
- self.mStatus = definitions.eStatus_VToDo_InProcess
- elif temp == definitions.cICalProperty_STATUS_CANCELLED:
- self.mStatus = definitions.eStatus_VToDo_Cancelled
-
- # Get PERCENT-COMPLETE
- self.mPercentComplete = self.loadValueInteger(definitions.cICalProperty_PERCENT_COMPLETE)
-
- # Get COMPLETED
- temp = self.loadValueDateTime(definitions.cICalProperty_COMPLETED)
- self.mHasCompleted = temp is not None
- if self.mHasCompleted:
- self.mCompleted = temp
-
-
- def validate(self, doFix=False):
- """
- Validate the data in this component and optionally fix any problems, else raise. If
- loggedProblems is not None it must be a C{list} and problem descriptions are appended
- to that.
- """
-
- fixed, unfixed = super(PyCalendarVToDo, self).validate(doFix)
-
- # Extra constraint: only one of DUE or DURATION
- if self.hasProperty(definitions.cICalProperty_DUE) and self.hasProperty(definitions.cICalProperty_DURATION):
- # Fix by removing the DURATION
- logProblem = "[%s] Properties must not both be present: %s, %s" % (
- self.getType(),
- definitions.cICalProperty_DUE,
- definitions.cICalProperty_DURATION,
- )
- if doFix:
- self.removeProperties(definitions.cICalProperty_DURATION)
- fixed.append(logProblem)
- else:
- unfixed.append(logProblem)
-
- # Extra constraint: DTSTART must be present if DURATION is present
- if self.hasProperty(definitions.cICalProperty_DURATION) and not self.hasProperty(definitions.cICalProperty_DTSTART):
- # Cannot fix this one
- logProblem = "[%s] Property must be present: %s with %s" % (
- self.getType(),
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DURATION,
- )
- unfixed.append(logProblem)
-
- return fixed, unfixed
-
-
- # Editing
- def editStatus(self, status):
- # Only if it is different
- if self.mStatus != status:
- # Updated cached values
- self.mStatus = status
-
- # Remove existing STATUS & COMPLETED items
- self.removeProperties(definitions.cICalProperty_STATUS)
- self.removeProperties(definitions.cICalProperty_COMPLETED)
- self.mHasCompleted = False
-
- # Now create properties
- value = None
- if status == definitions.eStatus_VToDo_NeedsAction:
- value = definitions.cICalProperty_STATUS_NEEDS_ACTION
- if status == definitions.eStatus_VToDo_Completed:
- value = definitions.cICalProperty_STATUS_COMPLETED
- # Add the completed item
- self.mCompleted.setNowUTC()
- self.mHasCompleted = True
- prop = PyCalendarProperty(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
- self.addProperty(prop)
- elif status == definitions.eStatus_VToDo_InProcess:
- value = definitions.cICalProperty_STATUS_IN_PROCESS
- elif status == definitions.eStatus_VToDo_Cancelled:
- value = definitions.cICalProperty_STATUS_CANCELLED
- prop = PyCalendarProperty(definitions.cICalProperty_STATUS, value)
- self.addProperty(prop)
-
-
- def editCompleted(self, completed):
- # Remove existing COMPLETED item
- self.removeProperties(definitions.cICalProperty_COMPLETED)
- self.mHasCompleted = False
-
- # Always UTC
- self.mCompleted = completed.duplicate()
- self.mCompleted.adjustToUTC()
- self.mHasCompleted = True
- prop = PyCalendarProperty(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
- self.addProperty(prop)
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- definitions.cICalProperty_RECURRENCE_ID,
- definitions.cICalProperty_DTSTART,
- definitions.cICalProperty_DURATION,
- definitions.cICalProperty_DUE,
- definitions.cICalProperty_COMPLETED,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvunknownpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vunknown.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vunknown.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vunknown.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,66 +0,0 @@
</span><del>-##
-# Copyright (c) 2011-2012 Cyrus Daboo. 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 pycalendar import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-import uuid
-
-class PyCalendarUnknownComponent(PyCalendarComponent):
-
- propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
- def __init__(self, parent=None, comptype=""):
- super(PyCalendarUnknownComponent, self).__init__(parent=parent)
- self.mType = comptype
- self.mMapKey = str(uuid.uuid4())
-
-
- def duplicate(self, parent=None):
- return super(PyCalendarUnknownComponent, self).duplicate(parent=parent, comptype=self.mType)
-
-
- def getType(self):
- return self.mType
-
-
- def getBeginDelimiter(self):
- return "BEGIN:" + self.mType
-
-
- def getEndDelimiter(self):
- return "END:" + self.mType
-
-
- def getMimeComponentName(self):
- return "unknown"
-
-
- def getMapKey(self):
- return self.mMapKey
-
-
- def getSortKey(self):
- """
- We do not want unknown components sorted.
- """
- return ""
-
-
- def sortedPropertyKeyOrder(self):
- return (
- definitions.cICalProperty_UID,
- )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarxmldefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendarxmldefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/xmldefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/xmldefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/xmldefinitions.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/xmldefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+# Generic XML definitions
+
+iCalendar20_namespace = "urn:ietf:params:xml:ns:icalendar-2.0"
+
+components = "components"
+properties = "properties"
+parameters = "parameters"
+
+value_binary = "binary"
+value_boolean = "boolean"
+value_cal_address = "cal-address"
+value_date = "date"
+value_date_time = "date-time"
+value_duration = "duration"
+value_float = "float"
+value_integer = "integer"
+value_period = "period"
+value_text = "text"
+value_unknown = "unknown"
+value_uri = "uri"
+value_utc_offset = "utc-offset"
+
+period_start = "start"
+period_end = "end"
+period_duration = "duration"
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarxmldefspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/xmldefs.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/xmldefs.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/xmldefs.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,104 +0,0 @@
</span><del>-##
-# Copyright (c) 2007-2012 Cyrus Daboo. 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.
-##
-
-import xml.etree.cElementTree as XML
-
-# iCalendar/vCard XML definitions
-
-iCalendar20_namespace = "urn:ietf:params:xml:ns:icalendar-2.0"
-
-icalendar = "icalendar"
-components = "components"
-properties = "properties"
-parameters = "parameters"
-
-value_binary = "binary"
-value_boolean = "boolean"
-value_cal_address = "cal-address"
-value_date = "date"
-value_date_time = "date-time"
-value_duration = "duration"
-value_integer = "integer"
-value_period = "period"
-value_recur = "recur"
-value_text = "text"
-value_unknown = "unknown"
-value_uri = "uri"
-value_utc_offset = "utc-offset"
-
-period_start = "start"
-period_end = "end"
-period_duration = "duration"
-
-recur_freq = "freq"
-recur_freq_secondly = "SECONDLY"
-recur_freq_minutely = "MINUTELY"
-recur_freq_hourly = "HOURLY"
-recur_freq_daily = "DAILY"
-recur_freq_weekly = "WEEKLY"
-recur_freq_monthly = "MONTHLY"
-recur_freq_yearly = "YEARLY"
-
-recur_count = "count"
-recur_until = "until"
-recur_interval = "interval"
-
-recur_bysecond = "bysecond"
-recur_byminute = "byminute"
-recur_byhour = "byhour"
-recur_byday = "byday"
-recur_bymonthday = "bymonthday"
-recur_byyearday = "byyearday"
-recur_byweekno = "byweekno"
-recur_bymonth = "bymonth"
-recur_bysetpos = "bysetpos"
-recur_wkst = "wkst"
-
-req_status_code = "code"
-req_status_description = "description"
-req_status_data = "data"
-
-vCard40_namespace = "urn:ietf:params:xml:ns:vcard-4.0"
-
-def makeTag(namespace, name):
- return "{%s}%s" % (namespace, name.lower(),)
-
-
-
-def toString(root):
-
- data = """<?xml version="1.0" encoding="utf-8"?>\n"""
-
- INDENT = 2
-
- # Generate indentation
- def _indentNode(node, level=0):
-
- if node.text is not None and node.text.strip():
- return
- elif len(node.getchildren()):
- indent = "\n" + " " * (level + 1) * INDENT
- node.text = indent
- for child in node.getchildren():
- child.tail = indent
- _indentNode(child, level + 1)
- if len(node.getchildren()):
- node.getchildren()[-1].tail = "\n" + " " * level * INDENT
-
- _indentNode(root, 0)
- data += XML.tostring(root) + "\n"
-
- return data
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarxmlutilspyfromrev11912PyCalendarbranchesjson2srcpycalendarxmlutilspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/xmlutils.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/xmlutils.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/xmlutils.py         (rev 0)
+++ PyCalendar/trunk/src/pycalendar/xmlutils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+##
+# Copyright (c) 2007-2013 Cyrus Daboo. 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.
+##
+
+import xml.etree.cElementTree as XML
+
+def makeTag(namespace, name):
+ return "{%s}%s" % (namespace, name.lower(),)
+
+
+
+def toString(root):
+
+ data = """<?xml version="1.0" encoding="utf-8"?>\n"""
+
+ INDENT = 2
+
+ # Generate indentation
+ def _indentNode(node, level=0):
+
+ if node.text is not None and node.text.strip():
+ return
+ elif len(node.getchildren()):
+ indent = "\n" + " " * (level + 1) * INDENT
+ node.text = indent
+ for child in node.getchildren():
+ child.tail = indent
+ _indentNode(child, level + 1)
+ if len(node.getchildren()):
+ node.getchildren()[-1].tail = "\n" + " " * level * INDENT
+
+ _indentNode(root, 0)
+ data += XML.tostring(root) + "\n"
+
+ return data
</ins></span></pre></div>
<a id="PyCalendartrunksrczonal__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrczonalrulepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/rule.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/rule.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/rule.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,14 +14,14 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar import definitions
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.recurrence import Recurrence
+from pycalendar.icalendar.vtimezonedaylight import Daylight
+from pycalendar.icalendar.vtimezonestandard import Standard
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> from pycalendar.utils import daysInMonth
</span><del>-from pycalendar.vtimezonestandard import PyCalendarVTimezoneStandard
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
-from pycalendar.vtimezonedaylight import PyCalendarVTimezoneDaylight
-from pycalendar.property import PyCalendarProperty
-from pycalendar.recurrence import PyCalendarRecurrence
</del><span class="cx"> import utils
</span><span class="cx">
</span><span class="cx"> """
</span><span class="lines">@@ -114,23 +114,23 @@
</span><span class="cx"> # Some useful mapping tables
</span><span class="cx">
</span><span class="cx"> LASTDAY_NAME_TO_DAY = {
</span><del>- "lastSun": PyCalendarDateTime.SUNDAY,
- "lastMon": PyCalendarDateTime.MONDAY,
- "lastTue": PyCalendarDateTime.TUESDAY,
- "lastWed": PyCalendarDateTime.WEDNESDAY,
- "lastThu": PyCalendarDateTime.THURSDAY,
- "lastFri": PyCalendarDateTime.FRIDAY,
- "lastSat": PyCalendarDateTime.SATURDAY,
</del><ins>+ "lastSun": DateTime.SUNDAY,
+ "lastMon": DateTime.MONDAY,
+ "lastTue": DateTime.TUESDAY,
+ "lastWed": DateTime.WEDNESDAY,
+ "lastThu": DateTime.THURSDAY,
+ "lastFri": DateTime.FRIDAY,
+ "lastSat": DateTime.SATURDAY,
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> DAY_NAME_TO_DAY = {
</span><del>- "Sun": PyCalendarDateTime.SUNDAY,
- "Mon": PyCalendarDateTime.MONDAY,
- "Tue": PyCalendarDateTime.TUESDAY,
- "Wed": PyCalendarDateTime.WEDNESDAY,
- "Thu": PyCalendarDateTime.THURSDAY,
- "Fri": PyCalendarDateTime.FRIDAY,
- "Sat": PyCalendarDateTime.SATURDAY,
</del><ins>+ "Sun": DateTime.SUNDAY,
+ "Mon": DateTime.MONDAY,
+ "Tue": DateTime.TUESDAY,
+ "Wed": DateTime.WEDNESDAY,
+ "Thu": DateTime.THURSDAY,
+ "Fri": DateTime.FRIDAY,
+ "Sat": DateTime.SATURDAY,
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> LASTDAY_NAME_TO_RDAY = {
</span><span class="lines">@@ -144,13 +144,13 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> DAY_NAME_TO_RDAY = {
</span><del>- PyCalendarDateTime.SUNDAY: definitions.eRecurrence_WEEKDAY_SU,
- PyCalendarDateTime.MONDAY: definitions.eRecurrence_WEEKDAY_MO,
- PyCalendarDateTime.TUESDAY: definitions.eRecurrence_WEEKDAY_TU,
- PyCalendarDateTime.WEDNESDAY: definitions.eRecurrence_WEEKDAY_WE,
- PyCalendarDateTime.THURSDAY: definitions.eRecurrence_WEEKDAY_TH,
- PyCalendarDateTime.FRIDAY: definitions.eRecurrence_WEEKDAY_FR,
- PyCalendarDateTime.SATURDAY: definitions.eRecurrence_WEEKDAY_SA,
</del><ins>+ DateTime.SUNDAY: definitions.eRecurrence_WEEKDAY_SU,
+ DateTime.MONDAY: definitions.eRecurrence_WEEKDAY_MO,
+ DateTime.TUESDAY: definitions.eRecurrence_WEEKDAY_TU,
+ DateTime.WEDNESDAY: definitions.eRecurrence_WEEKDAY_WE,
+ DateTime.THURSDAY: definitions.eRecurrence_WEEKDAY_TH,
+ DateTime.FRIDAY: definitions.eRecurrence_WEEKDAY_FR,
+ DateTime.SATURDAY: definitions.eRecurrence_WEEKDAY_SA,
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> MONTH_NAME_TO_POS = {
</span><span class="lines">@@ -288,11 +288,11 @@
</span><span class="cx"> @param year: the year to determine the transition for
</span><span class="cx"> @type year: C{int}
</span><span class="cx">
</span><del>- @return: C{tuple} of L{PyCalendarDateTime} and C{str} (which is the special
</del><ins>+ @return: C{tuple} of L{DateTime} and C{str} (which is the special
</ins><span class="cx"> tzdata mode character
</span><span class="cx"> """
</span><span class="cx"> # Create a floating date-time
</span><del>- dt = PyCalendarDateTime()
</del><ins>+ dt = DateTime()
</ins><span class="cx">
</span><span class="cx"> # Setup base year/month/day
</span><span class="cx"> dt.setYear(year)
</span><span class="lines">@@ -342,7 +342,7 @@
</span><span class="cx"> Get RRULE BYxxx part items from the Rule data.
</span><span class="cx">
</span><span class="cx"> @param start: start date-time for the recurrence set
</span><del>- @type start: L{PyCalendarDateTime}
</del><ins>+ @type start: L{DateTime}
</ins><span class="cx"> @param indicatedDay: the day that the Rule indicates for recurrence
</span><span class="cx"> @type indicatedDay: C{int}
</span><span class="cx"> @param indicatedOffset: the offset that the Rule indicates for recurrence
</span><span class="lines">@@ -449,13 +449,13 @@
</span><span class="cx"> Generate a VTIMEZONE sub-component for this Rule.
</span><span class="cx">
</span><span class="cx"> @param vtz: VTIMEZONE to add to
</span><del>- @type vtz: L{PyCalendarVTimezone}
</del><ins>+ @type vtz: L{VTimezone}
</ins><span class="cx"> @param zonerule: the Zone rule line being used
</span><span class="cx"> @type zonerule: L{ZoneRule}
</span><span class="cx"> @param start: the start time for the first instance
</span><del>- @type start: L{PyCalendarDateTime}
</del><ins>+ @type start: L{DateTime}
</ins><span class="cx"> @param end: the start time for the last instance
</span><del>- @type end: L{PyCalendarDateTime}
</del><ins>+ @type end: L{DateTime}
</ins><span class="cx"> @param offsetfrom: the UTC offset-from
</span><span class="cx"> @type offsetfrom: C{int}
</span><span class="cx"> @param offsetto: the UTC offset-to
</span><span class="lines">@@ -467,31 +467,31 @@
</span><span class="cx"> # Determine type of component based on offset
</span><span class="cx"> dstoffset = self.getOffset()
</span><span class="cx"> if dstoffset == 0:
</span><del>- comp = PyCalendarVTimezoneStandard(parent=vtz)
</del><ins>+ comp = Standard(parent=vtz)
</ins><span class="cx"> else:
</span><del>- comp = PyCalendarVTimezoneDaylight(parent=vtz)
</del><ins>+ comp = Daylight(parent=vtz)
</ins><span class="cx">
</span><span class="cx"> # Do offsets
</span><del>- tzoffsetfrom = PyCalendarUTCOffsetValue(offsetfrom)
- tzoffsetto = PyCalendarUTCOffsetValue(offsetto)
</del><ins>+ tzoffsetfrom = UTCOffsetValue(offsetfrom)
+ tzoffsetto = UTCOffsetValue(offsetto)
</ins><span class="cx">
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
+ comp.addProperty(Property(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</ins><span class="cx">
</span><span class="cx"> # Do TZNAME
</span><span class="cx"> if zonerule.format.find("%") != -1:
</span><span class="cx"> tzname = zonerule.format % (self.letter if self.letter != "-" else "",)
</span><span class="cx"> else:
</span><span class="cx"> tzname = zonerule.format
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZNAME, tzname))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_TZNAME, tzname))
</ins><span class="cx">
</span><span class="cx"> # Do DTSTART
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_DTSTART, start))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_DTSTART, start))
</ins><span class="cx">
</span><span class="cx"> # Now determine the recurrences (use RDATE if only one year or
</span><span class="cx"> # number of instances is one)
</span><span class="cx"> if self.toYear != "only" and instanceCount != 1:
</span><del>- rrule = PyCalendarRecurrence()
</del><ins>+ rrule = Recurrence()
</ins><span class="cx"> rrule.setFreq(definitions.eRecurrence_YEARLY)
</span><span class="cx"> rrule.setByMonth((Rule.MONTH_NAME_TO_POS[self.inMonth],))
</span><span class="cx"> if self.onDay in Rule.LASTDAY_NAME_TO_RDAY:
</span><span class="lines">@@ -566,9 +566,9 @@
</span><span class="cx"> rrule.setUseUntil(True)
</span><span class="cx"> rrule.setUntil(until)
</span><span class="cx">
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_RRULE, rrule))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_RRULE, rrule))
</ins><span class="cx"> else:
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_RDATE, start))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_RDATE, start))
</ins><span class="cx">
</span><span class="cx"> comp.finalise()
</span><span class="cx"> vtz.addComponent(comp)
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrczonalteststest_rulepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tests/test_rule.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tests/test_rule.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tests/test_rule.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx">
</span><span class="cx"> import unittest
</span><span class="cx"> from zonal.rule import Rule, RuleSet
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx">
</span><span class="cx"> class TestRule(unittest.TestCase):
</span><span class="cx">
</span><span class="lines">@@ -37,9 +37,9 @@
</span><span class="cx">
</span><span class="cx"> def test_datetimeforyear(self):
</span><span class="cx"> data = (
</span><del>- ("Rule\tGuat\t2006\tonly\t-\tOct\t1\t0:00\t0\tS", 2006, PyCalendarDateTime(2006, 10, 1, 0, 0, 0), ""),
- ("Rule\tAlgeria\t1916\t1919\t-\tOct\tSun>=1\t23:00s\t0\t-", 1916, PyCalendarDateTime(1916, 10, 1, 23, 0, 0), "s"),
- ("Rule\tGhana\t1936\t1942\t-\tSep\t1\t0:00\t0:20\tGHST", 1937, PyCalendarDateTime(1937, 9, 1, 0, 0, 0), ""),
</del><ins>+ ("Rule\tGuat\t2006\tonly\t-\tOct\t1\t0:00\t0\tS", 2006, DateTime(2006, 10, 1, 0, 0, 0), ""),
+ ("Rule\tAlgeria\t1916\t1919\t-\tOct\tSun>=1\t23:00s\t0\t-", 1916, DateTime(1916, 10, 1, 23, 0, 0), "s"),
+ ("Rule\tGhana\t1936\t1942\t-\tSep\t1\t0:00\t0:20\tGHST", 1937, DateTime(1937, 9, 1, 0, 0, 0), ""),
</ins><span class="cx"> )
</span><span class="cx">
</span><span class="cx"> for ruletext, year, dt, special in data:
</span></span></pre></div>
<a id="PyCalendartrunksrczonalteststest_zonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tests/test_zone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tests/test_zone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tests/test_zone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx"> import unittest
</span><span class="cx"> from zonal.zone import Zone
</span><span class="cx"> from zonal.rule import RuleSet
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx">
</span><span class="cx"> class TestZone(unittest.TestCase):
</span><span class="cx">
</span><span class="lines">@@ -92,7 +92,7 @@
</span><span class="cx"> ruleset.parse(rules)
</span><span class="cx"> rules = {ruleset.name: ruleset}
</span><span class="cx">
</span><del>- cal = PyCalendar()
</del><ins>+ cal = Calendar()
</ins><span class="cx"> vtz = zone.vtimezone(cal, rules, 2006, 2011)
</span><span class="cx">
</span><span class="cx"> self.assertEqual(str(vtz), result)
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltzconvertpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tzconvert.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tzconvert.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tzconvert.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> from __future__ import with_statement
</span><span class="cx">
</span><span class="cx"> from difflib import unified_diff
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import getopt
</span><span class="cx"> import os
</span><span class="lines">@@ -126,7 +126,7 @@
</span><span class="cx"> Generate iCalendar data for all VTIMEZONEs or just those specified
</span><span class="cx"> """
</span><span class="cx">
</span><del>- cal = PyCalendar()
</del><ins>+ cal = Calendar()
</ins><span class="cx"> for zone in self.zones.itervalues():
</span><span class="cx"> if filterzones and zone.name not in filterzones:
</span><span class="cx"> continue
</span><span class="lines">@@ -151,7 +151,7 @@
</span><span class="cx"> for zone in self.zones.itervalues():
</span><span class="cx"> if filterzones and zone.name not in filterzones:
</span><span class="cx"> continue
</span><del>- cal = PyCalendar()
</del><ins>+ cal = Calendar()
</ins><span class="cx"> vtz = zone.vtimezone(cal, self.rules, minYear, maxYear)
</span><span class="cx"> cal.addComponent(vtz)
</span><span class="cx">
</span><span class="lines">@@ -251,7 +251,7 @@
</span><span class="cx"> if len(args) == 1:
</span><span class="cx"> rootdir = os.path.expanduser(args[0])
</span><span class="cx">
</span><del>- PyCalendar.sProdID = prodid
</del><ins>+ Calendar.sProdID = prodid
</ins><span class="cx">
</span><span class="cx"> zonedir = os.path.join(rootdir, "tzdata")
</span><span class="cx"> zonefiles = (
</span><span class="lines">@@ -284,14 +284,14 @@
</span><span class="cx"> ))
</span><span class="cx">
</span><span class="cx"> icsdir = "../2008i/zoneinfo"
</span><del>- cal = PyCalendar()
</del><ins>+ cal = Calendar()
</ins><span class="cx"> for file in (checkName,):
</span><span class="cx"> fin = open(os.path.join(icsdir, file + ".ics"), "r")
</span><span class="cx"> cal.parse(fin)
</span><span class="cx">
</span><span class="cx"> for vtz in cal.getVTimezoneDB():
</span><del>- #from pycalendar.vtimezoneelement import PyCalendarVTimezoneElement
- #vtz.mEmbedded.sort(PyCalendarVTimezoneElement.sort_dtstart)
</del><ins>+ #from pycalendar.vtimezoneelement import VTimezoneElement
+ #vtz.mEmbedded.sort(VTimezoneElement.sort_dtstart)
</ins><span class="cx"> for embedded in vtz.mEmbedded:
</span><span class="cx"> embedded.finalise()
</span><span class="cx"> vtz.finalise()
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltzdumppy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tzdump.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tzdump.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tzdump.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,22 +15,22 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar.calendar import Calendar
+import getopt
</ins><span class="cx"> import os
</span><span class="cx"> import sys
</span><del>-import getopt
-from pycalendar.exceptions import PyCalendarInvalidData
</del><span class="cx">
</span><span class="cx"> def loadCalendar(file, verbose):
</span><span class="cx">
</span><del>- cal = PyCalendar()
</del><ins>+ cal = Calendar()
</ins><span class="cx"> if verbose:
</span><span class="cx"> print "Parsing calendar data: %s" % (file,)
</span><span class="cx"> fin = open(file, "r")
</span><span class="cx"> try:
</span><span class="cx"> cal.parse(fin)
</span><del>- except PyCalendarInvalidData, e:
</del><ins>+ except InvalidData, e:
</ins><span class="cx"> print "Failed to parse bad data: %s" % (e.mData,)
</span><span class="cx"> raise
</span><span class="cx"> return cal
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx">
</span><span class="cx"> vtz = cal.getComponents()[0]
</span><span class="cx"> expanded = vtz.expandAll(start, end)
</span><del>- expanded.sort(cmp=lambda x, y: PyCalendarDateTime.sort(x[0], y[0]))
</del><ins>+ expanded.sort(cmp=lambda x, y: DateTime.sort(x[0], y[0]))
</ins><span class="cx"> return expanded
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -125,8 +125,8 @@
</span><span class="cx"> usage("Must have one argument")
</span><span class="cx"> fpath = os.path.expanduser(args[0])
</span><span class="cx">
</span><del>- start = PyCalendarDateTime(year=startYear, month=1, day=1)
- end = PyCalendarDateTime(year=endYear, month=1, day=1)
</del><ins>+ start = DateTime(year=startYear, month=1, day=1)
+ end = DateTime(year=endYear, month=1, day=1)
</ins><span class="cx">
</span><span class="cx"> cal = loadCalendar(fpath, verbose)
</span><span class="cx"> dates = getExpandedDates(cal, start, end)
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltzverifypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tzverify.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tzverify.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tzverify.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -15,13 +15,13 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> from tzconvert import tzconvert
</span><ins>+import getopt
</ins><span class="cx"> import os
</span><span class="cx"> import sys
</span><del>-import getopt
-from pycalendar.exceptions import PyCalendarInvalidData
</del><span class="cx">
</span><span class="cx"> def loadCalendarFromZoneinfo(zoneinfopath, skips=(), verbose=False, quiet=False):
</span><span class="cx">
</span><span class="lines">@@ -51,14 +51,14 @@
</span><span class="cx">
</span><span class="cx"> def loadCalendar(files, verbose):
</span><span class="cx">
</span><del>- cal = PyCalendar()
</del><ins>+ cal = Calendar()
</ins><span class="cx"> for file in files:
</span><span class="cx"> if verbose:
</span><span class="cx"> print "Parsing calendar data: %s" % (file,)
</span><span class="cx"> fin = open(file, "r")
</span><span class="cx"> try:
</span><span class="cx"> cal.parse(fin)
</span><del>- except PyCalendarInvalidData, e:
</del><ins>+ except InvalidData, e:
</ins><span class="cx"> print "Failed to parse bad data: %s" % (e.mData,)
</span><span class="cx"> raise
</span><span class="cx"> return CalendarZonesWrapper(calendar=cal)
</span><span class="lines">@@ -164,7 +164,7 @@
</span><span class="cx">
</span><span class="cx"> def sortedList(setdata):
</span><span class="cx"> l = list(setdata)
</span><del>- l.sort(cmp=lambda x, y: PyCalendarDateTime.sort(x[0], y[0]))
</del><ins>+ l.sort(cmp=lambda x, y: DateTime.sort(x[0], y[0]))
</ins><span class="cx"> return l
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -249,8 +249,8 @@
</span><span class="cx"> zonedir1 = os.path.expanduser(args[0])
</span><span class="cx"> zonedir2 = os.path.expanduser(args[1])
</span><span class="cx">
</span><del>- start = PyCalendarDateTime(year=startYear, month=1, day=1)
- end = PyCalendarDateTime(year=endYear, month=1, day=1)
</del><ins>+ start = DateTime(year=startYear, month=1, day=1)
+ end = DateTime(year=endYear, month=1, day=1)
</ins><span class="cx">
</span><span class="cx"> zonefiles = (
</span><span class="cx"> "northamerica",
</span></span></pre></div>
<a id="PyCalendartrunksrczonalutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/utils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/utils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/utils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span></span></pre></div>
<a id="PyCalendartrunksrczonalzonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/zone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/zone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/zone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-# Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+# Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Licensed under the Apache License, Version 2.0 (the "License");
</span><span class="cx"> # you may not use this file except in compliance with the License.
</span><span class="lines">@@ -14,14 +14,14 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.vtimezone import PyCalendarVTimezone
-from pycalendar.property import PyCalendarProperty
-from pycalendar import definitions
-from pycalendar.vtimezonestandard import PyCalendarVTimezoneStandard
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.vtimezone import VTimezone
+from pycalendar.icalendar.vtimezonestandard import Standard
+from pycalendar.utcoffsetvalue import UTCOffsetValue
+import rule
</ins><span class="cx"> import utils
</span><del>-import rule
</del><span class="cx">
</span><span class="cx"> """
</span><span class="cx"> Class that maintains a TZ data Zone.
</span><span class="lines">@@ -129,7 +129,7 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> # Start at 1/1/1800 with the offset from the initial zone rule
</span><del>- start = PyCalendarDateTime(year=1800, month=1, day=1, hours=0, minutes=0, seconds=0)
</del><ins>+ start = DateTime(year=1800, month=1, day=1, hours=0, minutes=0, seconds=0)
</ins><span class="cx"> start_offset = self.rules[0].getUTCOffset()
</span><span class="cx"> start_stdoffset = self.rules[0].getUTCOffset()
</span><span class="cx"> startdt = start.duplicate()
</span><span class="lines">@@ -178,7 +178,7 @@
</span><span class="cx"> """
</span><span class="cx"> Generate a VTIMEZONE for this Zone.
</span><span class="cx">
</span><del>- @param calendar: the L{PyCalendar} object for the VCALENDAR in which the VTIMEZONE
</del><ins>+ @param calendar: the L{Calendar} object for the VCALENDAR in which the VTIMEZONE
</ins><span class="cx"> will be created.
</span><span class="cx"> @param rules: the C{dict} containing the set of Rules currently defined.
</span><span class="cx"> @param startYear: a C{int} containing the first year that should be present
</span><span class="lines">@@ -187,11 +187,11 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> # Get a VTIMEZONE component
</span><del>- vtz = PyCalendarVTimezone(parent=calendar)
</del><ins>+ vtz = VTimezone(parent=calendar)
</ins><span class="cx">
</span><span class="cx"> # Add TZID property
</span><del>- vtz.addProperty(PyCalendarProperty(definitions.cICalProperty_TZID, self.name))
- vtz.addProperty(PyCalendarProperty("X-LIC-LOCATION", self.name))
</del><ins>+ vtz.addProperty(Property(definitions.cICalProperty_TZID, self.name))
+ vtz.addProperty(Property("X-LIC-LOCATION", self.name))
</ins><span class="cx">
</span><span class="cx"> transitions = self.expand(rules, minYear, maxYear)
</span><span class="cx">
</span><span class="lines">@@ -270,7 +270,7 @@
</span><span class="cx"> RDATEs assuming all other properties are the same.
</span><span class="cx">
</span><span class="cx"> @param vtz: the VTIMEZONE object to compress
</span><del>- @type vtz: L{PyCalendarVTimezone}
</del><ins>+ @type vtz: L{VTimezone}
</ins><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> # Map the similar sub-components together
</span><span class="lines">@@ -385,16 +385,16 @@
</span><span class="cx"> month = int(rule.Rule.MONTH_NAME_TO_POS[splits[1]])
</span><span class="cx"> if len(splits) > 2 and not splits[2].startswith("#"):
</span><span class="cx"> if splits[2] == "lastSun":
</span><del>- dt = PyCalendarDateTime(year=year, month=month, day=1)
- dt.setDayOfWeekInMonth(-1, PyCalendarDateTime.SUNDAY)
</del><ins>+ dt = DateTime(year=year, month=month, day=1)
+ dt.setDayOfWeekInMonth(-1, DateTime.SUNDAY)
</ins><span class="cx"> splits[2] = dt.getDay()
</span><span class="cx"> elif splits[2] == "lastSat":
</span><del>- dt = PyCalendarDateTime(year=year, month=month, day=1)
- dt.setDayOfWeekInMonth(-1, PyCalendarDateTime.SATURDAY)
</del><ins>+ dt = DateTime(year=year, month=month, day=1)
+ dt.setDayOfWeekInMonth(-1, DateTime.SATURDAY)
</ins><span class="cx"> splits[2] = dt.getDay()
</span><span class="cx"> elif splits[2] == "Sun>=1":
</span><del>- dt = PyCalendarDateTime(year=year, month=month, day=1)
- dt.setDayOfWeekInMonth(1, PyCalendarDateTime.SUNDAY)
</del><ins>+ dt = DateTime(year=year, month=month, day=1)
+ dt.setDayOfWeekInMonth(1, DateTime.SUNDAY)
</ins><span class="cx"> splits[2] = dt.getDay()
</span><span class="cx"> day = int(splits[2])
</span><span class="cx"> if len(splits) > 3 and not splits[3].startswith("#"):
</span><span class="lines">@@ -408,7 +408,7 @@
</span><span class="cx"> if len(splits) > 2:
</span><span class="cx"> seconds = int(splits[2])
</span><span class="cx">
</span><del>- dt = PyCalendarDateTime(year=year, month=month, day=day, hours=hours, minutes=minutes, seconds=seconds)
</del><ins>+ dt = DateTime(year=year, month=month, day=day, hours=hours, minutes=minutes, seconds=seconds)
</ins><span class="cx"> self._cached_until = utils.DateTime(dt, mode)
</span><span class="cx"> return self._cached_until
</span><span class="cx">
</span><span class="lines">@@ -493,27 +493,27 @@
</span><span class="cx"> def vtimezone(self, vtz, zonerule, start, end, offsetfrom, offsetto):
</span><span class="cx">
</span><span class="cx"> # Determine type of component based on offset
</span><del>- comp = PyCalendarVTimezoneStandard(parent=vtz)
</del><ins>+ comp = Standard(parent=vtz)
</ins><span class="cx">
</span><span class="cx"> # Do offsets
</span><del>- tzoffsetfrom = PyCalendarUTCOffsetValue(offsetfrom)
- tzoffsetto = PyCalendarUTCOffsetValue(offsetto)
</del><ins>+ tzoffsetfrom = UTCOffsetValue(offsetfrom)
+ tzoffsetto = UTCOffsetValue(offsetto)
</ins><span class="cx">
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
+ comp.addProperty(Property(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</ins><span class="cx">
</span><span class="cx"> # Do TZNAME
</span><span class="cx"> if self.format.find("%") != -1:
</span><span class="cx"> tzname = self.format % ("S",)
</span><span class="cx"> else:
</span><span class="cx"> tzname = self.format
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZNAME, tzname))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_TZNAME, tzname))
</ins><span class="cx">
</span><span class="cx"> # Do DTSTART
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_DTSTART, start))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_DTSTART, start))
</ins><span class="cx">
</span><span class="cx"> # Recurrence
</span><del>- comp.addProperty(PyCalendarProperty(definitions.cICalProperty_RDATE, start))
</del><ins>+ comp.addProperty(Property(definitions.cICalProperty_RDATE, start))
</ins><span class="cx">
</span><span class="cx"> comp.finalise()
</span><span class="cx"> vtz.addComponent(comp)
</span></span></pre>
</div>
</div>
</body>
</html>