Skip to content

Commit 20f3d83

Browse files
Merge branch 'main' into releases/v0.3.1
2 parents 9943336 + 46a19e0 commit 20f3d83

File tree

6 files changed

+95
-62
lines changed

6 files changed

+95
-62
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ requires-python = ">=3.10"
99
dependencies = [
1010
"deepmerge",
1111
"openpyxl"
12+
"safer"
1213
]
1314

1415
[project.scripts]

src/jsonchain/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
A small package to aid in the use of the chaining techniques taught by Structural Python
33
"""
44

5-
__version__ = "0.3.0"
5+
__version__ = "0.4.0"
66

77

88
from .io import (load_json, dump_json)

src/jsonchain/envelope.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@
33

44
PYMAX = max
55
PYMIN = min
6+
PYABS = abs
67

7-
def envelope_tree(tree: dict | list, levels: list[Hashable | None], leaf: Hashable | None, agg_func: callable, with_trace: bool = True) -> dict:
8+
def envelope_tree(
9+
tree: dict | list,
10+
levels: list[Hashable | None],
11+
leaf: Hashable | None,
12+
agg_func: callable,
13+
with_trace: bool = True
14+
) -> dict:
815
"""
9-
Envelopes the tree at the leaf node with 'agg_func'.
16+
Returns a new dict tree
1017
"""
1118
env_acc = {}
1219
# If we are at the last branch...
1320
if not levels:
1421
if isinstance(tree, list):
1522
tree = {idx: leaf for idx, leaf in enumerate(tree)}
1623
leaf_acc = {}
17-
for k, leaves in tree.items():
18-
if leaf is not None:
19-
leaf_acc.update({k: leaves[leaf]})
24+
for leaf_key, leaf_value in tree.items():
25+
if leaf is not None and leaf_key == leaf:
26+
leaf_acc.update({leaf_key: leaf_value})
2027
else:
2128
leaf_acc = tree
2229
# ...create a dict of the enveloped value and the key
@@ -85,4 +92,13 @@ def min(x: list[float | int | None]) -> float | int | None:
8592
Returns the max value in 'x' while ignoring "None".
8693
If all values in 'x' are None, then None is returned.
8794
"""
88-
return PYMIN([y for y in x if y is not None])
95+
return PYMIN([y for y in x if y is not None])
96+
97+
98+
def abs(x: float | int | None) -> float | int | None:
99+
"""
100+
Performs abs but passes None through if x is None.
101+
"""
102+
if x is None:
103+
return x
104+
return abs(x)

src/jsonchain/io.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import json
22
import pathlib
3+
import safer
34
from typing import Any, Optional
45

56
def load_json(filepath: str | pathlib.Path) -> dict | list:
67
"""
78
Loads the JSON data at 'filepath' into a Python object.
89
"""
9-
with open(filepath, 'r') as file:
10+
with safer.open(filepath, 'r') as file:
1011
return json.load(file)
1112

1213

@@ -15,5 +16,5 @@ def dump_json(object: list | dict, filepath: str | pathlib.Path, indent=2) -> No
1516
Dumps the 'object' (which must be JSON-serializable) into a JSON
1617
file at 'filepath'.
1718
"""
18-
with open(filepath, 'w') as file:
19+
with safer.open(filepath, 'w') as file:
1920
json.dump(object, file, indent=indent)

src/jsonchain/tree.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ def retrieve_leaves(
106106
leaf: list[Hashable] | Hashable | None,
107107
) -> dict:
108108
"""
109-
Envelopes the tree at the leaf node with 'agg_func'.
109+
Retrieves the leaf nodes at levels -> leaf and puts the leaf nodes
110+
under the top-level keys.
110111
"""
111112
env_acc = {}
112113
key_error_msg = (
@@ -195,6 +196,7 @@ def filter_keys(
195196
tree: dict,
196197
include_keys: Optional[list[str]] = None,
197198
exclude_keys: Optional[list[str]] = None,
199+
include_startswith: Optional[str | list[str]] = None,
198200
include_keys_startswith: Optional[str | list[str]] = None
199201
) -> dict:
200202
"""

0 commit comments

Comments
 (0)