Make etags always strings.

This somewhat helps with environments where ducktyping is not an option
(e.g. databases)
This commit is contained in:
Markus Unterwaditzer 2014-04-05 18:29:12 +02:00
parent 08d3a6f2e0
commit 3670bed66d
4 changed files with 22 additions and 9 deletions

View file

@ -41,6 +41,8 @@ class StorageTests(object):
hrefs.sort()
assert hrefs == sorted(s.list())
for href, etag in hrefs:
assert isinstance(href, (str, unicode))
assert isinstance(etag, (str, unicode))
assert s.has(href)
obj, etag2 = s.get(href)
assert etag == etag2

View file

@ -36,6 +36,9 @@ class Storage(object):
- ETAG: Checksum of item, or something similar that changes when the
object does.
All of the above properties should be strings. 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
to many collections (e.g. a vdir) and the given collection name will be

View file

@ -15,6 +15,10 @@ import vdirsyncer.log as log
logger = log.get('storage.filesystem')
def _get_etag(fpath):
return '{:.9f}'.format(os.path.getmtime(fpath))
class FilesystemStorage(Storage):
'''Saves data in vdir collection
@ -61,13 +65,13 @@ class FilesystemStorage(Storage):
for fname in os.listdir(self.path):
fpath = os.path.join(self.path, fname)
if os.path.isfile(fpath) and fname.endswith(self.fileext):
yield fname, os.path.getmtime(fpath)
yield fname, _get_etag(fpath)
def get(self, href):
fpath = self._get_filepath(href)
with open(fpath, 'rb') as f:
return (Item(f.read().decode(self.encoding)),
os.path.getmtime(fpath))
_get_etag(fpath))
def has(self, href):
return os.path.isfile(self._get_filepath(href))
@ -79,7 +83,7 @@ class FilesystemStorage(Storage):
raise exceptions.AlreadyExistingError(obj.uid)
with open(fpath, 'wb+') as f:
f.write(obj.raw.encode(self.encoding))
return href, os.path.getmtime(fpath)
return href, _get_etag(fpath)
def update(self, href, obj, etag):
fpath = self._get_filepath(href)
@ -88,19 +92,19 @@ class FilesystemStorage(Storage):
.format(href, obj.uid))
if not os.path.exists(fpath):
raise exceptions.NotFoundError(obj.uid)
actual_etag = os.path.getmtime(fpath)
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'))
return os.path.getmtime(fpath)
return _get_etag(fpath)
def delete(self, href, etag):
fpath = self._get_filepath(href)
if not os.path.isfile(fpath):
raise exceptions.NotFoundError(href)
actual_etag = os.path.getmtime(fpath)
actual_etag = _get_etag(fpath)
if etag != actual_etag:
raise exceptions.WrongEtagError(etag, actual_etag)
os.remove(fpath)

View file

@ -7,11 +7,15 @@
:license: MIT, see LICENSE for more details.
'''
import datetime
import random
from vdirsyncer.storage.base import Storage
import vdirsyncer.exceptions as exceptions
def _get_etag():
return '{:.9f}'.format(random.random())
class MemoryStorage(Storage):
'''
@ -37,7 +41,7 @@ class MemoryStorage(Storage):
href = self._get_href(obj.uid)
if href in self.items:
raise exceptions.AlreadyExistingError(obj.uid)
etag = datetime.datetime.now()
etag = _get_etag()
self.items[href] = (etag, obj)
return href, etag
@ -48,7 +52,7 @@ class MemoryStorage(Storage):
if etag != actual_etag:
raise exceptions.WrongEtagError(etag, actual_etag)
new_etag = datetime.datetime.now()
new_etag = _get_etag()
self.items[href] = (new_etag, obj)
return new_etag