Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDILab开源决策智能平台
treevalue
提交
029f029e
T
treevalue
项目概览
OpenDILab开源决策智能平台
/
treevalue
大约 1 年 前同步成功
通知
3
Star
213
Fork
3
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
treevalue
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
029f029e
编写于
1月 04, 2022
作者:
HansBug
😆
1
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'main' into dev/potc
上级
042dd730
7a627e8e
变更
32
隐藏空白更改
内联
并排
Showing
32 changed file
with
1280 addition
and
128 deletion
+1280
-128
docs/source/api_doc/tree/common.rst
docs/source/api_doc/tree/common.rst
+43
-0
docs/source/api_doc/tree/tree.rst
docs/source/api_doc/tree/tree.rst
+8
-0
requirements-doc.txt
requirements-doc.txt
+1
-1
test/tree/common/test_delay.py
test/tree/common/test_delay.py
+68
-0
test/tree/common/test_storage.py
test/tree/common/test_storage.py
+167
-4
test/tree/func/test_func.py
test/tree/func/test_func.py
+145
-1
test/tree/func/test_outer.py
test/tree/func/test_outer.py
+43
-0
test/tree/general/base.py
test/tree/general/base.py
+51
-2
test/tree/tree/test_flatten.py
test/tree/tree/test_flatten.py
+43
-3
test/tree/tree/test_functional.py
test/tree/tree/test_functional.py
+66
-1
test/tree/tree/test_service.py
test/tree/tree/test_service.py
+33
-1
test/tree/tree/test_structural.py
test/tree/tree/test_structural.py
+70
-1
test/tree/tree/test_tree.py
test/tree/tree/test_tree.py
+15
-1
treevalue/tree/common/__init__.py
treevalue/tree/common/__init__.py
+1
-0
treevalue/tree/common/base.pyx
treevalue/tree/common/base.pyx
+2
-2
treevalue/tree/common/delay.pxd
treevalue/tree/common/delay.pxd
+27
-0
treevalue/tree/common/delay.pyx
treevalue/tree/common/delay.pyx
+142
-0
treevalue/tree/common/storage.pxd
treevalue/tree/common/storage.pxd
+9
-4
treevalue/tree/common/storage.pyx
treevalue/tree/common/storage.pyx
+69
-25
treevalue/tree/func/cfunc.pxd
treevalue/tree/func/cfunc.pxd
+8
-5
treevalue/tree/func/cfunc.pyx
treevalue/tree/func/cfunc.pyx
+84
-28
treevalue/tree/func/func.py
treevalue/tree/func/func.py
+7
-5
treevalue/tree/general/general.py
treevalue/tree/general/general.py
+8
-6
treevalue/tree/tree/__init__.py
treevalue/tree/tree/__init__.py
+1
-1
treevalue/tree/tree/flatten.pyx
treevalue/tree/tree/flatten.pyx
+7
-4
treevalue/tree/tree/functional.pxd
treevalue/tree/tree/functional.pxd
+3
-2
treevalue/tree/tree/functional.pyx
treevalue/tree/tree/functional.pyx
+31
-9
treevalue/tree/tree/service.pyx
treevalue/tree/tree/service.pyx
+14
-5
treevalue/tree/tree/structural.pxd
treevalue/tree/tree/structural.pxd
+3
-2
treevalue/tree/tree/structural.pyx
treevalue/tree/tree/structural.pyx
+32
-13
treevalue/tree/tree/tree.pxd
treevalue/tree/tree/tree.pxd
+11
-0
treevalue/tree/tree/tree.pyx
treevalue/tree/tree/tree.pyx
+68
-2
未找到文件。
docs/source/api_doc/tree/common.rst
浏览文件 @
029f029e
...
...
@@ -36,3 +36,46 @@ RawWrapper
.. autoclass:: RawWrapper
:members: __init__, value
.. _apidoc_tree_common_delayed_partial:
delayed_partial
----------------------
.. autofunction:: delayed_partial
.. _apidoc_tree_common_undelay:
undelay
---------------
.. autofunction:: undelay
.. _apidoc_tree_common_delayedproxy:
DelayedProxy
-------------------
.. autoclass:: DelayedProxy
:members: value, fvalue
.. _apidoc_tree_common_delayedvalueproxy:
DelayedValueProxy
-------------------
.. autoclass:: DelayedValueProxy
:members: __cinit__, value, fvalue
.. _apidoc_tree_common_delayedfuncproxy:
DelayedFuncProxy
-------------------
.. autoclass:: DelayedFuncProxy
:members: __cinit__, value, fvalue
docs/source/api_doc/tree/tree.rst
浏览文件 @
029f029e
...
...
@@ -12,6 +12,14 @@ TreeValue
:members: __init__, __getattribute__, __setattr__, __delattr__, __contains__, __repr__, __iter__, __hash__, __eq__, _attr_extern, __len__, __bool__, __str__, __getstate__, __setstate__, get
.. _apidoc_tree_tree_delayed:
delayed
---------------
.. autofunction:: delayed
.. _apidoc_tree_tree_jsonify:
jsonify
...
...
requirements-doc.txt
浏览文件 @
029f029e
...
...
@@ -2,7 +2,7 @@ sphinx~=3.2.0
sphinx_rtd_theme~=0.4.3
enum_tools
sphinx-toolbox
plantumlcli>=0.0.
2
plantumlcli>=0.0.
4
packaging
sphinx-multiversion~=0.2.4
where~=1.0.2
...
...
test/tree/common/test_delay.py
0 → 100644
浏览文件 @
029f029e
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
test/tree/common/test_storage.py
浏览文件 @
029f029e
...
...
@@ -2,10 +2,10 @@ 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
# noinspection PyArgumentList,DuplicatedCode
,PyTypeChecker
@
pytest
.
mark
.
unittest
class
TestTreeStorage
:
def
test_init
(
self
):
...
...
@@ -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
...
...
@@ -34,6 +80,23 @@ class TestTreeStorage:
assert
t
.
get_or_default
(
'fff'
,
233
)
==
233
t1
=
create_storage
({
'a'
:
delayed_partial
(
lambda
:
t
.
get
(
'a'
)),
'b'
:
delayed_partial
(
lambda
:
t
.
get
(
'b'
)),
'c'
:
delayed_partial
(
lambda
:
t
.
get
(
'c'
)),
'd'
:
delayed_partial
(
lambda
:
t
.
get
(
'd'
)),
})
assert
t1
.
get_or_default
(
'a'
,
233
)
==
1
assert
t1
.
get_or_default
(
'b'
,
233
)
==
2
assert
t1
.
get_or_default
(
'c'
,
233
)
==
{
'x'
:
3
,
'y'
:
4
}
assert
isinstance
(
t1
.
get_or_default
(
'd'
,
233
),
TreeStorage
)
assert
t1
.
get_or_default
(
'd'
,
233
).
get_or_default
(
'x'
,
233
)
==
3
assert
t1
.
get_or_default
(
'd'
,
233
).
get_or_default
(
'y'
,
233
)
==
4
assert
t1
.
get_or_default
(
'fff'
,
233
)
==
233
assert
t1
.
get_or_default
(
'fff'
,
delayed_partial
(
lambda
:
2345
))
==
2345
assert
not
t1
.
contains
(
'fff'
)
def
test_set
(
self
):
t
=
create_storage
({})
t
.
set
(
'a'
,
1
)
...
...
@@ -122,6 +185,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
}
...
...
@@ -177,7 +253,7 @@ class TestTreeStorage:
h2
=
{
'x'
:
3
,
'y'
:
4
}
t
=
create_storage
({
'a'
:
1
,
'b'
:
2
,
'c'
:
raw
(
h1
),
'd'
:
h2
})
t1
=
t
.
deepcopyx
(
lambda
x
:
-
x
if
isinstance
(
x
,
int
)
else
{
'holy'
:
'shit'
})
t1
=
t
.
deepcopyx
(
lambda
x
:
-
x
if
isinstance
(
x
,
int
)
else
{
'holy'
:
'shit'
}
,
False
)
assert
t1
.
get
(
'a'
)
==
-
1
assert
t1
.
get
(
'b'
)
==
-
2
assert
t1
.
get
(
'c'
)
==
{
'holy'
:
'shit'
}
...
...
@@ -232,6 +308,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
}
...
...
@@ -253,6 +342,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
.
deepcopy_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_repr
(
self
):
h1
=
{
'x'
:
3
,
'y'
:
4
}
h2
=
{
'x'
:
3
,
'y'
:
4
}
...
...
@@ -272,6 +374,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 +403,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 +430,39 @@ 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.'
)
def
test_hash
(
self
):
h
=
{}
h1
=
{
'x'
:
3
,
'y'
:
4
}
t
=
create_storage
({
'a'
:
1
,
'b'
:
2
,
'd'
:
h1
})
t1
=
create_storage
({
'a'
:
delayed_partial
(
lambda
:
t
.
get
(
'a'
)),
'b'
:
delayed_partial
(
lambda
:
t
.
get
(
'b'
)),
'd'
:
delayed_partial
(
lambda
:
t
.
get
(
'd'
)),
})
t2
=
create_storage
({
'a'
:
delayed_partial
(
lambda
:
t
.
get
(
'a'
)),
'b'
:
delayed_partial
(
lambda
:
3
),
'd'
:
delayed_partial
(
lambda
:
t
.
get
(
'd'
)),
})
h
[
t
]
=
1
assert
t1
in
h
assert
h
[
t1
]
==
1
assert
t2
not
in
h
test/tree/func/test_func.py
浏览文件 @
029f029e
...
...
@@ -3,7 +3,7 @@ from operator import __mul__
import
pytest
from
treevalue.tree
import
func_treelize
,
TreeValue
,
method_treelize
,
classmethod_treelize
from
treevalue.tree
import
func_treelize
,
TreeValue
,
method_treelize
,
classmethod_treelize
,
delayed
# noinspection DuplicatedCode
...
...
@@ -257,3 +257,147 @@ class TestTreeFuncFunc:
'f'
:
[
4
],
},
})
def
test_delay_support
(
self
):
@
func_treelize
(
return_type
=
TreeValue
)
def
f
(
x
,
y
,
z
):
return
x
+
y
*
2
+
z
*
3
t1
=
TreeValue
({
'a'
:
1
,
'b'
:
delayed
(
lambda
x
:
x
**
2
,
3
),
'c'
:
{
'x'
:
2
,
'y'
:
delayed
(
lambda
:
4
)},
})
t2
=
TreeValue
({
'a'
:
delayed
(
lambda
x
:
x
+
1
,
t1
.
a
),
'b'
:
delayed
(
lambda
:
t1
.
c
.
y
),
'c'
:
delayed
(
lambda
:
5
),
})
t3
=
delayed
(
lambda
:
6
)
assert
f
(
t1
,
t2
,
t3
)
==
TreeValue
({
'a'
:
23
,
'b'
:
35
,
'c'
:
{
'x'
:
30
,
'y'
:
32
},
})
t1
=
TreeValue
({
'a'
:
1
,
'b'
:
delayed
(
lambda
x
:
x
**
2
,
3
),
'c'
:
{
'x'
:
2
,
'y'
:
delayed
(
lambda
:
4
)},
})
t2
=
TreeValue
({
'a'
:
delayed
(
lambda
x
:
x
+
1
,
t1
.
a
),
'b'
:
delayed
(
lambda
:
t1
.
c
.
y
),
'c'
:
delayed
(
lambda
:
5
),
})
t3
=
delayed
(
lambda
:
6
)
assert
f
(
x
=
t1
,
y
=
t2
,
z
=
t3
)
==
TreeValue
({
'a'
:
23
,
'b'
:
35
,
'c'
:
{
'x'
:
30
,
'y'
:
32
},
})
def
test_delayed_treelize
(
self
):
t1
=
TreeValue
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
},
})
t2
=
TreeValue
({
'a'
:
11
,
'b'
:
23
,
'x'
:
{
'c'
:
35
,
'd'
:
47
},
})
cnt_1
=
0
@
func_treelize
(
delayed
=
True
)
def
total
(
a
,
b
):
nonlocal
cnt_1
cnt_1
+=
1
return
a
+
b
# positional
t3
=
total
(
t1
,
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
TreeValue
({
'c'
:
38
,
'd'
:
51
})
assert
cnt_1
==
3
assert
t3
==
TreeValue
({
'a'
:
12
,
'b'
:
25
,
'x'
:
{
'c'
:
38
,
'd'
:
51
}
})
assert
cnt_1
==
4
# keyword
cnt_1
=
0
t3
=
total
(
a
=
t1
,
b
=
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
TreeValue
({
'c'
:
38
,
'd'
:
51
})
assert
cnt_1
==
3
assert
t3
==
TreeValue
({
'a'
:
12
,
'b'
:
25
,
'x'
:
{
'c'
:
38
,
'd'
:
51
}
})
assert
cnt_1
==
4
# positional, with constant
cnt_1
=
0
t3
=
total
(
1
,
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
TreeValue
({
'c'
:
36
,
'd'
:
48
})
assert
cnt_1
==
3
assert
t3
==
TreeValue
({
'a'
:
12
,
'b'
:
24
,
'x'
:
{
'c'
:
36
,
'd'
:
48
}
})
assert
cnt_1
==
4
# keyword, with constant
cnt_1
=
0
t3
=
total
(
b
=
1
,
a
=
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
TreeValue
({
'c'
:
36
,
'd'
:
48
})
assert
cnt_1
==
3
assert
t3
==
TreeValue
({
'a'
:
12
,
'b'
:
24
,
'x'
:
{
'c'
:
36
,
'd'
:
48
}
})
assert
cnt_1
==
4
# positional, with delay
cnt_1
=
0
t4
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t1
)})
t5
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t2
)})
t6
=
total
(
t4
,
t5
)
assert
cnt_1
==
0
assert
t6
.
v
.
a
==
12
assert
cnt_1
==
1
assert
t6
.
v
.
x
==
TreeValue
({
'c'
:
38
,
'd'
:
51
})
assert
cnt_1
==
3
assert
t6
==
TreeValue
({
'v'
:
{
'a'
:
12
,
'b'
:
25
,
'x'
:
{
'c'
:
38
,
'd'
:
51
}},
})
assert
cnt_1
==
4
# keyword, with delay
cnt_1
=
0
t4
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t1
)})
t5
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t2
)})
t6
=
total
(
a
=
t4
,
b
=
t5
)
assert
cnt_1
==
0
assert
t6
.
v
.
a
==
12
assert
cnt_1
==
1
assert
t6
.
v
.
x
==
TreeValue
({
'c'
:
38
,
'd'
:
51
})
assert
cnt_1
==
3
assert
t6
==
TreeValue
({
'v'
:
{
'a'
:
12
,
'b'
:
25
,
'x'
:
{
'c'
:
38
,
'd'
:
51
}},
})
assert
cnt_1
==
4
test/tree/func/test_outer.py
浏览文件 @
029f029e
...
...
@@ -38,3 +38,46 @@ class TestTreeFuncOuter:
with
pytest
.
raises
(
KeyError
):
_
=
ssum
(
t1
,
t3
)
def
test_delayed_treelize
(
self
):
t1
=
TreeValue
({
'a'
:
1
,
'x'
:
{
'c'
:
3
,
'd'
:
4
},
})
t2
=
TreeValue
({
'a'
:
11
,
'b'
:
23
,
'x'
:
{
'c'
:
35
,
},
})
cnt_1
=
0
@
func_treelize
(
delayed
=
True
,
mode
=
'outer'
,
missing
=
0
)
def
total
(
a
,
b
):
nonlocal
cnt_1
cnt_1
+=
1
return
a
+
b
# positional
t3
=
total
(
t1
,
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
TreeValue
({
'c'
:
38
,
'd'
:
4
})
assert
cnt_1
==
3
assert
t3
==
TreeValue
({
'a'
:
12
,
'b'
:
23
,
'x'
:
{
'c'
:
38
,
'd'
:
4
}
})
assert
cnt_1
==
4
# keyword
cnt_1
=
0
t3
=
total
(
a
=
t1
,
b
=
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
TreeValue
({
'c'
:
38
,
'd'
:
4
})
assert
cnt_1
==
3
assert
t3
==
TreeValue
({
'a'
:
12
,
'b'
:
23
,
'x'
:
{
'c'
:
38
,
'd'
:
4
}
})
assert
cnt_1
==
4
test/tree/general/base.py
浏览文件 @
029f029e
...
...
@@ -5,7 +5,7 @@ from typing import Type
import
numpy
as
np
import
pytest
from
treevalue.tree
import
func_treelize
,
TreeValue
,
raw
,
mapping
from
treevalue.tree
import
func_treelize
,
TreeValue
,
raw
,
mapping
,
delayed
def
get_tree_test
(
tree_value_clazz
:
Type
[
TreeValue
]):
...
...
@@ -356,8 +356,38 @@ def get_tree_test(tree_value_clazz: Type[TreeValue]):
assert
t2
.
add
(
t1
)
==
tree_value_clazz
({
'a'
:
2
,
'b'
:
4
,
'x'
:
{
'c'
:
6
,
'd'
:
8
}})
def
test_map
(
self
):
cnt
=
0
def
f
(
x
):
nonlocal
cnt
cnt
+=
1
return
x
+
2
t1
=
tree_value_clazz
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
}})
assert
t1
.
map
(
lambda
x
:
x
+
2
)
==
tree_value_clazz
({
'a'
:
3
,
'b'
:
4
,
'x'
:
{
'c'
:
5
,
'd'
:
6
}})
assert
cnt
==
0
t2
=
t1
.
map
(
f
)
assert
cnt
==
4
assert
t2
==
tree_value_clazz
({
'a'
:
3
,
'b'
:
4
,
'x'
:
{
'c'
:
5
,
'd'
:
6
}})
cnt
=
0
t3
=
tree_value_clazz
({
'a'
:
delayed
(
lambda
:
t1
.
a
),
'b'
:
delayed
(
lambda
:
t1
.
b
),
'x'
:
delayed
(
lambda
:
t1
.
x
),
})
assert
cnt
==
0
t4
=
t3
.
map
(
f
,
delayed
=
True
)
assert
cnt
==
0
assert
t4
.
a
==
3
assert
cnt
==
1
assert
t4
==
tree_value_clazz
({
'a'
:
3
,
'b'
:
4
,
'x'
:
{
'c'
:
5
,
'd'
:
6
}})
assert
cnt
==
4
assert
t4
.
a
==
3
assert
cnt
==
4
def
test_type
(
self
):
t1
=
tree_value_clazz
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
}})
...
...
@@ -572,4 +602,23 @@ def get_tree_test(tree_value_clazz: Type[TreeValue]):
assert
ssum
(
t1
,
t2
)
==
tree_value_clazz
({
'a'
:
12
,
'b'
:
22
,
'x'
:
{
'c'
:
36
,
'd'
:
52
}})
cnt_1
=
0
@
tree_value_clazz
.
func
(
delayed
=
True
)
def
ssumx
(
x
,
y
):
nonlocal
cnt_1
cnt_1
+=
1
return
x
+
y
cnt_1
=
0
t3
=
ssumx
(
t1
,
t2
)
assert
cnt_1
==
0
assert
t3
.
a
==
12
assert
cnt_1
==
1
assert
t3
.
x
==
tree_value_clazz
({
'c'
:
36
,
'd'
:
52
})
assert
cnt_1
==
3
assert
t3
==
tree_value_clazz
({
'a'
:
12
,
'b'
:
22
,
'x'
:
{
'c'
:
36
,
'd'
:
52
}})
assert
cnt_1
==
4
return
_TestClass
test/tree/tree/test_flatten.py
浏览文件 @
029f029e
import
pytest
from
treevalue.tree
import
TreeValue
,
raw
,
flatten
,
unflatten
,
flatten_values
,
flatten_keys
from
treevalue.tree
import
TreeValue
,
raw
,
flatten
,
unflatten
,
flatten_values
,
flatten_keys
,
delayed
class
MyTreeValue
(
TreeValue
):
...
...
@@ -22,15 +22,37 @@ class TestTreeTreeFlatten:
((
'd'
,
'y'
),
4
)
]
t1
=
TreeValue
({
'a'
:
delayed
(
lambda
:
t
.
a
),
'b'
:
delayed
(
lambda
:
t
.
b
),
'c'
:
delayed
(
lambda
:
t
.
c
),
'd'
:
delayed
(
lambda
:
t
.
d
),
})
flatted
=
sorted
(
flatten
(
t1
))
assert
flatted
==
[
((
'a'
,),
1
),
((
'b'
,),
2
),
((
'c'
,),
{
'x'
:
3
,
'y'
:
4
}),
((
'd'
,
'x'
),
3
),
((
'd'
,
'y'
),
4
)
]
def
test_flatten_values
(
self
):
t
=
TreeValue
({
'a'
:
1
,
'b'
:
5
,
'c'
:
{
'x'
:
3
,
'y'
:
4
},
'd'
:
{
'x'
:
3
,
'y'
:
4
}})
flatted_values
=
sorted
(
flatten_values
(
t
))
assert
flatted_values
==
[
1
,
3
,
3
,
4
,
4
,
5
]
t1
=
TreeValue
({
'a'
:
delayed
(
lambda
:
t
.
a
),
'b'
:
delayed
(
lambda
:
t
.
b
),
'c'
:
delayed
(
lambda
:
t
.
c
),
'd'
:
delayed
(
lambda
:
t
.
d
),
})
flatted_values
=
sorted
(
flatten_values
(
t1
))
assert
flatted_values
==
[
1
,
3
,
3
,
4
,
4
,
5
]
def
test_flatten_keys
(
self
):
t
=
TreeValue
({
'a'
:
1
,
'd'
:
{
'x'
:
3
,
'y'
:
4
},
'e'
:
raw
({
'x'
:
3
,
'y'
:
4
}),
'b'
:
5
,
'c'
:
{
'x'
:
3
,
'y'
:
4
}})
flatted_keys
=
sorted
(
flatten_keys
(
t
))
assert
flatted_keys
==
[
(
'a'
,),
...
...
@@ -42,6 +64,24 @@ class TestTreeTreeFlatten:
(
'e'
,),
]
t1
=
TreeValue
({
'a'
:
delayed
(
lambda
:
t
.
a
),
'b'
:
delayed
(
lambda
:
t
.
b
),
'c'
:
delayed
(
lambda
:
t
.
c
),
'd'
:
delayed
(
lambda
:
t
.
d
),
'e'
:
delayed
(
lambda
:
t
.
e
),
})
flatted_keys
=
sorted
(
flatten_keys
(
t1
))
assert
flatted_keys
==
[
(
'a'
,),
(
'b'
,),
(
'c'
,
'x'
,),
(
'c'
,
'y'
,),
(
'd'
,
'x'
,),
(
'd'
,
'y'
,),
(
'e'
,),
]
def
test_unflatten
(
self
):
flatted
=
[
((
'a'
,),
1
),
...
...
test/tree/tree/test_functional.py
浏览文件 @
029f029e
...
...
@@ -3,7 +3,7 @@ from operator import __mul__
import
pytest
from
treevalue.tree
import
TreeValue
,
mapping
,
raw
,
mask
,
filter_
,
reduce_
from
treevalue.tree
import
TreeValue
,
mapping
,
raw
,
mask
,
filter_
,
reduce_
,
delayed
# noinspection DuplicatedCode
...
...
@@ -30,6 +30,59 @@ class TestTreeTreeFunctional:
})
assert
tv6
==
TreeValue
({
'a'
:
1.0
,
'b'
:
2.0
,
'c'
:
{
'x'
:
2.0
,
'y'
:
3.0
}})
tv8
=
TreeValue
({
'v'
:
delayed
(
lambda
:
tv1
)})
assert
mapping
(
tv8
,
lambda
x
:
x
+
2
)
==
TreeValue
({
'v'
:
{
'a'
:
3
,
'b'
:
4
,
'c'
:
{
'x'
:
4
,
'y'
:
5
}
}})
def
test_mapping_delayed
(
self
):
tv1
=
TreeValue
({
'a'
:
1
,
'b'
:
2
,
'c'
:
{
'x'
:
2
,
'y'
:
3
}})
tv8
=
TreeValue
({
'v'
:
delayed
(
lambda
:
tv1
)})
assert
mapping
(
tv8
,
lambda
x
:
x
+
2
,
delayed
=
True
)
==
TreeValue
({
'v'
:
{
'a'
:
3
,
'b'
:
4
,
'c'
:
{
'x'
:
4
,
'y'
:
5
}
}})
cnt_f
,
cnt_v
=
0
,
0
def
f
(
x
):
nonlocal
cnt_f
cnt_f
+=
1
return
TreeValue
({
'a'
:
x
*
2
,
'b'
:
x
+
1
,
'c'
:
x
**
2
,
})
def
v
():
nonlocal
cnt_v
cnt_v
+=
1
return
3
t
=
TreeValue
({
'a'
:
1
,
'b'
:
delayed
(
f
,
1
),
'x'
:
{
'c'
:
delayed
(
v
),
'd'
:
4
,
},
'y'
:
delayed
(
f
,
3
),
})
t1
=
mapping
(
t
,
lambda
x
:
(
x
+
3
)
**
2
,
delayed
=
True
)
assert
cnt_v
==
0
assert
cnt_f
==
0
assert
t1
==
TreeValue
({
'a'
:
16
,
'b'
:
{
'a'
:
25
,
'b'
:
25
,
'c'
:
16
,
},
'x'
:
{
'c'
:
36
,
'd'
:
49
,
},
'y'
:
{
'a'
:
81
,
'b'
:
49
,
'c'
:
144
,
},
})
assert
cnt_v
==
1
assert
cnt_f
==
2
assert
t
==
TreeValue
({
'a'
:
1
,
'b'
:
{
'a'
:
2
,
'b'
:
2
,
'c'
:
1
,
},
'x'
:
{
'c'
:
3
,
'd'
:
4
,
},
'y'
:
{
'a'
:
6
,
'b'
:
4
,
'c'
:
9
,
},
})
assert
cnt_v
==
1
assert
cnt_f
==
2
def
test_mask
(
self
):
class
MyTreeValue
(
TreeValue
):
pass
...
...
@@ -46,6 +99,10 @@ class TestTreeTreeFunctional:
with
pytest
.
raises
(
TypeError
):
assert
mask
(
t2
,
m2
)
t1
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t
)})
m11
=
TreeValue
({
'v'
:
delayed
(
lambda
:
m1
)})
assert
mask
(
t1
,
m11
)
==
TreeValue
({
'v'
:
{
'a'
:
1
}})
def
test_filter
(
self
):
class
MyTreeValue
(
TreeValue
):
pass
...
...
@@ -56,6 +113,9 @@ class TestTreeTreeFunctional:
assert
filter_
(
t
,
lambda
x
:
x
<
3
,
remove_empty
=
False
)
==
MyTreeValue
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{}})
assert
filter_
(
t
,
lambda
x
:
x
%
2
==
1
)
==
MyTreeValue
({
'a'
:
1
,
'x'
:
{
'c'
:
3
}})
t2
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t
)})
assert
filter_
(
t2
,
lambda
x
:
x
<
3
)
==
TreeValue
({
'v'
:
{
'a'
:
1
,
'b'
:
2
}})
def
test_reduce
(
self
):
class
MyTreeValue
(
TreeValue
):
pass
...
...
@@ -74,3 +134,8 @@ class TestTreeTreeFunctional:
assert
reduce_
(
t2
,
lambda
**
kwargs
:
TreeValue
(
{
k
+
k
:
(
v
**
2
if
not
isinstance
(
v
,
TreeValue
)
else
v
)
for
k
,
v
in
kwargs
.
items
()}))
==
MyTreeValue
(
{
'aa'
:
1
,
'bb'
:
4
,
'xx'
:
{
'cc'
:
9
,
'dd'
:
16
}})
t1
=
MyTreeValue
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
}})
t3
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t1
),
'v2'
:
delayed
(
lambda
:
t1
)})
assert
reduce_
(
t3
,
lambda
**
kwargs
:
sum
(
kwargs
.
values
()))
==
20
assert
reduce_
(
t3
,
lambda
**
kwargs
:
reduce
(
__mul__
,
list
(
kwargs
.
values
())))
==
576
test/tree/tree/test_service.py
浏览文件 @
029f029e
import
pytest
from
treevalue.tree
import
jsonify
,
TreeValue
,
clone
,
typetrans
,
raw
,
walk
from
treevalue.tree
import
jsonify
,
TreeValue
,
clone
,
typetrans
,
raw
,
walk
,
delayed
# noinspection DuplicatedCode
...
...
@@ -19,6 +19,18 @@ class TestTreeTreeService:
}
assert
tv2
.
c
==
{
'x'
:
2
,
'y'
:
3
}
tv3
=
TreeValue
({
'a'
:
delayed
(
lambda
:
tv1
.
a
),
'b'
:
delayed
(
lambda
:
tv1
.
b
),
'c1'
:
delayed
(
lambda
:
tv1
.
c
),
'c2'
:
delayed
(
lambda
:
tv2
.
c
),
})
assert
jsonify
(
tv3
)
==
{
'a'
:
1
,
'b'
:
2
,
'c1'
:
{
'x'
:
2
,
'y'
:
3
},
'c2'
:
{
'x'
:
2
,
'y'
:
3
}
}
assert
tv3
.
c1
==
TreeValue
({
'x'
:
2
,
'y'
:
3
})
assert
tv3
.
c2
==
{
'x'
:
2
,
'y'
:
3
}
def
test_clone
(
self
):
tv1
=
TreeValue
({
'a'
:
1
,
'b'
:
2
,
'c'
:
{
'x'
:
2
,
'y'
:
3
}})
tv2
=
clone
(
tv1
)
...
...
@@ -63,6 +75,14 @@ class TestTreeTreeService:
assert
tv5
.
x
.
c
is
not
tv3
.
x
.
c
assert
tv5
.
x
.
d
is
not
tv3
.
x
.
d
tv6
=
TreeValue
({
'a'
:
delayed
(
lambda
:
tv3
.
a
),
'b'
:
delayed
(
lambda
:
tv3
.
b
),
'x'
:
delayed
(
lambda
:
tv3
.
x
),
})
tv7
=
clone
(
tv6
,
lambda
x
:
x
)
assert
tv7
==
tv3
def
test_typetrans
(
self
):
class
MyTreeValue
(
TreeValue
):
pass
...
...
@@ -99,3 +119,15 @@ class TestTreeTreeService:
(
'c'
,
'x'
,):
2
,
(
'c'
,
'y'
,):
3
,
}
tv2
=
MyTreeValue
({
'a'
:
delayed
(
lambda
:
tv1
.
a
),
'b'
:
delayed
(
lambda
:
tv1
.
b
),
'c'
:
delayed
(
lambda
:
tv1
.
c
),
})
assert
dict
(
walk
(
tv2
))
==
{
(
'a'
,):
1
,
(
'b'
,):
2
,
(
'c'
,
'x'
,):
2
,
(
'c'
,
'y'
,):
3
,
}
test/tree/tree/test_structural.py
浏览文件 @
029f029e
import
pytest
from
treevalue.tree
import
TreeValue
,
mapping
,
union
,
raw
,
subside
,
rise
from
treevalue.tree
import
TreeValue
,
mapping
,
union
,
raw
,
subside
,
rise
,
delayed
# noinspection DuplicatedCode
...
...
@@ -16,10 +16,37 @@ class TestTreeTreeStructural:
t1
=
MyTreeValue
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
}})
assert
union
(
t
,
t1
)
==
TreeValue
({
'a'
:
(
1
,
1
),
'b'
:
(
2
,
2
),
'x'
:
{
'c'
:
(
3
,
3
),
'd'
:
(
4
,
4
)}})
assert
union
(
t
,
t1
,
return_type
=
MyTreeValue
)
==
MyTreeValue
(
{
'a'
:
(
1
,
1
),
'b'
:
(
2
,
2
),
'x'
:
{
'c'
:
(
3
,
3
),
'd'
:
(
4
,
4
)}})
assert
union
(
t1
,
t
)
==
MyTreeValue
({
'a'
:
(
1
,
1
),
'b'
:
(
2
,
2
),
'x'
:
{
'c'
:
(
3
,
3
),
'd'
:
(
4
,
4
)}})
assert
union
(
1
,
2
)
==
(
1
,
2
)
assert
union
(
1
,
2
,
return_type
=
TreeValue
)
==
(
1
,
2
)
tp
=
MyTreeValue
({
'v'
:
delayed
(
lambda
:
t
)})
tp1
=
TreeValue
({
'v'
:
delayed
(
lambda
:
t1
)})
assert
union
(
tp
,
tp1
)
==
MyTreeValue
({
'v'
:
{
'a'
:
(
1
,
1
),
'b'
:
(
2
,
2
),
'x'
:
{
'c'
:
(
3
,
3
),
'd'
:
(
4
,
4
)}}})
assert
union
(
tp1
,
tp
)
==
TreeValue
({
'v'
:
{
'a'
:
(
1
,
1
),
'b'
:
(
2
,
2
),
'x'
:
{
'c'
:
(
3
,
3
),
'd'
:
(
4
,
4
)}}})
t
=
MyTreeValue
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
}})
t1
=
TreeValue
({
'a'
:
delayed
(
lambda
:
t
.
x
.
c
),
'x'
:
{
'c'
:
delayed
(
lambda
:
t
.
a
),
'd'
:
delayed
(
lambda
:
t
.
b
),
}
})
assert
union
(
t
,
t1
,
mode
=
'outer'
,
missing
=
None
)
==
MyTreeValue
({
'a'
:
(
1
,
3
),
'b'
:
(
2
,
None
),
'x'
:
{
'c'
:
(
3
,
1
),
'd'
:
(
None
,
2
)},
})
def
test_union_delayed
(
self
):
class
MyTreeValue
(
TreeValue
):
pass
t
=
TreeValue
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
}})
t1
=
MyTreeValue
({
'a'
:
11
,
'b'
:
22
,
'x'
:
{
'c'
:
33
,
'd'
:
44
}})
assert
union
(
t
,
t1
,
delayed
=
True
)
==
TreeValue
({
'a'
:
(
1
,
11
),
'b'
:
(
2
,
22
),
'x'
:
{
'c'
:
(
3
,
33
),
'd'
:
(
4
,
44
)}})
def
test_subside
(
self
):
assert
subside
({
'a'
:
(
1
,
2
),
'b'
:
[
3
,
4
]})
==
{
'a'
:
(
1
,
2
),
'b'
:
[
3
,
4
]}
assert
subside
({
'a'
:
(
1
,
2
),
'b'
:
[
3
,
4
]},
return_type
=
TreeValue
)
==
{
'a'
:
(
1
,
2
),
'b'
:
[
3
,
4
]}
...
...
@@ -88,6 +115,30 @@ class TestTreeTreeStructural:
assert
subside
({
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
},
'e'
:
[
3
,
4
,
5
]})
==
\
{
'a'
:
1
,
'b'
:
2
,
'x'
:
{
'c'
:
3
,
'd'
:
4
},
'e'
:
[
3
,
4
,
5
]}
def
test_subside_delayed
(
self
):
class
MyTreeValue
(
TreeValue
):
pass
original2
=
{
'a'
:
TreeValue
({
'a'
:
1
,
'b'
:
2
}),
'x'
:
{
'c'
:
MyTreeValue
({
'a'
:
3
,
'b'
:
4
}),
'd'
:
[
MyTreeValue
({
'a'
:
5
,
'b'
:
6
}),
MyTreeValue
({
'a'
:
7
,
'b'
:
8
}),
]
},
'k'
:
'233'
}
assert
subside
(
original2
,
delayed
=
True
)
==
TreeValue
({
'a'
:
raw
({
'a'
:
1
,
'k'
:
'233'
,
'x'
:
{
'c'
:
3
,
'd'
:
[
5
,
7
]}}),
'b'
:
raw
({
'a'
:
2
,
'k'
:
'233'
,
'x'
:
{
'c'
:
4
,
'd'
:
[
6
,
8
]}}),
})
assert
subside
(
original2
,
return_type
=
MyTreeValue
,
delayed
=
True
)
==
MyTreeValue
({
'a'
:
raw
({
'a'
:
1
,
'k'
:
'233'
,
'x'
:
{
'c'
:
3
,
'd'
:
[
5
,
7
]}}),
'b'
:
raw
({
'a'
:
2
,
'k'
:
'233'
,
'x'
:
{
'c'
:
4
,
'd'
:
[
6
,
8
]}}),
})
def
test_rise
(
self
):
t1
=
TreeValue
({
'x'
:
raw
({
'a'
:
[
1
,
2
],
'b'
:
[
2
,
3
]}),
'y'
:
raw
({
'a'
:
[
5
,
6
,
7
],
'b'
:
[
7
,
8
]})})
assert
rise
(
t1
)
==
{
...
...
@@ -203,3 +254,21 @@ class TestTreeTreeStructural:
rise
(
t5
,
template
=
[
object
,
object
,
object
,
object
,
object
,
...])
assert
rise
(
1
)
==
1
t1
=
TreeValue
({
'x'
:
raw
({
'a'
:
[
1
,
2
],
'b'
:
[
2
,
3
]}),
'y'
:
raw
({
'a'
:
[
5
,
6
,
7
],
'b'
:
[
7
,
8
]})})
assert
rise
(
t1
)
==
{
'a'
:
TreeValue
({
'x'
:
[
1
,
2
],
'y'
:
[
5
,
6
,
7
]}),
'b'
:
[
TreeValue
({
'x'
:
2
,
'y'
:
7
}),
TreeValue
({
'x'
:
3
,
'y'
:
8
}),
]
}
t10
=
MyTreeValue
({
'v'
:
delayed
(
lambda
:
t1
)})
assert
rise
(
t10
)
==
{
'a'
:
MyTreeValue
({
'v'
:
{
'x'
:
[
1
,
2
],
'y'
:
[
5
,
6
,
7
]}}),
'b'
:
[
MyTreeValue
({
'v'
:
{
'x'
:
2
,
'y'
:
7
}}),
MyTreeValue
({
'v'
:
{
'x'
:
3
,
'y'
:
8
}}),
]
}
test/tree/tree/test_tree.py
浏览文件 @
029f029e
...
...
@@ -3,7 +3,7 @@ import re
import
pytest
from
treevalue
import
raw
,
TreeValue
from
treevalue
import
raw
,
TreeValue
,
delayed
class
_Container
:
...
...
@@ -121,6 +121,20 @@ class TestTreeTreeTree:
assert
"c --> <TreeValue"
in
repr
(
tv2
)
assert
"(The same address as <root>)"
in
repr
(
tv2
)
tv3
=
TreeValue
({
'a'
:
delayed
(
lambda
:
tv1
.
a
),
'b'
:
delayed
(
lambda
:
tv1
.
b
),
'c'
:
delayed
(
lambda
:
tv1
.
c
),
})
assert
re
.
match
(
r
"<TreeValue 0x[0-9a-f]+>"
,
repr
(
tv3
))
assert
re
.
match
(
r
"<TreeValue 0x[0-9a-f]+>"
,
repr
(
tv3
.
c
))
assert
"a --> 1"
in
str
(
tv3
)
assert
"b --> 2"
in
str
(
tv3
)
assert
"x --> 2"
in
str
(
tv3
)
assert
"y --> 3"
in
str
(
tv3
)
assert
"c --> <TreeValue"
in
str
(
tv3
)
def
test_tree_value_iter
(
self
):
# Attention: dict(tv1) is not supported in python 3.7+
tv1
=
TreeValue
({
'a'
:
1
,
'b'
:
2
,
'c'
:
{
'x'
:
2
,
'y'
:
3
}})
...
...
treevalue/tree/common/__init__.py
浏览文件 @
029f029e
from
.base
import
raw
,
unraw
,
RawWrapper
from
.delay
import
DelayedProxy
,
delayed_partial
,
undelay
,
DelayedValueProxy
,
DelayedFuncProxy
from
.storage
import
TreeStorage
,
create_storage
treevalue/tree/common/base.pyx
浏览文件 @
029f029e
...
...
@@ -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.
...
...
treevalue/tree/common/delay.pxd
0 → 100644
浏览文件 @
029f029e
# distutils:language=c++
# cython:language_level=3
from
libcpp
cimport
bool
cdef
class
DelayedProxy
:
cpdef
object
value
(
self
)
cpdef
object
fvalue
(
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
)
cdef
DelayedProxy
_c_delayed_partial
(
func
,
args
,
kwargs
)
cpdef
object
undelay
(
object
p
,
bool
is_final
=
*
)
treevalue/tree/common/delay.pyx
0 → 100644
浏览文件 @
029f029e
# distutils:language=c++
# cython:language_level=3
import
cython
from
libcpp
cimport
bool
cdef
class
DelayedProxy
:
"""
Overview:
Base class of all the delayed proxy class.
"""
cpdef
object
value
(
self
):
r
"""
Overview:
Get value of the delayed proxy.
Should make sure the result is cached.
Can be accessed in :func:`treevalue.tree.common.undelay` when ``is_final`` is ``False``.
Returns:
- value (:obj:`object`): Calculation result.
"""
raise
NotImplementedError
# pragma: no cover
cpdef
object
fvalue
(
self
):
r
"""
Overview:
Get value of the delayed proxy.
Can be accessed in :func:`treevalue.tree.common.undelay` when ``is_final`` is ``True``.
Returns:
- value (:obj:`object`): Calculation result.
"""
return
self
.
value
()
cdef
class
DelayedValueProxy
(
DelayedProxy
):
"""
Overview:
Simple function delayed proxy.
"""
def
__cinit__
(
self
,
object
func
):
"""
Overview:
Constructor of class :class:`treevalue.tree.common.DelayedValueProxy`.
Arguments:
- func (:obj:`object`): Function to be called, which can be called without arguments.
\
Delayed proxy is supported.
"""
self
.
func
=
func
self
.
calculated
=
False
self
.
val
=
None
cpdef
object
value
(
self
):
cdef
object
f
if
not
self
.
calculated
:
f
=
undelay
(
self
.
func
,
False
)
self
.
val
=
f
()
self
.
calculated
=
True
return
self
.
val
cdef
class
DelayedFuncProxy
(
DelayedProxy
):
"""
Overview:
Simple function delayed proxy.
"""
def
__cinit__
(
self
,
object
func
,
tuple
args
,
dict
kwargs
):
"""
Overview:
Constructor of class :class:`treevalue.tree.common.DelayedFuncProxy`.
Arguments:
- func (:obj:`object`): Function to be called, which can be called with given arguments.
\
Delayed proxy is supported.
- args (:obj:`tuple`): Positional arguments to be used, delayed proxy is supported.
- kwargs (:obj:`dict`): Key-word arguments to be used, delayed proxy is supported.
"""
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
:
pas
=
[]
pks
=
{}
f
=
undelay
(
self
.
func
,
False
)
for
item
in
self
.
args
:
pas
.
append
(
undelay
(
item
,
False
))
for
key
,
item
in
self
.
kwargs
.
items
():
pks
[
key
]
=
undelay
(
item
,
False
)
self
.
val
=
f
(
*
pas
,
**
pks
)
self
.
calculated
=
True
return
self
.
val
cdef
inline
DelayedProxy
_c_delayed_partial
(
func
,
args
,
kwargs
):
if
args
or
kwargs
:
return
DelayedFuncProxy
(
func
,
args
,
kwargs
)
else
:
return
DelayedValueProxy
(
func
)
@
cython
.
binding
(
True
)
def
delayed_partial
(
func
,
*
args
,
**
kwargs
):
"""
Overview:
Build a delayed partial object.
Similar to :func:`functools.partial`.
Returns:
- delayed: Delayed object.
"""
return
_c_delayed_partial
(
func
,
args
,
kwargs
)
@
cython
.
binding
(
True
)
cpdef
inline
object
undelay
(
object
p
,
bool
is_final
=
True
):
r
"""
Overview:
Get the value of a given object, it can be a delayed proxy, a simple object or \
a nested delayed proxy.
Arguments:
- p (:obj:`object`): Given object to be undelay.
- is_final (:obj:`bool`): Is final value getting or not, default is ``True``.
Returns:
- value (:obj:`object): Actual value of the given ``p``.
"""
if
isinstance
(
p
,
DelayedProxy
):
if
is_final
:
return
p
.
fvalue
()
else
:
return
p
.
value
()
else
:
return
p
treevalue/tree/common/storage.pxd
浏览文件 @
029f029e
# distutils:language=c++
# cython:language_level=3
from
libcpp
cimport
bool
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
...
...
@@ -19,13 +21,16 @@ cdef class TreeStorage:
cpdef
public
dict
dump
(
self
)
cpdef
public
dict
deepdump
(
self
)
cpdef
public
dict
deepdumpx
(
self
,
copy_func
)
cpdef
public
dict
jsondumpx
(
self
,
copy_func
,
object
need_raw
)
cpdef
public
dict
jsondumpx
(
self
,
copy_func
,
bool
need_raw
,
bool
allow_delayed
)
cpdef
public
TreeStorage
copy
(
self
)
cpdef
public
TreeStorage
deepcopy
(
self
)
cpdef
public
TreeStorage
deepcopyx
(
self
,
copy_func
)
cpdef
public
TreeStorage
deepcopyx
(
self
,
copy_func
,
bool
allow_delayed
)
cpdef
public
dict
detach
(
self
)
cpdef
public
void
copy_from
(
self
,
TreeStorage
ts
)
cpdef
public
void
deepcopy_from
(
self
,
TreeStorage
ts
)
cpdef
public
void
deepcopyx_from
(
self
,
TreeStorage
ts
,
copy_func
)
cpdef
public
void
deepcopyx_from
(
self
,
TreeStorage
ts
,
copy_func
,
bool
allow_delayed
)
cpdef
public
object
create_storage
(
dict
value
)
cdef
object
_c_undelay_data
(
dict
data
,
object
k
,
object
v
)
cdef
object
_c_undelay_not_none_data
(
dict
data
,
object
k
,
object
v
)
cdef
object
_c_undelay_check_data
(
dict
data
,
object
k
,
object
v
)
treevalue/tree/common/storage.pyx
浏览文件 @
029f029e
...
...
@@ -4,13 +4,15 @@
from
copy
import
deepcopy
from
libc.string
cimport
strlen
from
libcpp
cimport
bool
from
.base
cimport
raw
,
unraw
from
.delay
cimport
undelay
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,13 +37,17 @@ cdef class TreeStorage:
self
.
map
[
key
]
=
value
cpdef
public
object
get
(
self
,
str
key
):
cdef
object
v
,
nv
try
:
return
self
.
map
[
key
]
v
=
self
.
map
[
key
]
return
_c_undelay_data
(
self
.
map
,
key
,
v
)
except
KeyError
:
raise
KeyError
(
f
"Key
{
repr
(
key
)
}
not found in this tree."
)
cpdef
public
object
get_or_default
(
self
,
str
key
,
object
default
):
return
self
.
map
.
get
(
key
,
default
)
cdef
object
v
,
nv
v
=
self
.
map
.
get
(
key
,
default
)
return
_c_undelay_check_data
(
self
.
map
,
key
,
v
)
cpdef
public
void
del_
(
self
,
str
key
)
except
*
:
try
:
...
...
@@ -65,17 +71,20 @@ cdef class TreeStorage:
return
self
.
deepdumpx
(
deepcopy
)
cpdef
public
dict
deepdumpx
(
self
,
copy_func
):
return
self
.
jsondumpx
(
copy_func
,
True
)
return
self
.
jsondumpx
(
copy_func
,
True
,
False
)
cpdef
public
dict
jsondumpx
(
self
,
copy_func
,
object
need_raw
):
cpdef
public
dict
jsondumpx
(
self
,
copy_func
,
bool
need_raw
,
bool
allow_delayed
):
cdef
dict
result
=
{}
cdef
str
k
cdef
object
v
,
obj
cdef
object
v
,
obj
,
nv
for
k
,
v
in
self
.
map
.
items
():
if
not
allow_delayed
:
v
=
_c_undelay_data
(
self
.
map
,
k
,
v
)
if
isinstance
(
v
,
TreeStorage
):
result
[
k
]
=
v
.
jsondumpx
(
copy_func
,
need_raw
)
result
[
k
]
=
v
.
jsondumpx
(
copy_func
,
need_raw
,
allow_delayed
)
else
:
obj
=
copy_func
(
v
)
obj
=
copy_func
(
v
)
if
not
allow_delayed
else
v
if
need_raw
:
obj
=
raw
(
obj
)
result
[
k
]
=
obj
...
...
@@ -83,43 +92,48 @@ cdef class TreeStorage:
return
result
cpdef
public
TreeStorage
copy
(
self
):
return
self
.
deepcopyx
(
_keep_object
)
return
self
.
deepcopyx
(
_keep_object
,
True
)
cpdef
public
TreeStorage
deepcopy
(
self
):
return
self
.
deepcopyx
(
deepcopy
)
return
self
.
deepcopyx
(
deepcopy
,
False
)
cpdef
public
TreeStorage
deepcopyx
(
self
,
copy_func
):
cdef
type
cls
=
type
(
self
)
return
create_storage
(
self
.
deepdumpx
(
copy_func
))
cpdef
public
TreeStorage
deepcopyx
(
self
,
copy_func
,
bool
allow_delayed
):
return
create_storage
(
self
.
jsondumpx
(
copy_func
,
True
,
allow_delayed
))
cpdef
public
dict
detach
(
self
):
return
self
.
map
cpdef
public
void
copy_from
(
self
,
TreeStorage
ts
):
self
.
deepcopyx_from
(
ts
,
_keep_object
)
self
.
deepcopyx_from
(
ts
,
_keep_object
,
True
)
cpdef
public
void
deepcopy_from
(
self
,
TreeStorage
ts
):
self
.
deepcopyx_from
(
ts
,
deepcopy
)
self
.
deepcopyx_from
(
ts
,
deepcopy
,
False
)
cpdef
public
void
deepcopyx_from
(
self
,
TreeStorage
ts
,
copy_func
):
cpdef
public
void
deepcopyx_from
(
self
,
TreeStorage
ts
,
copy_func
,
bool
allow_delayed
):
cdef
dict
detached
=
ts
.
detach
()
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
:
v
=
detached
[
k
]
if
not
allow_delayed
:
v
=
_c_undelay_data
(
detached
,
k
,
v
)
if
isinstance
(
v
,
TreeStorage
):
if
k
in
self
.
map
and
isinstance
(
self
.
map
[
k
],
TreeStorage
):
self
.
map
[
k
].
copy_from
(
v
)
self
.
map
[
k
].
deepcopyx_from
(
v
,
copy_func
,
allow_delayed
)
else
:
newv
=
TreeStorage
({})
newv
.
copy_from
(
v
)
newv
.
deepcopyx_from
(
v
,
copy_func
,
allow_delayed
)
self
.
map
[
k
]
=
newv
else
:
self
.
map
[
k
]
=
copy_func
(
v
)
if
not
allow_delayed
:
self
.
map
[
k
]
=
copy_func
(
v
)
else
:
self
.
map
[
k
]
=
v
else
:
del
self
.
map
[
k
]
...
...
@@ -145,12 +159,16 @@ 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_v
=
_c_undelay_data
(
self
.
map
,
key
,
self_v
)
other_v
=
other_map
[
key
]
other_v
=
_c_undelay_data
(
other_map
,
key
,
other_v
)
if
self_v
!=
other_v
:
return
False
return
True
...
...
@@ -161,7 +179,7 @@ cdef class TreeStorage:
cdef
str
k
cdef
object
v
cdef
list
_items
=
[]
for
k
,
v
in
sorted
(
self
.
map
.
items
(),
key
=
lambda
x
:
x
[
0
]):
for
k
,
v
in
sorted
(
self
.
items
(),
key
=
lambda
x
:
x
[
0
]):
_items
.
append
((
k
,
v
))
return
hash
(
tuple
(
_items
))
...
...
@@ -170,10 +188,18 @@ 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
():
yield
_c_undelay_data
(
self
.
map
,
k
,
v
)
def
items
(
self
):
return
self
.
map
.
items
()
cdef
str
k
cdef
object
v
,
nv
for
k
,
v
in
self
.
map
.
items
():
v
=
_c_undelay_data
(
self
.
map
,
k
,
v
)
yield
k
,
v
cpdef
object
create_storage
(
dict
value
):
cdef
dict
_map
=
{}
...
...
@@ -187,3 +213,21 @@ cpdef object create_storage(dict value):
_map
[
k
]
=
unraw
(
v
)
return
TreeStorage
(
_map
)
cdef
inline
object
_c_undelay_data
(
dict
data
,
object
k
,
object
v
):
cdef
object
nv
=
undelay
(
v
)
if
nv
is
not
v
:
data
[
k
]
=
nv
return
nv
cdef
inline
object
_c_undelay_not_none_data
(
dict
data
,
object
k
,
object
v
):
cdef
object
nv
=
undelay
(
v
)
if
nv
is
not
v
and
k
is
not
None
:
data
[
k
]
=
nv
return
nv
cdef
inline
object
_c_undelay_check_data
(
dict
data
,
object
k
,
object
v
):
cdef
object
nv
=
undelay
(
v
)
if
nv
is
not
v
and
k
in
data
:
data
[
k
]
=
nv
return
nv
\ No newline at end of file
treevalue/tree/func/cfunc.pxd
浏览文件 @
029f029e
...
...
@@ -5,11 +5,14 @@ from libcpp cimport bool
from
.modes
cimport
_e_tree_mode
cdef
object
_c_func_treelize_run
(
object
func
,
list
args
,
dict
kwargs
,
_e_tree_mode
mode
,
bool
inherit
,
bool
allow_missing
,
object
missing_func
)
cdef
object
_c_wrap_func_treelize_run
(
object
func
,
list
args
,
dict
kwargs
,
_e_tree_mode
mode
,
bool
inherit
,
bool
allow_missing
,
object
missing_func
,
bool
delayed
)
cdef
object
_c_func_treelize_run
(
object
func
,
list
args
,
dict
kwargs
,
_e_tree_mode
mode
,
bool
inherit
,
bool
allow_missing
,
object
missing_func
,
bool
delayed
)
cpdef
object
_d_func_treelize
(
object
func
,
object
mode
,
object
return_type
,
bool
inherit
,
object
missing
,
object
subside
,
object
rise
)
cdef
_c_common_value
(
object
item
)
bool
delayed
,
object
subside
,
object
rise
)
cdef
object
_c_common_value
(
object
item
)
cdef
tuple
_c_missing_process
(
object
missing
)
cpdef
object
func_treelize
(
object
mode
=
*
,
object
return_type
=
*
,
bool
inherit
=
*
,
object
missing
=
*
,
object
subside
=
*
,
object
rise
=
*
)
bool
delayed
=
*
,
object
subside
=
*
,
object
rise
=
*
)
treevalue/tree/func/cfunc.pyx
浏览文件 @
029f029e
...
...
@@ -8,20 +8,40 @@ from hbutils.design import SingletonMark
from
libcpp
cimport
bool
from
.modes
cimport
_e_tree_mode
,
_c_keyset
,
_c_load_mode
,
_c_check
from
..common.storage
cimport
TreeStorage
from
..common.delay
import
delayed_partial
from
..common.delay
cimport
undelay
from
..common.storage
cimport
TreeStorage
,
_c_undelay_not_none_data
,
_c_undelay_data
from
..tree.structural
cimport
_c_subside
,
_c_rise
from
..tree.tree
cimport
TreeValue
_VALUE_IS_MISSING
=
SingletonMark
(
'value_is_missing'
)
MISSING_NOT_ALLOW
=
SingletonMark
(
"missing_not_allow"
)
cdef
inline
object
_c_wrap_func_treelize_run
(
object
func
,
list
args
,
dict
kwargs
,
_e_tree_mode
mode
,
bool
inherit
,
bool
allow_missing
,
object
missing_func
,
bool
delayed
):
cdef
list
_l_args
=
[]
cdef
dict
_d_kwargs
=
{}
cdef
str
k
,
ak
cdef
object
av
,
v
,
nv
for
av
,
k
,
v
in
args
:
_l_args
.
append
(
_c_undelay_not_none_data
(
av
,
k
,
v
))
for
ak
,
(
av
,
k
,
v
)
in
kwargs
.
items
():
_d_kwargs
[
ak
]
=
_c_undelay_not_none_data
(
av
,
k
,
v
)
return
_c_func_treelize_run
(
func
,
_l_args
,
_d_kwargs
,
mode
,
inherit
,
allow_missing
,
missing_func
,
delayed
)
cdef
object
_c_func_treelize_run
(
object
func
,
list
args
,
dict
kwargs
,
_e_tree_mode
mode
,
bool
inherit
,
bool
allow_missing
,
object
missing_func
):
cdef
object
_c_func_treelize_run
(
object
func
,
list
args
,
dict
kwargs
,
_e_tree_mode
mode
,
bool
inherit
,
bool
allow_missing
,
object
missing_func
,
bool
delayed
):
cdef
list
ck_args
=
[]
cdef
list
ck_kwargs
=
[]
cdef
bool
has_tree
=
False
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
for
v
in
args
:
if
isinstance
(
v
,
TreeStorage
):
ck_args
.
append
((
v
.
detach
(),
True
))
...
...
@@ -66,17 +86,28 @@ cdef object _c_func_treelize_run(object func, list args, dict kwargs,
for
i
,
(
av
,
at
)
in
enumerate
(
ck_args
):
if
at
:
try
:
_l_args
.
append
(
av
[
k
])
v
=
av
[
k
]
if
delayed
:
_l_args
.
append
((
av
,
k
,
v
))
else
:
v
=
_c_undelay_data
(
av
,
k
,
v
)
_l_args
.
append
(
v
)
except
KeyError
:
if
allow_missing
:
_l_args
.
append
(
_VALUE_IS_MISSING
)
if
delayed
:
_l_args
.
append
((
None
,
None
,
_VALUE_IS_MISSING
))
else
:
_l_args
.
append
(
_VALUE_IS_MISSING
)
else
:
raise
KeyError
(
"Missing is off, key {key} not found in {item}."
.
format
(
key
=
repr
(
k
),
item
=
repr
(
av
),
))
else
:
if
inherit
:
_l_args
.
append
(
av
)
if
delayed
:
_l_args
.
append
((
None
,
None
,
av
))
else
:
_l_args
.
append
(
undelay
(
av
))
else
:
raise
TypeError
(
"Inherit is off, tree value expected but {type} found in args {index}."
.
format
(
type
=
repr
(
type
(
av
).
__name__
),
index
=
repr
(
i
),
...
...
@@ -86,29 +117,45 @@ cdef object _c_func_treelize_run(object func, list args, dict kwargs,
for
ak
,
av
,
at
in
ck_kwargs
:
if
at
:
try
:
_d_kwargs
[
ak
]
=
av
[
k
]
v
=
av
[
k
]
if
delayed
:
_d_kwargs
[
ak
]
=
(
av
,
k
,
v
)
else
:
v
=
_c_undelay_data
(
av
,
k
,
v
)
_d_kwargs
[
ak
]
=
v
except
KeyError
:
if
allow_missing
:
_d_kwargs
[
ak
]
=
_VALUE_IS_MISSING
if
delayed
:
_d_kwargs
[
ak
]
=
(
None
,
None
,
_VALUE_IS_MISSING
)
else
:
_d_kwargs
[
ak
]
=
_VALUE_IS_MISSING
else
:
raise
KeyError
(
"Missing is off, key {key} not found in {item}."
.
format
(
key
=
repr
(
k
),
item
=
repr
(
av
),
))
else
:
if
inherit
:
_d_kwargs
[
ak
]
=
av
if
delayed
:
_d_kwargs
[
ak
]
=
(
None
,
None
,
av
)
else
:
_d_kwargs
[
ak
]
=
undelay
(
av
)
else
:
raise
TypeError
(
"Inherit is off, tree value expected but {type} found in args {index}."
.
format
(
type
=
repr
(
type
(
av
).
__name__
),
index
=
repr
(
ak
),
))
_d_res
[
k
]
=
_c_func_treelize_run
(
func
,
_l_args
,
_d_kwargs
,
mode
,
inherit
,
allow_missing
,
missing_func
)
if
delayed
:
_d_res
[
k
]
=
delayed_partial
(
_c_wrap_func_treelize_run
,
func
,
_l_args
,
_d_kwargs
,
mode
,
inherit
,
allow_missing
,
missing_func
,
delayed
)
else
:
_d_res
[
k
]
=
_c_func_treelize_run
(
func
,
_l_args
,
_d_kwargs
,
mode
,
inherit
,
allow_missing
,
missing_func
,
delayed
)
return
TreeStorage
(
_d_res
)
def
_w_subside_func
(
object
value
,
bool
dict_
=
True
,
bool
list_
=
True
,
bool
tuple_
=
True
,
bool
inherit
=
True
):
return
_c_subside
(
value
,
dict_
,
list_
,
tuple_
,
inherit
)[
0
]
def
_w_subside_func
(
object
value
,
bool
dict_
=
True
,
bool
list_
=
True
,
bool
tuple_
=
True
,
bool
inherit
=
True
,
object
mode
=
'strict'
,
object
missing
=
MISSING_NOT_ALLOW
,
bool
delayed
=
False
):
return
_c_subside
(
value
,
dict_
,
list_
,
tuple_
,
inherit
,
mode
,
missing
,
delayed
)[
0
]
def
_w_rise_func
(
object
tree
,
bool
dict_
=
True
,
bool
list_
=
True
,
bool
tuple_
=
True
,
object
template
=
None
):
return
_c_rise
(
tree
,
dict_
,
list_
,
tuple_
,
template
)
...
...
@@ -116,16 +163,18 @@ def _w_rise_func(object tree, bool dict_=True, bool list_=True, bool tuple_=True
# runtime function
def
_w_func_treelize_run
(
*
args
,
object
__w_func
,
_e_tree_mode
__w_mode
,
object
__w_return_type
,
bool
__w_inherit
,
bool
__w_allow_missing
,
object
__w_missing_func
,
object
__w_subside
,
object
__w_rise
,
**
kwargs
):
bool
__w_delayed
,
object
__w_subside
,
object
__w_rise
,
**
kwargs
):
cdef
list
_a_args
=
[(
item
.
_detach
()
if
isinstance
(
item
,
TreeValue
)
else
item
)
for
item
in
args
]
cdef
dict
_a_kwargs
=
{
k
:
(
v
.
_detach
()
if
isinstance
(
v
,
TreeValue
)
else
v
)
for
k
,
v
in
kwargs
.
items
()}
cdef
dict
_w_subside_cfg
if
__w_subside
is
not
None
:
_a_args
=
[
_w_subside_func
(
item
,
**
__w_subside
)
for
item
in
_a_args
]
_a_kwargs
=
{
key
:
_w_subside_func
(
value
,
**
__w_subside
)
for
key
,
value
in
_a_kwargs
.
items
()}
_w_subside_cfg
=
{
'delayed'
:
__w_delayed
,
**
__w_subside
}
_a_args
=
[
_w_subside_func
(
item
,
**
_w_subside_cfg
)
for
item
in
_a_args
]
_a_kwargs
=
{
key
:
_w_subside_func
(
value
,
**
_w_subside_cfg
)
for
key
,
value
in
_a_kwargs
.
items
()}
cdef
object
_st_res
=
_c_func_treelize_run
(
__w_func
,
_a_args
,
_a_kwargs
,
__w_mode
,
__w_inherit
,
__w_allow_missing
,
__w_missing_func
)
__w_inherit
,
__w_allow_missing
,
__w_missing_func
,
__w_delayed
)
cdef
object
_o_res
if
__w_return_type
is
not
None
:
...
...
@@ -144,15 +193,10 @@ def _w_func_treelize_run(*args, object __w_func, _e_tree_mode __w_mode, object _
else
:
return
None
MISSING_NOT_ALLOW
=
SingletonMark
(
"missing_not_allow"
)
cdef
_c_common_value
(
object
item
):
cdef
object
_c_common_value
(
object
item
):
return
item
# build-time function
cpdef
object
_d_func_treelize
(
object
func
,
object
mode
,
object
return_type
,
bool
inherit
,
object
missing
,
object
subside
,
object
rise
):
cdef
_e_tree_mode
_v_mode
=
_c_load_mode
(
mode
)
cdef
inline
tuple
_c_missing_process
(
object
missing
):
cdef
bool
allow_missing
cdef
object
missing_func
if
missing
is
MISSING_NOT_ALLOW
:
...
...
@@ -162,6 +206,16 @@ cpdef object _d_func_treelize(object func, object mode, object return_type, bool
allow_missing
=
True
missing_func
=
missing
if
callable
(
missing
)
else
partial
(
_c_common_value
,
missing
)
return
allow_missing
,
missing_func
# build-time function
cpdef
object
_d_func_treelize
(
object
func
,
object
mode
,
object
return_type
,
bool
inherit
,
object
missing
,
bool
delayed
,
object
subside
,
object
rise
):
cdef
_e_tree_mode
_v_mode
=
_c_load_mode
(
mode
)
cdef
bool
allow_missing
cdef
object
missing_func
allow_missing
,
missing_func
=
_c_missing_process
(
missing
)
cdef
object
_v_subside
,
_v_rise
if
subside
is
not
None
and
not
isinstance
(
subside
,
dict
):
_v_subside
=
{}
if
subside
else
None
...
...
@@ -175,12 +229,12 @@ cpdef object _d_func_treelize(object func, object mode, object return_type, bool
_c_check
(
_v_mode
,
return_type
,
inherit
,
allow_missing
,
missing_func
)
return
partial
(
_w_func_treelize_run
,
__w_func
=
func
,
__w_mode
=
_v_mode
,
__w_return_type
=
return_type
,
__w_inherit
=
inherit
,
__w_allow_missing
=
allow_missing
,
__w_missing_func
=
missing_func
,
__w_subside
=
_v_subside
,
__w_rise
=
_v_rise
)
__w_
delayed
=
delayed
,
__w_
subside
=
_v_subside
,
__w_rise
=
_v_rise
)
@
cython
.
binding
(
True
)
cpdef
object
func_treelize
(
object
mode
=
'strict'
,
object
return_type
=
TreeValue
,
bool
inherit
=
True
,
object
missing
=
MISSING_NOT_ALLOW
,
object
subside
=
None
,
object
rise
=
None
):
bool
delayed
=
False
,
object
subside
=
None
,
object
rise
=
None
):
"""
Overview:
Wrap a common function to tree-supported function.
...
...
@@ -191,6 +245,8 @@ cpdef object func_treelize(object mode='strict', object return_type=TreeValue,
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled,
\
default is ``False``, which means to all the calculation at once.
- subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not,
\
and subside configuration, default is `None` which means do not use subside.
\
When subside is `True`, it will use all the default arguments in `subside` function.
...
...
@@ -213,4 +269,4 @@ cpdef object func_treelize(object mode='strict', object return_type=TreeValue,
>>> ssum(t1, t2) # TreeValue({'a': 12, 'b': 24, 'x': {'c': 36, 'd': 9}})
"""
return
partial
(
_d_func_treelize
,
mode
=
mode
,
return_type
=
return_type
,
inherit
=
inherit
,
missing
=
missing
,
subside
=
subside
,
rise
=
rise
)
inherit
=
inherit
,
missing
=
missing
,
delayed
=
delayed
,
subside
=
subside
,
rise
=
rise
)
treevalue/tree/func/func.py
浏览文件 @
029f029e
...
...
@@ -12,7 +12,7 @@ TreeClassType_ = TypeVar("TreeClassType_", bound=TreeValue)
def
func_treelize
(
mode
:
str
=
'strict'
,
return_type
:
Optional
[
Type
[
TreeClassType_
]]
=
TreeValue
,
inherit
:
bool
=
True
,
missing
:
Union
[
Any
,
Callable
]
=
MISSING_NOT_ALLOW
,
inherit
:
bool
=
True
,
missing
:
Union
[
Any
,
Callable
]
=
MISSING_NOT_ALLOW
,
delayed
:
bool
=
False
,
subside
:
Union
[
Mapping
,
bool
,
None
]
=
None
,
rise
:
Union
[
Mapping
,
bool
,
None
]
=
None
):
"""
Overview:
...
...
@@ -21,9 +21,11 @@ def func_treelize(mode: str = 'strict', return_type: Optional[Type[TreeClassType
Arguments:
- mode (:obj:`str`): Mode of the wrapping, default is `strict`.
- return_type (:obj:`Optional[Type[TreeClassType_]]`): Return type of the wrapped function, default is `TreeValue`.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- inherit (:obj:`bool`): Allow inherit
ing
in wrapped function, default is `True`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled,
\
default is ``False``, which means to all the calculation at once.
- subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not,
\
and subside configuration, default is `None` which means do not use subside.
\
When subside is `True`, it will use all the default arguments in `subside` function.
...
...
@@ -47,7 +49,7 @@ def func_treelize(mode: str = 'strict', return_type: Optional[Type[TreeClassType
"""
def
_decorator
(
func
):
_treelized
=
_c_func_treelize
(
mode
,
return_type
,
inherit
,
missing
,
subside
,
rise
)(
func
)
_treelized
=
_c_func_treelize
(
mode
,
return_type
,
inherit
,
missing
,
delayed
,
subside
,
rise
)(
func
)
@
wraps
(
func
)
def
_new_func
(
*
args
,
**
kwargs
):
...
...
@@ -82,7 +84,7 @@ def method_treelize(mode: str = 'strict', return_type: Optional[Type[TreeClassTy
- mode (:obj:`str`): Mode of the wrapping, default is `strict`.
- return_type (:obj:`Optional[Type[TreeClassType_]]`): Return type of the wrapped function,
\
default is `AUTO_DETECT_RETURN_VALUE`, which means automatically use the decorated method's class.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- inherit (:obj:`bool`): Allow inherit
ing
in wrapped function, default is `True`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not,
\
...
...
@@ -154,7 +156,7 @@ def classmethod_treelize(mode: str = 'strict', return_type: Optional[Type[TreeCl
- mode (:obj:`str`): Mode of the wrapping, default is `strict`.
- return_type (:obj:`Optional[Type[TreeClassType_]]`): Return type of the wrapped function,
\
default is `AUTO_DETECT_RETURN_VALUE`, which means automatically use the decorated method's class.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- inherit (:obj:`bool`): Allow inherit
ing
in wrapped function, default is `True`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not,
\
...
...
treevalue/tree/general/general.py
浏览文件 @
029f029e
...
...
@@ -147,13 +147,14 @@ def general_tree_value(base: Optional[Mapping[str, Any]] = None,
return
typetrans
(
self
,
clazz
)
@
_decorate_method
def
map
(
self
,
mapper
):
def
map
(
self
,
mapper
,
delayed
=
False
):
"""
Overview:
Do mapping on every value in this tree.
Arguments:
- func (:obj:): Function for mapping
- delayed (:obj:`bool`): Enable delayed mode for this mapping.
Returns:
- tree (:obj:`_TreeValue`): Mapped tree value object.
...
...
@@ -164,7 +165,7 @@ def general_tree_value(base: Optional[Mapping[str, Any]] = None,
>>> t.map(lambda: 1) # FastTreeValue({'a': 1, 'b': 1, 'x': {'c': 1, 'd': 1}})
>>> t.map(lambda x, p: p) # FastTreeValue({'a': ('a',), 'b': ('b',), 'x': {'c': ('x', 'c'), 'd': ('x', 'd')}})
"""
return
mapping
(
self
,
mapper
)
return
mapping
(
self
,
mapper
,
delayed
)
@
_decorate_method
def
mask
(
self
,
mask_
:
TreeValue
,
remove_empty
:
bool
=
True
):
...
...
@@ -308,9 +309,8 @@ def general_tree_value(base: Optional[Mapping[str, Any]] = None,
@
classmethod
@
_decorate_method
def
func
(
cls
,
mode
:
str
=
'strict'
,
inherit
:
bool
=
True
,
missing
:
Union
[
Any
,
Callable
]
=
MISSING_NOT_ALLOW
,
subside
:
Union
[
Mapping
,
bool
,
None
]
=
None
,
rise
:
Union
[
Mapping
,
bool
,
None
]
=
None
):
missing
:
Union
[
Any
,
Callable
]
=
MISSING_NOT_ALLOW
,
delayed
:
bool
=
False
,
subside
:
Union
[
Mapping
,
bool
,
None
]
=
None
,
rise
:
Union
[
Mapping
,
bool
,
None
]
=
None
):
"""
Overview:
Wrap a common function to tree-supported function based on this type.
...
...
@@ -320,6 +320,8 @@ def general_tree_value(base: Optional[Mapping[str, Any]] = None,
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled,
\
default is ``False``, which means to all the calculation at once.
- subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not,
\
and subside configuration, default is `None` which means do not use subside.
\
When subside is `True`, it will use all the default arguments in `subside` function.
...
...
@@ -343,7 +345,7 @@ def general_tree_value(base: Optional[Mapping[str, Any]] = None,
>>> ssum(1, 2) # 3
>>> ssum(t1, t2) # FastTreeValue({'a': 12, 'b': 24, 'x': {'c': 36, 'd': 9}})
"""
return
func_treelize
(
mode
,
cls
,
inherit
,
missing
,
subside
,
rise
)
return
func_treelize
(
mode
,
cls
,
inherit
,
missing
,
delayed
,
subside
,
rise
)
@
classmethod
@
_decorate_method
...
...
treevalue/tree/tree/__init__.py
浏览文件 @
029f029e
...
...
@@ -4,4 +4,4 @@ from .graph import graphics
from
.io
import
loads
,
load
,
dumps
,
dump
from
.service
import
jsonify
,
clone
,
typetrans
,
walk
from
.structural
import
subside
,
union
,
rise
from
.tree
import
TreeValue
from
.tree
import
TreeValue
,
delayed
treevalue/tree/tree/flatten.pyx
浏览文件 @
029f029e
...
...
@@ -6,15 +6,16 @@
import
cython
from
.tree
cimport
TreeValue
from
..common.storage
cimport
TreeStorage
from
..common.storage
cimport
TreeStorage
,
_c_undelay_data
cdef
void
_c_flatten
(
TreeStorage
st
,
tuple
path
,
list
res
)
except
*
:
cdef
dict
data
=
st
.
detach
()
cdef
tuple
curpath
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
for
k
,
v
in
data
.
items
():
v
=
_c_undelay_data
(
data
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
isinstance
(
v
,
TreeStorage
):
_c_flatten
(
v
,
curpath
,
res
)
...
...
@@ -47,8 +48,9 @@ cdef void _c_flatten_values(TreeStorage st, list res) except *:
cdef
dict
data
=
st
.
detach
()
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
for
k
,
v
in
data
.
items
():
v
=
_c_undelay_data
(
data
,
k
,
v
)
if
isinstance
(
v
,
TreeStorage
):
_c_flatten_values
(
v
,
res
)
else
:
...
...
@@ -75,8 +77,9 @@ cdef void _c_flatten_keys(TreeStorage st, tuple path, list res) except *:
cdef
tuple
curpath
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
for
k
,
v
in
data
.
items
():
v
=
_c_undelay_data
(
data
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
isinstance
(
v
,
TreeStorage
):
_c_flatten_keys
(
v
,
curpath
,
res
)
...
...
treevalue/tree/tree/functional.pxd
浏览文件 @
029f029e
...
...
@@ -12,8 +12,9 @@ cdef object _c_no_arg(object func, object v, object p)
cdef
object
_c_one_arg
(
object
func
,
object
v
,
object
p
)
cdef
object
_c_two_args
(
object
func
,
object
v
,
object
p
)
cdef
object
_c_wrap_mapping_func
(
object
func
)
cdef
TreeStorage
_c_mapping
(
TreeStorage
st
,
object
func
,
tuple
path
)
cpdef
TreeValue
mapping
(
TreeValue
tree
,
object
func
)
cdef
object
_c_delayed_mapping
(
object
so
,
object
func
,
tuple
path
,
bool
delayed
)
cdef
TreeStorage
_c_mapping
(
TreeStorage
st
,
object
func
,
tuple
path
,
bool
delayed
)
cpdef
TreeValue
mapping
(
TreeValue
tree
,
object
func
,
bool
delayed
=
*
)
cdef
TreeStorage
_c_filter_
(
TreeStorage
st
,
object
func
,
tuple
path
,
bool
remove_empty
)
cpdef
TreeValue
filter_
(
TreeValue
tree
,
object
func
,
bool
remove_empty
=
*
)
cdef
object
_c_mask
(
TreeStorage
st
,
object
sm
,
tuple
path
,
bool
remove_empty
)
...
...
treevalue/tree/tree/functional.pyx
浏览文件 @
029f029e
...
...
@@ -8,7 +8,9 @@ from functools import partial
from
libcpp
cimport
bool
from
.tree
cimport
TreeValue
from
..common.storage
cimport
TreeStorage
from
..common.delay
cimport
undelay
from
..common.delay
import
delayed_partial
from
..common.storage
cimport
TreeStorage
,
_c_undelay_data
cdef
inline
object
_c_no_arg
(
object
func
,
object
v
,
object
p
):
return
func
()
...
...
@@ -33,24 +35,40 @@ cdef inline object _c_wrap_mapping_func(object func):
else
:
return
partial
(
_c_no_arg
,
func
)
cdef
TreeStorage
_c_mapping
(
TreeStorage
st
,
object
func
,
tuple
path
):
cdef
object
_c_delayed_mapping
(
object
so
,
object
func
,
tuple
path
,
bool
delayed
):
cdef
object
nso
=
undelay
(
so
)
if
isinstance
(
nso
,
TreeValue
):
nso
=
nso
.
_detach
()
if
isinstance
(
nso
,
TreeStorage
):
return
_c_mapping
(
nso
,
func
,
path
,
delayed
)
else
:
return
func
(
nso
,
path
)
cdef
TreeStorage
_c_mapping
(
TreeStorage
st
,
object
func
,
tuple
path
,
bool
delayed
):
cdef
dict
_d_st
=
st
.
detach
()
cdef
dict
_d_res
=
{}
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
cdef
tuple
curpath
for
k
,
v
in
_d_st
.
items
():
if
not
delayed
:
v
=
_c_undelay_data
(
_d_st
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
isinstance
(
v
,
TreeStorage
):
_d_res
[
k
]
=
_c_mapping
(
v
,
func
,
curpath
)
_d_res
[
k
]
=
_c_mapping
(
v
,
func
,
curpath
,
delayed
)
else
:
_d_res
[
k
]
=
func
(
v
,
curpath
)
if
delayed
:
_d_res
[
k
]
=
delayed_partial
(
_c_delayed_mapping
,
v
,
func
,
curpath
,
delayed
)
else
:
_d_res
[
k
]
=
func
(
v
,
curpath
)
return
TreeStorage
(
_d_res
)
@
cython
.
binding
(
True
)
cpdef
TreeValue
mapping
(
TreeValue
tree
,
object
func
):
cpdef
TreeValue
mapping
(
TreeValue
tree
,
object
func
,
bool
delayed
=
False
):
"""
Overview:
Do mapping on every value in this tree.
...
...
@@ -80,17 +98,18 @@ cpdef TreeValue mapping(TreeValue tree, object func):
>>> mapping(t, lambda: 1) # TreeValue({'a': 1, 'b': 1, 'x': {'c': 1, 'd': 1}})
>>> mapping(t, lambda x, p: p) # TreeValue({'a': ('a',), 'b': ('b',), 'x': {'c': ('x', 'c'), 'd': ('x', 'd')}})
"""
return
type
(
tree
)(
_c_mapping
(
tree
.
_detach
(),
_c_wrap_mapping_func
(
func
),
()))
return
type
(
tree
)(
_c_mapping
(
tree
.
_detach
(),
_c_wrap_mapping_func
(
func
),
()
,
delayed
))
cdef
TreeStorage
_c_filter_
(
TreeStorage
st
,
object
func
,
tuple
path
,
bool
remove_empty
):
cdef
dict
_d_st
=
st
.
detach
()
cdef
dict
_d_res
=
{}
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
cdef
tuple
curpath
cdef
TreeStorage
curst
for
k
,
v
in
_d_st
.
items
():
v
=
_c_undelay_data
(
_d_st
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
isinstance
(
v
,
TreeStorage
):
curst
=
_c_filter_
(
v
,
func
,
curpath
,
remove_empty
)
...
...
@@ -148,9 +167,11 @@ cdef object _c_mask(TreeStorage st, object sm, tuple path, bool remove_empty):
cdef
tuple
curpath
cdef
object
curres
for
k
,
v
in
_d_st
.
items
():
v
=
_c_undelay_data
(
_d_st
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
_b_tree_mask
:
mv
=
_d_sm
[
k
]
mv
=
_c_undelay_data
(
_d_sm
,
k
,
mv
)
else
:
mv
=
sm
...
...
@@ -194,10 +215,11 @@ cdef object _c_reduce(TreeStorage st, object func, tuple path, object return_typ
cdef
dict
_d_kwargs
=
{}
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
cdef
tuple
curpath
cdef
object
curst
for
k
,
v
in
_d_st
.
items
():
v
=
_c_undelay_data
(
_d_st
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
isinstance
(
v
,
TreeStorage
):
curst
=
_c_reduce
(
v
,
func
,
curpath
,
return_type
)
...
...
treevalue/tree/tree/service.pyx
浏览文件 @
029f029e
...
...
@@ -9,7 +9,7 @@ import cython
from
libcpp
cimport
bool
from
.tree
cimport
TreeValue
from
..common.storage
cimport
TreeStorage
from
..common.storage
cimport
TreeStorage
,
_c_undelay_data
cdef
object
_keep_object
(
object
obj
):
return
obj
...
...
@@ -29,7 +29,7 @@ cpdef object jsonify(TreeValue val):
Example:
>>> jsonify(TreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})) # {'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}
"""
return
val
.
_detach
().
jsondumpx
(
_keep_object
,
False
)
return
val
.
_detach
().
jsondumpx
(
_keep_object
,
False
,
False
)
@
cython
.
binding
(
True
)
cpdef
TreeValue
clone
(
TreeValue
t
,
object
copy_value
=
None
):
...
...
@@ -50,10 +50,18 @@ cpdef TreeValue clone(TreeValue t, object copy_value=None):
>>> t = TreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> clone(t.x) # TreeValue({'c': 3, 'd': 4})
"""
cdef
bool
need_copy
if
not
callable
(
copy_value
):
copy_value
=
copy
.
deepcopy
if
copy_value
else
_keep_object
if
copy_value
:
need_copy
=
True
copy_value
=
copy
.
deepcopy
else
:
need_copy
=
False
copy_value
=
_keep_object
else
:
need_copy
=
True
return
type
(
t
)(
t
.
_detach
().
deepcopyx
(
copy_value
))
return
type
(
t
)(
t
.
_detach
().
deepcopyx
(
copy_value
,
not
need_copy
))
@
cython
.
binding
(
True
)
cpdef
TreeValue
typetrans
(
TreeValue
t
,
object
return_type
):
...
...
@@ -87,9 +95,10 @@ def _p_walk(TreeStorage tree, object type_, tuple path, bool include_nodes):
cdef
dict
data
=
tree
.
detach
()
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
cdef
tuple
curpath
for
k
,
v
in
data
.
items
():
v
=
_c_undelay_data
(
data
,
k
,
v
)
curpath
=
path
+
(
k
,)
if
isinstance
(
v
,
TreeStorage
):
yield
from
_p_walk
(
v
,
type_
,
curpath
,
include_nodes
)
...
...
treevalue/tree/tree/structural.pxd
浏览文件 @
029f029e
...
...
@@ -11,10 +11,11 @@ cdef class _SubsideCall:
cdef
object
_c_subside_process
(
tuple
value
,
object
it
)
cdef
tuple
_c_subside_build
(
object
value
,
bool
dict_
,
bool
list_
,
bool
tuple_
)
cdef
void
_c_subside_missing
()
cdef
object
_c_subside
(
object
value
,
bool
dict_
,
bool
list_
,
bool
tuple_
,
bool
inherit
)
cdef
object
_c_subside
(
object
value
,
bool
dict_
,
bool
list_
,
bool
tuple_
,
bool
inherit
,
object
mode
,
object
missing
,
bool
delayed
)
cdef
object
_c_subside_keep_type
(
object
t
)
cpdef
object
subside
(
object
value
,
bool
dict_
=
*
,
bool
list_
=
*
,
bool
tuple_
=
*
,
object
return_type
=
*
,
bool
inherit
=
*
)
object
return_type
=
*
,
bool
inherit
=
*
,
object
mode
=
*
,
object
missing
=
*
,
bool
delayed
=
*
)
cdef
object
_c_rise_tree_builder
(
tuple
p
,
object
it
)
cdef
tuple
_c_rise_tree_process
(
object
t
)
...
...
treevalue/tree/tree/structural.pyx
浏览文件 @
029f029e
...
...
@@ -6,13 +6,16 @@
from
itertools
import
chain
import
cython
from
hbutils.design
import
SingletonMark
from
libcpp
cimport
bool
from
.tree
cimport
TreeValue
from
..common.storage
cimport
TreeStorage
from
..func.cfunc
cimport
_c_func_treelize_run
from
..common.storage
cimport
TreeStorage
,
_c_undelay_data
from
..func.cfunc
cimport
_c_func_treelize_run
,
_c_missing_process
from
..func.modes
cimport
_c_load_mode
MISSING_NOT_ALLOW
=
SingletonMark
(
"missing_not_allow"
)
cdef
object
_c_subside_process
(
tuple
value
,
object
it
):
cdef
type
type_
cdef
list
items
...
...
@@ -76,25 +79,29 @@ cdef tuple _c_subside_build(object value, bool dict_, bool list_, bool tuple_):
else
:
return
(
object
,
None
),
(
value
,),
()
STRICT
=
_c_load_mode
(
'STRICT'
)
cdef
inline
void
_c_subside_missing
():
pass
cdef
object
_c_subside
(
object
value
,
bool
dict_
,
bool
list_
,
bool
tuple_
,
bool
inherit
):
cdef
object
_c_subside
(
object
value
,
bool
dict_
,
bool
list_
,
bool
tuple_
,
bool
inherit
,
object
mode
,
object
missing
,
bool
delayed
):
cdef
object
builder
,
_i_args
,
_i_types
builder
,
_i_args
,
_i_types
=
_c_subside_build
(
value
,
dict_
,
list_
,
tuple_
)
cdef
list
args
=
list
(
_i_args
)
cdef
bool
allow_missing
cdef
object
missing_func
allow_missing
,
missing_func
=
_c_missing_process
(
missing
)
return
_c_func_treelize_run
(
_SubsideCall
(
builder
),
args
,
{},
STRICT
,
inherit
,
False
,
_c_subside_missing
),
_i_types
_c_load_mode
(
mode
),
inherit
,
allow_missing
,
missing_func
,
delayed
),
_i_types
cdef
inline
object
_c_subside_keep_type
(
object
t
):
return
t
@
cython
.
binding
(
True
)
cpdef
object
subside
(
object
value
,
bool
dict_
=
True
,
bool
list_
=
True
,
bool
tuple_
=
True
,
object
return_type
=
None
,
bool
inherit
=
True
):
object
return_type
=
None
,
bool
inherit
=
True
,
object
mode
=
'strict'
,
object
missing
=
MISSING_NOT_ALLOW
,
bool
delayed
=
False
):
"""
Overview:
Drift down the structures (list, tuple, dict) down to the tree's value.
...
...
@@ -108,6 +115,11 @@ cpdef object subside(object value, bool dict_=True, bool list_=True, bool tuple_
will be auto detected when there is exactly one tree value type in this original value,
\
otherwise the default will be `TreeValue`.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- mode (:obj:`str`): Mode of the wrapping, default is `strict`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled,
\
default is ``False``, which means to all the calculation at once.
Returns:
- return (:obj:`_TreeValue`): Subsided tree value.
...
...
@@ -132,7 +144,7 @@ cpdef object subside(object value, bool dict_=True, bool list_=True, bool tuple_
>>> #}), all structures above the tree values are subsided to the bottom of the tree.
"""
cdef
object
result
,
_i_types
result
,
_i_types
=
_c_subside
(
value
,
dict_
,
list_
,
tuple_
,
inherit
)
result
,
_i_types
=
_c_subside
(
value
,
dict_
,
list_
,
tuple_
,
inherit
,
mode
,
missing
,
delayed
)
cdef
object
type_
cdef
set
types
...
...
@@ -150,7 +162,8 @@ cpdef object subside(object value, bool dict_=True, bool list_=True, bool tuple_
return
type_
(
result
)
@
cython
.
binding
(
True
)
def
union
(
*
trees
,
object
return_type
=
None
,
bool
inherit
=
True
):
def
union
(
*
trees
,
object
return_type
=
None
,
bool
inherit
=
True
,
object
mode
=
'strict'
,
object
missing
=
MISSING_NOT_ALLOW
,
bool
delayed
=
False
):
"""
Overview:
Union tree values together.
...
...
@@ -158,7 +171,12 @@ def union(*trees, object return_type=None, bool inherit=True):
Arguments:
- trees (:obj:`_TreeValue`): Tree value objects.
- return_type (:obj:`Optional[Type[_ClassType]]`): Return type of the wrapped function, default is `TreeValue`.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- inherit (:obj:`bool`): Allow inheriting in wrapped function, default is `True`.
- mode (:obj:`str`): Mode of the wrapping, default is `strict`.
- missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing,
\
default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected.
- delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled,
\
default is ``False``, which means to all the calculation at once.
Returns:
- result (:obj:`TreeValue`): Unionised tree value.
...
...
@@ -169,7 +187,7 @@ def union(*trees, object return_type=None, bool inherit=True):
>>> union(t, tx) # TreeValue({'a': (1, True), 'b': (2, False), 'x': {'c': (3, True), 'd': (4, False)}})
"""
cdef
object
result
,
_i_types
result
,
_i_types
=
_c_subside
(
tuple
(
trees
),
True
,
True
,
True
,
inherit
)
result
,
_i_types
=
_c_subside
(
tuple
(
trees
),
True
,
True
,
True
,
inherit
,
mode
,
missing
,
delayed
)
cdef
object
type_
cdef
list
types
...
...
@@ -200,7 +218,7 @@ cdef object _c_rise_tree_builder(tuple p, object it):
cdef
tuple
_c_rise_tree_process
(
object
t
):
cdef
str
k
cdef
object
v
cdef
object
v
,
nv
cdef
list
_l_items
,
_l_values
cdef
object
_i_item
,
_i_value
cdef
dict
detached
...
...
@@ -209,6 +227,7 @@ cdef tuple _c_rise_tree_process(object t):
_l_items
=
[]
_l_values
=
[]
for
k
,
v
in
detached
.
items
():
v
=
_c_undelay_data
(
detached
,
k
,
v
)
_i_item
,
_i_value
=
_c_rise_tree_process
(
v
)
_l_items
.
append
((
k
,
_i_item
))
_l_values
.
append
(
_i_value
)
...
...
@@ -262,7 +281,7 @@ cdef tuple _c_rise_struct_process(list objs, object template):
_l_obj_0
=
len
(
objs
[
0
])
if
_l_obj_0
<
_l_temp
-
2
:
raise
ValueError
(
f
"At least
{
repr
(
_l_temp
-
2
)
}
value expected due to template "
f
"
{
repr
(
template
)
}
, but length is
{
repr
(
_l_obj_0
)
}
."
)
f
"
{
repr
(
template
)
}
, but length is
{
repr
(
_l_obj_0
)
}
."
)
_a_template
=
type
(
template
)(
chain
(
template
[:
-
2
],
(
template
[
-
2
],)
*
(
_l_obj_0
-
_l_temp
+
2
)))
else
:
...
...
treevalue/tree/tree/tree.pxd
浏览文件 @
029f029e
# distutils:language=c++
# cython:language_level=3
from
libcpp
cimport
bool
from
..common.delay
cimport
DelayedProxy
from
..common.storage
cimport
TreeStorage
cdef
class
TreeValue
:
...
...
@@ -15,3 +18,11 @@ cdef class TreeValue:
cdef
str
_prefix_fix
(
object
text
,
object
prefix
)
cdef
object
_build_tree
(
TreeStorage
st
,
object
type_
,
str
prefix
,
dict
id_pool
,
tuple
path
)
cdef
class
DetachedDelayedProxy
(
DelayedProxy
):
cdef
DelayedProxy
proxy
cdef
readonly
bool
calculated
cdef
object
val
cpdef
object
value
(
self
)
cpdef
object
fvalue
(
self
)
\ No newline at end of file
treevalue/tree/tree/tree.pyx
浏览文件 @
029f029e
...
...
@@ -7,7 +7,8 @@ from operator import itemgetter
import
cython
from
hbutils.design
import
SingletonMark
from
..common.storage
cimport
TreeStorage
,
create_storage
from
..common.delay
cimport
undelay
,
_c_delayed_partial
,
DelayedProxy
from
..common.storage
cimport
TreeStorage
,
create_storage
,
_c_undelay_data
from
...utils
import
format_tree
_GET_NO_DEFAULT
=
SingletonMark
(
'get_no_default'
)
...
...
@@ -385,7 +386,7 @@ cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool,
cdef
list
children
=
[]
cdef
str
k
,
_t_prefix
cdef
object
v
cdef
object
v
,
nv
cdef
dict
data
cdef
tuple
curpath
if
nid
in
id_pool
:
...
...
@@ -395,6 +396,7 @@ cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool,
id_pool
[
nid
]
=
path
data
=
st
.
detach
()
for
k
,
v
in
sorted
(
data
.
items
()):
v
=
_c_undelay_data
(
data
,
k
,
v
)
curpath
=
path
+
(
k
,)
_t_prefix
=
f
'
{
k
}
--> '
if
isinstance
(
v
,
TreeStorage
):
...
...
@@ -404,3 +406,67 @@ cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool,
self_repr
=
_prefix_fix
(
self_repr
,
prefix
)
return
self_repr
,
children
cdef
class
DetachedDelayedProxy
(
DelayedProxy
):
def
__init__
(
self
,
DelayedProxy
proxy
):
self
.
proxy
=
proxy
self
.
calculated
=
False
self
.
val
=
None
cpdef
object
value
(
self
):
if
not
self
.
calculated
:
self
.
val
=
undelay
(
self
.
proxy
,
False
)
self
.
calculated
=
True
return
self
.
val
cpdef
object
fvalue
(
self
):
cdef
object
v
=
self
.
value
()
if
isinstance
(
v
,
TreeValue
):
v
=
v
.
_detach
()
return
v
@
cython
.
binding
(
True
)
def
delayed
(
func
,
*
args
,
**
kwargs
):
r
"""
Overview:
Use delayed function in treevalue.
The given ``func`` will not be called until its value is accessed, and \
it will be only called once, after that the delayed node will be replaced by the actual value.
Arguments:
- func: Delayed function.
- args: Positional arguments.
- kwargs: Key-word arguments.
Examples::
>>> from treevalue import TreeValue, delayed
>>>
>>> def f(x):
>>> print('f is called, x is', x)
>>> return x ** x
>>>
>>> t = TreeValue({'a': delayed(f, 2), 'x': delayed(f, 3)})
>>> t.a
f is called, x is 2
4
>>> t.x
f is called, x is 3
27
>>> t.a
4
>>> t.x
27
>>> t = TreeValue({'a': delayed(f, 2), 'x': delayed(f, 3)})
>>> print(t)
f is called, x is 2
f is called, x is 3
<TreeValue 0x7f0fb7f03198>
├── a --> 4
└── x --> 27
>>> print(t)
<TreeValue 0x7f0fb7f03198>
├── a --> 4
└── x --> 27
"""
return
DetachedDelayedProxy
(
_c_delayed_partial
(
func
,
args
,
kwargs
))
HansBug
😆
@HansBug
mentioned in commit
03354468
·
1月 05, 2022
mentioned in commit
03354468
mentioned in commit 033544685d52647a7053c86eb54730344231c239
开关提交列表
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录