hestia-earth-utils 0.16.14__tar.gz → 0.16.16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/PKG-INFO +2 -2
  2. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/blank_node.py +34 -16
  3. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/cycle.py +24 -5
  4. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/pivot/_shared.py +0 -1
  5. hestia_earth_utils-0.16.16/hestia_earth/utils/version.py +1 -0
  6. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth_utils.egg-info/PKG-INFO +2 -2
  7. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth_utils.egg-info/requires.txt +1 -1
  8. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_api.py +0 -1
  9. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_blank_node.py +36 -21
  10. hestia_earth_utils-0.16.16/tests/test_calculation_status.py +30 -0
  11. hestia_earth_utils-0.16.16/tests/test_cycle.py +38 -0
  12. hestia_earth_utils-0.16.14/hestia_earth/utils/version.py +0 -1
  13. hestia_earth_utils-0.16.14/tests/test_calculation_status.py +0 -40
  14. hestia_earth_utils-0.16.14/tests/test_cycle.py +0 -18
  15. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/MANIFEST.in +0 -0
  16. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/README.md +0 -0
  17. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/bin/hestia-format-upload +0 -0
  18. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/bin/hestia-pivot-csv +0 -0
  19. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/__init__.py +0 -0
  20. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/api.py +0 -0
  21. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/calculation_status.py +0 -0
  22. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/date.py +0 -0
  23. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/descriptive_stats.py +0 -0
  24. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/emission.py +0 -0
  25. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/lookup.py +0 -0
  26. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/lookup_utils.py +0 -0
  27. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/model.py +0 -0
  28. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/pipeline.py +0 -0
  29. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/pivot/__init__.py +0 -0
  30. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/pivot/pivot_csv.py +0 -0
  31. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/pivot/pivot_json.py +0 -0
  32. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/request.py +0 -0
  33. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/stats.py +0 -0
  34. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/storage/__init__.py +0 -0
  35. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/storage/_azure_client.py +0 -0
  36. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/storage/_local_client.py +0 -0
  37. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/storage/_s3_client.py +0 -0
  38. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/storage/_sns_client.py +0 -0
  39. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/table.py +0 -0
  40. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/term.py +0 -0
  41. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth/utils/tools.py +0 -0
  42. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth_utils.egg-info/SOURCES.txt +0 -0
  43. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth_utils.egg-info/dependency_links.txt +0 -0
  44. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/hestia_earth_utils.egg-info/top_level.txt +0 -0
  45. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/setup.cfg +0 -0
  46. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/setup.py +0 -0
  47. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_date.py +0 -0
  48. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_descriptive_stats.py +0 -0
  49. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_emission.py +0 -0
  50. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_lookup.py +0 -0
  51. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_lookup_utils.py +0 -0
  52. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_model.py +0 -0
  53. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_pipeline.py +0 -0
  54. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_request.py +0 -0
  55. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_stats.py +0 -0
  56. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_table.py +0 -0
  57. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_term.py +0 -0
  58. {hestia_earth_utils-0.16.14 → hestia_earth_utils-0.16.16}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hestia_earth_utils
3
- Version: 0.16.14
3
+ Version: 0.16.16
4
4
  Summary: HESTIA's utils library
5
5
  Home-page: https://gitlab.com/hestia-earth/hestia-utils
6
6
  Author: HESTIA Team
@@ -13,7 +13,7 @@ Requires-Dist: hestia-earth-schema>=35.0.1
13
13
  Requires-Dist: requests>=2.24.0
14
14
  Requires-Dist: urllib3~=1.26.0
15
15
  Requires-Dist: python-dateutil>=2.8.1
16
- Requires-Dist: pandas>=2
16
+ Requires-Dist: pandas<3,>=2
17
17
  Requires-Dist: flatten_json
18
18
  Dynamic: author
19
19
  Dynamic: author-email
@@ -186,6 +186,38 @@ def get_node_value(
186
186
  _BLANK_NODE_GROUPING_KEYS = {TermTermType.EMISSION: ["methodModel"]}
187
187
 
188
188
 
189
+ def _pluralize_key(key: str):
190
+ return key + ("" if key.endswith("s") else "s")
191
+
192
+
193
+ def _blank_node_ids(values: list):
194
+ return sorted(list(set(list(map(lambda v: v.get("@id"), values)))))
195
+
196
+
197
+ def _blank_node_sub_values(blank_nodes: list, key: str):
198
+ values = flatten(map(lambda v: v.get(key, []), blank_nodes))
199
+ return {_pluralize_key(key): _blank_node_ids(values)} if values else {}
200
+
201
+
202
+ def _blank_node_data(blank_nodes: list):
203
+ value = get_node_value(
204
+ {
205
+ "term": blank_nodes[0].get("term"),
206
+ "value": list(map(get_node_value, blank_nodes)),
207
+ }
208
+ )
209
+ sub_values = ["inputs", "operation", "transformation"]
210
+ has_cycle_value = any(
211
+ [
212
+ all([get_node_value(v) is not None, not v.get("transformation")])
213
+ for v in blank_nodes
214
+ ]
215
+ )
216
+ return {"value": value, "hasCycleValue": has_cycle_value} | reduce(
217
+ lambda p, c: p | _blank_node_sub_values(blank_nodes, c), sub_values, {}
218
+ )
219
+
220
+
189
221
  def get_blank_nodes_calculation_status(
190
222
  node: dict, list_key: str, termType: TermTermType
191
223
  ):
@@ -214,20 +246,6 @@ def get_blank_nodes_calculation_status(
214
246
  blank_nodes_by_term = group_by_keys(blank_nodes, ["term"])
215
247
  blank_nodes_grouping_keys = _BLANK_NODE_GROUPING_KEYS.get(termType) or []
216
248
 
217
- def blank_node_data(blank_nodes: list):
218
- value = get_node_value(
219
- {
220
- "term": blank_nodes[0].get("term"),
221
- "value": list(map(get_node_value, blank_nodes)),
222
- }
223
- )
224
- inputs = flatten(map(lambda v: v.get("inputs", []), blank_nodes))
225
- return {"value": value} | (
226
- {"inputs": sorted(list(map(lambda v: v.get("@id"), inputs)))}
227
- if inputs
228
- else {}
229
- )
230
-
231
249
  def map_blank_node(term_id: str):
232
250
  values = blank_nodes_by_term.get(term_id, [])
233
251
  grouped_blank_nodes = (
@@ -239,9 +257,9 @@ def get_blank_nodes_calculation_status(
239
257
  {}
240
258
  if not values
241
259
  else (
242
- {k: blank_node_data(v) for k, v in grouped_blank_nodes.items()}
260
+ {k: _blank_node_data(v) for k, v in grouped_blank_nodes.items()}
243
261
  if grouped_blank_nodes
244
- else blank_node_data([values[0]])
262
+ else _blank_node_data([values[0]])
245
263
  )
246
264
  )
247
265
 
@@ -4,10 +4,16 @@ from .tools import flatten
4
4
  from .blank_node import get_blank_nodes_calculation_status
5
5
 
6
6
 
7
- def _extend_missing_inputs(value: dict, input_ids: set):
8
- included_inputs = set(flatten([v.get("inputs", []) for v in value.values()]))
9
- missing_inputs = input_ids - included_inputs
10
- return {"missingInputs": sorted(list(missing_inputs))} if missing_inputs else {}
7
+ def _extend_missing_values(
8
+ value: dict, all_values: set, key: str, must_have_key: bool = False
9
+ ):
10
+ included_values = set(flatten([v.get(key, []) for v in value.values()]))
11
+ missing_values = all_values - included_values
12
+ return (
13
+ {"missing" + key.capitalize(): sorted(list(missing_values))}
14
+ if all([missing_values, not must_have_key or included_values])
15
+ else {}
16
+ )
11
17
 
12
18
 
13
19
  def get_cycle_emissions_calculation_status(cycle: dict):
@@ -30,7 +36,20 @@ def get_cycle_emissions_calculation_status(cycle: dict):
30
36
  cycle, "emissions", TermTermType.EMISSION
31
37
  )
32
38
  input_ids = set([v.get("term", {}).get("@id") for v in cycle.get("inputs", [])])
39
+ transformation_ids = set(
40
+ [v.get("term", {}).get("@id") for v in cycle.get("transformations", [])]
41
+ )
33
42
  return {
34
- k: v | (_extend_missing_inputs(v, input_ids) if "InputsProduction" in k else {})
43
+ k: v
44
+ | (
45
+ _extend_missing_values(v, input_ids, "inputs")
46
+ if "InputsProduction" in k
47
+ else {}
48
+ )
49
+ | (
50
+ _extend_missing_values(
51
+ v, transformation_ids, "transformations", must_have_key=True
52
+ )
53
+ )
35
54
  for k, v in status.items()
36
55
  }
@@ -6,7 +6,6 @@ from flatten_json import flatten as flatten_json
6
6
 
7
7
  from ..tools import list_sum
8
8
 
9
-
10
9
  EXCLUDE_FIELDS = ["@type", "type", "@context"]
11
10
  EXCLUDE_PRIVATE_FIELDS = [
12
11
  "added",
@@ -0,0 +1 @@
1
+ VERSION = "0.16.16"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hestia_earth_utils
3
- Version: 0.16.14
3
+ Version: 0.16.16
4
4
  Summary: HESTIA's utils library
5
5
  Home-page: https://gitlab.com/hestia-earth/hestia-utils
6
6
  Author: HESTIA Team
@@ -13,7 +13,7 @@ Requires-Dist: hestia-earth-schema>=35.0.1
13
13
  Requires-Dist: requests>=2.24.0
14
14
  Requires-Dist: urllib3~=1.26.0
15
15
  Requires-Dist: python-dateutil>=2.8.1
16
- Requires-Dist: pandas>=2
16
+ Requires-Dist: pandas<3,>=2
17
17
  Requires-Dist: flatten_json
18
18
  Dynamic: author
19
19
  Dynamic: author-email
@@ -2,5 +2,5 @@ hestia-earth-schema>=35.0.1
2
2
  requests>=2.24.0
3
3
  urllib3~=1.26.0
4
4
  python-dateutil>=2.8.1
5
- pandas>=2
5
+ pandas<3,>=2
6
6
  flatten_json
@@ -17,7 +17,6 @@ from hestia_earth.utils.api import (
17
17
  find_term_ids_by_names,
18
18
  )
19
19
 
20
-
21
20
  fake_related_response = {"results": [[{"@id": "related_id"}]]}
22
21
  fake_download_response = {"@id": "id", "@type": "type"}
23
22
 
@@ -1,14 +1,14 @@
1
1
  import os
2
+ import json
3
+ from pytest import mark
4
+ from unittest.mock import patch
5
+ from hestia_earth.schema import TermTermType
2
6
 
3
- # import json
4
- # from pytest import mark
5
- # from hestia_earth.schema import TermTermType
6
-
7
- from tests.utils import fixtures_path
7
+ from tests.utils import EMISSION_IDS, fixtures_path
8
8
  from hestia_earth.utils.blank_node import (
9
9
  get_node_value,
10
10
  ArrayTreatment,
11
- # get_blank_nodes_calculation_status,
11
+ get_blank_nodes_calculation_status,
12
12
  )
13
13
 
14
14
  fixtures_folder = os.path.join(fixtures_path, "blank_node")
@@ -57,18 +57,33 @@ def test_get_node_value():
57
57
  assert get_node_value(blank_node, "value", array_treatment=ArrayTreatment.SUM) == 30
58
58
 
59
59
 
60
- # @mark.parametrize(
61
- # 'folder,list_key,termType',
62
- # [
63
- # ('cycle', 'emissions', TermTermType.EMISSION),
64
- # ]
65
- # )
66
- # def test_get_blank_nodes_calculation_status(folder: str, list_key: str, termType: TermTermType):
67
- # with open(f"{calculation_status_folder}/{folder}/node.jsonld", encoding='utf-8') as f:
68
- # node = json.load(f)
69
-
70
- # with open(f"{calculation_status_folder}/{folder}/{list_key}-{termType.value}.json", encoding='utf-8') as f:
71
- # expected = json.load(f)
72
-
73
- # result = get_blank_nodes_calculation_status(node, list_key=list_key, termType=termType)
74
- # assert result == expected, folder
60
+ @mark.parametrize(
61
+ "folder,list_key,termType",
62
+ [
63
+ ("cycle", "emissions", TermTermType.EMISSION),
64
+ ("cycle-with-transformations", "emissions", TermTermType.EMISSION),
65
+ ],
66
+ )
67
+ @patch(
68
+ "hestia_earth.utils.blank_node.cycle_emissions_in_system_boundary",
69
+ return_value=EMISSION_IDS,
70
+ )
71
+ def test_get_blank_nodes_calculation_status(
72
+ mock_, folder: str, list_key: str, termType: TermTermType
73
+ ):
74
+ with open(
75
+ f"{calculation_status_folder}/{folder}/node.jsonld", encoding="utf-8"
76
+ ) as f:
77
+ node = json.load(f)
78
+
79
+ with open(
80
+ f"{calculation_status_folder}/{folder}/{list_key}-{termType.value}.json",
81
+ encoding="utf-8",
82
+ ) as f:
83
+ expected = json.load(f)
84
+
85
+ result = get_blank_nodes_calculation_status(
86
+ node, list_key=list_key, termType=termType
87
+ )
88
+ print(json.dumps(result, indent=2))
89
+ assert result == expected, folder
@@ -0,0 +1,30 @@
1
+ import os
2
+ import json
3
+
4
+ from tests.utils import fixtures_path
5
+ from hestia_earth.utils.calculation_status import _emissions_with_status
6
+
7
+ fixtures_folder = os.path.join(fixtures_path, "calculation_status")
8
+
9
+
10
+ def test_emissions_with_status():
11
+ with open(os.path.join(fixtures_folder, "nodes.json")) as f:
12
+ nodes = json.load(f)
13
+
14
+ result = _emissions_with_status(nodes[0])
15
+ assert result == {
16
+ "emissions-total": 202,
17
+ "emissions-complete": 55,
18
+ "emissions-incomplete": 1,
19
+ "emissions-missing": 146,
20
+ "emissions": result["emissions"], # ignore
21
+ }
22
+
23
+ result = _emissions_with_status(nodes[1])
24
+ assert result == {
25
+ "emissions-total": 202,
26
+ "emissions-complete": 0,
27
+ "emissions-incomplete": 13,
28
+ "emissions-missing": 189,
29
+ "emissions": result["emissions"], # ignore
30
+ }
@@ -0,0 +1,38 @@
1
+ import os
2
+ import json
3
+ import pytest
4
+ from unittest.mock import patch
5
+
6
+ from tests.utils import EMISSION_IDS, fixtures_path
7
+ from hestia_earth.utils.cycle import get_cycle_emissions_calculation_status
8
+
9
+ fixtures_folder = os.path.join(fixtures_path, "blank_node", "calculation_status")
10
+ _folders = [
11
+ d
12
+ for d in os.listdir(fixtures_folder)
13
+ if os.path.isdir(os.path.join(fixtures_folder, d))
14
+ ]
15
+
16
+
17
+ @pytest.mark.parametrize("folder", _folders)
18
+ @patch(
19
+ "hestia_earth.utils.blank_node.cycle_emissions_in_system_boundary",
20
+ return_value=EMISSION_IDS,
21
+ )
22
+ def test_get_cycle_emissions_calculation_status(mock_, folder: str):
23
+ with open(
24
+ os.path.join(fixtures_folder, folder, "node.jsonld"), encoding="utf-8"
25
+ ) as f:
26
+ cycle = json.load(f)
27
+
28
+ with open(
29
+ os.path.join(
30
+ fixtures_folder, folder, "emissions-emission-with-missing-inputs.json"
31
+ ),
32
+ encoding="utf-8",
33
+ ) as f:
34
+ expected = json.load(f)
35
+
36
+ result = get_cycle_emissions_calculation_status(cycle)
37
+ print(json.dumps(result, indent=2))
38
+ assert result == expected
@@ -1 +0,0 @@
1
- VERSION = "0.16.14"
@@ -1,40 +0,0 @@
1
- # import os
2
- # import json
3
-
4
- # from tests.utils import fixtures_path
5
- # from hestia_earth.utils.calculation_status import _emissions_with_status, get_nodes_calculations_status_dataframe
6
-
7
- # fixtures_folder = os.path.join(fixtures_path, 'calculation_status')
8
-
9
-
10
- # def test_emissions_with_status():
11
- # with open(os.path.join(fixtures_folder, 'nodes.json')) as f:
12
- # nodes = json.load(f)
13
-
14
- # result = _emissions_with_status(nodes[0])
15
- # assert result == {
16
- # 'emissions-total': 193,
17
- # 'emissions-complete': 56,
18
- # 'emissions-incomplete': 1,
19
- # 'emissions-missing': 136,
20
- # 'emissions': result['emissions'] # ignore
21
- # }
22
-
23
- # result = _emissions_with_status(nodes[1])
24
- # assert result == {
25
- # 'emissions-total': 193,
26
- # 'emissions-complete': 0,
27
- # 'emissions-incomplete': 13,
28
- # 'emissions-missing': 180,
29
- # 'emissions': result['emissions'] # ignore
30
- # }
31
-
32
-
33
- # def test_get_nodes_calculations_status_dataframe():
34
- # with open(os.path.join(fixtures_folder, 'nodes.json')) as f:
35
- # nodes = json.load(f)
36
-
37
- # expected = open(os.path.join(fixtures_folder, 'result.csv'), 'r').read()
38
-
39
- # df = get_nodes_calculations_status_dataframe(nodes, file_format='csv')
40
- # assert df.to_csv(None, index=None) == expected
@@ -1,18 +0,0 @@
1
- # import os
2
- # import json
3
-
4
- # from tests.utils import fixtures_path
5
- # from hestia_earth.utils.cycle import get_cycle_emissions_calculation_status
6
-
7
-
8
- # def test_get_cycle_emissions_calculation_status():
9
- # folder = os.path.join(fixtures_path, 'blank_node', 'calculation_status', 'cycle')
10
-
11
- # with open(f"{folder}/node.jsonld", encoding='utf-8') as f:
12
- # cycle = json.load(f)
13
-
14
- # with open(f"{folder}/emissions-emission-with-missing-inputs.json", encoding='utf-8') as f:
15
- # expected = json.load(f)
16
-
17
- # result = get_cycle_emissions_calculation_status(cycle)
18
- # assert result == expected