Move "obscure" exceptions into their own modules

This commit is contained in:
Markus Unterwaditzer 2014-05-03 00:15:51 +02:00
parent 233e8524ab
commit 9616f0bbfe
5 changed files with 36 additions and 38 deletions

View file

@ -240,7 +240,7 @@ class TestCaldavStorage(DavStorageTests):
monkeypatch.setattr('requests.sessions.Session.request', request)
with pytest.raises(exceptions.StorageError):
with pytest.raises(ValueError):
self.storage_class(**args)
assert len(calls) == 1

View file

@ -10,10 +10,9 @@
import pytest
from . import assert_item_equals, normalize_item
import vdirsyncer.exceptions as exceptions
from vdirsyncer.storage.base import Item
from vdirsyncer.storage.memory import MemoryStorage
from vdirsyncer.sync import sync
from vdirsyncer.sync import sync, SyncConflict, StorageEmpty
def empty_storage(x):
@ -51,7 +50,7 @@ def test_missing_status_and_different_items():
item2 = Item(u'UID:1\nhoho')
a.upload(item1)
b.upload(item2)
with pytest.raises(exceptions.SyncConflict):
with pytest.raises(SyncConflict):
sync(a, b, status)
assert not status
sync(a, b, status, conflict_resolution='a wins')
@ -137,7 +136,7 @@ def test_conflict_resolution_both_etags_new(winning_storage):
assert status
a.update(href_a, Item(u'UID:1\nitem a'), etag_a)
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, conflict_resolution='{} wins'.format(winning_storage))
item_a, _ = a.get(href_a)
@ -203,8 +202,8 @@ def test_empty_storage_dataloss():
a.upload(Item(u'UID:2'))
status = {}
sync(a, b, status)
with pytest.raises(exceptions.StorageEmpty):
with pytest.raises(StorageEmpty):
sync(MemoryStorage(), b, status)
with pytest.raises(exceptions.StorageEmpty):
with pytest.raises(StorageEmpty):
sync(a, MemoryStorage(), status)

View file

@ -3,6 +3,9 @@
vdirsyncer.exceptions
~~~~~~~~~~~~~~~~~~~~~
Contains exception classes used by vdirsyncer. Not all exceptions are here,
only the most commonly used ones.
:copyright: (c) 2014 Markus Unterwaditzer
:license: MIT, see LICENSE for more details.
'''
@ -33,29 +36,3 @@ class AlreadyExistingError(PreconditionFailed):
class WrongEtagError(PreconditionFailed):
'''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]

View file

@ -84,7 +84,7 @@ class DavStorage(Storage):
)
response.raise_for_status()
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):
return {

View file

@ -22,6 +22,28 @@ from .utils import iteritems, itervalues
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):
download = []
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.
:param conflict_resolution: Either 'a wins' or 'b wins'. If none is
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
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
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))
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))
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.')
status[uid] = a_href, a_meta['etag'], b_href, b_meta['etag']
elif conflict_resolution is None:
raise exceptions.SyncConflict()
raise SyncConflict()
elif conflict_resolution == 'a wins':
sync_logger.info('...{} wins.'.format(a_storage))
action_update(uid, 'a', 'b')(storages, status, conflict_resolution)