python-library-tree-model 0.1.0__py3-none-any.whl
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.
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
tree_model/__init__.py,sha256=xQN9JRG8UWPOxEx4tOEKca9oBeUPOpDjEnHLaaQrwGE,3765
|
|
2
|
+
python_library_tree_model-0.1.0.dist-info/METADATA,sha256=wWA8BkB1qipnBbyQaK7pnEWpNiciLX042pH-d-nUcYk,169
|
|
3
|
+
python_library_tree_model-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
4
|
+
python_library_tree_model-0.1.0.dist-info/RECORD,,
|
tree_model/__init__.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterator
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field, PrivateAttr
|
|
7
|
+
from reactive_model import ListRefModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TreeModel(BaseModel):
|
|
11
|
+
name: str = Field(..., description="节点名称")
|
|
12
|
+
parent: Optional["TreeModel"] = Field(None, description="父节点")
|
|
13
|
+
|
|
14
|
+
_children: ListRefModel["TreeModel"] = PrivateAttr(default_factory=ListRefModel)
|
|
15
|
+
_on_delete: list[Callable[[], None]] = PrivateAttr(default_factory=list)
|
|
16
|
+
_name_separator: str = PrivateAttr(".")
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def full_name(self) -> str:
|
|
20
|
+
if self.parent is None:
|
|
21
|
+
return self.name
|
|
22
|
+
return f"{self.parent.full_name}{self._name_separator}{self.name}"
|
|
23
|
+
|
|
24
|
+
def add_child(self, child: "TreeModel") -> None:
|
|
25
|
+
if child.parent is not None:
|
|
26
|
+
raise ValueError(f"child {child.name!r} 已经有 parent")
|
|
27
|
+
if self._name_separator in child.name:
|
|
28
|
+
raise ValueError(f"child {child.name!r} 不允许包含名称分隔符")
|
|
29
|
+
if any(item is child for item in self._children.value):
|
|
30
|
+
raise ValueError("child 已经是子节点")
|
|
31
|
+
|
|
32
|
+
child.parent = self
|
|
33
|
+
self._children.value.append(child)
|
|
34
|
+
child.on_delete(lambda: self._remove_child(child))
|
|
35
|
+
|
|
36
|
+
def _remove_child(self, child: "TreeModel") -> None:
|
|
37
|
+
children = self._children.value
|
|
38
|
+
for index, item in enumerate(children):
|
|
39
|
+
if item is child:
|
|
40
|
+
del children[index]
|
|
41
|
+
break
|
|
42
|
+
|
|
43
|
+
def delete(self) -> None:
|
|
44
|
+
for child in list(self._children.value):
|
|
45
|
+
child.delete()
|
|
46
|
+
|
|
47
|
+
self._children.value.clear()
|
|
48
|
+
self.parent = None
|
|
49
|
+
|
|
50
|
+
for fn in self._on_delete:
|
|
51
|
+
fn()
|
|
52
|
+
self._on_delete.clear()
|
|
53
|
+
|
|
54
|
+
def on_delete(self, callback: Callable[[], None]) -> Callable[[], None]:
|
|
55
|
+
self._on_delete.append(callback)
|
|
56
|
+
return callback
|
|
57
|
+
|
|
58
|
+
def find_child(
|
|
59
|
+
self,
|
|
60
|
+
predicate: Callable[["TreeModel"], bool],
|
|
61
|
+
recursive: bool = False,
|
|
62
|
+
) -> "TreeModel | None":
|
|
63
|
+
for child in self._children.value:
|
|
64
|
+
if predicate(child):
|
|
65
|
+
return child
|
|
66
|
+
if recursive:
|
|
67
|
+
found = child.find_child(predicate, recursive=True)
|
|
68
|
+
if found is not None:
|
|
69
|
+
return found
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
def filter_child(
|
|
73
|
+
self,
|
|
74
|
+
predicate: Callable[["TreeModel"], bool],
|
|
75
|
+
recursive: bool = False,
|
|
76
|
+
) -> list["TreeModel"]:
|
|
77
|
+
result: list[TreeModel] = []
|
|
78
|
+
for child in self._children.value:
|
|
79
|
+
if predicate(child):
|
|
80
|
+
result.append(child)
|
|
81
|
+
if recursive:
|
|
82
|
+
result.extend(child.filter_child(predicate, recursive=True))
|
|
83
|
+
return result
|
|
84
|
+
|
|
85
|
+
def exists_child(
|
|
86
|
+
self,
|
|
87
|
+
predicate: Callable[["TreeModel"], bool],
|
|
88
|
+
recursive: bool = False,
|
|
89
|
+
) -> bool:
|
|
90
|
+
return self.find_child(predicate, recursive=recursive) is not None
|
|
91
|
+
|
|
92
|
+
def get_child(
|
|
93
|
+
self,
|
|
94
|
+
predicate: Callable[["TreeModel"], bool],
|
|
95
|
+
recursive: bool = False,
|
|
96
|
+
) -> "TreeModel":
|
|
97
|
+
child = self.find_child(predicate, recursive=recursive)
|
|
98
|
+
if child is None:
|
|
99
|
+
raise ValueError("未找到符合条件的子节点")
|
|
100
|
+
return child
|
|
101
|
+
|
|
102
|
+
def find_child_by_name(self, name: str, recursive: bool = False) -> "TreeModel | None":
|
|
103
|
+
return self.find_child(lambda node: node.name == name, recursive=recursive)
|
|
104
|
+
|
|
105
|
+
def __iter__(self) -> Iterator["TreeModel"]:
|
|
106
|
+
return iter(self._children.value)
|
|
107
|
+
|
|
108
|
+
def __len__(self) -> int:
|
|
109
|
+
return len(self._children.value)
|