Unify terminology obj => item

This commit is contained in:
Markus Unterwaditzer 2014-04-06 00:21:28 +02:00
parent 2b81ba4ffd
commit 7f01b22642
7 changed files with 75 additions and 73 deletions

View file

@ -44,9 +44,9 @@ class StorageTests(object):
assert isinstance(href, (str, unicode))
assert isinstance(etag, (str, unicode))
assert s.has(href)
obj, etag2 = s.get(href)
item, etag2 = s.get(href)
assert etag == etag2
assert 'UID:{}'.format(obj.uid) in obj.raw
assert 'UID:{}'.format(item.uid) in item.raw
def test_upload_already_existing(self):
s = self._get_storage()
@ -81,10 +81,10 @@ class StorageTests(object):
def test_wrong_etag(self):
s = self._get_storage()
obj = self._create_bogus_item(1)
href, etag = s.upload(obj)
item = self._create_bogus_item(1)
href, etag = s.upload(item)
with pytest.raises(exceptions.PreconditionFailed):
s.update(href, obj, '"lolnope"')
s.update(href, item, '"lolnope"')
with pytest.raises(exceptions.PreconditionFailed):
s.delete(href, '"lolnope"')

View file

@ -135,10 +135,10 @@ def test_conflict_resolution_both_etags_new():
with pytest.raises(exceptions.SyncConflict):
sync(a, b, status)
sync(a, b, status, conflict_resolution='a wins')
obj_a, _ = a.get(href_a)
obj_b, _ = b.get(href_b)
assert_item_equals(obj_a, obj_b)
n = normalize_item(obj_a)
item_a, _ = a.get(href_a)
item_b, _ = b.get(href_b)
assert_item_equals(item_a, item_b)
n = normalize_item(item_a)
assert u'UID:1' in n
assert u'ASDASD' in n

View file

@ -29,15 +29,17 @@ class Storage(object):
implement.
Terminology:
- UID: Global identifier of the item, across storages.
- HREF: Per-storage identifier of item, might be UID. The reason items
aren't just referenced by their UID is because the CalDAV and CardDAV
specifications make this imperformant to implement.
- ETAG: Checksum of item, or something similar that changes when the
object does.
- ITEM: Instance of the Item class, represents a calendar event, task or
contact.
- UID: String; Global identifier of the item, across storages.
- HREF: String; Per-storage identifier of item, might be UID. The reason
items aren't just referenced by their UID is because the CalDAV and
CardDAV specifications make this imperformant to implement.
- ETAG: String; Checksum of item, or something similar that changes when the
item does.
All of the above properties should be strings. If bytestrings, an ASCII
encoding is assumed.
Strings can be either unicode strings or bytestrings. If bytestrings, an
ASCII encoding is assumed.
:param collection: If None, the given URL or path is already directly
referring to a collection. Otherwise it will be treated as a basepath
@ -77,7 +79,7 @@ class Storage(object):
def get(self, href):
'''
:param href: href to fetch
:returns: (object, etag)
:returns: (item, etag)
'''
raise NotImplementedError()
@ -86,11 +88,11 @@ class Storage(object):
:param hrefs: list of hrefs to fetch
:raises: :exc:`vdirsyncer.exceptions.PreconditionFailed` if one of the
items couldn't be found.
:returns: iterable of (href, obj, etag)
:returns: iterable of (href, item, etag)
'''
for href in hrefs:
obj, etag = self.get(href)
yield href, obj, etag
item, etag = self.get(href)
yield href, item, etag
def has(self, href):
'''
@ -99,17 +101,17 @@ class Storage(object):
'''
raise NotImplementedError()
def upload(self, obj):
def upload(self, item):
'''
Upload a new object, raise
Upload a new item, raise
:exc:`vdirsyncer.exceptions.PreconditionFailed` if it already exists.
:returns: (href, etag)
'''
raise NotImplementedError()
def update(self, href, obj, etag):
def update(self, href, item, etag):
'''
Update the object, raise
Update the item, raise
:exc:`vdirsyncer.exceptions.PreconditionFailed` if the etag on the
server doesn't match the given etag or if the item doesn't exist.
@ -119,7 +121,7 @@ class Storage(object):
def delete(self, href, etag):
'''
Delete the object by href, raise
Delete the item by href, raise
:exc:`vdirsyncer.exceptions.PreconditionFailed` when item has a
different etag or doesn't exist.
'''

View file

@ -103,9 +103,9 @@ class DavStorage(HttpStorageBase):
response.raise_for_status()
def get(self, href):
((actual_href, obj, etag),) = self.get_multi([href])
((actual_href, item, etag),) = self.get_multi([href])
assert href == actual_href
return obj, etag
return item, etag
def get_multi(self, hrefs):
if not hrefs:
@ -129,7 +129,7 @@ class DavStorage(HttpStorageBase):
for element in root.iter('{DAV:}response'):
href = self._normalize_href(
element.find('{DAV:}href').text.decode(response.encoding))
obj = element \
raw = element \
.find('{DAV:}propstat') \
.find('{DAV:}prop') \
.find(self.get_multi_data_query).text
@ -137,11 +137,11 @@ class DavStorage(HttpStorageBase):
.find('{DAV:}propstat') \
.find('{DAV:}prop') \
.find('{DAV:}getetag').text
if isinstance(obj, bytes):
obj = obj.decode(response.encoding)
if isinstance(raw, bytes):
raw = raw.decode(response.encoding)
if isinstance(etag, bytes):
etag = etag.decode(response.encoding)
rv.append((href, Item(obj), etag))
rv.append((href, Item(raw), etag))
try:
hrefs_left.remove(href)
except KeyError:
@ -159,7 +159,7 @@ class DavStorage(HttpStorageBase):
else:
return True
def _put(self, href, obj, etag):
def _put(self, href, item, etag):
headers = self._default_headers()
headers['Content-Type'] = self.item_mimetype
if etag is None:
@ -171,25 +171,25 @@ class DavStorage(HttpStorageBase):
response = self._request(
'PUT',
href,
data=obj.raw.encode('utf-8'),
data=item.raw.encode('utf-8'),
headers=headers
)
self._check_response(response)
etag = response.headers.get('etag', None)
if not etag:
obj2, etag = self.get(href)
assert obj2.uid == obj.uid
item2, etag = self.get(href)
assert item2.uid == item.uid
return href, etag
def update(self, href, obj, etag):
def update(self, href, item, etag):
href = self._normalize_href(href)
if etag is None:
raise ValueError('etag must be given and must not be None.')
return self._put(href, obj, etag)
return self._put(href, item, etag)
def upload(self, obj):
href = self._get_href(obj.uid)
return self._put(href, obj, None)
def upload(self, item):
href = self._get_href(item.uid)
return self._put(href, item, None)
def delete(self, href, etag):
href = self._normalize_href(href)

View file

@ -76,28 +76,28 @@ class FilesystemStorage(Storage):
def has(self, href):
return os.path.isfile(self._get_filepath(href))
def upload(self, obj):
href = self._get_href(obj.uid)
def upload(self, item):
href = self._get_href(item.uid)
fpath = self._get_filepath(href)
if os.path.exists(fpath):
raise exceptions.AlreadyExistingError(obj.uid)
raise exceptions.AlreadyExistingError(item.uid)
with open(fpath, 'wb+') as f:
f.write(obj.raw.encode(self.encoding))
f.write(item.raw.encode(self.encoding))
return href, _get_etag(fpath)
def update(self, href, obj, etag):
def update(self, href, item, etag):
fpath = self._get_filepath(href)
if href != self._get_href(obj.uid):
if href != self._get_href(item.uid):
logger.warning('href != uid + fileext: href={}; uid={}'
.format(href, obj.uid))
.format(href, item.uid))
if not os.path.exists(fpath):
raise exceptions.NotFoundError(obj.uid)
raise exceptions.NotFoundError(item.uid)
actual_etag = _get_etag(fpath)
if etag != actual_etag:
raise exceptions.WrongEtagError(etag, actual_etag)
with open(fpath, 'wb') as f:
f.write(obj.raw.encode('utf-8'))
f.write(item.raw.encode('utf-8'))
return _get_etag(fpath)
def delete(self, href, etag):

View file

@ -23,37 +23,37 @@ class MemoryStorage(Storage):
'''
def __init__(self, **kwargs):
self.items = {} # href => (etag, object)
self.items = {} # href => (etag, item)
super(MemoryStorage, self).__init__(**kwargs)
def list(self):
for href, (etag, obj) in self.items.items():
for href, (etag, item) in self.items.items():
yield href, etag
def get(self, href):
etag, obj = self.items[href]
return obj, etag
etag, item = self.items[href]
return item, etag
def has(self, href):
return href in self.items
def upload(self, obj):
href = self._get_href(obj.uid)
def upload(self, item):
href = self._get_href(item.uid)
if href in self.items:
raise exceptions.AlreadyExistingError(obj.uid)
raise exceptions.AlreadyExistingError(item.uid)
etag = _get_etag()
self.items[href] = (etag, obj)
self.items[href] = (etag, item)
return href, etag
def update(self, href, obj, etag):
if href != self._get_href(obj.uid) or href not in self.items:
def update(self, href, item, etag):
if href != self._get_href(item.uid) or href not in self.items:
raise exceptions.NotFoundError(href)
actual_etag, _ = self.items[href]
if etag != actual_etag:
raise exceptions.WrongEtagError(etag, actual_etag)
new_etag = _get_etag()
self.items[href] = (new_etag, obj)
self.items[href] = (new_etag, item)
return new_etag
def delete(self, href, etag):

View file

@ -23,21 +23,21 @@ def prepare_list(storage, href_to_uid):
if href in href_to_uid:
props['uid'] = href_to_uid[href]
else:
obj, new_etag = storage.get(href)
item, new_etag = storage.get(href)
assert etag == new_etag
props['uid'] = obj.uid
props['obj'] = obj
props['uid'] = item.uid
props['item'] = item
yield href, props
def prefetch(storage, item_list, hrefs):
hrefs_to_prefetch = []
for href in hrefs:
if 'obj' not in item_list[href]:
if 'item' not in item_list[href]:
hrefs_to_prefetch.append(href)
for href, obj, etag in storage.get_multi(hrefs_to_prefetch):
for href, item, etag in storage.get_multi(hrefs_to_prefetch):
assert item_list[href]['etag'] == etag
item_list[href]['obj'] = obj
item_list[href]['item'] = item
def sync(storage_a, storage_b, status, conflict_resolution=None):
@ -63,7 +63,7 @@ def sync(storage_a, storage_b, status, conflict_resolution=None):
(href_b, uid)
for uid, (href_a, etag_a, href_b, etag_b) in status.iteritems()
)
# href => {'etag': etag, 'obj': optional object, 'uid': uid}
# href => {'etag': etag, 'item': optional item, 'uid': uid}
list_a = dict(prepare_list(storage_a, a_href_to_uid))
list_b = dict(prepare_list(storage_b, b_href_to_uid))
@ -97,8 +97,8 @@ def action_upload(uid, source, dest):
source_href = source_uid_to_href[uid]
source_etag = source_list[source_href]['etag']
obj = source_list[source_href]['obj']
dest_href, dest_etag = dest_storage.upload(obj)
item = source_list[source_href]['item']
dest_href, dest_etag = dest_storage.upload(item)
source_status = (source_href, source_etag)
dest_status = (dest_href, dest_etag)
@ -119,8 +119,8 @@ def action_update(uid, source, dest):
dest_href = dest_uid_to_href[uid]
old_etag = dest_list[dest_href]['etag']
obj = source_list[source_href]['obj']
dest_etag = dest_storage.update(dest_href, obj, old_etag)
item = source_list[source_href]['item']
dest_etag = dest_storage.update(dest_href, item, old_etag)
source_status = (source_href, source_etag)
dest_status = (dest_href, dest_etag)
@ -157,7 +157,7 @@ def action_conflict_resolve(uid):
b_href = b_uid_to_href[uid]
a_meta = list_a[a_href]
b_meta = list_b[b_href]
if a_meta['obj'].raw == b_meta['obj'].raw:
if a_meta['item'].raw == b_meta['item'].raw:
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: