Merge pull request #71 from untitaker/icalendar_sorting

Preserve order of parameters and properties
This commit is contained in:
Markus Unterwaditzer 2014-06-03 23:46:08 +02:00
commit f32809813a
3 changed files with 30 additions and 10 deletions

View file

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

View file

@ -7,8 +7,7 @@
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
''' '''
from vdirsyncer.utils.vobject import split_collection, join_collection, \ import vdirsyncer.utils.vobject as vobject
hash_item
from .. import normalize_item, VCARD_TEMPLATE, BARE_EVENT_TEMPLATE, \ from .. import normalize_item, VCARD_TEMPLATE, BARE_EVENT_TEMPLATE, \
EVENT_TEMPLATE EVENT_TEMPLATE
@ -18,7 +17,7 @@ _simple_joined = u'\r\n'.join((
VCARD_TEMPLATE.format(r=123), VCARD_TEMPLATE.format(r=123),
VCARD_TEMPLATE.format(r=345), VCARD_TEMPLATE.format(r=345),
VCARD_TEMPLATE.format(r=678), VCARD_TEMPLATE.format(r=678),
u'END:VADDRESSBOOK' u'END:VADDRESSBOOK\r\n'
)) ))
_simple_split = [ _simple_split = [
@ -29,16 +28,19 @@ _simple_split = [
def test_split_collection_simple(): 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] == \ assert [normalize_item(item) for item in given] == \
[normalize_item(item) for item in _simple_split] [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(): def test_join_collection_simple():
given = join_collection(_simple_split) given = vobject.join_collection(_simple_split)
print(given)
print(_simple_joined)
assert normalize_item(given) == normalize_item(_simple_joined) 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(): def test_split_collection_timezones():
@ -66,7 +68,8 @@ def test_split_collection_timezones():
[timezone, u'END:VCALENDAR'] [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( expected = set(
normalize_item(u'\r\n'.join(( normalize_item(u'\r\n'.join((
u'BEGIN:VCALENDAR', item, timezone, u'END:VCALENDAR' u'BEGIN:VCALENDAR', item, timezone, u'END:VCALENDAR'
@ -81,4 +84,4 @@ def test_hash_item():
a = EVENT_TEMPLATE.format(r=1) a = EVENT_TEMPLATE.format(r=1)
b = u'\n'.join(line for line in a.splitlines() b = u'\n'.join(line for line in a.splitlines()
if u'PRODID' not in line and u'VERSION' not in line) 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.cal
import icalendar.parser import icalendar.parser
import icalendar.caselessdict
from . import text_type, itervalues from . import text_type, itervalues
@ -36,6 +37,15 @@ IGNORE_PROPS = _process_properties(
'REV' '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): def normalize_item(text, ignore_props=IGNORE_PROPS, use_icalendar=True):
try: try:
@ -90,7 +100,12 @@ def to_unicode_lines(item):
'''icalendar doesn't provide an efficient way of getting the ical data as '''icalendar doesn't provide an efficient way of getting the ical data as
unicode. So let's do it ourselves.''' 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: if content_line:
# https://github.com/untitaker/vdirsyncer/issues/70 # https://github.com/untitaker/vdirsyncer/issues/70
# icalendar escapes semicolons which are not supposed to get # icalendar escapes semicolons which are not supposed to get