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

dev(hansbug): add delayed proxy into treevalue base

上级 8a78ab28
import pytest
from treevalue.tree.common import DelayedProxy, delayed_partial
@pytest.mark.unittest
class TestTreeDelay:
def test_delayed_partial_simple(self):
cnt = 0
def f():
nonlocal cnt
cnt += 1
return 1
pv = delayed_partial(f)
assert cnt == 0
assert isinstance(pv, DelayedProxy)
assert pv.value() == 1
assert cnt == 1
assert pv.value() == 1
assert cnt == 1
def test_delayed_partial_func(self):
cnt = 0
def f(x, y):
nonlocal cnt
cnt += 1
return x + y * 2 + 1
pv = delayed_partial(f, 2, y=3)
assert cnt == 0
assert isinstance(pv, DelayedProxy)
assert pv.value() == 9
assert cnt == 1
assert pv.value() == 9
assert cnt == 1
def test_delayed_partial_complex(self):
cnt1, cnt2 = 0, 0
def f1():
nonlocal cnt1
cnt1 += 1
return 1
def f2(x, y):
nonlocal cnt2
cnt2 += 1
return (x + 1) ** 2 + y + 2
pv = delayed_partial(f2, delayed_partial(f1), delayed_partial(f1))
assert cnt1 == 0
assert cnt2 == 0
assert isinstance(pv, DelayedProxy)
assert pv.value() == 7
assert cnt1 == 2
assert cnt2 == 1
assert pv.value() == 7
assert cnt1 == 2
assert cnt2 == 1
from .base import raw, unraw, RawWrapper
from .delay import DelayedProxy, delayed_partial, unwrap_proxy
from .storage import TreeStorage, create_storage
# distutils:language=c++
# cython:language_level=3
from libcpp cimport bool
cdef class DelayedProxy:
cpdef object value(self)
cdef class DelayedValueProxy(DelayedProxy):
cdef readonly object func
cdef readonly bool calculated
cdef object val
cpdef object value(self)
cdef class DelayedFuncProxy(DelayedProxy):
cdef readonly object func
cdef readonly tuple args
cdef readonly dict kwargs
cdef readonly bool calculated
cdef object val
cpdef object value(self)
cpdef object unwrap_proxy(object proxy)
# distutils:language=c++
# cython:language_level=3
import cython
cdef class DelayedProxy:
cpdef object value(self):
raise NotImplementedError # pragma: no cover
cdef class DelayedValueProxy(DelayedProxy):
def __cinit__(self, object func):
self.func = func
self.calculated = False
self.val = None
cpdef object value(self):
cdef object f
if not self.calculated:
f = unwrap_proxy(self.func)
self.val = f()
self.calculated = True
return self.val
cdef class DelayedFuncProxy(DelayedProxy):
def __cinit__(self, object func, tuple args, dict kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
self.calculated = False
self.val = None
cpdef object value(self):
cdef list pas
cdef dict pks
cdef str key
cdef object item
cdef object f
if not self.calculated:
f = unwrap_proxy(self.func)
pas = []
pks = {}
for item in self.args:
pas.append(unwrap_proxy(item))
for key, item in self.kwargs.items():
pks[key] = unwrap_proxy(item)
self.val = f(*pas, **pks)
self.calculated = True
return self.val
def delayed_partial(func, *args, **kwargs):
if args or kwargs:
return DelayedFuncProxy(func, args, kwargs)
else:
return DelayedValueProxy(func)
@cython.binding(True)
cpdef inline object unwrap_proxy(object proxy):
if isinstance(proxy, DelayedProxy):
return unwrap_proxy(proxy.value())
else:
return proxy
......@@ -4,7 +4,7 @@
ctypedef unsigned char boolean
ctypedef unsigned int uint
cdef void _key_validate(const char*key) except *
cdef void _key_validate(const char *key) except *
cdef class TreeStorage:
cdef readonly dict map
......
......@@ -6,11 +6,12 @@ from copy import deepcopy
from libc.string cimport strlen
from .base cimport raw, unraw
from .delay cimport unwrap_proxy, DelayedProxy
cdef inline object _keep_object(object obj):
return obj
cdef inline void _key_validate(const char*key) except *:
cdef inline void _key_validate(const char *key) except *:
cdef int n = strlen(key)
if n < 1:
raise KeyError(f'Key {repr(key)} is too short, minimum length is 1 but {n} found.')
......@@ -35,8 +36,15 @@ cdef class TreeStorage:
self.map[key] = value
cpdef public object get(self, str key):
cdef object v, newv
try:
return self.map[key]
v = self.map[key]
newv = unwrap_proxy(v)
if newv is not v:
self.map[key] = v
return newv
else:
return v
except KeyError:
raise KeyError(f"Key {repr(key)} not found in this tree.")
......@@ -70,11 +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
cdef object v, obj, newv
for k, v in self.map.items():
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)
......@@ -106,7 +119,7 @@ cdef class TreeStorage:
cdef set keys = set(self.map.keys()) | set(detached.keys())
cdef str k
cdef object
cdef object v, nv
cdef TreeStorage newv
for k in keys:
if k in detached:
......@@ -119,6 +132,10 @@ 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]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册