Enforce read-only attribute

This commit is contained in:
Markus Unterwaditzer 2014-12-27 11:22:48 +01:00
parent 1d8c606005
commit 9b442ebcf3
4 changed files with 39 additions and 3 deletions

View file

@ -9,6 +9,7 @@
import pytest
import vdirsyncer.exceptions as exceptions
from vdirsyncer.storage.base import Item
from vdirsyncer.storage.memory import MemoryStorage
from vdirsyncer.sync import BothReadOnly, StorageEmpty, SyncConflict, sync
@ -251,10 +252,14 @@ def test_both_readonly():
def test_readonly():
a = MemoryStorage()
b = MemoryStorage(read_only=True)
b = MemoryStorage()
status = {}
href_a, _ = a.upload(Item(u'UID:1'))
href_b, _ = b.upload(Item(u'UID:2'))
b.read_only = True
with pytest.raises(exceptions.ReadOnlyError):
b.upload(Item(u'UID:3'))
sync(a, b, status)
assert len(status) == 2 and a.has(href_a) and not b.has(href_a)
sync(a, b, status)

View file

@ -44,3 +44,7 @@ class AlreadyExistingError(PreconditionFailed):
class WrongEtagError(PreconditionFailed):
'''Wrong etag'''
class ReadOnlyError(Error):
'''Storage is read-only.'''

View file

@ -7,13 +7,31 @@
:license: MIT, see LICENSE for more details.
'''
import functools
from .. import exceptions
from ..utils import uniq
from ..utils.compat import with_metaclass
from ..utils.vobject import Item # noqa
class Storage(object):
def mutating_storage_method(f):
@functools.wraps(f)
def inner(self, *args, **kwargs):
if self.read_only:
raise exceptions.ReadOnlyError('This storage is read-only.')
return f(self, *args, **kwargs)
return inner
class StorageMeta(type):
def __init__(cls, name, bases, d):
for method in ('update', 'upload', 'delete'):
setattr(cls, method, mutating_storage_method(getattr(cls, method)))
return super(StorageMeta, cls).__init__(name, bases, d)
class Storage(with_metaclass(StorageMeta)):
'''Superclass of all storages, mainly useful to summarize the interface to
implement.
@ -63,8 +81,9 @@ class Storage(object):
if read_only is None:
read_only = self.read_only
if self.read_only and not read_only:
raise ValueError('This storage is read-only.')
raise ValueError('This storage can only be read-only.')
self.read_only = bool(read_only)
if collection and instance_name:
instance_name = '{}/{}'.format(instance_name, collection)
self.instance_name = instance_name

View file

@ -27,3 +27,11 @@ else: # pragma: no cover
text_type = str
iteritems = lambda x: x.items()
itervalues = lambda x: x.values()
def with_metaclass(meta, *bases):
'''Original code from six, by Benjamin Peterson.'''
class metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})