From 3670bed66d5ffe06737dc9c82762a2f6f64afe09 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Sat, 5 Apr 2014 18:29:12 +0200 Subject: [PATCH] Make etags always strings. This somewhat helps with environments where ducktyping is not an option (e.g. databases) --- tests/storage/__init__.py | 2 ++ vdirsyncer/storage/base.py | 3 +++ vdirsyncer/storage/filesystem.py | 16 ++++++++++------ vdirsyncer/storage/memory.py | 10 +++++++--- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py index 77ecc6f..61899a1 100644 --- a/tests/storage/__init__.py +++ b/tests/storage/__init__.py @@ -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 diff --git a/vdirsyncer/storage/base.py b/vdirsyncer/storage/base.py index 06c88e2..9785cc4 100644 --- a/vdirsyncer/storage/base.py +++ b/vdirsyncer/storage/base.py @@ -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 diff --git a/vdirsyncer/storage/filesystem.py b/vdirsyncer/storage/filesystem.py index 2051908..860291e 100644 --- a/vdirsyncer/storage/filesystem.py +++ b/vdirsyncer/storage/filesystem.py @@ -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) diff --git a/vdirsyncer/storage/memory.py b/vdirsyncer/storage/memory.py index 1b8b96b..93eb331 100644 --- a/vdirsyncer/storage/memory.py +++ b/vdirsyncer/storage/memory.py @@ -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