|
2 | 2 |
|
3 | 3 | import re |
4 | 4 | from collections import OrderedDict, defaultdict |
5 | | -from typing import Any, Dict, List, Optional, Tuple, Type |
| 5 | +from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar |
6 | 6 |
|
7 | 7 | from bigtree.node.node import Node |
8 | 8 | from bigtree.tree.search import find_child_by_name, find_name |
|
51 | 51 | "newick_to_tree", |
52 | 52 | ] |
53 | 53 |
|
| 54 | +T = TypeVar("T", bound=Node) |
| 55 | + |
54 | 56 |
|
55 | 57 | def add_path_to_tree( |
56 | | - tree: Node, |
| 58 | + tree: T, |
57 | 59 | path: str, |
58 | 60 | sep: str = "/", |
59 | 61 | duplicate_name_allowed: bool = True, |
60 | 62 | node_attrs: Dict[str, Any] = {}, |
61 | | -) -> Node: |
| 63 | +) -> T: |
62 | 64 | """Add nodes and attributes to existing tree *in-place*, return node of path added. |
63 | 65 | Adds to existing tree from list of path strings. |
64 | 66 |
|
@@ -136,11 +138,11 @@ def add_path_to_tree( |
136 | 138 |
|
137 | 139 |
|
138 | 140 | def add_dict_to_tree_by_path( |
139 | | - tree: Node, |
| 141 | + tree: T, |
140 | 142 | path_attrs: Dict[str, Dict[str, Any]], |
141 | 143 | sep: str = "/", |
142 | 144 | duplicate_name_allowed: bool = True, |
143 | | -) -> Node: |
| 145 | +) -> T: |
144 | 146 | """Add nodes and attributes to tree *in-place*, return root of tree. |
145 | 147 | Adds to existing tree from nested dictionary, ``key``: path, ``value``: dict of attribute name and attribute value. |
146 | 148 |
|
@@ -208,7 +210,7 @@ def add_dict_to_tree_by_path( |
208 | 210 | return root_node |
209 | 211 |
|
210 | 212 |
|
211 | | -def add_dict_to_tree_by_name(tree: Node, name_attrs: Dict[str, Dict[str, Any]]) -> Node: |
| 213 | +def add_dict_to_tree_by_name(tree: T, name_attrs: Dict[str, Dict[str, Any]]) -> T: |
212 | 214 | """Add attributes to existing tree *in-place*. |
213 | 215 | Adds to existing tree from nested dictionary, ``key``: name, ``value``: dict of attribute name and attribute value. |
214 | 216 |
|
@@ -254,13 +256,13 @@ def add_dict_to_tree_by_name(tree: Node, name_attrs: Dict[str, Dict[str, Any]]) |
254 | 256 |
|
255 | 257 |
|
256 | 258 | def add_dataframe_to_tree_by_path( |
257 | | - tree: Node, |
| 259 | + tree: T, |
258 | 260 | data: pd.DataFrame, |
259 | 261 | path_col: str = "", |
260 | 262 | attribute_cols: List[str] = [], |
261 | 263 | sep: str = "/", |
262 | 264 | duplicate_name_allowed: bool = True, |
263 | | -) -> Node: |
| 265 | +) -> T: |
264 | 266 | """Add nodes and attributes to tree *in-place*, return root of tree. |
265 | 267 | Adds to existing tree from pandas DataFrame. |
266 | 268 |
|
@@ -350,11 +352,11 @@ def add_dataframe_to_tree_by_path( |
350 | 352 |
|
351 | 353 |
|
352 | 354 | def add_dataframe_to_tree_by_name( |
353 | | - tree: Node, |
| 355 | + tree: T, |
354 | 356 | data: pd.DataFrame, |
355 | 357 | name_col: str = "", |
356 | 358 | attribute_cols: List[str] = [], |
357 | | -) -> Node: |
| 359 | +) -> T: |
358 | 360 | """Add attributes to existing tree *in-place*. |
359 | 361 | Adds to existing tree from pandas DataFrame. |
360 | 362 |
|
@@ -418,13 +420,13 @@ def add_dataframe_to_tree_by_name( |
418 | 420 |
|
419 | 421 |
|
420 | 422 | def add_polars_to_tree_by_path( |
421 | | - tree: Node, |
| 423 | + tree: T, |
422 | 424 | data: pl.DataFrame, |
423 | 425 | path_col: str = "", |
424 | 426 | attribute_cols: List[str] = [], |
425 | 427 | sep: str = "/", |
426 | 428 | duplicate_name_allowed: bool = True, |
427 | | -) -> Node: |
| 429 | +) -> T: |
428 | 430 | """Add nodes and attributes to tree *in-place*, return root of tree. |
429 | 431 | Adds to existing tree from polars DataFrame. |
430 | 432 |
|
@@ -516,11 +518,11 @@ def add_polars_to_tree_by_path( |
516 | 518 |
|
517 | 519 |
|
518 | 520 | def add_polars_to_tree_by_name( |
519 | | - tree: Node, |
| 521 | + tree: T, |
520 | 522 | data: pl.DataFrame, |
521 | 523 | name_col: str = "", |
522 | 524 | attribute_cols: List[str] = [], |
523 | | -) -> Node: |
| 525 | +) -> T: |
524 | 526 | """Add attributes to existing tree *in-place*. |
525 | 527 | Adds to existing tree from polars DataFrame. |
526 | 528 |
|
@@ -586,8 +588,8 @@ def add_polars_to_tree_by_name( |
586 | 588 | def str_to_tree( |
587 | 589 | tree_string: str, |
588 | 590 | tree_prefix_list: List[str] = [], |
589 | | - node_type: Type[Node] = Node, |
590 | | -) -> Node: |
| 591 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 592 | +) -> T: |
591 | 593 | r"""Construct tree from tree string |
592 | 594 |
|
593 | 595 | Examples: |
@@ -655,8 +657,8 @@ def list_to_tree( |
655 | 657 | paths: List[str], |
656 | 658 | sep: str = "/", |
657 | 659 | duplicate_name_allowed: bool = True, |
658 | | - node_type: Type[Node] = Node, |
659 | | -) -> Node: |
| 660 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 661 | +) -> T: |
660 | 662 | """Construct tree from list of path strings. |
661 | 663 |
|
662 | 664 | Path should contain ``Node`` name, separated by `sep`. |
@@ -715,8 +717,8 @@ def list_to_tree( |
715 | 717 | def list_to_tree_by_relation( |
716 | 718 | relations: List[Tuple[str, str]], |
717 | 719 | allow_duplicates: bool = False, |
718 | | - node_type: Type[Node] = Node, |
719 | | -) -> Node: |
| 720 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 721 | +) -> T: |
720 | 722 | """Construct tree from list of tuple containing parent-child names. |
721 | 723 |
|
722 | 724 | Root node is inferred when parent is empty, or when name appears as parent but not as child. |
@@ -764,8 +766,8 @@ def dict_to_tree( |
764 | 766 | path_attrs: Dict[str, Any], |
765 | 767 | sep: str = "/", |
766 | 768 | duplicate_name_allowed: bool = True, |
767 | | - node_type: Type[Node] = Node, |
768 | | -) -> Node: |
| 769 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 770 | +) -> T: |
769 | 771 | """Construct tree from nested dictionary using path, |
770 | 772 | ``key``: path, ``value``: dict of attribute name and attribute value. |
771 | 773 |
|
@@ -854,8 +856,8 @@ def nested_dict_to_tree( |
854 | 856 | node_attrs: Dict[str, Any], |
855 | 857 | name_key: str = "name", |
856 | 858 | child_key: str = "children", |
857 | | - node_type: Type[Node] = Node, |
858 | | -) -> Node: |
| 859 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 860 | +) -> T: |
859 | 861 | """Construct tree from nested recursive dictionary. |
860 | 862 |
|
861 | 863 | - ``key``: `name_key`, `child_key`, or any attributes key. |
@@ -901,8 +903,8 @@ def nested_dict_to_tree( |
901 | 903 | assert_length_not_empty(node_attrs, "Dictionary", "node_attrs") |
902 | 904 |
|
903 | 905 | def _recursive_add_child( |
904 | | - child_dict: Dict[str, Any], parent_node: Optional[Node] = None |
905 | | - ) -> Node: |
| 906 | + child_dict: Dict[str, Any], parent_node: Optional[T] = None |
| 907 | + ) -> T: |
906 | 908 | """Recursively add child to tree, given child attributes and parent node. |
907 | 909 |
|
908 | 910 | Args: |
@@ -934,8 +936,8 @@ def dataframe_to_tree( |
934 | 936 | attribute_cols: List[str] = [], |
935 | 937 | sep: str = "/", |
936 | 938 | duplicate_name_allowed: bool = True, |
937 | | - node_type: Type[Node] = Node, |
938 | | -) -> Node: |
| 939 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 940 | +) -> T: |
939 | 941 | """Construct tree from pandas DataFrame using path, return root of tree. |
940 | 942 |
|
941 | 943 | `path_col` and `attribute_cols` specify columns for node path and attributes to construct tree. |
@@ -1040,8 +1042,8 @@ def dataframe_to_tree_by_relation( |
1040 | 1042 | parent_col: str = "", |
1041 | 1043 | attribute_cols: List[str] = [], |
1042 | 1044 | allow_duplicates: bool = False, |
1043 | | - node_type: Type[Node] = Node, |
1044 | | -) -> Node: |
| 1045 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 1046 | +) -> T: |
1045 | 1047 | """Construct tree from pandas DataFrame using parent and child names, return root of tree. |
1046 | 1048 |
|
1047 | 1049 | Root node is inferred when parent name is empty, or when name appears in parent column but not in child column. |
@@ -1138,7 +1140,7 @@ def _retrieve_attr(_row: Dict[str, Any]) -> Dict[str, Any]: |
1138 | 1140 | node_attrs["name"] = _row[child_col] |
1139 | 1141 | return node_attrs |
1140 | 1142 |
|
1141 | | - def _recursive_add_child(parent_node: Node) -> None: |
| 1143 | + def _recursive_add_child(parent_node: T) -> None: |
1142 | 1144 | """Recursive add child to tree, given current node. |
1143 | 1145 |
|
1144 | 1146 | Args: |
@@ -1168,8 +1170,8 @@ def polars_to_tree( |
1168 | 1170 | attribute_cols: List[str] = [], |
1169 | 1171 | sep: str = "/", |
1170 | 1172 | duplicate_name_allowed: bool = True, |
1171 | | - node_type: Type[Node] = Node, |
1172 | | -) -> Node: |
| 1173 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 1174 | +) -> T: |
1173 | 1175 | """Construct tree from polars DataFrame using path, return root of tree. |
1174 | 1176 |
|
1175 | 1177 | `path_col` and `attribute_cols` specify columns for node path and attributes to construct tree. |
@@ -1275,8 +1277,8 @@ def polars_to_tree_by_relation( |
1275 | 1277 | parent_col: str = "", |
1276 | 1278 | attribute_cols: List[str] = [], |
1277 | 1279 | allow_duplicates: bool = False, |
1278 | | - node_type: Type[Node] = Node, |
1279 | | -) -> Node: |
| 1280 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 1281 | +) -> T: |
1280 | 1282 | """Construct tree from polars DataFrame using parent and child names, return root of tree. |
1281 | 1283 |
|
1282 | 1284 | Root node is inferred when parent name is empty, or when name appears in parent column but not in child column. |
@@ -1373,7 +1375,7 @@ def _retrieve_attr(_row: Dict[str, Any]) -> Dict[str, Any]: |
1373 | 1375 | node_attrs["name"] = _row[child_col] |
1374 | 1376 | return node_attrs |
1375 | 1377 |
|
1376 | | - def _recursive_add_child(parent_node: Node) -> None: |
| 1378 | + def _recursive_add_child(parent_node: T) -> None: |
1377 | 1379 | """Recursive add child to tree, given current node. |
1378 | 1380 |
|
1379 | 1381 | Args: |
@@ -1402,8 +1404,8 @@ def newick_to_tree( |
1402 | 1404 | tree_string: str, |
1403 | 1405 | length_attr: str = "length", |
1404 | 1406 | attr_prefix: str = "&&NHX:", |
1405 | | - node_type: Type[Node] = Node, |
1406 | | -) -> Node: |
| 1407 | + node_type: Type[T] = Node, # type: ignore[assignment] |
| 1408 | +) -> T: |
1407 | 1409 | """Construct tree from Newick notation, return root of tree. |
1408 | 1410 |
|
1409 | 1411 | In the Newick Notation (or New Hampshire Notation) |
@@ -1460,24 +1462,24 @@ def newick_to_tree( |
1460 | 1462 | assert_length_not_empty(tree_string, "Tree string", "tree_string") |
1461 | 1463 |
|
1462 | 1464 | # Store results (for tracking) |
1463 | | - depth_nodes: Dict[int, List[Node]] = defaultdict(list) |
| 1465 | + depth_nodes: Dict[int, List[T]] = defaultdict(list) |
1464 | 1466 | unlabelled_node_counter: int = 0 |
1465 | 1467 | current_depth: int = 1 |
1466 | 1468 | tree_string_idx: int = 0 |
1467 | 1469 |
|
1468 | 1470 | # Store states (for assertions and checks) |
1469 | 1471 | current_state: NewickState = NewickState.PARSE_STRING |
1470 | | - current_node: Optional[Node] = None |
| 1472 | + current_node: Optional[T] = None |
1471 | 1473 | cumulative_string: str = "" |
1472 | 1474 | cumulative_string_value: str = "" |
1473 | 1475 |
|
1474 | 1476 | def _create_node( |
1475 | | - _new_node: Optional[Node], |
| 1477 | + _new_node: Optional[T], |
1476 | 1478 | _cumulative_string: str, |
1477 | 1479 | _unlabelled_node_counter: int, |
1478 | | - _depth_nodes: Dict[int, List[Node]], |
| 1480 | + _depth_nodes: Dict[int, List[T]], |
1479 | 1481 | _current_depth: int, |
1480 | | - ) -> Tuple[Node, int]: |
| 1482 | + ) -> Tuple[T, int]: |
1481 | 1483 | """Create node at checkpoint. |
1482 | 1484 |
|
1483 | 1485 | Args: |
|
0 commit comments