Skip to content

Commit 64e8082

Browse files
committed
Merge branch 'main' into doc/readme
2 parents a241169 + b028e05 commit 64e8082

File tree

5 files changed

+337
-39
lines changed

5 files changed

+337
-39
lines changed

test/tree/common/test_storage.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
from treevalue.tree.common import create_storage, raw, TreeStorage, delayed_partial
66

7+
try:
8+
_ = reversed({}.keys())
9+
except TypeError:
10+
_reversible = False
11+
else:
12+
_reversible = True
13+
714

815
# noinspection PyArgumentList,DuplicatedCode,PyTypeChecker
916
@pytest.mark.unittest
@@ -501,33 +508,49 @@ def test_keys(self):
501508
h2 = {'x': 3, 'y': 4}
502509
t = create_storage({'a': 1, 'b': 2, 'c': raw(h1), 'd': h2, 'f': h2})
503510

504-
assert set(t.keys()) == {'a', 'b', 'c', 'd', 'f'}
505-
assert set(t.get('f').keys()) == {'x', 'y'}
511+
assert set(t.iter_keys()) == {'a', 'b', 'c', 'd', 'f'}
512+
assert set(t.get('f').iter_keys()) == {'x', 'y'}
513+
514+
if _reversible:
515+
assert list(t.iter_rev_keys()) == list(t.iter_keys())[::-1]
516+
else:
517+
with pytest.raises(TypeError):
518+
t.iter_rev_keys()
506519

507520
def test_values(self):
508521
h1 = {'x': 3, 'y': 4}
509522
t = create_storage({'a': 1, 'b': 2, 'd': h1})
510523

511-
assert set(t.get('d').values()) == {3, 4}
512-
assert len(list(t.values())) == 3
513-
assert 1 in t.values()
514-
assert 2 in t.values()
524+
assert set(t.get('d').iter_values()) == {3, 4}
525+
assert len(list(t.iter_values())) == 3
526+
assert 1 in t.iter_values()
527+
assert 2 in t.iter_values()
528+
if _reversible:
529+
assert list(t.iter_rev_values()) == list(t.iter_values())[::-1]
530+
else:
531+
with pytest.raises(TypeError):
532+
_ = list(t.iter_rev_values())
515533

516534
t1 = create_storage({
517535
'a': delayed_partial(lambda: t.get('a')),
518536
'b': delayed_partial(lambda: t.get('b')),
519537
'd': delayed_partial(lambda: t.get('d')),
520538
})
521-
assert set(t1.get('d').values()) == {3, 4}
522-
assert len(list(t1.values())) == 3
523-
assert 1 in t1.values()
524-
assert 2 in t1.values()
539+
assert set(t1.get('d').iter_values()) == {3, 4}
540+
assert len(list(t1.iter_values())) == 3
541+
assert 1 in t1.iter_values()
542+
assert 2 in t1.iter_values()
543+
if _reversible:
544+
assert list(t1.iter_rev_values()) == list(t1.iter_values())[::-1]
545+
else:
546+
with pytest.raises(TypeError):
547+
_ = list(t1.iter_rev_values())
525548

526549
def test_items(self):
527550
h1 = {'x': 3, 'y': 4}
528551
t = create_storage({'a': 1, 'b': 2, 'd': raw(h1)})
529552

530-
for k, v in t.items():
553+
for k, v in t.iter_items():
531554
if k == 'a':
532555
assert v == 1
533556
elif k == 'b':
@@ -537,12 +560,18 @@ def test_items(self):
537560
else:
538561
pytest.fail('Should not reach here.')
539562

563+
if _reversible:
564+
assert list(t.iter_rev_items()) == list(t.iter_items())[::-1]
565+
else:
566+
with pytest.raises(TypeError):
567+
_ = list(t.iter_rev_items())
568+
540569
t1 = create_storage({
541570
'a': delayed_partial(lambda: t.get('a')),
542571
'b': delayed_partial(lambda: t.get('b')),
543572
'd': delayed_partial(lambda: t.get('d')),
544573
})
545-
for k, v in t1.items():
574+
for k, v in t1.iter_items():
546575
if k == 'a':
547576
assert v == 1
548577
elif k == 'b':
@@ -552,6 +581,12 @@ def test_items(self):
552581
else:
553582
pytest.fail('Should not reach here.')
554583

584+
if _reversible:
585+
assert list(t1.iter_rev_values()) == list(t1.iter_values())[::-1]
586+
else:
587+
with pytest.raises(TypeError):
588+
_ = list(t1.iter_rev_values())
589+
555590
def test_hash(self):
556591
h = {}
557592

test/tree/tree/test_tree.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55

66
from treevalue import raw, TreeValue, delayed
77

8+
try:
9+
_ = reversed({}.keys())
10+
except TypeError:
11+
_reversible = False
12+
else:
13+
_reversible = True
14+
815

916
class _Container:
1017
def __init__(self, value):
@@ -240,12 +247,14 @@ def test_tree_value_bool(self):
240247
assert tv2
241248
assert not tv2.c
242249

243-
def test_tee_value_hash_equal(self):
250+
def test_tree_value_hash_equal(self):
244251
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}})
245252
assert tv1 == tv1
246253
assert not tv1 == 2
247254
assert tv1 == TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}})
255+
assert tv1 != TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 4}})
248256
assert tv1.c == TreeValue({'x': 2, 'y': 3})
257+
assert tv1.c != TreeValue({'x': 2, 'y': 3, 'z': 4})
249258

250259
d = {
251260
tv1: 1,
@@ -330,23 +339,61 @@ def test_pop(self):
330339

331340
def test_keys(self):
332341
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}, 'd': raw({'x': 2, 'y': 3})})
342+
assert len(tv1.keys()) == 4
333343
assert set(tv1.keys()) == {'a', 'b', 'c', 'd'}
344+
assert 'a' in tv1.keys()
345+
assert 'b' in tv1.keys()
346+
assert 'c' in tv1.keys()
347+
assert 'd' in tv1.keys()
348+
assert 'e' not in tv1.keys()
349+
350+
assert repr(tv1.keys()) == "treevalue_keys(['a', 'b', 'c', 'd'])"
351+
if _reversible:
352+
assert list(reversed(tv1.keys())) == list(tv1.keys())[::-1]
353+
else:
354+
with pytest.raises(TypeError):
355+
reversed(tv1.keys())
334356

335357
def test_values(self):
336358
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}})
359+
assert len(tv1.values()) == 3
337360
assert set(tv1.c.values()) == {2, 3}
338-
assert len(list(tv1.values())) == 3
339361
assert 1 in tv1.values()
340362
assert 2 in tv1.values()
363+
assert 3 not in tv1.values()
364+
assert TreeValue({'x': 2, 'y': 3}) in tv1.values()
365+
assert TreeValue({'x': 2, 'y': 4}) not in tv1.values()
366+
367+
assert repr(TreeValue({'a': 1, 'b': 2}).values()) == 'treevalue_values([1, 2])'
368+
if _reversible:
369+
assert list(reversed(tv1.values())) == list(tv1.values())[::-1]
370+
else:
371+
with pytest.raises(TypeError):
372+
reversed(tv1.values())
341373

342374
def test_items(self):
343375
tv1 = TreeValue({'a': 1, 'b': 2, 'c': {'x': 2, 'y': 3}, 'd': raw({'x': 2, 'y': 3})})
376+
assert len(tv1.items()) == 4
344377
assert sorted(tv1.items()) == [
345378
('a', 1),
346379
('b', 2),
347380
('c', TreeValue({'x': 2, 'y': 3})),
348381
('d', {'x': 2, 'y': 3}),
349382
]
383+
assert ('a', 1) in tv1.items()
384+
assert ('b', 2) in tv1.items()
385+
assert ('a', 2) not in tv1.items()
386+
assert ('c', TreeValue({'x': 2, 'y': 3})) in tv1.items()
387+
assert ('c', TreeValue({'x': 2, 'y': 4})) not in tv1.items()
388+
assert ('d', {'x': 2, 'y': 3}) in tv1.items()
389+
assert ('d', {'x': 2, 'y': 4}) not in tv1.items()
390+
391+
assert repr(TreeValue({'a': 1, 'b': 2}).items()) == "treevalue_items([('a', 1), ('b', 2)])"
392+
if _reversible:
393+
assert list(reversed(tv1.items())) == list(tv1.items())[::-1]
394+
else:
395+
with pytest.raises(TypeError):
396+
reversed(tv1.items())
350397

351398
class MyTreeValue(TreeValue):
352399
pass

treevalue/tree/common/storage.pyx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,27 +185,41 @@ cdef class TreeStorage:
185185
cdef str k
186186
cdef object v
187187
cdef list _items = []
188-
for k, v in sorted(self.items(), key=lambda x: x[0]):
188+
for k, v in sorted(self.iter_items(), key=lambda x: x[0]):
189189
_items.append((k, v))
190190

191191
return hash(tuple(_items))
192192

193-
def keys(self):
193+
def iter_keys(self):
194194
return self.map.keys()
195195

196-
def values(self):
196+
def iter_rev_keys(self):
197+
return reversed(self.map.keys())
198+
199+
def iter_values(self):
197200
cdef str k
198201
cdef object v, nv
199202
for k, v in self.map.items():
200203
yield _c_undelay_data(self.map, k, v)
201204

202-
def items(self):
205+
def iter_rev_values(self):
206+
cdef str k
207+
cdef object v, nv
208+
for k, v in reversed(self.map.items()):
209+
yield _c_undelay_data(self.map, k, v)
210+
211+
def iter_items(self):
203212
cdef str k
204213
cdef object v, nv
205214
for k, v in self.map.items():
206-
v = _c_undelay_data(self.map, k, v)
215+
yield k, _c_undelay_data(self.map, k, v)
216+
217+
def iter_rev_items(self):
218+
cdef str k
219+
cdef object v, nv
220+
for k, v in reversed(self.map.items()):
221+
yield k, _c_undelay_data(self.map, k, v)
207222

208-
yield k, v
209223

210224
cpdef object create_storage(dict value):
211225
cdef dict _map = {}

treevalue/tree/tree/tree.pxd

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ from libcpp cimport bool
66
from ..common.delay cimport DelayedProxy
77
from ..common.storage cimport TreeStorage
88

9+
cdef class _CObject:
10+
pass
11+
912
cdef class TreeValue:
1013
cdef readonly TreeStorage _st
1114
cdef readonly type _type
@@ -20,9 +23,29 @@ cdef class TreeValue:
2023
cpdef get(self, str key, object default= *)
2124
cpdef pop(self, str key, object default= *)
2225

26+
cpdef treevalue_keys keys(self)
27+
cpdef treevalue_values values(self)
28+
cpdef treevalue_items items(self)
29+
2330
cdef str _prefix_fix(object text, object prefix)
31+
cdef str _title_repr(TreeStorage st, object type_)
2432
cdef object _build_tree(TreeStorage st, object type_, str prefix, dict id_pool, tuple path)
2533

34+
# noinspection PyPep8Naming
35+
cdef class treevalue_keys(_CObject):
36+
cdef readonly TreeStorage _st
37+
cdef readonly type _type
38+
39+
# noinspection PyPep8Naming
40+
cdef class treevalue_values(_CObject):
41+
cdef readonly TreeStorage _st
42+
cdef readonly type _type
43+
44+
# noinspection PyPep8Naming
45+
cdef class treevalue_items(_CObject):
46+
cdef readonly TreeStorage _st
47+
cdef readonly type _type
48+
2649
cdef class DetachedDelayedProxy(DelayedProxy):
2750
cdef DelayedProxy proxy
2851
cdef readonly bool calculated

0 commit comments

Comments
 (0)