Skip to content

Commit 025cc29

Browse files
authored
Merge pull request #29 from leonardbinet/mypy
v1.3.0 - stronger typing
2 parents fed7c54 + 7f79e4b commit 025cc29

File tree

8 files changed

+152
-153
lines changed

8 files changed

+152
-153
lines changed

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
- name: Mypy check
4141
run: |
4242
pip install mypy
43-
mypy lighttree
43+
mypy --install-types --non-interactive lighttree
4444
- name: Test with pytest
4545
run: |
4646
pytest

lighttree/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
from .interactive import TreeBasedObj
2-
from .tree import Tree, Node, Key, KeyedNode, KeyedTree
2+
from .tree import Tree, Key, KeyedNode, KeyedTree
3+
from .node import Node, AutoIdNode
34

4-
__all__ = ["Tree", "Node", "TreeBasedObj", "Key", "KeyedNode", "KeyedTree"]
5+
__all__ = [
6+
"Tree",
7+
"Node",
8+
"AutoIdNode",
9+
"TreeBasedObj",
10+
"Key",
11+
"KeyedNode",
12+
"KeyedTree",
13+
]

lighttree/implementations/json_tree.py

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,48 @@
11
from typing import Dict, Optional, Any, Union, List
2-
from lighttree import Node, Tree, Key
2+
from lighttree import Tree, Key, AutoIdNode
33
from lighttree.node import NodeId
44
from lighttree.interactive import TreeBasedObj
55

66

77
class JsonTree(Tree):
8-
def __init__(
9-
self, d: Optional[Dict] = None, strict: bool = True, path_separator: str = "."
10-
) -> None:
8+
def __init__(self, d: Optional[Dict] = None, strict: bool = True) -> None:
119
"""
1210
:param d:
1311
:param strict: if False, will convert tuples into arrays, else raise error
14-
:param path_separator: separator used to build path
1512
"""
16-
super(JsonTree, self).__init__(path_separator=path_separator)
13+
super(JsonTree, self).__init__()
1714
if d is not None:
1815
self._fill(d, strict=strict, key=None)
1916

20-
@staticmethod
21-
def _concat(a: Any, b: Any) -> str:
22-
if not a and not b:
23-
return ""
24-
if not a:
25-
return str(b)
26-
return ".".join([str(a), str(b)])
27-
28-
def _fill(self, data: Any, key: Key, strict: bool, path: str = "") -> None:
17+
def _fill(
18+
self, data: Any, key: Optional[Key], strict: bool, path: Optional[List] = None
19+
) -> None:
2920
pid: Optional[NodeId]
21+
path_: List = path or []
3022
if self.is_empty():
3123
pid = None
3224
else:
33-
pid = self.get_node_id_by_path(path=path)
25+
pid = self.get_node_id_by_path(path=path_)
26+
3427
if isinstance(data, list) or not strict and isinstance(data, tuple):
35-
k = self.insert_node(Node(keyed=False), parent_id=pid, key=key)
36-
path = self._concat(path, k)
28+
k = self.insert_node(AutoIdNode(keyed=False), parent_id=pid, key=key)
3729
for el in data:
38-
self._fill(el, strict=strict, path=path, key=None)
30+
self._fill(el, strict=strict, path=path_ + ([k] if k else []), key=None)
3931
return
4032
if isinstance(data, dict):
41-
k = self.insert_node(Node(keyed=True), key=key, parent_id=pid)
42-
path = self._concat(path, k)
33+
k = self.insert_node(AutoIdNode(keyed=True), key=key, parent_id=pid)
4334
for sk, el in data.items():
44-
self._fill(el, strict=strict, path=path, key=sk)
35+
self._fill(el, strict=strict, path=path_ + ([k] if k else []), key=sk)
4536
return
4637
if isinstance(data, (str, int, float)):
4738
self.insert_node(
48-
Node(accept_children=False, repr_=str(data), data=data),
39+
AutoIdNode(accept_children=False, repr_=str(data), data=data),
4940
parent_id=pid,
5041
key=key,
5142
)
5243
return
5344
if data is None:
54-
self.insert_node(Node(accept_children=False), parent_id=pid)
45+
self.insert_node(AutoIdNode(accept_children=False), parent_id=pid)
5546
return
5647
raise TypeError("Unsupported type %s" % type(data))
5748

lighttree/node.py

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,63 @@
11
import uuid
22
from typing import Optional, Any, Tuple
3+
from dataclasses import dataclass
34

45
NodeId = str
56

67

7-
class Node(object):
8-
def __init__(
9-
self,
10-
identifier: Optional[NodeId] = None,
11-
auto_uuid: bool = True,
12-
keyed: bool = True,
13-
accept_children: bool = True,
14-
repr_: Optional[str] = None,
15-
data: Any = None,
16-
) -> None:
17-
"""
18-
:param identifier: node identifier, must be unique per tree
19-
"""
20-
if identifier is None:
21-
if not auto_uuid:
22-
raise ValueError("Required identifier")
23-
identifier = str(uuid.uuid4())
24-
self.identifier = identifier
25-
self.keyed = keyed
26-
self.accept_children = accept_children
27-
self.repr = repr_
28-
self.data = data
8+
@dataclass
9+
class Node:
10+
11+
identifier: NodeId
12+
keyed: bool = True
13+
accept_children: bool = True
14+
repr_: Optional[str] = None
15+
data: Any = None
2916

3017
def line_repr(self, depth: int, **kwargs: Any) -> Tuple[str, str]:
3118
"""Control how node is displayed in tree representation.
32-
_
33-
├── one end
34-
│ └── two myEnd
35-
└── three
19+
First returned string is how node is represented on left, second string is how node is represented on right.
20+
21+
MyTree
22+
├── one OneEnd
23+
│ └── two twoEnd
24+
└── three threeEnd
3625
"""
37-
if self.repr is not None:
38-
return self.repr, ""
26+
if self.repr_ is not None:
27+
return self.repr_, ""
3928
if not self.accept_children:
40-
return str(self.data), ""
29+
if hasattr(self.data, "__str__"):
30+
return str(self.data), ""
31+
return "", ""
4132
if self.keyed:
4233
return "{}", ""
4334
return "[]", ""
4435

45-
def __eq__(self, other: Any) -> bool:
46-
if not isinstance(other, self.__class__):
47-
return False
48-
return self.identifier == other.identifier
4936

50-
def __str__(self) -> str:
51-
return "%s, id=%s" % (self.__class__.__name__, self.identifier)
37+
class AutoIdNode(Node):
38+
def __init__(
39+
self,
40+
identifier: Optional[NodeId] = None,
41+
keyed: bool = True,
42+
accept_children: bool = True,
43+
repr_: Optional[str] = None,
44+
data: Any = None,
45+
):
46+
47+
self._auto_generated_id: bool
48+
identifier_: NodeId
49+
50+
if identifier is None:
51+
identifier_ = str(uuid.uuid4())
52+
self._auto_generated_id = True
53+
else:
54+
identifier_ = identifier
55+
self._auto_generated_id = False
5256

53-
def __repr__(self) -> str:
54-
return self.__str__()
57+
super(AutoIdNode, self).__init__(
58+
identifier=identifier_,
59+
keyed=keyed,
60+
accept_children=accept_children,
61+
repr_=repr_,
62+
data=data,
63+
)

0 commit comments

Comments
 (0)