mirror of
https://github.com/internetarchive/warcprox.git
synced 2025-01-18 13:22:09 +01:00
implement or explicitly disallow other top-level dict operations on ORM Document, and add more automated tests
This commit is contained in:
parent
e8db41763b
commit
536bf8d1d8
@ -47,7 +47,7 @@ class WatchedDict(dict, object):
|
||||
|
||||
def popitem(self):
|
||||
self.callback(self.field)
|
||||
return dict.popitem()
|
||||
return dict.popitem(self)
|
||||
|
||||
def setdefault(self, *args):
|
||||
self.callback(self.field)
|
||||
@ -57,9 +57,8 @@ class WatchedDict(dict, object):
|
||||
else:
|
||||
return dict.setdefault(self, *args)
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
# looks a little tricky
|
||||
raise Exception('not implemented')
|
||||
# XXX worth implementing?
|
||||
update = None
|
||||
|
||||
class WatchedList(list, object):
|
||||
def __init__(self, l, callback, field):
|
||||
@ -100,9 +99,8 @@ class WatchedList(list, object):
|
||||
self.callback(self.field)
|
||||
return list.pop(self, index)
|
||||
|
||||
def clear(self):
|
||||
self.callback(self.field)
|
||||
return list.clear(self)
|
||||
# python 2.7 doesn't have this anyway
|
||||
clear = None
|
||||
|
||||
def sort(self, key=None, reverse=False):
|
||||
self.callback(self.field)
|
||||
@ -157,14 +155,6 @@ class Document(dict, object):
|
||||
|
||||
@classproperty
|
||||
def table(cls):
|
||||
'''
|
||||
Returns default table name, which is the class name, lowercased.
|
||||
|
||||
Subclasses can override the table name like so:
|
||||
|
||||
class Something(doublethink.Document):
|
||||
table = 'my_table_name'
|
||||
'''
|
||||
return cls.__name__.lower()
|
||||
|
||||
@classmethod
|
||||
@ -214,7 +204,20 @@ class Document(dict, object):
|
||||
if key in self._updates:
|
||||
del self._updates[key]
|
||||
|
||||
# XXX probably need the other stuff like in WatchedDict
|
||||
def setdefault(self, *args):
|
||||
need_update = False
|
||||
if not args[0] in self:
|
||||
need_update = True
|
||||
result = dict.setdefault(self, *args)
|
||||
if need_update:
|
||||
self._updated(args[0])
|
||||
return result
|
||||
|
||||
# dict methods we don't want to support
|
||||
clear = None
|
||||
pop = None
|
||||
popitem = None
|
||||
update = None
|
||||
|
||||
def _updated(self, field):
|
||||
# callback for all updates
|
||||
@ -277,11 +280,12 @@ class Document(dict, object):
|
||||
'unexpected result %s from rethinkdb query %s' % (
|
||||
result, query))
|
||||
if not should_insert and self._deletes:
|
||||
self._r.table(self.table).replace(
|
||||
r.row.without(self._deletes)).run()
|
||||
query = self._r.table(self.table).replace(
|
||||
r.row.without(self._deletes))
|
||||
result = query.run()
|
||||
if result['errors']: # primary key not found
|
||||
should_insert = True
|
||||
elif not result['replaced'] == 0:
|
||||
elif result['replaced'] != 1:
|
||||
raise Exception(
|
||||
'unexpected result %s from rethinkdb query %s' % (
|
||||
result, query))
|
||||
|
2
setup.py
2
setup.py
@ -3,7 +3,7 @@ import codecs
|
||||
|
||||
setuptools.setup(
|
||||
name='doublethink',
|
||||
version='0.2.0.dev64',
|
||||
version='0.2.0.dev65',
|
||||
packages=['doublethink'],
|
||||
classifiers=[
|
||||
'Programming Language :: Python :: 2.7',
|
||||
|
@ -321,16 +321,14 @@ def test_orm(r):
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'d': 'e', 'o': 'p'}, 'f': ['q', 'h'], 'i': 't'}
|
||||
|
||||
# list manipulations
|
||||
d.f.append(['sublist'])
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'d': 'e', 'o': 'p'},
|
||||
'f': ['q', 'h', ['sublist']], 'i': 't'}
|
||||
|
||||
### list.clear not in python 2.7
|
||||
# d.f[2].clear()
|
||||
# assert d._updates == {
|
||||
# 'm': 'n', 'c': {'d': 'e', 'o': 'p'},
|
||||
# 'f': ['q', 'h', []], 'i': 't'}
|
||||
with pytest.raises(TypeError):
|
||||
d.f[2].clear()
|
||||
|
||||
result = d.f.pop()
|
||||
assert result == ['sublist']
|
||||
@ -364,20 +362,102 @@ def test_orm(r):
|
||||
'm': 'n', 'c': {'d': 'e', 'o': 'p'},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
expected = dict(d)
|
||||
# more nested field dict operations
|
||||
del d['c']['d']
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'o': 'p'},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
d['c'].clear()
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
assert d['c'].setdefault('aa') is None
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'aa': None},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
d['c'].setdefault('aa', 'bb') is None
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'aa': None},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
d['c'].setdefault('cc', 'dd') == 'dd'
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'aa': None, 'cc': 'dd'},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
d['c'].setdefault('cc') == 'dd'
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'aa': None, 'cc': 'dd'},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
d['c'].setdefault('cc', 'ee') == 'dd'
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'aa': None, 'cc': 'dd'},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
assert d['c'].pop('cc') == 'dd'
|
||||
assert d._updates == {
|
||||
'm': 'n', 'c': {'aa': None},
|
||||
'f': ['u', 'v', {'w': 'x', 'y': 'z'}], 'i': 't'}
|
||||
|
||||
assert d['f'][2].popitem()
|
||||
assert d._updates['f'][2] in ({'w':'x'}, {'y':'z'})
|
||||
|
||||
d.save()
|
||||
assert d._updates == {}
|
||||
assert d._deletes == set()
|
||||
|
||||
d_copy = SomeDoc.load(r, d.id)
|
||||
assert d == d_copy
|
||||
|
||||
d['zuh'] = 'toot'
|
||||
d.save()
|
||||
assert d != d_copy
|
||||
d_copy.refresh()
|
||||
assert d == d_copy
|
||||
|
||||
# top level dict operations
|
||||
with pytest.raises(TypeError):
|
||||
d.clear()
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
d.pop('m')
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
d.popitem()
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
d.update({'x':'y'})
|
||||
|
||||
assert d.setdefault('ee') is None
|
||||
assert d._updates == {'ee': None}
|
||||
|
||||
d.setdefault('ee', 'ff') is None
|
||||
assert d._updates == {'ee': None}
|
||||
|
||||
d.setdefault('gg', 'hh') == 'hh'
|
||||
assert d._updates == {'ee': None, 'gg': 'hh'}
|
||||
|
||||
d.setdefault('gg') == 'hh'
|
||||
assert d._updates == {'ee': None, 'gg': 'hh'}
|
||||
|
||||
d.setdefault('gg', 'ii') == 'hh'
|
||||
assert d._updates == {'ee': None, 'gg': 'hh'}
|
||||
|
||||
d.save()
|
||||
assert d._updates == {}
|
||||
assert d._deletes == set()
|
||||
|
||||
d_copy = SomeDoc.load(r, d.id)
|
||||
assert d == d_copy
|
||||
d['yuh'] = 'soot'
|
||||
d.save()
|
||||
assert d != d_copy
|
||||
d_copy.refresh()
|
||||
assert d == d_copy
|
||||
|
||||
def test_orm_pk(r):
|
||||
class NonstandardPrimaryKey(doublethink.Document):
|
||||
@classmethod
|
||||
|
Loading…
x
Reference in New Issue
Block a user