Preserve order of parameters and properties

Since version 3.7, icalendar supports the preserving of the order of
the ICS file's parameters and properties. We can use this to avoid
unnecessary changes for .ics files managed with singlefilestorage.
This commit is contained in:
Markus Unterwaditzer 2014-06-03 17:13:25 +02:00
parent 2f299504ce
commit 9087b62647
3 changed files with 30 additions and 10 deletions

View file

@ -5,6 +5,7 @@ python:
- "3.4"
env:
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=filesystem REQUIREMENTS=release
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=filesystem REQUIREMENTS=release PKGS='icalendar==3.6'
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=filesystem REQUIREMENTS=devel
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=database REQUIREMENTS=devel
- BUILD=tests DAV_SERVER=owncloud REQUIREMENTS=release
@ -12,5 +13,6 @@ env:
install:
- "./build.sh install"
- '[ -z "$PKGS" ] || pip install $PKGS'
script:
- "./build.sh run"

View file

@ -7,8 +7,7 @@
:license: MIT, see LICENSE for more details.
'''
from vdirsyncer.utils.vobject import split_collection, join_collection, \
hash_item
import vdirsyncer.utils.vobject as vobject
from .. import normalize_item, VCARD_TEMPLATE, BARE_EVENT_TEMPLATE, \
EVENT_TEMPLATE
@ -18,7 +17,7 @@ _simple_joined = u'\r\n'.join((
VCARD_TEMPLATE.format(r=123),
VCARD_TEMPLATE.format(r=345),
VCARD_TEMPLATE.format(r=678),
u'END:VADDRESSBOOK'
u'END:VADDRESSBOOK\r\n'
))
_simple_split = [
@ -29,16 +28,19 @@ _simple_split = [
def test_split_collection_simple():
given = split_collection(_simple_joined)
given = list(vobject.split_collection(_simple_joined))
assert [normalize_item(item) for item in given] == \
[normalize_item(item) for item in _simple_split]
if vobject.ICALENDAR_ORIGINAL_ORDER_SUPPORT:
assert [x.splitlines() for x in given] == \
[x.splitlines() for x in _simple_split]
def test_join_collection_simple():
given = join_collection(_simple_split)
print(given)
print(_simple_joined)
given = vobject.join_collection(_simple_split)
assert normalize_item(given) == normalize_item(_simple_joined)
if vobject.ICALENDAR_ORIGINAL_ORDER_SUPPORT:
assert given.splitlines() == _simple_joined.splitlines()
def test_split_collection_timezones():
@ -66,7 +68,8 @@ def test_split_collection_timezones():
[timezone, u'END:VCALENDAR']
)
given = set(normalize_item(item) for item in split_collection(full))
given = set(normalize_item(item)
for item in vobject.split_collection(full))
expected = set(
normalize_item(u'\r\n'.join((
u'BEGIN:VCALENDAR', item, timezone, u'END:VCALENDAR'
@ -81,4 +84,4 @@ def test_hash_item():
a = EVENT_TEMPLATE.format(r=1)
b = u'\n'.join(line for line in a.splitlines()
if u'PRODID' not in line and u'VERSION' not in line)
assert hash_item(a) == hash_item(b)
assert vobject.hash_item(a) == vobject.hash_item(b)

View file

@ -10,6 +10,7 @@ import hashlib
import icalendar.cal
import icalendar.parser
import icalendar.caselessdict
from . import text_type, itervalues
@ -36,6 +37,15 @@ IGNORE_PROPS = _process_properties(
'REV'
)
# Whether the installed icalendar version has
# https://github.com/collective/icalendar/pull/136
# (support for keeping the order of properties and parameters)
#
# This basically checks whether the superclass of all icalendar classes has a
# method from OrderedDict.
ICALENDAR_ORIGINAL_ORDER_SUPPORT = \
hasattr(icalendar.caselessdict.CaselessDict, '__reversed__')
def normalize_item(text, ignore_props=IGNORE_PROPS, use_icalendar=True):
try:
@ -90,7 +100,12 @@ def to_unicode_lines(item):
'''icalendar doesn't provide an efficient way of getting the ical data as
unicode. So let's do it ourselves.'''
for content_line in item.content_lines():
if ICALENDAR_ORIGINAL_ORDER_SUPPORT:
content_lines = item.content_lines(sorted=False)
else:
content_lines = item.content_lines()
for content_line in content_lines:
if content_line:
# https://github.com/untitaker/vdirsyncer/issues/70
# icalendar escapes semicolons which are not supposed to get