mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Move "obscure" exceptions into their own modules
This commit is contained in:
parent
233e8524ab
commit
9616f0bbfe
5 changed files with 36 additions and 38 deletions
|
|
@ -240,7 +240,7 @@ class TestCaldavStorage(DavStorageTests):
|
||||||
|
|
||||||
monkeypatch.setattr('requests.sessions.Session.request', request)
|
monkeypatch.setattr('requests.sessions.Session.request', request)
|
||||||
|
|
||||||
with pytest.raises(exceptions.StorageError):
|
with pytest.raises(ValueError):
|
||||||
self.storage_class(**args)
|
self.storage_class(**args)
|
||||||
assert len(calls) == 1
|
assert len(calls) == 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,9 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from . import assert_item_equals, normalize_item
|
from . import assert_item_equals, normalize_item
|
||||||
import vdirsyncer.exceptions as exceptions
|
|
||||||
from vdirsyncer.storage.base import Item
|
from vdirsyncer.storage.base import Item
|
||||||
from vdirsyncer.storage.memory import MemoryStorage
|
from vdirsyncer.storage.memory import MemoryStorage
|
||||||
from vdirsyncer.sync import sync
|
from vdirsyncer.sync import sync, SyncConflict, StorageEmpty
|
||||||
|
|
||||||
|
|
||||||
def empty_storage(x):
|
def empty_storage(x):
|
||||||
|
|
@ -51,7 +50,7 @@ def test_missing_status_and_different_items():
|
||||||
item2 = Item(u'UID:1\nhoho')
|
item2 = Item(u'UID:1\nhoho')
|
||||||
a.upload(item1)
|
a.upload(item1)
|
||||||
b.upload(item2)
|
b.upload(item2)
|
||||||
with pytest.raises(exceptions.SyncConflict):
|
with pytest.raises(SyncConflict):
|
||||||
sync(a, b, status)
|
sync(a, b, status)
|
||||||
assert not status
|
assert not status
|
||||||
sync(a, b, status, conflict_resolution='a wins')
|
sync(a, b, status, conflict_resolution='a wins')
|
||||||
|
|
@ -137,7 +136,7 @@ def test_conflict_resolution_both_etags_new(winning_storage):
|
||||||
assert status
|
assert status
|
||||||
a.update(href_a, Item(u'UID:1\nitem a'), etag_a)
|
a.update(href_a, Item(u'UID:1\nitem a'), etag_a)
|
||||||
b.update(href_b, Item(u'UID:1\nitem b'), etag_b)
|
b.update(href_b, Item(u'UID:1\nitem b'), etag_b)
|
||||||
with pytest.raises(exceptions.SyncConflict):
|
with pytest.raises(SyncConflict):
|
||||||
sync(a, b, status)
|
sync(a, b, status)
|
||||||
sync(a, b, status, conflict_resolution='{} wins'.format(winning_storage))
|
sync(a, b, status, conflict_resolution='{} wins'.format(winning_storage))
|
||||||
item_a, _ = a.get(href_a)
|
item_a, _ = a.get(href_a)
|
||||||
|
|
@ -203,8 +202,8 @@ def test_empty_storage_dataloss():
|
||||||
a.upload(Item(u'UID:2'))
|
a.upload(Item(u'UID:2'))
|
||||||
status = {}
|
status = {}
|
||||||
sync(a, b, status)
|
sync(a, b, status)
|
||||||
with pytest.raises(exceptions.StorageEmpty):
|
with pytest.raises(StorageEmpty):
|
||||||
sync(MemoryStorage(), b, status)
|
sync(MemoryStorage(), b, status)
|
||||||
|
|
||||||
with pytest.raises(exceptions.StorageEmpty):
|
with pytest.raises(StorageEmpty):
|
||||||
sync(a, MemoryStorage(), status)
|
sync(a, MemoryStorage(), status)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
vdirsyncer.exceptions
|
vdirsyncer.exceptions
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Contains exception classes used by vdirsyncer. Not all exceptions are here,
|
||||||
|
only the most commonly used ones.
|
||||||
|
|
||||||
:copyright: (c) 2014 Markus Unterwaditzer
|
:copyright: (c) 2014 Markus Unterwaditzer
|
||||||
:license: MIT, see LICENSE for more details.
|
:license: MIT, see LICENSE for more details.
|
||||||
'''
|
'''
|
||||||
|
|
@ -33,29 +36,3 @@ class AlreadyExistingError(PreconditionFailed):
|
||||||
|
|
||||||
class WrongEtagError(PreconditionFailed):
|
class WrongEtagError(PreconditionFailed):
|
||||||
'''Wrong etag'''
|
'''Wrong etag'''
|
||||||
|
|
||||||
|
|
||||||
class StorageError(Error):
|
|
||||||
'''Internal or initialization errors with storage.'''
|
|
||||||
|
|
||||||
|
|
||||||
class SyncError(Error):
|
|
||||||
'''Errors related to synchronization.'''
|
|
||||||
|
|
||||||
|
|
||||||
class SyncConflict(SyncError):
|
|
||||||
'''
|
|
||||||
Two items changed since the last sync, they now have different contents and
|
|
||||||
no conflict resolution method was given.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class StorageEmpty(SyncError):
|
|
||||||
'''
|
|
||||||
One storage unexpectedly got completely empty between two synchronizations.
|
|
||||||
The first argument is the empty storage.
|
|
||||||
'''
|
|
||||||
|
|
||||||
@property
|
|
||||||
def empty_storage(self):
|
|
||||||
return self.args[0]
|
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ class DavStorage(Storage):
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
if self.dav_header not in response.headers.get('DAV', ''):
|
if self.dav_header not in response.headers.get('DAV', ''):
|
||||||
raise exceptions.StorageError('URL is not a collection')
|
raise ValueError('URL is not a collection')
|
||||||
|
|
||||||
def _default_headers(self):
|
def _default_headers(self):
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,28 @@ from .utils import iteritems, itervalues
|
||||||
sync_logger = log.get(__name__)
|
sync_logger = log.get(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SyncError(exceptions.Error):
|
||||||
|
'''Errors related to synchronization.'''
|
||||||
|
|
||||||
|
|
||||||
|
class SyncConflict(SyncError):
|
||||||
|
'''
|
||||||
|
Two items changed since the last sync, they now have different contents and
|
||||||
|
no conflict resolution method was given.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class StorageEmpty(SyncError):
|
||||||
|
'''
|
||||||
|
One storage unexpectedly got completely empty between two synchronizations.
|
||||||
|
The first argument is the empty storage.
|
||||||
|
'''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def empty_storage(self):
|
||||||
|
return self.args[0]
|
||||||
|
|
||||||
|
|
||||||
def prepare_list(storage, href_to_status):
|
def prepare_list(storage, href_to_status):
|
||||||
download = []
|
download = []
|
||||||
for href, etag in storage.list():
|
for href, etag in storage.list():
|
||||||
|
|
@ -55,9 +77,9 @@ def sync(storage_a, storage_b, status, conflict_resolution=None,
|
||||||
If this is the first sync, an empty dictionary should be provided.
|
If this is the first sync, an empty dictionary should be provided.
|
||||||
:param conflict_resolution: Either 'a wins' or 'b wins'. If none is
|
:param conflict_resolution: Either 'a wins' or 'b wins'. If none is
|
||||||
provided, the sync function will raise
|
provided, the sync function will raise
|
||||||
:py:exc:`vdirsyncer.exceptions.SyncConflict`.
|
:py:exc:`SyncConflict`.
|
||||||
:param force_delete: When one storage got completely emptied between two
|
:param force_delete: When one storage got completely emptied between two
|
||||||
syncs, :py:exc:`vdirsyncer.exceptions.StorageEmpty` is raised for
|
syncs, :py:exc:`StorageEmpty` is raised for
|
||||||
safety. Setting this parameter to ``True`` disables this safety
|
safety. Setting this parameter to ``True`` disables this safety
|
||||||
measure.
|
measure.
|
||||||
'''
|
'''
|
||||||
|
|
@ -74,7 +96,7 @@ def sync(storage_a, storage_b, status, conflict_resolution=None,
|
||||||
list_b = dict(prepare_list(storage_b, b_href_to_status))
|
list_b = dict(prepare_list(storage_b, b_href_to_status))
|
||||||
|
|
||||||
if bool(list_a) != bool(list_b) and status and not force_delete:
|
if bool(list_a) != bool(list_b) and status and not force_delete:
|
||||||
raise exceptions.StorageEmpty(storage_b if list_a else storage_a)
|
raise StorageEmpty(storage_b if list_a else storage_a)
|
||||||
|
|
||||||
a_uid_to_href = dict((x['uid'], href) for href, x in iteritems(list_a))
|
a_uid_to_href = dict((x['uid'], href) for href, x in iteritems(list_a))
|
||||||
b_uid_to_href = dict((x['uid'], href) for href, x in iteritems(list_b))
|
b_uid_to_href = dict((x['uid'], href) for href, x in iteritems(list_b))
|
||||||
|
|
@ -165,7 +187,7 @@ def action_conflict_resolve(uid):
|
||||||
sync_logger.info('...same content on both sides.')
|
sync_logger.info('...same content on both sides.')
|
||||||
status[uid] = a_href, a_meta['etag'], b_href, b_meta['etag']
|
status[uid] = a_href, a_meta['etag'], b_href, b_meta['etag']
|
||||||
elif conflict_resolution is None:
|
elif conflict_resolution is None:
|
||||||
raise exceptions.SyncConflict()
|
raise SyncConflict()
|
||||||
elif conflict_resolution == 'a wins':
|
elif conflict_resolution == 'a wins':
|
||||||
sync_logger.info('...{} wins.'.format(a_storage))
|
sync_logger.info('...{} wins.'.format(a_storage))
|
||||||
action_update(uid, 'a', 'b')(storages, status, conflict_resolution)
|
action_update(uid, 'a', 'b')(storages, status, conflict_resolution)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue