verysimpletree 2.0.0__tar.gz → 2.0.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-2.0.0 → verysimpletree-2.0.2}/PKG-INFO +25 -2
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/README.md +24 -1
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/pyproject.toml +1 -1
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/pyproject.toml.orig +1 -1
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/verysimpletree/test_tree.py +53 -0
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/verysimpletree/tree.py +6 -5
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/verysimpletree/.coverage +0 -0
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/verysimpletree/__init__.py +0 -0
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/verysimpletree/py.typed +0 -0
- {verysimpletree-2.0.0 → verysimpletree-2.0.2}/verysimpletree/util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: verysimpletree
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: lightweight tree data structure
|
|
5
5
|
Author: Alex Gorji
|
|
6
6
|
Author-email: Alex Gorji <aligorji@hotmail.com>
|
|
@@ -20,6 +20,29 @@ An abstract lightweight tree class for managing tree structures.
|
|
|
20
20
|
|
|
21
21
|
Requires Python 3.11 or newer.
|
|
22
22
|
|
|
23
|
+
## Typed list representations
|
|
24
|
+
|
|
25
|
+
`TreeNodeListRepresentation[ValueT]` describes `[value, child, ...]` recursively.
|
|
26
|
+
`create_tree_from_list()` accepts the same value type as
|
|
27
|
+
`get_list_representation()`, including scalar values for a single attribute:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from verysimpletree.tree import TreeNodeListRepresentation
|
|
31
|
+
|
|
32
|
+
representation: TreeNodeListRepresentation[int] = [
|
|
33
|
+
10,
|
|
34
|
+
[3, [2, [1], [1]], [1]],
|
|
35
|
+
[7, [4], [3]],
|
|
36
|
+
]
|
|
37
|
+
# For a concrete Tree subclass whose constructor accepts value:
|
|
38
|
+
tree = MyTree.create_tree_from_list(representation, "value")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For multiple attributes, each node value is a list of attribute values, ordered
|
|
42
|
+
to match `represented_attribute_names`. Child representations must be lists.
|
|
43
|
+
The value type checks the representation's contents; it does not verify that
|
|
44
|
+
attribute names or values match the subclass constructor.
|
|
45
|
+
|
|
23
46
|
## Development
|
|
24
47
|
|
|
25
48
|
Use a current uv release; development and package builds are verified with
|
|
@@ -51,7 +74,7 @@ To enable publishing on GitLab:
|
|
|
51
74
|
3. Add `UV_PUBLISH_TOKEN` as a masked, protected CI/CD variable containing a
|
|
52
75
|
PyPI API token scoped to the `verysimpletree` project.
|
|
53
76
|
4. Set the version in `pyproject.toml`, update `uv.lock`, and commit the changes.
|
|
54
|
-
5. Push a matching stable version tag, such as `v2.0.
|
|
77
|
+
5. Push a matching stable version tag, such as `v2.0.1`.
|
|
55
78
|
|
|
56
79
|
Publishing runs automatically only for protected stable version tags, after
|
|
57
80
|
checks, tests, and the build pass. The tag must match the package version.
|
|
@@ -2,6 +2,29 @@ An abstract lightweight tree class for managing tree structures.
|
|
|
2
2
|
|
|
3
3
|
Requires Python 3.11 or newer.
|
|
4
4
|
|
|
5
|
+
## Typed list representations
|
|
6
|
+
|
|
7
|
+
`TreeNodeListRepresentation[ValueT]` describes `[value, child, ...]` recursively.
|
|
8
|
+
`create_tree_from_list()` accepts the same value type as
|
|
9
|
+
`get_list_representation()`, including scalar values for a single attribute:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from verysimpletree.tree import TreeNodeListRepresentation
|
|
13
|
+
|
|
14
|
+
representation: TreeNodeListRepresentation[int] = [
|
|
15
|
+
10,
|
|
16
|
+
[3, [2, [1], [1]], [1]],
|
|
17
|
+
[7, [4], [3]],
|
|
18
|
+
]
|
|
19
|
+
# For a concrete Tree subclass whose constructor accepts value:
|
|
20
|
+
tree = MyTree.create_tree_from_list(representation, "value")
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For multiple attributes, each node value is a list of attribute values, ordered
|
|
24
|
+
to match `represented_attribute_names`. Child representations must be lists.
|
|
25
|
+
The value type checks the representation's contents; it does not verify that
|
|
26
|
+
attribute names or values match the subclass constructor.
|
|
27
|
+
|
|
5
28
|
## Development
|
|
6
29
|
|
|
7
30
|
Use a current uv release; development and package builds are verified with
|
|
@@ -33,7 +56,7 @@ To enable publishing on GitLab:
|
|
|
33
56
|
3. Add `UV_PUBLISH_TOKEN` as a masked, protected CI/CD variable containing a
|
|
34
57
|
PyPI API token scoped to the `verysimpletree` project.
|
|
35
58
|
4. Set the version in `pyproject.toml`, update `uv.lock`, and commit the changes.
|
|
36
|
-
5. Push a matching stable version tag, such as `v2.0.
|
|
59
|
+
5. Push a matching stable version tag, such as `v2.0.1`.
|
|
37
60
|
|
|
38
61
|
Publishing runs automatically only for protected stable version tags, after
|
|
39
62
|
checks, tests, and the build pass. The tag must match the package version.
|
|
@@ -4,6 +4,7 @@ from unittest import TestCase
|
|
|
4
4
|
from verysimpletree.tree import (
|
|
5
5
|
ChildNotFoundError,
|
|
6
6
|
Tree,
|
|
7
|
+
TreeNodeListRepresentation,
|
|
7
8
|
TreeReferenceError,
|
|
8
9
|
grandchild1,
|
|
9
10
|
)
|
|
@@ -68,6 +69,23 @@ class C(Tree[Any]):
|
|
|
68
69
|
return True
|
|
69
70
|
|
|
70
71
|
|
|
72
|
+
class IntegerTree(Tree["IntegerTree"]):
|
|
73
|
+
def __init__(self, value: int) -> None:
|
|
74
|
+
super().__init__()
|
|
75
|
+
self.value = value
|
|
76
|
+
|
|
77
|
+
def _check_child_to_be_added(self, child: "IntegerTree") -> bool:
|
|
78
|
+
if not isinstance(child, IntegerTree):
|
|
79
|
+
raise TypeError("Expected an IntegerTree node")
|
|
80
|
+
return True
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _node_value(node: Tree[Any]) -> int:
|
|
84
|
+
if not isinstance(node, IntegerTree):
|
|
85
|
+
raise TypeError("Expected an IntegerTree node")
|
|
86
|
+
return node.value
|
|
87
|
+
|
|
88
|
+
|
|
71
89
|
def _node_name(node: Tree[Any]) -> str:
|
|
72
90
|
if not isinstance(node, (A, B, C)):
|
|
73
91
|
raise TypeError("Expected an A, B, or C node")
|
|
@@ -460,6 +478,41 @@ class Test(TreeTestCase):
|
|
|
460
478
|
|
|
461
479
|
|
|
462
480
|
class TreeListRepresentationTestCase(TreeTestCase):
|
|
481
|
+
def test_create_tree_from_typed_nested_integer_list(self) -> None:
|
|
482
|
+
representation: TreeNodeListRepresentation[int] = [
|
|
483
|
+
10,
|
|
484
|
+
[3, [2, [1], [1]], [1]],
|
|
485
|
+
[7, [4], [3, [2], [1]]],
|
|
486
|
+
]
|
|
487
|
+
tree = IntegerTree.create_tree_from_list(representation, "value")
|
|
488
|
+
assert tree.get_list_representation(key=_node_value) == representation
|
|
489
|
+
assert [node.value for node in tree.traverse()] == [
|
|
490
|
+
10,
|
|
491
|
+
3,
|
|
492
|
+
2,
|
|
493
|
+
1,
|
|
494
|
+
1,
|
|
495
|
+
1,
|
|
496
|
+
7,
|
|
497
|
+
4,
|
|
498
|
+
3,
|
|
499
|
+
2,
|
|
500
|
+
1,
|
|
501
|
+
]
|
|
502
|
+
|
|
503
|
+
def test_create_tree_from_typed_integer_root(self) -> None:
|
|
504
|
+
representation: TreeNodeListRepresentation[int] = [10]
|
|
505
|
+
tree = IntegerTree.create_tree_from_list(representation, "value")
|
|
506
|
+
assert tree.value == 10
|
|
507
|
+
assert tree.is_leaf
|
|
508
|
+
|
|
509
|
+
def test_create_tree_from_list_rejects_scalar_child(self) -> None:
|
|
510
|
+
representation: TreeNodeListRepresentation[int] = [10, 3]
|
|
511
|
+
with self.assertRaisesRegex(
|
|
512
|
+
TypeError, "Each child representation must be a list"
|
|
513
|
+
):
|
|
514
|
+
IntegerTree.create_tree_from_list(representation, "value")
|
|
515
|
+
|
|
463
516
|
def test_get_list_representation_all(self) -> None:
|
|
464
517
|
assert self.root.get_list_representation(key=_node_name) == [
|
|
465
518
|
"root",
|
|
@@ -20,7 +20,7 @@ class ChildNotFoundError(TreeException):
|
|
|
20
20
|
T = TypeVar("T", bound="Tree[Any]")
|
|
21
21
|
|
|
22
22
|
ValueT = TypeVar("ValueT")
|
|
23
|
-
|
|
23
|
+
TreeNodeListRepresentation = list[Union[ValueT, "TreeNodeListRepresentation[ValueT]"]]
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class Tree(ABC, Generic[T]):
|
|
@@ -218,11 +218,10 @@ class Tree(ABC, Generic[T]):
|
|
|
218
218
|
self._reset_iterators()
|
|
219
219
|
return child
|
|
220
220
|
|
|
221
|
-
# typing with T and Generic[T] etc. seems to be faulty. Return value of _create_node is Tree[T].
|
|
222
221
|
@classmethod
|
|
223
222
|
def create_tree_from_list(
|
|
224
223
|
cls,
|
|
225
|
-
tree_list_representation:
|
|
224
|
+
tree_list_representation: TreeNodeListRepresentation[ValueT],
|
|
226
225
|
represented_attribute_names: str | list[str],
|
|
227
226
|
) -> T:
|
|
228
227
|
represented_attribute_names = make_list(represented_attribute_names)
|
|
@@ -240,6 +239,8 @@ class Tree(ABC, Generic[T]):
|
|
|
240
239
|
|
|
241
240
|
node = _create_node(make_list(tree_list_representation[0]))
|
|
242
241
|
for child_list_representation in tree_list_representation[1:]:
|
|
242
|
+
if not isinstance(child_list_representation, list):
|
|
243
|
+
raise TypeError("Each child representation must be a list.")
|
|
243
244
|
child = cls.create_tree_from_list(
|
|
244
245
|
child_list_representation, represented_attribute_names
|
|
245
246
|
)
|
|
@@ -500,13 +501,13 @@ class Tree(ABC, Generic[T]):
|
|
|
500
501
|
|
|
501
502
|
def get_list_representation(
|
|
502
503
|
self, key: Callable[["Tree[Any]"], ValueT]
|
|
503
|
-
) ->
|
|
504
|
+
) -> TreeNodeListRepresentation[ValueT]:
|
|
504
505
|
"""Return [value, child, ...], applying key to every node.
|
|
505
506
|
|
|
506
507
|
Mixed-type trees are supported. Callbacks using subclass attributes
|
|
507
508
|
must narrow the node type before accessing those attributes.
|
|
508
509
|
"""
|
|
509
|
-
result:
|
|
510
|
+
result: TreeNodeListRepresentation[ValueT] = [key(self)]
|
|
510
511
|
for child in self._children:
|
|
511
512
|
result.append(child.get_list_representation(key=key))
|
|
512
513
|
return result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|