Skip to content

Commit fb77a64

Browse files
committed
Refactoring and type hinting
1 parent fdac68f commit fb77a64

3 files changed

Lines changed: 27 additions & 19 deletions

File tree

dpath/segments.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
from copy import deepcopy
22
from fnmatch import fnmatchcase
3-
from typing import List, Sequence, Tuple
3+
from typing import List, Sequence, Tuple, Iterator, Any, Dict, Union
44

55
from dpath import options
66
from dpath.exceptions import InvalidGlob, InvalidKeyName, PathNotFound
77
from dpath.util import PathSegment
88

99

10-
def kvs(node):
10+
def make_walkable(node) -> Iterator[Tuple[PathSegment, Any]]:
1111
"""
12-
Return a (key, value) iterator for the node.
12+
Returns an iterator which yields tuple pairs of (node index, node value), regardless of node type.
1313
14-
kvs(node) -> (generator -> (key, value))
14+
* For dict nodes `node.items()` will be returned.
15+
* For sequence nodes (lists/tuples/etc.) a zip between index number and index value will be returned.
16+
* Edge cases will result in an empty iterator being returned.
17+
18+
make_walkable(node) -> (generator -> (key, value))
1519
"""
1620
try:
1721
return iter(node.items())
@@ -28,8 +32,6 @@ def kvs(node):
2832
def leaf(thing):
2933
"""
3034
Return True if thing is a leaf, otherwise False.
31-
32-
leaf(thing) -> bool
3335
"""
3436
leaves = (bytes, str, int, float, bool, type(None))
3537

@@ -40,8 +42,6 @@ def leafy(thing):
4042
"""
4143
Same as leaf(thing), but also treats empty sequences and
4244
dictionaries as True.
43-
44-
leafy(thing) -> bool
4545
"""
4646

4747
try:
@@ -59,20 +59,21 @@ def walk(obj, location=()):
5959
walk(obj) -> (generator -> (segments, value))
6060
"""
6161
if not leaf(obj):
62-
for k, v in kvs(obj):
62+
for k, v in make_walkable(obj):
6363
length = None
6464

6565
try:
6666
length = len(k)
67-
except:
67+
except TypeError:
6868
pass
6969

7070
if length is not None and length == 0 and not options.ALLOW_EMPTY_STRING_KEYS:
7171
raise InvalidKeyName("Empty string keys not allowed without "
7272
"dpath.options.ALLOW_EMPTY_STRING_KEYS=True: "
7373
"{}".format(location + (k,)))
74-
yield ((location + (k,)), v)
75-
for k, v in kvs(obj):
74+
yield (location + (k,)), v
75+
76+
for k, v in make_walkable(obj):
7677
for found in walk(v, location + (k,)):
7778
yield found
7879

@@ -240,7 +241,7 @@ def match(segments, glob):
240241
return False
241242

242243

243-
def extend(thing, index, value=None):
244+
def extend(thing: List, index: int, value=None):
244245
"""
245246
Extend a sequence like thing such that it contains at least index +
246247
1 many elements. The extension values will be None (default).
@@ -265,7 +266,12 @@ def extend(thing, index, value=None):
265266
return thing
266267

267268

268-
def __default_creator__(current, segments: List[str], i: int, hints: Sequence[Tuple[PathSegment, type]] = ()):
269+
def __default_creator__(
270+
current: Union[Dict, List],
271+
segments: List[PathSegment],
272+
i: int,
273+
hints: Sequence[Tuple[PathSegment, type]] = ()
274+
):
269275
"""
270276
Create missing path components. If the segment is an int, then it will
271277
create a list. Otherwise a dictionary is created.

dpath/util.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from collections.abc import MutableMapping, MutableSequence
22
from enum import IntFlag, auto
3-
from typing import Union, List, Any, Dict, Callable
3+
from typing import Union, List, Any, Dict, Callable, Sequence, Tuple
44

55
from dpath import options, segments
66
from dpath.exceptions import InvalidKeyName, PathNotFound
@@ -20,6 +20,9 @@ class MergeType(IntFlag):
2020
# Type alias for filter functions
2121
Filter = Callable[[Any], bool] # (Any) -> bool
2222

23+
# Type alias for creator functions
24+
Creator = Callable[[Union[Dict, List], List[PathSegment], int, Sequence[Tuple[PathSegment, type]]], None]
25+
2326

2427
def _split_path(path: str, separator: str) -> Union[List[PathSegment], PathSegment]:
2528
"""
@@ -48,8 +51,7 @@ def _split_path(path: str, separator: str) -> Union[List[PathSegment], PathSegme
4851
return split_segments
4952

5053

51-
# todo: Type hint creator arg
52-
def new(obj: Dict, path: str, value, separator="/", creator=None) -> Dict:
54+
def new(obj: Dict, path: str, value, separator="/", creator: Creator = None) -> Dict:
5355
"""
5456
Set the element at the terminus of path to value, and create
5557
it if it does not exist (as opposed to 'set' that can only
@@ -289,7 +291,7 @@ def are_both_mutable(o1, o2):
289291
return False
290292

291293
def merger(dst, src, _segments=()):
292-
for key, found in segments.kvs(src):
294+
for key, found in segments.make_walkable(src):
293295
# Our current path in the source.
294296
current_path = _segments + (key,)
295297

tests/test_segments.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_kvs(node):
4343
Given a node, kvs should produce a key that when used to extract
4444
from the node renders the exact same value given.
4545
"""
46-
for k, v in api.kvs(node):
46+
for k, v in api.make_walkable(node):
4747
assert node[k] is v
4848

4949

0 commit comments

Comments
 (0)