verysimpletree 1.0__tar.gz → 1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {verysimpletree-1.0 → verysimpletree-1.2}/PKG-INFO +1 -1
- {verysimpletree-1.0 → verysimpletree-1.2}/pyproject.toml +1 -1
- {verysimpletree-1.0 → verysimpletree-1.2}/verysimpletree/test_tree.py +61 -5
- {verysimpletree-1.0 → verysimpletree-1.2}/verysimpletree/tree.py +46 -23
- verysimpletree-1.2/verysimpletree/util.py +12 -0
- {verysimpletree-1.0 → verysimpletree-1.2}/README.md +0 -0
- {verysimpletree-1.0 → verysimpletree-1.2}/verysimpletree/.coverage +0 -0
- {verysimpletree-1.0 → verysimpletree-1.2}/verysimpletree/__init__.py +0 -0
- {verysimpletree-1.0 → verysimpletree-1.2}/verysimpletree/py.typed +0 -0
|
@@ -15,8 +15,8 @@ class BContent:
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class A(Tree[Any]):
|
|
18
|
-
def __init__(self, name, parent=None, *args, **
|
|
19
|
-
super().__init__(*args, **
|
|
18
|
+
def __init__(self, name, parent=None, *args, **kwargs):
|
|
19
|
+
super().__init__(*args, **kwargs)
|
|
20
20
|
self._children = []
|
|
21
21
|
self._parent = parent
|
|
22
22
|
self.name = name
|
|
@@ -35,8 +35,8 @@ class A(Tree[Any]):
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class B(Tree[Any]):
|
|
38
|
-
def __init__(self, name, *args, **
|
|
39
|
-
super().__init__(*args, **
|
|
38
|
+
def __init__(self, name, *args, **kwargs):
|
|
39
|
+
super().__init__(*args, **kwargs)
|
|
40
40
|
self.name = name
|
|
41
41
|
self.content = BContent(value=10)
|
|
42
42
|
|
|
@@ -44,8 +44,17 @@ class B(Tree[Any]):
|
|
|
44
44
|
if not isinstance(child, Tree):
|
|
45
45
|
raise TypeError
|
|
46
46
|
|
|
47
|
+
class C(Tree[Any]):
|
|
48
|
+
def __init__(self, name, value, *args, **kwargs):
|
|
49
|
+
super().__init__(*args, **kwargs)
|
|
50
|
+
self.name = name
|
|
51
|
+
self.value = value
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
def _check_child_to_be_added(self, child): # pragma: no cover
|
|
54
|
+
if not isinstance(child, Tree):
|
|
55
|
+
raise TypeError
|
|
56
|
+
|
|
57
|
+
class TreeTestCase(TestCase):
|
|
49
58
|
def setUp(self) -> None:
|
|
50
59
|
self.root = A(name='root')
|
|
51
60
|
self.child1 = self.root.add_child_by_name('child1')
|
|
@@ -57,6 +66,7 @@ class TestTree(TestCase):
|
|
|
57
66
|
self.grandchild3 = self.child4.add_child_by_name('grandchild3')
|
|
58
67
|
self.greatgrandchild1 = self.grandchild2.add_child_by_name('greatgrandchild1')
|
|
59
68
|
|
|
69
|
+
class Test(TreeTestCase):
|
|
60
70
|
def test_is_last_child(self):
|
|
61
71
|
t = self.root
|
|
62
72
|
for node in t.traverse():
|
|
@@ -206,6 +216,52 @@ class TestTree(TestCase):
|
|
|
206
216
|
with self.assertRaises(ValueError):
|
|
207
217
|
self.root.get_tree_representation(space=0)
|
|
208
218
|
|
|
219
|
+
def test_get_tree_representation(self):
|
|
220
|
+
expected = """└── root
|
|
221
|
+
├── child1
|
|
222
|
+
├── child2
|
|
223
|
+
│ ├── grandchild1
|
|
224
|
+
│ └── grandchild2
|
|
225
|
+
│ └── greatgrandchild1
|
|
226
|
+
├── child3
|
|
227
|
+
└── child4
|
|
228
|
+
└── grandchild3
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
assert self.root.get_tree_representation() == expected
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class TreeListRepresentationTestCase(TreeTestCase):
|
|
235
|
+
|
|
236
|
+
def test_get_list_representation_all(self):
|
|
237
|
+
assert self.root.get_list_representation(key=lambda node: node.name) == ['root', ['child1'], ['child2', ['grandchild1'], ['grandchild2', ['greatgrandchild1']]], ['child3'], ['child4', ['grandchild3']]]
|
|
238
|
+
|
|
239
|
+
def test_get_list_representation_only_root(self):
|
|
240
|
+
a = A(name='root')
|
|
241
|
+
assert a.get_list_representation(key=lambda node: node.name) == ['root']
|
|
242
|
+
|
|
243
|
+
def test_create_tree_from_list(self):
|
|
244
|
+
tree = A.create_tree_from_list(self.root.get_list_representation(key=lambda node: node.name), 'name')
|
|
245
|
+
assert tree.get_list_representation(key=lambda node: node.name) == self.root.get_list_representation(key=lambda node: node.name)
|
|
246
|
+
|
|
247
|
+
def test_create_tree_from_list_only_root(self):
|
|
248
|
+
tree = A.create_tree_from_list(self.root.get_list_representation(key=lambda node: node.name), 'name')
|
|
249
|
+
assert tree.get_list_representation(key=lambda node: node.name) == self.root.get_list_representation(key=lambda node: node.name)
|
|
250
|
+
|
|
251
|
+
def test_create_tree_from_list_with_name_and_value(self):
|
|
252
|
+
def _copy_node(node, current_value):
|
|
253
|
+
copied = C(name=node.name, value=current_value)
|
|
254
|
+
current_value += 1
|
|
255
|
+
for child in node.get_children():
|
|
256
|
+
copied.add_child(_copy_node(child, current_value=current_value))
|
|
257
|
+
return copied
|
|
258
|
+
|
|
259
|
+
copied_c = _copy_node(self.root, 0)
|
|
260
|
+
representation = copied_c.get_list_representation(key=lambda node: [node.name, node.value])
|
|
261
|
+
assert representation == [['root', 0], [['child1', 1]], [['child2', 1], [['grandchild1', 2]], [['grandchild2', 2], [['greatgrandchild1', 3]]]], [['child3', 1]], [['child4', 1], [['grandchild3', 2]]]]
|
|
262
|
+
tree = C.create_tree_from_list(representation, ['name', 'value'])
|
|
263
|
+
assert tree.get_list_representation(key=lambda node: [node.name, node.value]) == copied_c.get_list_representation(key=lambda node: [node.name, node.value])
|
|
264
|
+
|
|
209
265
|
|
|
210
266
|
class TestNodeReturnValue(TestCase):
|
|
211
267
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from typing import Optional, Callable, Iterator, TypeVar, Any, Generic, cast, Union
|
|
3
3
|
|
|
4
|
+
from verysimpletree.util import make_list
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
class TreeException(Exception):
|
|
6
8
|
pass
|
|
@@ -41,7 +43,7 @@ class Tree(ABC, Generic[T]):
|
|
|
41
43
|
|
|
42
44
|
def _raw_traverse(self: T) -> Iterator[T]:
|
|
43
45
|
yield self
|
|
44
|
-
for child in self.
|
|
46
|
+
for child in self._children:
|
|
45
47
|
for node in child._raw_traverse():
|
|
46
48
|
yield node
|
|
47
49
|
|
|
@@ -74,7 +76,7 @@ class Tree(ABC, Generic[T]):
|
|
|
74
76
|
def is_first_child(self) -> bool:
|
|
75
77
|
if self.is_root:
|
|
76
78
|
return True
|
|
77
|
-
if cast(T, self.up).
|
|
79
|
+
if cast(T, self.up)._children[0] == self:
|
|
78
80
|
return True
|
|
79
81
|
return False
|
|
80
82
|
|
|
@@ -90,7 +92,7 @@ class Tree(ABC, Generic[T]):
|
|
|
90
92
|
"""
|
|
91
93
|
if self.is_root:
|
|
92
94
|
return True
|
|
93
|
-
if cast(T, self.up).
|
|
95
|
+
if cast(T, self.up)._children[-1] == self:
|
|
94
96
|
return True
|
|
95
97
|
return False
|
|
96
98
|
|
|
@@ -122,8 +124,8 @@ class Tree(ABC, Generic[T]):
|
|
|
122
124
|
:return: next sibling. ``None`` if this is the last current child of the parent.
|
|
123
125
|
:rtype: :obj:`~tree.tree.Tree`
|
|
124
126
|
"""
|
|
125
|
-
if self.up and self != self.up.
|
|
126
|
-
return cast(T, self.up.
|
|
127
|
+
if self.up and self != self.up._children[-1]:
|
|
128
|
+
return cast(T, self.up._children[self.up._children.index(self) + 1])
|
|
127
129
|
else:
|
|
128
130
|
return None
|
|
129
131
|
|
|
@@ -135,8 +137,8 @@ class Tree(ABC, Generic[T]):
|
|
|
135
137
|
:return: previous sibling. ``None`` if this is the first child of the parent.
|
|
136
138
|
:rtype: :obj:`~tree.tree.Tree`
|
|
137
139
|
"""
|
|
138
|
-
if self.up and self != self.up.
|
|
139
|
-
return cast(T, self.up.
|
|
140
|
+
if self.up and self != self.up._children[0]:
|
|
141
|
+
return cast(T, self.up._children[self.up._children.index(self) - 1])
|
|
140
142
|
else:
|
|
141
143
|
return None
|
|
142
144
|
|
|
@@ -167,7 +169,22 @@ class Tree(ABC, Generic[T]):
|
|
|
167
169
|
if self._is_leaf is True:
|
|
168
170
|
self._is_leaf = False
|
|
169
171
|
return child
|
|
170
|
-
|
|
172
|
+
|
|
173
|
+
# typing with T and Generic[T] etc. seems to be faulty. Return value of _create_node is Tree[T].
|
|
174
|
+
@classmethod
|
|
175
|
+
def create_tree_from_list(cls, tree_list_representation: list[list[Any]], represented_attribute_names: list[str]) -> T:
|
|
176
|
+
represented_attribute_names = make_list(represented_attribute_names)
|
|
177
|
+
def _create_node(represented_values: list[Any]) -> T:
|
|
178
|
+
if len(represented_values) != len(represented_attribute_names):
|
|
179
|
+
raise ValueError(f'create_tree_from_list: represented_attribute_names must be of length {len(represented_values)}.')
|
|
180
|
+
root_kwargs = {attr:val for attr, val in zip(represented_attribute_names, represented_values)}
|
|
181
|
+
return cast(T, cls(**root_kwargs))
|
|
182
|
+
node = _create_node(make_list(tree_list_representation[0]))
|
|
183
|
+
for child_list_representation in tree_list_representation [1:]:
|
|
184
|
+
child = cls.create_tree_from_list(child_list_representation, represented_attribute_names)
|
|
185
|
+
node.add_child(child)
|
|
186
|
+
return node
|
|
187
|
+
|
|
171
188
|
def get_children(self: T) -> list[T]:
|
|
172
189
|
"""
|
|
173
190
|
:obj:`~tree.tree.Tree` method
|
|
@@ -183,7 +200,7 @@ class Tree(ABC, Generic[T]):
|
|
|
183
200
|
:return: list of added children of type.d
|
|
184
201
|
:rtype: list[:obj:`~tree.tree.Tree`]
|
|
185
202
|
"""
|
|
186
|
-
return [cast(T, ch) for ch in self.
|
|
203
|
+
return [cast(T, ch) for ch in self._children if isinstance(ch, type_)]
|
|
187
204
|
|
|
188
205
|
def get_distance(self, reference: Optional[T] = None) -> int:
|
|
189
206
|
"""
|
|
@@ -233,14 +250,14 @@ class Tree(ABC, Generic[T]):
|
|
|
233
250
|
if level == 0:
|
|
234
251
|
output = [self]
|
|
235
252
|
elif level == 1:
|
|
236
|
-
output = self.
|
|
253
|
+
output = self._children
|
|
237
254
|
else:
|
|
238
255
|
output = []
|
|
239
256
|
for child in self.get_layer(level - 1):
|
|
240
257
|
if child.is_leaf:
|
|
241
258
|
output.append(child)
|
|
242
259
|
else:
|
|
243
|
-
output.extend(child.
|
|
260
|
+
output.extend(child._children)
|
|
244
261
|
|
|
245
262
|
if key is None:
|
|
246
263
|
return output
|
|
@@ -262,7 +279,7 @@ class Tree(ABC, Generic[T]):
|
|
|
262
279
|
"""
|
|
263
280
|
output: list[Union[Any, list[Any]]] = []
|
|
264
281
|
child: T
|
|
265
|
-
for child in self.
|
|
282
|
+
for child in self._children:
|
|
266
283
|
if not child.is_leaf:
|
|
267
284
|
output.append(child.get_leaves(key=key))
|
|
268
285
|
else:
|
|
@@ -333,9 +350,9 @@ class Tree(ABC, Generic[T]):
|
|
|
333
350
|
if parent is None:
|
|
334
351
|
return '0'
|
|
335
352
|
elif self.get_level() == 1:
|
|
336
|
-
return str(parent.
|
|
353
|
+
return str(parent._children.index(self) + 1)
|
|
337
354
|
else:
|
|
338
|
-
return f"{parent.get_position_in_tree()}.{parent.
|
|
355
|
+
return f"{parent.get_position_in_tree()}.{parent._children.index(self) + 1}"
|
|
339
356
|
|
|
340
357
|
def get_reversed_path_to_root(self) -> list[T]:
|
|
341
358
|
"""
|
|
@@ -406,6 +423,12 @@ class Tree(ABC, Generic[T]):
|
|
|
406
423
|
if key:
|
|
407
424
|
tree_representation.key = cast(Callable[[Tree[Any]], Any], key)
|
|
408
425
|
return tree_representation.get_representation()
|
|
426
|
+
|
|
427
|
+
def get_list_representation(self, key: Callable[["Tree[T]"], Any]) -> list[list[Any]]:
|
|
428
|
+
result: list[list[Any]] = [key(self)]
|
|
429
|
+
for child in self._children:
|
|
430
|
+
result.append(child.get_list_representation(key=key))
|
|
431
|
+
return result
|
|
409
432
|
|
|
410
433
|
def get_number_of_layers(self) -> int:
|
|
411
434
|
"""
|
|
@@ -453,10 +476,10 @@ class Tree(ABC, Generic[T]):
|
|
|
453
476
|
:param child:
|
|
454
477
|
:return: None
|
|
455
478
|
"""
|
|
456
|
-
if child not in self.
|
|
479
|
+
if child not in self._children:
|
|
457
480
|
raise ChildNotFoundError
|
|
458
481
|
child._parent = None
|
|
459
|
-
self.
|
|
482
|
+
self._children.remove(child)
|
|
460
483
|
self._reset_iterators()
|
|
461
484
|
|
|
462
485
|
def remove_children(self) -> None:
|
|
@@ -467,7 +490,7 @@ class Tree(ABC, Generic[T]):
|
|
|
467
490
|
|
|
468
491
|
:return: None
|
|
469
492
|
"""
|
|
470
|
-
for child in self.
|
|
493
|
+
for child in self._children[:]:
|
|
471
494
|
parent = child.get_parent()
|
|
472
495
|
if parent is not None:
|
|
473
496
|
parent.remove(child)
|
|
@@ -482,16 +505,16 @@ class Tree(ABC, Generic[T]):
|
|
|
482
505
|
:return: None
|
|
483
506
|
"""
|
|
484
507
|
if hasattr(old, '__call__'):
|
|
485
|
-
list_of_olds = [ch for ch in self.
|
|
508
|
+
list_of_olds = [ch for ch in self._children if old(ch)]
|
|
486
509
|
else:
|
|
487
|
-
list_of_olds = [ch for ch in self.
|
|
510
|
+
list_of_olds = [ch for ch in self._children if ch == old]
|
|
488
511
|
if not list_of_olds:
|
|
489
512
|
raise ValueError(f"{old} not in list.")
|
|
490
513
|
self._check_child_to_be_added(new)
|
|
491
|
-
old_index = self.
|
|
492
|
-
old_child = self.
|
|
493
|
-
self.
|
|
494
|
-
self.
|
|
514
|
+
old_index = self._children.index(list_of_olds[index])
|
|
515
|
+
old_child = self._children[old_index]
|
|
516
|
+
self._children.remove(old_child)
|
|
517
|
+
self._children.insert(old_index, new)
|
|
495
518
|
old_child._parent = None
|
|
496
519
|
self._reset_iterators()
|
|
497
520
|
new._parent = self
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|