diff --git a/tests/storage/test_http.py b/tests/storage/test_http.py index 493283d..4d300f6 100644 --- a/tests/storage/test_http.py +++ b/tests/storage/test_http.py @@ -9,64 +9,8 @@ from requests import Response -from tests import normalize_item, SIMPLE_TEMPLATE, BARE_EVENT_TEMPLATE -from vdirsyncer.storage.http import HttpStorage, split_collection - - -def test_split_collection_simple(): - input = u'\r\n'.join(( - u'BEGIN:VADDRESSBOOK', - SIMPLE_TEMPLATE.format(r=123), - SIMPLE_TEMPLATE.format(r=345), - SIMPLE_TEMPLATE.format(r=678), - u'END:VADDRESSBOOK' - )) - - given = split_collection(input) - expected = [ - SIMPLE_TEMPLATE.format(r=123), - SIMPLE_TEMPLATE.format(r=345), - SIMPLE_TEMPLATE.format(r=678) - ] - - assert set(normalize_item(item) for item in given) == \ - set(normalize_item(item) for item in expected) - - -def test_split_collection_timezones(): - items = [ - BARE_EVENT_TEMPLATE.format(r=123), - BARE_EVENT_TEMPLATE.format(r=345) - ] - - timezone = ( - u'BEGIN:VTIMEZONE\r\n' - u'TZID:/mozilla.org/20070129_1/Asia/Tokyo\r\n' - u'X-LIC-LOCATION:Asia/Tokyo\r\n' - u'BEGIN:STANDARD\r\n' - u'TZOFFSETFROM:+0900\r\n' - u'TZOFFSETTO:+0900\r\n' - u'TZNAME:JST\r\n' - u'DTSTART:19700101T000000\r\n' - u'END:STANDARD\r\n' - u'END:VTIMEZONE' - ) - - full = u'\r\n'.join( - [u'BEGIN:VCALENDAR'] + - items + - [timezone, u'END:VCALENDAR'] - ) - - given = set(normalize_item(item) for item in split_collection(full)) - expected = set( - normalize_item(u'\r\n'.join(( - u'BEGIN:VCALENDAR', item, timezone, u'END:VCALENDAR' - ))) - for item in items - ) - - assert given == expected +from tests import normalize_item +from vdirsyncer.storage.http import HttpStorage def test_list(monkeypatch): diff --git a/tests/test_utils.py b/tests/test_utils.py index 124e3dc..7468626 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -9,6 +9,9 @@ import pytest import vdirsyncer.utils as utils +from vdirsyncer.utils.vobject import split_collection + +from . import normalize_item, SIMPLE_TEMPLATE, BARE_EVENT_TEMPLATE def test_parse_options(): @@ -103,3 +106,61 @@ def test_get_password_from_system_keyring(monkeypatch, resources_to_test): _password = utils.get_password(username, resource) assert _password == password assert netrc_calls == [hostname] + + +def test_split_collection_simple(): + input = u'\r\n'.join(( + u'BEGIN:VADDRESSBOOK', + SIMPLE_TEMPLATE.format(r=123), + SIMPLE_TEMPLATE.format(r=345), + SIMPLE_TEMPLATE.format(r=678), + u'END:VADDRESSBOOK' + )) + + given = split_collection(input) + expected = [ + SIMPLE_TEMPLATE.format(r=123), + SIMPLE_TEMPLATE.format(r=345), + SIMPLE_TEMPLATE.format(r=678) + ] + + assert set(normalize_item(item) for item in given) == \ + set(normalize_item(item) for item in expected) + + +def test_split_collection_timezones(): + items = [ + BARE_EVENT_TEMPLATE.format(r=123), + BARE_EVENT_TEMPLATE.format(r=345) + ] + + timezone = ( + u'BEGIN:VTIMEZONE\r\n' + u'TZID:/mozilla.org/20070129_1/Asia/Tokyo\r\n' + u'X-LIC-LOCATION:Asia/Tokyo\r\n' + u'BEGIN:STANDARD\r\n' + u'TZOFFSETFROM:+0900\r\n' + u'TZOFFSETTO:+0900\r\n' + u'TZNAME:JST\r\n' + u'DTSTART:19700101T000000\r\n' + u'END:STANDARD\r\n' + u'END:VTIMEZONE' + ) + + full = u'\r\n'.join( + [u'BEGIN:VCALENDAR'] + + items + + [timezone, u'END:VCALENDAR'] + ) + + given = set(normalize_item(item) for item in split_collection(full)) + expected = set( + normalize_item(u'\r\n'.join(( + u'BEGIN:VCALENDAR', item, timezone, u'END:VCALENDAR' + ))) + for item in items + ) + + assert given == expected + + diff --git a/vdirsyncer/storage/http.py b/vdirsyncer/storage/http.py index 5fa1c8c..25160d1 100644 --- a/vdirsyncer/storage/http.py +++ b/vdirsyncer/storage/http.py @@ -7,56 +7,13 @@ :license: MIT, see LICENSE for more details. ''' -import icalendar.cal -import icalendar.parser - from .base import Item, Storage -from ..utils import expand_path, get_password, itervalues, request, \ - text_type, urlparse +from ..utils import expand_path, get_password, request, text_type, urlparse +from ..utils.vobject import split_collection USERAGENT = 'vdirsyncer' -def split_collection(text, inline=(u'VTIMEZONE',), - wrap_items_with=(u'VCALENDAR',)): - assert isinstance(text, text_type) - collection = icalendar.cal.Component.from_ical(text) - items = collection.subcomponents - - if collection.name in wrap_items_with: - start = u'BEGIN:{}'.format(collection.name) - end = u'END:{}'.format(collection.name) - else: - start = end = u'' - - inlined_items = {} - for item in items: - if item.name in inline: - inlined_items[item.name] = item - - for item in items: - if item.name not in inline: - lines = [] - lines.append(start) - for inlined_item in itervalues(inlined_items): - lines.extend(to_unicode_lines(inlined_item)) - - lines.extend(to_unicode_lines(item)) - lines.append(end) - lines.append(u'') - - yield u''.join(line + u'\r\n' for line in lines if line) - - -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 content_line: - yield icalendar.parser.foldline(content_line) - - def prepare_auth(auth, username, password): if (username and password) or auth == 'basic': return (username, password) diff --git a/vdirsyncer/utils.py b/vdirsyncer/utils/__init__.py similarity index 99% rename from vdirsyncer/utils.py rename to vdirsyncer/utils/__init__.py index ffea748..8cc3150 100644 --- a/vdirsyncer/utils.py +++ b/vdirsyncer/utils/__init__.py @@ -11,7 +11,7 @@ import os import sys import requests -from . import log +from .. import log logger = log.get(__name__) diff --git a/vdirsyncer/utils/vobject.py b/vdirsyncer/utils/vobject.py new file mode 100644 index 0000000..55cacb3 --- /dev/null +++ b/vdirsyncer/utils/vobject.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +''' + vdirsyncer.utils.vobject + ~~~~~~~~~~~~~~~~~~~~~~~~ + + :copyright: (c) 2014 Markus Unterwaditzer + :license: MIT, see LICENSE for more details. +''' +import icalendar.cal +import icalendar.parser + +from . import text_type, itervalues + + +def split_collection(text, inline=(u'VTIMEZONE',), + wrap_items_with=(u'VCALENDAR',)): + assert isinstance(text, text_type) + collection = icalendar.cal.Component.from_ical(text) + items = collection.subcomponents + + if collection.name in wrap_items_with: + start = u'BEGIN:{}'.format(collection.name) + end = u'END:{}'.format(collection.name) + else: + start = end = u'' + + inlined_items = {} + for item in items: + if item.name in inline: + inlined_items[item.name] = item + + for item in items: + if item.name not in inline: + lines = [] + lines.append(start) + for inlined_item in itervalues(inlined_items): + lines.extend(to_unicode_lines(inlined_item)) + + lines.extend(to_unicode_lines(item)) + lines.append(end) + lines.append(u'') + + yield u''.join(line + u'\r\n' for line in lines if line) + + +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 content_line: + yield icalendar.parser.foldline(content_line)