mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Autopep8
This commit is contained in:
parent
784c0edb5d
commit
98e49de418
12 changed files with 71 additions and 21 deletions
|
|
@ -11,26 +11,31 @@ import os
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
from vdirsyncer.sync import sync_classes
|
from vdirsyncer.sync import sync_classes
|
||||||
|
|
||||||
|
|
||||||
def _path(p):
|
def _path(p):
|
||||||
p = os.path.expanduser(p)
|
p = os.path.expanduser(p)
|
||||||
p = os.path.abspath(p)
|
p = os.path.abspath(p)
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
def get_config_parser(env):
|
def get_config_parser(env):
|
||||||
fname = env.get('VDIRSYNCER_CONFIG', _path('~/.vdirsyncer/config'))
|
fname = env.get('VDIRSYNCER_CONFIG', _path('~/.vdirsyncer/config'))
|
||||||
c = ConfigParser.SafeConfigParser()
|
c = ConfigParser.SafeConfigParser()
|
||||||
c.read(fname)
|
c.read(fname)
|
||||||
return dict((c, c.items(c)) for c in c.sections())
|
return dict((c, c.items(c)) for c in c.sections())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
env = os.environ
|
env = os.environ
|
||||||
cfg = get_config_parser(env)
|
cfg = get_config_parser(env)
|
||||||
_main(env, cfg)
|
_main(env, cfg)
|
||||||
|
|
||||||
|
|
||||||
def _main(env, file_cfg):
|
def _main(env, file_cfg):
|
||||||
app = argvard.Argvard()
|
app = argvard.Argvard()
|
||||||
|
|
||||||
sync = argvard.Command()
|
sync = argvard.Command()
|
||||||
|
|
||||||
@sync_command.main('[accounts...]')
|
@sync_command.main('[accounts...]')
|
||||||
def sync_main(accounts=None):
|
def sync_main(accounts=None):
|
||||||
if accounts is None:
|
if accounts is None:
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@
|
||||||
|
|
||||||
|
|
||||||
class Error(Exception):
|
class Error(Exception):
|
||||||
|
|
||||||
'''Baseclass for all errors.'''
|
'''Baseclass for all errors.'''
|
||||||
|
|
||||||
|
|
||||||
class PreconditionFailed(Error):
|
class PreconditionFailed(Error):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
- The item doesn't exist although it should
|
- The item doesn't exist although it should
|
||||||
- The item exists although it shouldn't
|
- The item exists although it shouldn't
|
||||||
|
|
@ -24,16 +26,20 @@ class PreconditionFailed(Error):
|
||||||
|
|
||||||
|
|
||||||
class NotFoundError(PreconditionFailed):
|
class NotFoundError(PreconditionFailed):
|
||||||
|
|
||||||
'''Item not found'''
|
'''Item not found'''
|
||||||
|
|
||||||
|
|
||||||
class AlreadyExistingError(PreconditionFailed):
|
class AlreadyExistingError(PreconditionFailed):
|
||||||
|
|
||||||
'''Item already exists'''
|
'''Item already exists'''
|
||||||
|
|
||||||
|
|
||||||
class WrongEtagError(PreconditionFailed):
|
class WrongEtagError(PreconditionFailed):
|
||||||
|
|
||||||
'''Wrong etag'''
|
'''Wrong etag'''
|
||||||
|
|
||||||
|
|
||||||
class StorageError(Error):
|
class StorageError(Error):
|
||||||
|
|
||||||
'''Internal or initialization errors with storage.'''
|
'''Internal or initialization errors with storage.'''
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@
|
||||||
:license: MIT, see LICENSE for more details.
|
:license: MIT, see LICENSE for more details.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
class Item(object):
|
class Item(object):
|
||||||
|
|
||||||
'''should-be-immutable wrapper class for VCALENDAR and VCARD'''
|
'''should-be-immutable wrapper class for VCALENDAR and VCARD'''
|
||||||
|
|
||||||
def __init__(self, raw):
|
def __init__(self, raw):
|
||||||
self.raw = raw
|
self.raw = raw
|
||||||
self._uid = None
|
self._uid = None
|
||||||
|
|
@ -23,6 +26,7 @@ class Item(object):
|
||||||
|
|
||||||
|
|
||||||
class Storage(object):
|
class Storage(object):
|
||||||
|
|
||||||
'''Superclass of all storages, mainly useful to summarize the interface to
|
'''Superclass of all storages, mainly useful to summarize the interface to
|
||||||
implement.
|
implement.
|
||||||
|
|
||||||
|
|
@ -32,6 +36,7 @@ class Storage(object):
|
||||||
- ETAG: Checksum of item, or something similar that changes when the object does
|
- ETAG: Checksum of item, or something similar that changes when the object does
|
||||||
'''
|
'''
|
||||||
fileext = '.txt'
|
fileext = '.txt'
|
||||||
|
|
||||||
def __init__(self, item_class=Item):
|
def __init__(self, item_class=Item):
|
||||||
self.item_class = item_class
|
self.item_class = item_class
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,13 @@ import datetime
|
||||||
|
|
||||||
CALDAV_DT_FORMAT = '%Y%m%dT%H%M%SZ'
|
CALDAV_DT_FORMAT = '%Y%m%dT%H%M%SZ'
|
||||||
|
|
||||||
|
|
||||||
class CaldavStorage(Storage):
|
class CaldavStorage(Storage):
|
||||||
|
|
||||||
'''hrefs are full URLs to items'''
|
'''hrefs are full URLs to items'''
|
||||||
_session = None
|
_session = None
|
||||||
fileext = '.ics'
|
fileext = '.ics'
|
||||||
|
|
||||||
def __init__(self, url, username='', password='', start_date=None,
|
def __init__(self, url, username='', password='', start_date=None,
|
||||||
end_date=None, verify=True, auth='basic',
|
end_date=None, verify=True, auth='basic',
|
||||||
useragent='vdirsyncer', _request_func=None, **kwargs):
|
useragent='vdirsyncer', _request_func=None, **kwargs):
|
||||||
|
|
@ -116,7 +119,8 @@ class CaldavStorage(Storage):
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
root = etree.XML(response.content)
|
root = etree.XML(response.content)
|
||||||
for element in root.iter('{DAV:}response'):
|
for element in root.iter('{DAV:}response'):
|
||||||
etag = element.find('{DAV:}propstat').find('{DAV:}prop').find('{DAV:}getetag').text
|
etag = element.find('{DAV:}propstat').find(
|
||||||
|
'{DAV:}prop').find('{DAV:}getetag').text
|
||||||
href = self._simplify_href(element.find('{DAV:}href').text)
|
href = self._simplify_href(element.find('{DAV:}href').text)
|
||||||
yield href, etag
|
yield href, etag
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,13 @@ import os
|
||||||
from vdirsyncer.storage.base import Storage, Item
|
from vdirsyncer.storage.base import Storage, Item
|
||||||
import vdirsyncer.exceptions as exceptions
|
import vdirsyncer.exceptions as exceptions
|
||||||
|
|
||||||
|
|
||||||
class FilesystemStorage(Storage):
|
class FilesystemStorage(Storage):
|
||||||
|
|
||||||
'''Saves data in vdir collection
|
'''Saves data in vdir collection
|
||||||
mtime is etag
|
mtime is etag
|
||||||
filename without path is href'''
|
filename without path is href'''
|
||||||
|
|
||||||
def __init__(self, path, fileext, **kwargs):
|
def __init__(self, path, fileext, **kwargs):
|
||||||
'''
|
'''
|
||||||
:param path: Absolute path to a *collection* inside a vdir.
|
:param path: Absolute path to a *collection* inside a vdir.
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,13 @@ import datetime
|
||||||
from vdirsyncer.storage.base import Item, Storage
|
from vdirsyncer.storage.base import Item, Storage
|
||||||
import vdirsyncer.exceptions as exceptions
|
import vdirsyncer.exceptions as exceptions
|
||||||
|
|
||||||
|
|
||||||
class MemoryStorage(Storage):
|
class MemoryStorage(Storage):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Saves data in RAM, only useful for testing.
|
Saves data in RAM, only useful for testing.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.items = {} # href => (etag, object)
|
self.items = {} # href => (etag, object)
|
||||||
super(MemoryStorage, self).__init__(**kwargs)
|
super(MemoryStorage, self).__init__(**kwargs)
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,12 @@ def sync(storage_a, storage_b, status):
|
||||||
modified by the function and should be passed to it at the next sync.
|
modified by the function and should be passed to it at the next sync.
|
||||||
If this is the first sync, an empty dictionary should be provided.
|
If this is the first sync, an empty dictionary should be provided.
|
||||||
'''
|
'''
|
||||||
a_href_to_uid = dict((href_a, uid) for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems())
|
a_href_to_uid = dict((href_a, uid)
|
||||||
b_href_to_uid = dict((href_b, uid) for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems())
|
for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems())
|
||||||
list_a = dict(prepare_list(storage_a, a_href_to_uid)) # href => {'etag': etag, 'obj': optional object, 'uid': uid}
|
b_href_to_uid = dict((href_b, uid)
|
||||||
|
for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems())
|
||||||
|
# href => {'etag': etag, 'obj': optional object, 'uid': uid}
|
||||||
|
list_a = dict(prepare_list(storage_a, a_href_to_uid))
|
||||||
list_b = dict(prepare_list(storage_b, b_href_to_uid))
|
list_b = dict(prepare_list(storage_b, b_href_to_uid))
|
||||||
a_uid_to_href = dict((x['uid'], href) for href, x in list_a.iteritems())
|
a_uid_to_href = dict((x['uid'], href) for href, x in list_a.iteritems())
|
||||||
b_uid_to_href = dict((x['uid'], href) for href, x in list_b.iteritems())
|
b_uid_to_href = dict((x['uid'], href) for href, x in list_b.iteritems())
|
||||||
|
|
@ -86,7 +89,8 @@ def sync(storage_a, storage_b, status):
|
||||||
dest_etag = dest_storage.update(dest_href, obj, old_etag)
|
dest_etag = dest_storage.update(dest_href, obj, old_etag)
|
||||||
source_status = (source_href, source_etag)
|
source_status = (source_href, source_etag)
|
||||||
dest_status = (dest_href, dest_etag)
|
dest_status = (dest_href, dest_etag)
|
||||||
status[uid] = source_status + dest_status if source == 'a' else dest_status + source_status
|
status[uid] = source_status + dest_status if source == 'a' else \
|
||||||
|
dest_status + source_status
|
||||||
elif action == 'delete':
|
elif action == 'delete':
|
||||||
if dest is not None:
|
if dest is not None:
|
||||||
dest_href = dest_uid_to_href[uid]
|
dest_href = dest_uid_to_href[uid]
|
||||||
|
|
@ -94,6 +98,7 @@ def sync(storage_a, storage_b, status):
|
||||||
dest_storage.delete(dest_href, dest_etag)
|
dest_storage.delete(dest_href, dest_etag)
|
||||||
del status[uid]
|
del status[uid]
|
||||||
|
|
||||||
|
|
||||||
def get_actions(list_a, list_b, status, a_uid_to_href, b_uid_to_href):
|
def get_actions(list_a, list_b, status, a_uid_to_href, b_uid_to_href):
|
||||||
prefetch_from_a = []
|
prefetch_from_a = []
|
||||||
prefetch_from_b = []
|
prefetch_from_b = []
|
||||||
|
|
@ -112,10 +117,12 @@ def get_actions(list_a, list_b, status, a_uid_to_href, b_uid_to_href):
|
||||||
if a['obj'].raw != b['obj'].raw:
|
if a['obj'].raw != b['obj'].raw:
|
||||||
1 / 0
|
1 / 0
|
||||||
status[uid] = (href_a, a['etag'], href_b, b['etag'])
|
status[uid] = (href_a, a['etag'], href_b, b['etag'])
|
||||||
elif uid in uids_a and uid not in uids_b: # new item was created in a
|
# new item was created in a
|
||||||
|
elif uid in uids_a and uid not in uids_b:
|
||||||
prefetch_from_a.append(href_a)
|
prefetch_from_a.append(href_a)
|
||||||
actions.append(('upload', uid, 'a', 'b'))
|
actions.append(('upload', uid, 'a', 'b'))
|
||||||
elif uid not in uids_a and uid in uids_b: # new item was created in b
|
# new item was created in b
|
||||||
|
elif uid not in uids_a and uid in uids_b:
|
||||||
prefetch_from_b.append(href_b)
|
prefetch_from_b.append(href_b)
|
||||||
actions.append(('upload', uid, 'b', 'a'))
|
actions.append(('upload', uid, 'b', 'a'))
|
||||||
else:
|
else:
|
||||||
|
|
@ -135,6 +142,7 @@ def get_actions(list_a, list_b, status, a_uid_to_href, b_uid_to_href):
|
||||||
actions.append(('delete', uid, None, 'a'))
|
actions.append(('delete', uid, None, 'a'))
|
||||||
elif uid not in uids_a and uid in uids_b: # was deleted from a
|
elif uid not in uids_a and uid in uids_b: # was deleted from a
|
||||||
actions.append(('delete', uid, None, 'b'))
|
actions.append(('delete', uid, None, 'b'))
|
||||||
elif uid not in uids_a and uid not in uids_b: # was deleted from a and b
|
# was deleted from a and b
|
||||||
|
elif uid not in uids_a and uid not in uids_b:
|
||||||
actions.append(('delete', uid, None, None))
|
actions.append(('delete', uid, None, None))
|
||||||
return actions, prefetch_from_a, prefetch_from_b
|
return actions, prefetch_from_a, prefetch_from_b
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ from vdirsyncer.storage.memory import MemoryStorage
|
||||||
from vdirsyncer.storage.caldav import CaldavStorage
|
from vdirsyncer.storage.caldav import CaldavStorage
|
||||||
import vdirsyncer.exceptions as exceptions
|
import vdirsyncer.exceptions as exceptions
|
||||||
|
|
||||||
|
|
||||||
class StorageTests(object):
|
class StorageTests(object):
|
||||||
|
|
||||||
def _create_bogus_item(self, uid):
|
def _create_bogus_item(self, uid):
|
||||||
return Item('''BEGIN:VCALENDAR
|
return Item('''BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
|
|
@ -33,6 +35,7 @@ UID:{}
|
||||||
END:VTODO
|
END:VTODO
|
||||||
END:VCALENDAR
|
END:VCALENDAR
|
||||||
'''.format(uid))
|
'''.format(uid))
|
||||||
|
|
||||||
def _get_storage(self, **kwargs):
|
def _get_storage(self, **kwargs):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
@ -56,14 +59,17 @@ END:VCALENDAR
|
||||||
def test_update_nonexisting(self):
|
def test_update_nonexisting(self):
|
||||||
s = self._get_storage()
|
s = self._get_storage()
|
||||||
item = self._create_bogus_item(1)
|
item = self._create_bogus_item(1)
|
||||||
self.assertRaises(exceptions.PreconditionFailed, s.update, 'huehue', item, 123)
|
self.assertRaises(
|
||||||
|
exceptions.PreconditionFailed, s.update, 'huehue', item, 123)
|
||||||
|
|
||||||
def test_wrong_etag(self):
|
def test_wrong_etag(self):
|
||||||
s = self._get_storage()
|
s = self._get_storage()
|
||||||
obj = self._create_bogus_item(1)
|
obj = self._create_bogus_item(1)
|
||||||
href, etag = s.upload(obj)
|
href, etag = s.upload(obj)
|
||||||
self.assertRaises(exceptions.PreconditionFailed, s.update, href, obj, 'lolnope')
|
self.assertRaises(
|
||||||
self.assertRaises(exceptions.PreconditionFailed, s.delete, href, 'lolnope')
|
exceptions.PreconditionFailed, s.update, href, obj, 'lolnope')
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.PreconditionFailed, s.delete, href, 'lolnope')
|
||||||
|
|
||||||
def test_delete_nonexisting(self):
|
def test_delete_nonexisting(self):
|
||||||
s = self._get_storage()
|
s = self._get_storage()
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ radicale.log.start()
|
||||||
|
|
||||||
|
|
||||||
class Response(object):
|
class Response(object):
|
||||||
|
|
||||||
'''Fake API of requests module'''
|
'''Fake API of requests module'''
|
||||||
|
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.status_code = x.status_code
|
self.status_code = x.status_code
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ from . import StorageTests
|
||||||
|
|
||||||
class FilesystemStorageTests(TestCase, StorageTests):
|
class FilesystemStorageTests(TestCase, StorageTests):
|
||||||
tmpdir = None
|
tmpdir = None
|
||||||
|
|
||||||
def _get_storage(self, **kwargs):
|
def _get_storage(self, **kwargs):
|
||||||
path = self.tmpdir = tempfile.mkdtemp()
|
path = self.tmpdir = tempfile.mkdtemp()
|
||||||
return FilesystemStorage(path=path, fileext='.txt', **kwargs)
|
return FilesystemStorage(path=path, fileext='.txt', **kwargs)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ from unittest import TestCase
|
||||||
from vdirsyncer.storage.memory import MemoryStorage
|
from vdirsyncer.storage.memory import MemoryStorage
|
||||||
from . import StorageTests
|
from . import StorageTests
|
||||||
|
|
||||||
|
|
||||||
class MemoryStorageTests(TestCase, StorageTests):
|
class MemoryStorageTests(TestCase, StorageTests):
|
||||||
|
|
||||||
def _get_storage(self, **kwargs):
|
def _get_storage(self, **kwargs):
|
||||||
return MemoryStorage(**kwargs)
|
return MemoryStorage(**kwargs)
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,13 @@ from vdirsyncer.storage.memory import MemoryStorage
|
||||||
from vdirsyncer.sync import sync
|
from vdirsyncer.sync import sync
|
||||||
import vdirsyncer.exceptions as exceptions
|
import vdirsyncer.exceptions as exceptions
|
||||||
|
|
||||||
|
|
||||||
def empty_storage(x):
|
def empty_storage(x):
|
||||||
return list(x.list()) == []
|
return list(x.list()) == []
|
||||||
|
|
||||||
|
|
||||||
class SyncTests(TestCase):
|
class SyncTests(TestCase):
|
||||||
|
|
||||||
def test_irrelevant_status(self):
|
def test_irrelevant_status(self):
|
||||||
a = MemoryStorage()
|
a = MemoryStorage()
|
||||||
b = MemoryStorage()
|
b = MemoryStorage()
|
||||||
|
|
@ -101,7 +104,9 @@ class SyncTests(TestCase):
|
||||||
item = Item('UID:1')
|
item = Item('UID:1')
|
||||||
a.upload(item)
|
a.upload(item)
|
||||||
b.upload(item)
|
b.upload(item)
|
||||||
status = {'1': ('1.txt', a.get('1.txt')[1], '1.txt', b.get('1.txt')[1])}
|
status = {
|
||||||
|
'1': ('1.txt', a.get('1.txt')[1], '1.txt', b.get('1.txt')[1])
|
||||||
|
}
|
||||||
old_status = dict(status)
|
old_status = dict(status)
|
||||||
a.update = b.update = a.upload = b.upload = \
|
a.update = b.update = a.upload = b.upload = \
|
||||||
lambda *a, **kw: self.fail('Method shouldn\'t have been called.')
|
lambda *a, **kw: self.fail('Method shouldn\'t have been called.')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue