Permalink
Browse files

Fixed some bugs with collections.OrderedDict; w/ tests. Cleaned up so…

…me error prints (now uses logging).
  • Loading branch information...
Eli Stevens
Eli Stevens committed Nov 30, 2011
1 parent 79e9622 commit 55efee69f60d0111f9cb539d77a5b29ee72ed318
Showing with 165 additions and 24 deletions.
  1. +25 −17 couchable/core.py
  2. +138 −7 couchable/testing/test_couchable.py
  3. +2 −0 release.sh
View
@@ -405,7 +405,11 @@ def store(self, what, skip=None):
with couchdb.multipart.MultipartWriter(fileobj, headers=None, subtype='form-data') as mpw:
mime_headers = {'Content-Disposition': '''form-data; name="_doc"'''}
- mpw.add('application/json', couchdb.json.encode(doc), mime_headers)
+ try:
+ mpw.add('application/json', couchdb.json.encode(doc), mime_headers)
+ except TypeError:
+ log_internal.exception("Cannot json.encode: {!r}".format(doc))
+ raise
for content_name, (content, content_type) in list(attachment_dict.items()):
mime_headers = {'Content-Disposition': '''form-data; name="_attachments"; filename="{}"'''.format(content_name)}
@@ -437,7 +441,7 @@ def store(self, what, skip=None):
#print ret_list
for (success, _id, _rev), (obj, doc) in itertools.izip(ret_list, bulk_list):
if not success:
- log_internal.warn("Error updating {} {}, {}: ".format(type(obj), _id, _rev) + repr(doc))
+ log_internal.warn("Error updating {}: {} @ {}".format(type(obj), _id, _rev)) # + repr(doc))
raise _rev
else:
obj._rev = _rev
@@ -462,12 +466,11 @@ def _store(self, obj):
func_tuple[0](obj, self)
if not hasattr(obj, '_id'):
- #obj._id = '{}:{}'.format(typestr(obj), uuid.uuid4()).lstrip('_')
newid(obj)
assert obj._id not in self._obj_by_id
if obj._id not in self._done_dict:
- self._done_dict[obj._id] = (obj, {}, [])
+ self._done_dict[obj._id] = (obj, {}, {})
attachment_dict = {}
@@ -493,8 +496,9 @@ def _pack(self, parent_doc, data, attachment_dict, name, isKey=False):
#print "Calling _pack: {}".format((data, attachment_dict, name))
#print ''.join(traceback.format_stack())
return handler(self, parent_doc, data, attachment_dict, name, isKey)
- except RuntimeError:
- log_internal.error(name)
+ #except RuntimeError:
+ # log_internal.error(name)
+ # raise
except Exception, e:
log_internal.error(name)
raise
@@ -790,7 +794,7 @@ def _pack_consargs_keyAsKey(self, parent_doc, data, attachment_dict, name, isKey
elif isinstance(data, tuple) and type(data) != tuple and type(data).__new__ != tuple.__new__:
return self._objInfo_consargs(data, {}, self._pack_list_noKey(parent_doc, list(data), attachment_dict, name, False))
else:
- return self._objInfo_consargs(data, {}, [self._pack_list_noKey(parent_doc, list(data), attachment_dict, name, False)])
+ return self._objInfo_consargs(data, {}, args=[self._pack_list_noKey(parent_doc, list(data), attachment_dict, name, False)])
@_packer(list)
def _pack_list_noKey(self, parent_doc, data, attachment_dict, name, isKey):
@@ -820,8 +824,6 @@ def _pack_list_noKey(self, parent_doc, data, attachment_dict, name, isKey):
return self._pack_object(parent_doc, data, attachment_dict, name, isKey)
- #return self._objInfo_consargs(data, {}, [self._pack_list_noKey(parent_doc, list(data), attachment_dict, name, False)])
-
return [self._pack(parent_doc, x, attachment_dict, '{}[{}]'.format(name, i), False) for i, x in enumerate(data)]
@_packer(dict)
@@ -856,18 +858,17 @@ def _pack_dict_keyMeansObject(self, parent_doc, data, attachment_dict, name, isO
if type(data) is collections.OrderedDict:
assert not isObjDict, "{}: {}".format(name, str(type(data)))
+ # We do this so that the ordered-ness doesn't prevent us from using
+ # it like a normal dict in views. May change this...
doc = self._pack_dict_keyMeansObject(parent_doc, dict(data.items()), attachment_dict, name, False)
- self._objInfo_consargs(data, doc, args=[[list(x) for x in data.items()]])
- #
- #self._objInfo_doc(data, doc)
- #doc[FIELD_NAME]['keyOrder'] = list(data.keys())
+
+ self._objInfo_consargs(data, doc, args=[self._pack_list_noKey(parent_doc, list(data.items()), attachment_dict, name, False)])
return doc
if type(data) is not dict:
assert not isObjDict, "{}: {}".format(name, str(type(data)))
- #return self._objInfo_consargs(data, {}, [], self._pack_dict_keyMeansObject(parent_doc, dict(data.items()), attachment_dict, name, False))
return self._pack_object(parent_doc, data, attachment_dict, name, False) # FIXME???
@@ -1009,13 +1010,15 @@ def _unpack(self, parent_doc, doc, loaded_dict, inst=None):
if 'args' in info and 'kwargs' in info:
#print cls, doc['args'], doc['kwargs']
+ args = None
+ kwargs = None
try:
args = self._unpack(parent_doc, info['args'], loaded_dict)
kwargs = self._unpack(parent_doc, info['kwargs'], loaded_dict)
inst = cls(*args, **kwargs)
except:
- print cls, args, kwargs
+ log_internal.error("Error unpacking args, kwargs for: {} {} {}".format(cls, args, kwargs))
raise
else:
@@ -1053,7 +1056,7 @@ def _unpack(self, parent_doc, doc, loaded_dict, inst=None):
else:
return {self._unpack(parent_doc, k, loaded_dict): self._unpack(parent_doc, v, loaded_dict) for k,v in doc.items()}
except:
- print "Error with:", doc
+ log_internal.exception("Error with: {}".format(doc))
raise
def load(self, what, loaded=None):
@@ -1143,7 +1146,11 @@ def load(self, what, loaded=None):
def _load(self, _id, loaded_dict):
if _id not in loaded_dict:
log_internal.info("Fetching object from DB: {}".format(_id))
- loaded_dict[_id] = self.db[_id]
+ try:
+ loaded_dict[_id] = self.db[_id]
+ except:
+ log_internal.exception("Error fetching id: {}".format(_id))
+ raise
doc = loaded_dict[_id]
@@ -1274,6 +1281,7 @@ def __init__(self, name):
id_list.append(str(uuid.uuid1()))
obj._id = sep.join(id_list).lstrip('_')
+ log_internal.debug("Assigning _id {} to {}".format(obj._id, obj))
# Attachments
def doGzip(data, compresslevel=1):
@@ -62,7 +62,10 @@ def __init__(self, **kwargs):
setattr(self, name, value)
def __repr__(self):
- return repr(self.__dict__)
+ return '<{!r} {!r} at {:#08x}>'.format(type(self), vars(self), id(self))
+
+ def __eq__(self, other):
+ return type(self) == type(other) and vars(self) == vars(other)
class SimpleKey(Simple):
def __eq__(self, other):
@@ -82,6 +85,9 @@ def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
+ def __repr__(self):
+ return '<{!r} {!r} at {:#08x}>'.format(type(self), vars(self), id(self))
+
class SimpleAttachment(couchable.CouchableAttachment):
def __init__(self, **kwargs):
for name, value in kwargs.items():
@@ -194,8 +200,8 @@ def test_2_baseTypeSubclasses_2(self):
obj = self.cdb.load(_id)
- print obj
- print obj.__dict__
+ #print obj
+ #print obj.__dict__
self.assertEqual(obj.x, 4)
self.assertEqual(type(obj), DictSubclass)
@@ -311,14 +317,106 @@ def test_3_namedtuple(self):
self.assertEqual(type(obj.ts), TupleSubclass)
self.assertEqual(obj.ts[3], 4)
- @attr('couchable')
- def test_31_odict(self):
+ @attr('couchable', 'odict')
+ def test_31_odict0_json(self):
+ limit = sys.getrecursionlimit()
+ try:
+ sys.setrecursionlimit(100)
+
+
+ kv_list = [(chr(ord('a') + i), i) for i in range(3)]
+ od = collections.OrderedDict()
+ for k,v in kv_list:
+ od[k] = v
+
+ obj = Simple(od=od)
+
+ _id = self.cdb.store(obj)
+
+ del obj
+ gc.collect()
+ self.assertFalse(self.cdb._obj_by_id, repr(self.cdb._obj_by_id.items()))
+
+ obj = self.cdb.load(_id)
+
+ self.assertEqual(type(obj.od), collections.OrderedDict)
+ self.assertEqual(list(obj.od.items()), kv_list)
+
+ finally:
+ sys.setrecursionlimit(limit)
+
+ @attr('couchable', 'odict')
+ def test_31_odict1_obj(self):
+ limit = sys.getrecursionlimit()
+ try:
+ sys.setrecursionlimit(100)
+
+
+ kv_list = [(chr(ord('a') + i), i) for i in range(3)]
+ kv_list += [('Simple', Simple(a=1, b=2))]
+ od = collections.OrderedDict()
+ for k,v in kv_list:
+ od[k] = v
+
+ obj = Simple(od=od)
+
+ _id = self.cdb.store(obj)
+
+ del obj
+ gc.collect()
+ self.assertFalse(self.cdb._obj_by_id, repr(self.cdb._obj_by_id.items()))
+
+ obj = self.cdb.load(_id)
+
+ self.assertEqual(type(obj.od), collections.OrderedDict)
+ self.assertEqual(list(obj.od.items()), kv_list)
+
+ finally:
+ sys.setrecursionlimit(limit)
+
+
+ @attr('couchable', 'odict')
+ def test_31_odict2_doc(self):
+ limit = sys.getrecursionlimit()
+ try:
+ sys.setrecursionlimit(200)
+
+ kv_list = []
+ #kv_list += [(chr(ord('a') + i), i) for i in range(3)]
+ kv_list += [('SimpleDoc', SimpleDoc(a=1, b=2))]
+ od = collections.OrderedDict()
+ for k,v in kv_list:
+ od[k] = v
+
+ obj = Simple(od=od)
+
+ _id = self.cdb.store(obj)
+
+ #print "Vars:", vars(kv_list[-1][1])
+
+ del obj
+ gc.collect()
+ # Can't assert this here, since we've got the Doc above...
+ #self.assertFalse(self.cdb._obj_by_id, repr(self.cdb._obj_by_id.items()))
+ self.assertEqual(len(self.cdb._obj_by_id), 1)
+
+ obj = self.cdb.load(_id)
+
+ self.assertEqual(type(obj.od), collections.OrderedDict)
+ self.assertEqual(list(obj.od.items()), kv_list)
+
+ finally:
+ sys.setrecursionlimit(limit)
+
+ @attr('couchable', 'odict')
+ def test_31_odict3_pickle(self):
limit = sys.getrecursionlimit()
try:
sys.setrecursionlimit(100)
kv_list = [(chr(ord('a') + i), i) for i in range(10)]
+ kv_list += [('SimplePickle', SimplePickle(a=1, b=2))]
od = collections.OrderedDict()
for k,v in kv_list:
od[k] = v
@@ -339,6 +437,39 @@ def test_31_odict(self):
finally:
sys.setrecursionlimit(limit)
+ @attr('couchable', 'odict')
+ def test_31_odict9_all(self):
+ limit = sys.getrecursionlimit()
+ try:
+ sys.setrecursionlimit(100)
+
+
+ kv_list = [(chr(ord('a') + i), i) for i in range(10)]
+ kv_list += [('Simple', Simple(a=1, b=2))]
+ kv_list += [('SimpleDoc', SimpleDoc(a=1, b=2))]
+ kv_list += [('SimplePickle', SimplePickle(a=1, b=2))]
+ od = collections.OrderedDict()
+ for k,v in kv_list:
+ od[k] = v
+
+ obj = Simple(od=od)
+
+ _id = self.cdb.store(obj)
+
+ del obj
+ gc.collect()
+ # Can't assert this here, since we've got the Doc above...
+ #self.assertFalse(self.cdb._obj_by_id, repr(self.cdb._obj_by_id.items()))
+ self.assertEqual(len(self.cdb._obj_by_id), 1)
+
+ obj = self.cdb.load(_id)
+
+ self.assertEqual(type(obj.od), collections.OrderedDict)
+ self.assertEqual(list(obj.od.items()), kv_list)
+
+ finally:
+ sys.setrecursionlimit(limit)
+
@attr('couchable')
def test_32_types(self):
obj = Simple(int=int)
@@ -568,7 +699,7 @@ def test_viewLoading3(self):
x = self.cdb.load(self.cdb.db.view('couchable/' + fullName, include_docs=True, startkey=['AAA'], endkey=['BBB', {}]).rows)
- print x
+ #print x
a, b = x
@@ -595,7 +726,7 @@ def test_viewLoading2(self):
x = self.cdb.load(id_list, self.cdb.db.view('couchable/' + fullName, include_docs=True, startkey=['BBB'], endkey=['CCC', {}]).rows)
- print x
+ #print x
b, c = x
View
@@ -6,6 +6,8 @@ UPLOAD=$2
if [ "$VER" == "" ]
then
echo "Must specify a version number."
+ echo "./release.sh 9.9.9a1 upload"
+ git tag | tail -n 10
exit
fi

0 comments on commit 55efee6

Please sign in to comment.