diff --git a/tests/utils/test_vobject.py b/tests/utils/test_vobject.py index 7462227..9c171ee 100644 --- a/tests/utils/test_vobject.py +++ b/tests/utils/test_vobject.py @@ -12,25 +12,42 @@ import vdirsyncer.utils.vobject as vobject from .. import normalize_item, VCARD_TEMPLATE, BARE_EVENT_TEMPLATE, \ EVENT_TEMPLATE -_simple_joined = u'\r\n'.join(( - u'BEGIN:VADDRESSBOOK', - VCARD_TEMPLATE.format(r=123), - VCARD_TEMPLATE.format(r=345), - VCARD_TEMPLATE.format(r=678), - u'END:VADDRESSBOOK\r\n' -)) - _simple_split = [ VCARD_TEMPLATE.format(r=123), VCARD_TEMPLATE.format(r=345), VCARD_TEMPLATE.format(r=678) ] +_simple_joined = u'\r\n'.join( + [u'BEGIN:VADDRESSBOOK'] + + _simple_split + + [u'END:VADDRESSBOOK\r\n'] +) + def test_split_collection_simple(): 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_split_collection_multiple_wrappers(): + joined = u'\r\n'.join( + u'BEGIN:VADDRESSBOOK\r\n' + + x + + u'\r\nEND:VADDRESSBOOK\r\n' + for x in _simple_split + ) + given = list(vobject.split_collection(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] diff --git a/vdirsyncer/utils/__init__.py b/vdirsyncer/utils/__init__.py index bc5363c..402496a 100644 --- a/vdirsyncer/utils/__init__.py +++ b/vdirsyncer/utils/__init__.py @@ -11,7 +11,7 @@ import os import requests from .. import log, exceptions -from .compat import urlparse, get_raw_input +from .compat import urlparse, get_raw_input, iteritems logger = log.get(__name__) @@ -35,13 +35,19 @@ def expand_path(p): def split_dict(d, f): '''Puts key into first dict if f(key), otherwise in second dict''' - a = {} - b = {} - for k, v in d.items(): - if f(k): - a[k] = v + a, b = split_sequence(iteritems(d), lambda item: f(item[0])) + return dict(a), dict(b) + + +def split_sequence(s, f): + '''Puts item into first list if f(item), else in second list''' + a = [] + b = [] + for item in s: + if f(item): + a.append(item) else: - b[k] = v + b.append(item) return a, b diff --git a/vdirsyncer/utils/vobject.py b/vdirsyncer/utils/vobject.py index f1bca9a..72d36bb 100644 --- a/vdirsyncer/utils/vobject.py +++ b/vdirsyncer/utils/vobject.py @@ -12,7 +12,7 @@ import icalendar.cal import icalendar.parser import icalendar.caselessdict -from . import cached_property +from . import cached_property, split_sequence from .compat import text_type, itervalues @@ -128,25 +128,25 @@ def split_collection(text, inline=(u'VTIMEZONE',), wrap_items_with=(u'VCALENDAR',)): '''Emits items in the order they occur in the text.''' assert isinstance(text, text_type) - collection = icalendar.cal.Component.from_ical(text) - items = collection.subcomponents + collections = icalendar.cal.Component.from_ical(text, multiple=True) + assert collections - if collection.name in wrap_items_with: - start = u'BEGIN:{}'.format(collection.name) - end = u'END:{}'.format(collection.name) - else: - start = end = u'' + for collection in collections: + items = collection.subcomponents - inlined_items = {} - for item in items: - if item.name in inline: - inlined_items[item.name] = item + if collection.name in wrap_items_with: + start = u'BEGIN:{}'.format(collection.name) + end = u'END:{}'.format(collection.name) + else: + start = end = u'' - for item in items: - if item.name not in inline: + inlined_items, normal_items = \ + split_sequence(items, lambda item: item.name in inline) + + for item in normal_items: lines = [] lines.append(start) - for inlined_item in itervalues(inlined_items): + for inlined_item in inlined_items: lines.extend(to_unicode_lines(inlined_item)) lines.extend(to_unicode_lines(item))