Skip to content

Commit

Permalink
Merge pull request #26 from leonardbinet/mypy
Browse files Browse the repository at this point in the history
Mypy - all interfaces typed
  • Loading branch information
leonardbinet authored Jul 13, 2021
2 parents 1da4680 + 83f9e71 commit c7ce458
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ black:
black lighttree tests setup.py

mypy:
mypy lighttree
mypy lighttree --disallow-untyped-defs

check: mypy black lint

Expand Down
4 changes: 2 additions & 2 deletions lighttree/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .interactive import TreeBasedObj
from .tree import Tree, Node
from .tree import Tree, Node, Key, KeyedNode, KeyedTree

__all__ = ["Tree", "Node", "TreeBasedObj"]
__all__ = ["Tree", "Node", "TreeBasedObj", "Key", "KeyedNode", "KeyedTree"]
25 changes: 16 additions & 9 deletions lighttree/implementations/json_tree.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from lighttree import Node, Tree
from typing import Dict, Optional, Any, Union, List
from lighttree import Node, Tree, Key


class JsonTree(Tree):
def __init__(self, d=None, strict=True, path_separator="."):
def __init__(
self, d: Dict = None, strict: bool = True, path_separator: str = "."
) -> None:
"""
:param d:
:param strict: if False, will convert tuples into arrays, else raise error
Expand All @@ -13,14 +16,16 @@ def __init__(self, d=None, strict=True, path_separator="."):
self._fill(d, strict=strict, key=None)

@staticmethod
def _concat(a, b):
def _concat(a: Any, b: Any) -> str:
if not a and not b:
return ""
if not a:
return str(b)
return ".".join([str(a), str(b)])

def _fill(self, data, key, strict, path=None):
def _fill(
self, data: Any, key: Key, strict: bool, path: Optional[str] = None
) -> None:
if isinstance(data, list) or not strict and isinstance(data, tuple):
k = self.insert_node(
Node(keyed=False), parent_id=path, key=key, by_path=True
Expand Down Expand Up @@ -50,10 +55,12 @@ def _fill(self, data, key, strict, path=None):
return
raise TypeError("Unsupported type %s" % type(data))

def to_dict(self):
def to_dict(self) -> Union[Dict, List, None]:
if self.root is None:
return None
return self._to_dict(self.root)

def _to_dict(self, nid):
def _to_dict(self, nid: str) -> Any:
_, n = self.get(nid)
if not n.accept_children:
return n.data
Expand All @@ -62,7 +69,7 @@ def _to_dict(self, nid):
for sk, sn in self.children(n.identifier):
d[sk] = self._to_dict(sn.identifier)
return d
d = []
l_ = []
for _, sn in self.children(n.identifier):
d.append(self._to_dict(sn.identifier))
return d
l_.append(self._to_dict(sn.identifier))
return l_
20 changes: 10 additions & 10 deletions lighttree/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from lighttree.tree import Tree


def is_valid_attr_name(item) -> bool:
def is_valid_attr_name(item: Any) -> bool:
if not isinstance(item, str):
return False
if item.startswith("__"):
Expand All @@ -20,7 +20,7 @@ def is_valid_attr_name(item) -> bool:
return True


def _coerce_attr(attr) -> Union[str, None]:
def _coerce_attr(attr: Any) -> Union[str, None]:
if not len(attr):
return None
new_attr = unicodedata.normalize("NFD", attr).encode("ASCII", "ignore").decode()
Expand Down Expand Up @@ -55,7 +55,7 @@ class Obj(object):
_STRING_KEY_CONSTRAINT = True
_COERCE_ATTR = False

def __init__(self, **kwargs) -> None:
def __init__(self, **kwargs: Any) -> None:
# will store non-valid names
self.__d: Dict[str, Any] = dict()
for k, v in kwargs.items():
Expand All @@ -69,14 +69,14 @@ def __init__(self, **kwargs) -> None:
)
self[k] = v

def __getitem__(self, item):
def __getitem__(self, item: Any) -> Any:
# when calling d[key]
if is_valid_attr_name(item):
return self.__getattribute__(item)
else:
return self.__d[item]

def __setitem__(self, key, value):
def __setitem__(self, key: Any, value: Any) -> None:
# d[key] = value
if not isinstance(key, str):
if self._STRING_KEY_CONSTRAINT:
Expand All @@ -101,7 +101,7 @@ def __keys(self) -> List[Any]:
k for k in self.__dict__.keys() if k not in ("_REPR_NAME", "_Obj__d")
]

def __contains__(self, item) -> bool:
def __contains__(self, item: Any) -> bool:
return item in self.__keys()

def __str__(self) -> str:
Expand Down Expand Up @@ -174,14 +174,14 @@ def _expand_attrs(self, depth: int) -> None:
child_node.identifier, root_path=child_root, depth=depth - 1
)

def __getattribute__(self, item):
def __getattribute__(self, item: Any) -> Any:
# called by __getattribute__ will always refer to valid attribute item
r = super(TreeBasedObj, self).__getattribute__(item)
if isinstance(r, TreeBasedObj):
r._expand_attrs(depth=1)
return r

def __getitem__(self, item):
def __getitem__(self, item: Any) -> Any:
if is_valid_attr_name(item):
r = super(TreeBasedObj, self).__getattribute__(item)
else:
Expand All @@ -190,7 +190,7 @@ def __getitem__(self, item):
r._expand_attrs(depth=1)
return r

def _show(self, *args, **kwargs) -> str:
def _show(self, *args: Any, **kwargs: Any) -> str:
tree_repr = self._tree.show(*args, **kwargs)
if self._root_path is None:
return "<%s>\n%s" % (
Expand All @@ -204,7 +204,7 @@ def _show(self, *args, **kwargs) -> str:
str(tree_repr),
)

def __call__(self, *args, **kwargs) -> Tree:
def __call__(self, *args: Any, **kwargs: Any) -> Tree:
return self._tree

def __str__(self) -> str:
Expand Down
10 changes: 5 additions & 5 deletions lighttree/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-

import uuid
from typing import Optional, Any, Tuple
from typing import Optional, Any, Tuple, Union


class Node(object):
Expand All @@ -12,7 +12,7 @@ def __init__(
auto_uuid: bool = True,
keyed: bool = True,
accept_children: bool = True,
repr_: Optional[str] = None,
repr_: Optional[Union[str, float]] = None,
data: Any = None,
) -> None:
"""
Expand All @@ -25,10 +25,10 @@ def __init__(
self.identifier = identifier
self.keyed = keyed
self.accept_children = accept_children
self.repr = repr_
self.repr = str(repr_) if repr_ is not None else None
self.data = data

def line_repr(self, depth: int, **kwargs) -> Tuple[str, str]:
def line_repr(self, depth: int, **kwargs: Any) -> Tuple[str, str]:
"""Control how node is displayed in tree representation.
_
├── one end
Expand All @@ -43,7 +43,7 @@ def line_repr(self, depth: int, **kwargs) -> Tuple[str, str]:
return "{}", ""
return "[]", ""

def __eq__(self, other) -> bool:
def __eq__(self, other: Any) -> bool:
if not isinstance(other, self.__class__):
return False
return self.identifier == other.identifier
Expand Down
Empty file added lighttree/py.typed
Empty file.
7 changes: 4 additions & 3 deletions lighttree/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Iterable,
cast,
Dict,
Any,
)
from collections import defaultdict
from operator import itemgetter
Expand Down Expand Up @@ -718,7 +719,7 @@ def show(
limit: Optional[int] = None,
line_max_length: int = 60,
key_delimiter: str = ": ",
**kwargs
**kwargs: Any
) -> str:
"""Return tree structure in hierarchy style.
Expand Down Expand Up @@ -832,13 +833,13 @@ def _line_prefix_repr(line_type: str, is_last_list: Tuple[bool, ...]) -> str:
if not is_last_list:
return ""
dt_vertical_line, dt_line_box, dt_line_corner = STYLES[line_type]
leading = "".join(
leading: str = "".join(
[
dt_vertical_line + " " * 3 if not is_last else " " * 4
for is_last in cast(Iterable[bool], is_last_list[0:-1])
]
)
lasting = dt_line_corner if is_last_list[-1] else dt_line_box
lasting: str = dt_line_corner if is_last_list[-1] else dt_line_box
return leading + lasting

def merge(
Expand Down
3 changes: 2 additions & 1 deletion lighttree/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from typing import Dict, Tuple

STYLES = {
STYLES: Dict[str, Tuple[str, str, str]] = {
"ascii": ("|", "|-- ", "+-- "),
"ascii-ex": ("\u2502", "\u251c\u2500\u2500 ", "\u2514\u2500\u2500 "),
"ascii-exr": ("\u2502", "\u251c\u2500\u2500 ", "\u2570\u2500\u2500 "),
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
description-file = README.md

[flake8]
ignore=E501,W503
ignore=E501,W503,W605
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from setuptools import setup

__version__ = "1.1.2"
__version__ = "1.1.3"

develop_requires = [
"pre-commit",
Expand All @@ -24,6 +24,9 @@
author_email="[email protected]",
license="MIT",
packages=["lighttree"],
package_data={
"lighttree": ["py.typed"],
},
keywords=["tree", "interactive"],
extras_require={"develop": develop_requires},
tests_require=develop_requires,
Expand Down
14 changes: 9 additions & 5 deletions tests/test_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,23 +536,27 @@ def test_show(self):

def test_prefix_repr(self):
self.assertEqual(
Tree._line_prefix_repr(line_type="ascii-ex", is_last_list=[]), ""
Tree._line_prefix_repr(
line_type="ascii-ex",
is_last_list=(),
),
"",
)
self.assertEqual(
Tree._line_prefix_repr(line_type="ascii-ex", is_last_list=[True]), "└── "
Tree._line_prefix_repr(line_type="ascii-ex", is_last_list=(True,)), "└── "
)
self.assertEqual(
Tree._line_prefix_repr(line_type="ascii-ex", is_last_list=[False]), "├── "
Tree._line_prefix_repr(line_type="ascii-ex", is_last_list=(False,)), "├── "
)
self.assertEqual(
Tree._line_prefix_repr(
line_type="ascii-ex", is_last_list=[True, False, True]
line_type="ascii-ex", is_last_list=(True, False, True)
),
" │ └── ",
)
self.assertEqual(
Tree._line_prefix_repr(
line_type="ascii-ex", is_last_list=[False, False, False]
line_type="ascii-ex", is_last_list=(False, False, False)
),
"│ │ ├── ",
)
Expand Down

0 comments on commit c7ce458

Please sign in to comment.