Skip to content

Commit

Permalink
Merge pull request #23 from opendilab/dev/delay
Browse files Browse the repository at this point in the history
dev(hansbug): add delay feature in treevalue && add mode and missing option to union and subside
  • Loading branch information
HansBug authored Jan 4, 2022
2 parents 588c536 + 17c2ac4 commit 7a627e8
Show file tree
Hide file tree
Showing 32 changed files with 1,280 additions and 128 deletions.
43 changes: 43 additions & 0 deletions docs/source/api_doc/tree/common.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

8 changes: 8 additions & 0 deletions docs/source/api_doc/tree/tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion requirements-doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
68 changes: 68 additions & 0 deletions test/tree/common/test_delay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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
171 changes: 167 additions & 4 deletions test/tree/common/test_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

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):
Expand All @@ -23,6 +23,52 @@ def test_get(self):
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
Expand All @@ -34,6 +80,23 @@ def test_get_or_default(self):

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)
Expand Down Expand Up @@ -122,6 +185,19 @@ def test_dump(self):
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}
Expand Down Expand Up @@ -177,7 +253,7 @@ def test_deepcopyx(self):
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'}
Expand Down Expand Up @@ -232,6 +308,19 @@ def test_copy_from(self):
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}
Expand All @@ -253,6 +342,19 @@ def test_deepcopy_from(self):
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}
Expand All @@ -272,6 +374,21 @@ def test_eq(self):
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}
Expand All @@ -286,10 +403,20 @@ def test_values(self):
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)})
Expand All @@ -303,3 +430,39 @@ def test_items(self):
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
Loading

0 comments on commit 7a627e8

Please sign in to comment.