提交 00896958 编写于 作者: HansBug's avatar HansBug 😆

dev(hansbug): add all delay support in storage

上级 94d4d9f7
......@@ -2,7 +2,7 @@ import pickle
import pytest
from treevalue.tree.common import create_storage, raw, TreeStorage
from treevalue.tree.common import create_storage, raw, TreeStorage, delayed_partial
# noinspection PyArgumentList,DuplicatedCode
......@@ -23,6 +23,52 @@ class TestTreeStorage:
with pytest.raises(KeyError):
_ = t.get('fff')
cnt1, cnt2, cnt3 = 0, 0, 0
def f1():
nonlocal cnt1
cnt1 += 1
return 2
def f2(x, y):
nonlocal cnt2
cnt2 += 1
return {'x': x, 'y': y}
def f3(x, y):
nonlocal cnt3
cnt3 += 1
return create_storage({'x': x, 'y': raw(y)})
t2 = create_storage({
'a': 1,
'b': delayed_partial(f1),
'c': delayed_partial(f2, delayed_partial(f1), 3),
'd': delayed_partial(f3, 3, delayed_partial(f2, 3, 4))
})
assert t2.get('a') == 1
assert cnt1 == 0
assert t2.get('b') == 2
assert cnt1 == 1
assert t2.get('b') == 2
assert cnt1 == 1
assert (cnt1, cnt2) == (1, 0)
assert t2.get('c') == {'x': 2, 'y': 3}
assert (cnt1, cnt2) == (2, 1)
assert t2.get('c') == {'x': 2, 'y': 3}
assert (cnt1, cnt2) == (2, 1)
assert (cnt1, cnt2, cnt3) == (2, 1, 0)
assert t2.get('d').get('x') == 3
assert t2.get('d').get('y') == {'x': 3, 'y': 4}
assert (cnt1, cnt2, cnt3) == (2, 2, 1)
assert t2.get('d').get('x') == 3
assert t2.get('d').get('y') == {'x': 3, 'y': 4}
assert (cnt1, cnt2, cnt3) == (2, 2, 1)
def test_get_or_default(self):
t = create_storage({'a': 1, 'b': 2, 'c': raw({'x': 3, 'y': 4}), 'd': {'x': 3, 'y': 4}})
assert t.get_or_default('a', 233) == 1
......@@ -122,6 +168,19 @@ class TestTreeStorage:
assert _dumped['d']['x'] == 3
assert _dumped['d']['y'] == 4
t2 = create_storage({
'a': 1,
'b': delayed_partial(lambda x: x + 1, 1),
'c': delayed_partial(lambda: h1),
'd': delayed_partial(lambda: create_storage(h2)),
})
_dumped = t2.dump()
assert _dumped['a'] == 1
assert _dumped['b'] == 2
assert _dumped['c'].value() is h1
assert _dumped['d']['x'] == 3
assert _dumped['d']['y'] == 4
def test_deepdump(self):
h1 = {'x': 3, 'y': 4}
h2 = {'x': 3, 'y': 4}
......@@ -232,6 +291,19 @@ class TestTreeStorage:
assert t1.get('f').get('y') == 4
assert t1.get('f') is not t.get('f')
t2 = create_storage({
'a': delayed_partial(lambda: 11),
'b': delayed_partial(lambda: 22),
'c': delayed_partial(lambda: {'x': 3, 'y': 5}),
'd': delayed_partial(lambda: create_storage({'x': 3, 'y': 7})),
})
t1.copy_from(t2)
assert t1.get('a') == 11
assert t1.get('b') == 22
assert t1.get('c') == {'x': 3, 'y': 5}
assert t1.get('d').get('x') == 3
assert t1.get('d').get('y') == 7
def test_deepcopy_from(self):
h1 = {'x': 3, 'y': 4}
h2 = {'x': 3, 'y': 4}
......@@ -272,6 +344,21 @@ class TestTreeStorage:
assert t == t
assert t == t1
assert t != t2
assert t != None
t3 = create_storage({
'a': delayed_partial(lambda: 11),
'b': delayed_partial(lambda: 22),
'c': delayed_partial(lambda: {'x': 3, 'y': 5}),
'd': delayed_partial(lambda: create_storage({'x': 3, 'y': 7})),
})
t4 = create_storage({
'a': delayed_partial(lambda: t3.get('a')),
'b': delayed_partial(lambda: t3.get('b')),
'c': delayed_partial(lambda: t3.get('c')),
'd': delayed_partial(lambda: t3.get('d')),
})
assert t3 == t4
def test_keys(self):
h1 = {'x': 3, 'y': 4}
......@@ -286,10 +373,20 @@ class TestTreeStorage:
t = create_storage({'a': 1, 'b': 2, 'd': h1})
assert set(t.get('d').values()) == {3, 4}
assert len(t.values()) == 3
assert len(list(t.values())) == 3
assert 1 in t.values()
assert 2 in t.values()
t1 = create_storage({
'a': delayed_partial(lambda: t.get('a')),
'b': delayed_partial(lambda: t.get('b')),
'd': delayed_partial(lambda: t.get('d')),
})
assert set(t1.get('d').values()) == {3, 4}
assert len(list(t1.values())) == 3
assert 1 in t1.values()
assert 2 in t1.values()
def test_items(self):
h1 = {'x': 3, 'y': 4}
t = create_storage({'a': 1, 'b': 2, 'd': raw(h1)})
......@@ -303,3 +400,18 @@ class TestTreeStorage:
assert v == h1
else:
pytest.fail('Should not reach here.')
t1 = create_storage({
'a': delayed_partial(lambda: t.get('a')),
'b': delayed_partial(lambda: t.get('b')),
'd': delayed_partial(lambda: t.get('d')),
})
for k, v in t1.items():
if k == 'a':
assert v == 1
elif k == 'b':
assert v == 2
elif k == 'd':
assert v == h1
else:
pytest.fail('Should not reach here.')
......@@ -39,7 +39,7 @@ cdef class RawWrapper:
self.val = state
@cython.binding(True)
cpdef public object raw(object obj):
cpdef inline object raw(object obj):
"""
Overview:
Try wrap the given ``obj`` to raw wrapper.
......@@ -57,7 +57,7 @@ cpdef public object raw(object obj):
return obj
@cython.binding(True)
cpdef public object unraw(object wrapped):
cpdef inline object unraw(object wrapped):
"""
Overview:
Try unwrap the given ``wrapped`` to original object.
......
......@@ -3,6 +3,8 @@
import cython
from .base cimport unraw
cdef class DelayedProxy:
cpdef object value(self):
raise NotImplementedError # pragma: no cover
......@@ -58,7 +60,8 @@ def delayed_partial(func, *args, **kwargs):
@cython.binding(True)
cpdef inline object unwrap_proxy(object proxy):
if isinstance(proxy, DelayedProxy):
return unwrap_proxy(proxy.value())
else:
return proxy
cdef object p = proxy
while isinstance(p, DelayedProxy):
p = p.value()
return unraw(p)
......@@ -6,7 +6,7 @@ from copy import deepcopy
from libc.string cimport strlen
from .base cimport raw, unraw
from .delay cimport unwrap_proxy, DelayedProxy
from .delay cimport unwrap_proxy
cdef inline object _keep_object(object obj):
return obj
......@@ -36,13 +36,13 @@ cdef class TreeStorage:
self.map[key] = value
cpdef public object get(self, str key):
cdef object v, newv
cdef object v, nv
try:
v = self.map[key]
newv = unwrap_proxy(v)
if newv is not v:
self.map[key] = v
return newv
nv = unwrap_proxy(v)
if nv is not v:
self.map[key] = nv
return nv
else:
return v
except KeyError:
......@@ -78,16 +78,16 @@ cdef class TreeStorage:
cpdef public dict jsondumpx(self, copy_func, object need_raw):
cdef dict result = {}
cdef str k
cdef object v, obj, newv
cdef object v, obj, nv
for k, v in self.map.items():
nv = unwrap_proxy(v)
if nv is not v:
v = nv
self.map[k] = v
if isinstance(v, TreeStorage):
result[k] = v.jsondumpx(copy_func, need_raw)
else:
newv = unwrap_proxy(v)
if newv is not v:
v = newv
self.map[k] = v
obj = copy_func(v)
if need_raw:
obj = raw(obj)
......@@ -124,6 +124,11 @@ cdef class TreeStorage:
for k in keys:
if k in detached:
v = detached[k]
nv = unwrap_proxy(v)
if nv is not v:
v = nv
detached[k] = v
if isinstance(v, TreeStorage):
if k in self.map and isinstance(self.map[k], TreeStorage):
self.map[k].copy_from(v)
......@@ -132,10 +137,6 @@ cdef class TreeStorage:
newv.copy_from(v)
self.map[k] = newv
else:
nv = unwrap_proxy(v)
if nv is not v:
v = nv
detached[k] = v
self.map[k] = copy_func(v)
else:
del self.map[k]
......@@ -162,12 +163,22 @@ cdef class TreeStorage:
cdef list other_keys = sorted(other.detach().keys())
cdef str key
cdef object self_v
cdef object other_v
cdef object self_v, self_nv
cdef object other_v, other_nv
if self_keys == other_keys:
for key in self_keys:
self_v = self.map[key]
self_nv = unwrap_proxy(self_v)
if self_nv is not self_v:
self_v = self_nv
self.map[key] = self_v
other_v = other_map[key]
other_nv = unwrap_proxy(other_v)
if other_nv is not other_v:
other_v = other_nv
other_map[key] = other_v
if self_v != other_v:
return False
return True
......@@ -187,10 +198,26 @@ cdef class TreeStorage:
return self.map.keys()
def values(self):
return self.map.values()
cdef str k
cdef object v, nv
for k, v in self.map.items():
nv = unwrap_proxy(v)
if nv is not v:
v = nv
self.map[k] = v
yield v
def items(self):
return self.map.items()
cdef str k
cdef object v, nv
for k, v in self.map.items():
nv = unwrap_proxy(v)
if nv is not v:
v = nv
self.map[k] = v
yield k, v
cpdef object create_storage(dict value):
cdef dict _map = {}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册