未验证 提交 b028e052 编写于 作者: HansBug's avatar HansBug 😆 提交者: GitHub

Merge pull request #48 from opendilab/dev/mutablemapping

dev(hansbug): upgrade keys, values and items for TreeValue class, like that in dict object
......@@ -4,6 +4,13 @@ import pytest
from treevalue.tree.common import create_storage, raw, TreeStorage, delayed_partial
try:
_ = reversed({}.keys())
except TypeError:
_reversible = False
else:
_reversible = True
# noinspection PyArgumentList,DuplicatedCode,PyTypeChecker
@pytest.mark.unittest
......@@ -501,33 +508,49 @@ class TestTreeStorage:
h2 = {'x': 3, 'y': 4}
t = create_storage({'a': 1, 'b': 2, 'c': raw(h1), 'd': h2, 'f': h2})
assert set(t.keys()) == {'a', 'b', 'c', 'd', 'f'}
assert set(t.get('f').keys()) == {'x', 'y'}
assert set(t.iter_keys()) == {'a', 'b', 'c', 'd', 'f'}
assert set(t.get('f').iter_keys()) == {'x', 'y'}
if _reversible:
assert list(t.iter_rev_keys()) == list(t.iter_keys())[::-1]
else:
with pytest.raises(TypeError):
t.iter_rev_keys()
def test_values(self):
h1 = {'x': 3, 'y': 4}
t = create_storage({'a': 1, 'b': 2, 'd': h1})
assert set(t.get('d').values()) == {3, 4}
assert len(list(t.values())) == 3
assert 1 in t.values()
assert 2 in t.values()
assert set(t.get('d').iter_values()) == {3, 4}
assert len(list(t.iter_values())) == 3
assert 1 in t.iter_values()
assert 2 in t.iter_values()
if _reversible:
assert list(t.iter_rev_values()) == list(t.iter_values())[::-1]
else:
with pytest.raises(TypeError):
_ = list(t.iter_rev_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()
assert set(t1.get('d').iter_values()) == {3, 4}
assert len(list(t1.iter_values())) == 3
assert 1 in t1.iter_values()
assert 2 in t1.iter_values()
if _reversible:
assert list(t1.iter_rev_values()) == list(t1.iter_values())[::-1]
else:
with pytest.raises(TypeError):
_ = list(t1.iter_rev_values())
def test_items(self):
h1 = {'x': 3, 'y': 4}
t = create_storage({'a': 1, 'b': 2, 'd': raw(h1)})
for k, v in t.items():
for k, v in t.iter_items():
if k == 'a':
assert v == 1
elif k == 'b':
......@@ -537,12 +560,18 @@ class TestTreeStorage:
else:
pytest.fail('Should not reach here.')
if _reversible:
assert list(t.iter_rev_items()) == list(t.iter_items())[::-1]
else:
with pytest.raises(TypeError):
_ = list(t.iter_rev_items())
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():
for k, v in t1.iter_items():
if k == 'a':
assert v == 1
elif k == 'b':
......@@ -552,6 +581,12 @@ class TestTreeStorage:
else:
pytest.fail('Should not reach here.')
if _reversible:
assert list(t1.iter_rev_values()) == list(t1.iter_values())[::-1]
else:
with pytest.raises(TypeError):
_ = list(t1.iter_rev_values())
def test_hash(self):
h = {}
......
......@@ -5,6 +5,13 @@ import pytest
from treevalue import raw, TreeValue, delayed
try:
_ = reversed({}.keys())
except TypeError:
_reversible = False
else:
_reversible = True
class _Container:
def __init__(self, value):
......@@ -240,12 +247,14 @@ class TestTreeTreeTree:
assert tv2
assert not tv2.c
def test_tee_value_hash_equal(self):
def test_tree_value_hash_equal(self):
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}})
assert tv1 == tv1
assert not tv1 == 2
assert tv1 == TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}})
assert tv1 != TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 4}})
assert tv1.c == TreeValue({'x': 2, 'y': 3})
assert tv1.c != TreeValue({'x': 2, 'y': 3, 'z': 4})
d = {
tv1: 1,
......@@ -330,23 +339,61 @@ class TestTreeTreeTree:
def test_keys(self):
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}, 'd': raw({'x': 2, 'y': 3})})
assert len(tv1.keys()) == 4
assert set(tv1.keys()) == {'a', 'b', 'c', 'd'}
assert 'a' in tv1.keys()
assert 'b' in tv1.keys()
assert 'c' in tv1.keys()
assert 'd' in tv1.keys()
assert 'e' not in tv1.keys()
assert repr(tv1.keys()) == "treevalue_keys(['a', 'b', 'c', 'd'])"
if _reversible:
assert list(reversed(tv1.keys())) == list(tv1.keys())[::-1]
else:
with pytest.raises(TypeError):
reversed(tv1.keys())
def test_values(self):
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}})
assert len(tv1.values()) == 3
assert set(tv1.c.values()) == {2, 3}
assert len(list(tv1.values())) == 3
assert 1 in tv1.values()
assert 2 in tv1.values()
assert 3 not in tv1.values()
assert TreeValue({'x': 2, 'y': 3}) in tv1.values()
assert TreeValue({'x': 2, 'y': 4}) not in tv1.values()
assert repr(TreeValue({'a': 1, 'b': 2}).values()) == 'treevalue_values([1, 2])'
if _reversible:
assert list(reversed(tv1.values())) == list(tv1.values())[::-1]
else:
with pytest.raises(TypeError):
reversed(tv1.values())
def test_items(self):
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}, 'd': raw({'x': 2, 'y': 3})})
assert len(tv1.items()) == 4
assert sorted(tv1.items()) == [
('a', 1),
('b', 2),
('c', TreeValue({'x': 2, 'y': 3})),
('d', {'x': 2, 'y': 3}),
]
assert ('a', 1) in tv1.items()
assert ('b', 2) in tv1.items()
assert ('a', 2) not in tv1.items()
assert ('c', TreeValue({'x': 2, 'y': 3})) in tv1.items()
assert ('c', TreeValue({'x': 2, 'y': 4})) not in tv1.items()
assert ('d', {'x': 2, 'y': 3}) in tv1.items()
assert ('d', {'x': 2, 'y': 4}) not in tv1.items()
assert repr(TreeValue({'a': 1, 'b': 2}).items()) == "treevalue_items([('a', 1), ('b', 2)])"
if _reversible:
assert list(reversed(tv1.items())) == list(tv1.items())[::-1]
else:
with pytest.raises(TypeError):
reversed(tv1.items())
class MyTreeValue(TreeValue):
pass
......
......@@ -185,27 +185,41 @@ cdef class TreeStorage:
cdef str k
cdef object v
cdef list _items = []
for k, v in sorted(self.items(), key=lambda x: x[0]):
for k, v in sorted(self.iter_items(), key=lambda x: x[0]):
_items.append((k, v))
return hash(tuple(_items))
def keys(self):
def iter_keys(self):
return self.map.keys()
def values(self):
def iter_rev_keys(self):
return reversed(self.map.keys())
def iter_values(self):
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):
def iter_rev_values(self):
cdef str k
cdef object v, nv
for k, v in reversed(self.map.items()):
yield _c_undelay_data(self.map, k, v)
def iter_items(self):
cdef str k
cdef object v, nv
for k, v in self.map.items():
v = _c_undelay_data(self.map, k, v)
yield k, _c_undelay_data(self.map, k, v)
def iter_rev_items(self):
cdef str k
cdef object v, nv
for k, v in reversed(self.map.items()):
yield k, _c_undelay_data(self.map, k, v)
yield k, v
cpdef object create_storage(dict value):
cdef dict _map = {}
......
......@@ -6,6 +6,9 @@ from libcpp cimport bool
from ..common.delay cimport DelayedProxy
from ..common.storage cimport TreeStorage
cdef class _CObject:
pass
cdef class TreeValue:
cdef readonly TreeStorage _st
cdef readonly type _type
......@@ -20,9 +23,29 @@ cdef class TreeValue:
cpdef get(self, str key, object default= *)
cpdef pop(self, str key, object default= *)
cpdef treevalue_keys keys(self)
cpdef treevalue_values values(self)
cpdef treevalue_items items(self)
cdef str _prefix_fix(object text, object prefix)
cdef str _title_repr(TreeStorage st, object type_)
cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool, tuple path)
# noinspection PyPep8Naming
cdef class treevalue_keys(_CObject):
cdef readonly TreeStorage _st
cdef readonly type _type
# noinspection PyPep8Naming
cdef class treevalue_values(_CObject):
cdef readonly TreeStorage _st
cdef readonly type _type
# noinspection PyPep8Naming
cdef class treevalue_items(_CObject):
cdef readonly TreeStorage _st
cdef readonly type _type
cdef class DetachedDelayedProxy(DelayedProxy):
cdef DelayedProxy proxy
cdef readonly bool calculated
......
......@@ -2,6 +2,7 @@
# cython:language_level=3
import os
from collections.abc import Sized, Container, Reversible
from operator import itemgetter
import cython
......@@ -11,6 +12,9 @@ from ..common.delay cimport undelay, _c_delayed_partial, DelayedProxy
from ..common.storage cimport TreeStorage, create_storage, _c_undelay_data
from ...utils import format_tree
cdef class _CObject:
pass
cdef inline object _item_unwrap(object v):
if isinstance(v, list) and len(v) == 1:
return v[0]
......@@ -392,7 +396,7 @@ cdef class TreeValue:
"""
cdef str k
cdef object v
for k, v in self._st.items():
for k, v in self._st.iter_items():
yield k, self._unraw(v)
@cython.binding(True)
......@@ -525,48 +529,97 @@ cdef class TreeValue:
return self._st
@cython.binding(True)
def keys(self):
cpdef treevalue_keys keys(self):
"""
Overview:
Get keys of this treevalue object, like the :class:`dict`.
Returns:
- keys: A generator of all the keys.
Examples::
>>> from treevalue import TreeValue
>>>
>>> t = TreeValue({'a': 1, 'b': 3, 'c': '233'})
>>> t.keys()
treevalue_keys(['a', 'b', 'c'])
>>> len(t.keys())
3
>>> list(t.keys())
['a', 'b', 'c']
>>> list(reversed(t.keys())) # only available in python3.8+
['c', 'b', 'a']
>>> 'a' in t.keys()
True
>>> 'f' in t.keys()
False
.. note::
:func:`reversed` is only available in python 3.8 or higher versions.
"""
return self._st.keys()
return treevalue_keys(self._st, self._type)
@cython.binding(True)
def values(self):
cpdef treevalue_values values(self):
"""
Overview:
Get value of this treevalue object, like the :class:`dict`.
Returns:
- values: A generator of all the values
Examples::
>>> from treevalue import TreeValue
>>>
>>> t = TreeValue({'a': 1, 'b': 3, 'c': '233'})
>>> t.values()
treevalue_values([1, 3, '233'])
>>> len(t.values())
3
>>> list(t.values())
[1, 3, '233']
>>> list(reversed(t.values())) # only supported on python3.8+
['233', 3, 1]
>>> 1 in t.values()
True
>>> 'fff' in t.values()
False
.. note::
:func:`reversed` is only available in python 3.8 or higher versions.
"""
cdef object v
for v in self._st.values():
if isinstance(v, TreeStorage):
yield self._type(v)
else:
yield v
return treevalue_values(self._st, self._type)
@cython.binding(True)
def items(self):
cpdef treevalue_items items(self):
"""
Overview:
Get pairs of keys and values of this treevalue object, like the :class:`items`.
Returns:
- items: A generator of pairs of keys and values.
Examples::
>>> from treevalue import TreeValue
>>>
>>> t = TreeValue({'a': 1, 'b': 3, 'c': '233'})
>>> t.items()
treevalue_items([('a', 1), ('b', 3), ('c', '233')])
>>> len(t.items())
3
>>> list(t.items())
[('a', 1), ('b', 3), ('c', '233')]
>>> list(reversed(t.items())) # only supported on python3.8+
[('c', '233'), ('b', 3), ('a', 1)]
>>> ('a', 1) in t.items()
True
>>> ('c', '234') in t.values()
False
.. note::
:func:`reversed` is only available in python 3.8 or higher versions.
"""
cdef str k
cdef object v
for k, v in self._st.items():
if isinstance(v, TreeStorage):
yield k, self._type(v)
else:
yield k, v
return treevalue_items(self._st, self._type)
cdef str _prefix_fix(object text, object prefix):
cdef list lines = []
......@@ -578,9 +631,12 @@ cdef str _prefix_fix(object text, object prefix):
return os.linesep.join(lines)
cdef inline str _title_repr(TreeStorage st, object type_):
return f'<{type_.__name__} {hex(id(st))}>'
cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool, tuple path):
cdef object nid = id(st)
cdef str self_repr = f'<{type_.__name__} {hex(nid)}>'
cdef str self_repr = _title_repr(st, type_)
cdef list children = []
cdef str k, _t_prefix
......@@ -605,6 +661,129 @@ cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool,
self_repr = _prefix_fix(self_repr, prefix)
return self_repr, children
try:
reversed({'a': 1}.keys())
except TypeError:
_reversible = False
else:
_reversible = True
# noinspection PyPep8Naming
cdef class treevalue_keys(_CObject, Sized, Container, Reversible):
def __cinit__(self, TreeStorage storage, type _type):
self._st = storage
self._type = _type
def __len__(self):
return self._st.size()
def __contains__(self, item):
return self._st.contains(item)
def _iter(self):
for k in self._st.iter_keys():
yield k
def __iter__(self):
return self._iter()
def _rev_iter(self):
for k in self._st.iter_rev_keys():
yield k
def __reversed__(self):
if _reversible:
return self._rev_iter()
else:
raise TypeError(f'{type(self).__name__!r} object is not reversible')
def __repr__(self):
return f'{type(self).__name__}({list(self)!r})'
# noinspection PyPep8Naming
cdef class treevalue_values(_CObject, Sized, Container, Reversible):
def __cinit__(self, TreeStorage storage, type _type):
self._st = storage
self._type = _type
def __len__(self):
return self._st.size()
def __contains__(self, item):
for v in self:
if item == v:
return True
return False
def _iter(self):
for v in self._st.iter_values():
if isinstance(v, TreeStorage):
yield self._type(v)
else:
yield v
def __iter__(self):
return self._iter()
def _rev_iter(self):
for v in self._st.iter_rev_values():
if isinstance(v, TreeStorage):
yield self._type(v)
else:
yield v
def __reversed__(self):
if _reversible:
return self._rev_iter()
else:
raise TypeError(f'{type(self).__name__!r} object is not reversible')
def __repr__(self):
return f'{type(self).__name__}({list(self)!r})'
# noinspection PyPep8Naming
cdef class treevalue_items(_CObject, Sized, Container, Reversible):
def __cinit__(self, TreeStorage storage, type _type):
self._st = storage
self._type = _type
def __len__(self):
return self._st.size()
def __contains__(self, item):
for k, v in self:
if item == (k, v):
return True
return False
def _iter(self):
for k, v in self._st.iter_items():
if isinstance(v, TreeStorage):
yield k, self._type(v)
else:
yield k, v
def __iter__(self):
return self._iter()
def _rev_iter(self):
for k, v in self._st.iter_rev_items():
if isinstance(v, TreeStorage):
yield k, self._type(v)
else:
yield k, v
def __reversed__(self):
if _reversible:
return self._rev_iter()
else:
raise TypeError(f'{type(self).__name__!r} object is not reversible')
def __repr__(self):
return f'{type(self).__name__}({list(self)!r})'
cdef class DetachedDelayedProxy(DelayedProxy):
def __init__(self, DelayedProxy proxy):
self.proxy = proxy
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册