hestia-earth-models 0.65.5__py3-none-any.whl → 0.65.7__py3-none-any.whl
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.
Potentially problematic release.
This version of hestia-earth-models might be problematic. Click here for more details.
- hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +9 -5
- hestia_earth/models/config/Cycle.json +2193 -0
- hestia_earth/models/config/ImpactAssessment.json +2041 -0
- hestia_earth/models/config/Site.json +471 -0
- hestia_earth/models/config/__init__.py +71 -0
- hestia_earth/models/config/run-calculations.json +42 -0
- hestia_earth/models/config/trigger-calculations.json +43 -0
- hestia_earth/models/hestia/landCover.py +70 -22
- hestia_earth/models/ipcc2019/animal/hoursWorkedPerDay.py +38 -0
- hestia_earth/models/mocking/search-results.json +833 -829
- hestia_earth/models/site/management.py +82 -22
- hestia_earth/models/utils/crop.py +5 -1
- hestia_earth/models/version.py +1 -1
- hestia_earth/orchestrator/__init__.py +40 -0
- hestia_earth/orchestrator/log.py +62 -0
- hestia_earth/orchestrator/models/__init__.py +118 -0
- hestia_earth/orchestrator/models/emissions/__init__.py +0 -0
- hestia_earth/orchestrator/models/emissions/deleted.py +15 -0
- hestia_earth/orchestrator/models/transformations.py +103 -0
- hestia_earth/orchestrator/strategies/__init__.py +0 -0
- hestia_earth/orchestrator/strategies/merge/__init__.py +42 -0
- hestia_earth/orchestrator/strategies/merge/merge_append.py +29 -0
- hestia_earth/orchestrator/strategies/merge/merge_default.py +1 -0
- hestia_earth/orchestrator/strategies/merge/merge_list.py +103 -0
- hestia_earth/orchestrator/strategies/merge/merge_node.py +59 -0
- hestia_earth/orchestrator/strategies/run/__init__.py +8 -0
- hestia_earth/orchestrator/strategies/run/add_blank_node_if_missing.py +85 -0
- hestia_earth/orchestrator/strategies/run/add_key_if_missing.py +9 -0
- hestia_earth/orchestrator/strategies/run/always.py +6 -0
- hestia_earth/orchestrator/utils.py +116 -0
- {hestia_earth_models-0.65.5.dist-info → hestia_earth_models-0.65.7.dist-info}/METADATA +27 -5
- {hestia_earth_models-0.65.5.dist-info → hestia_earth_models-0.65.7.dist-info}/RECORD +57 -13
- tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +1 -1
- tests/models/hestia/test_landCover.py +2 -1
- tests/models/ipcc2019/animal/test_hoursWorkedPerDay.py +22 -0
- tests/models/test_config.py +115 -0
- tests/orchestrator/__init__.py +0 -0
- tests/orchestrator/models/__init__.py +0 -0
- tests/orchestrator/models/emissions/__init__.py +0 -0
- tests/orchestrator/models/emissions/test_deleted.py +21 -0
- tests/orchestrator/models/test_transformations.py +29 -0
- tests/orchestrator/strategies/__init__.py +0 -0
- tests/orchestrator/strategies/merge/__init__.py +0 -0
- tests/orchestrator/strategies/merge/test_merge_append.py +33 -0
- tests/orchestrator/strategies/merge/test_merge_default.py +7 -0
- tests/orchestrator/strategies/merge/test_merge_list.py +327 -0
- tests/orchestrator/strategies/merge/test_merge_node.py +95 -0
- tests/orchestrator/strategies/run/__init__.py +0 -0
- tests/orchestrator/strategies/run/test_add_blank_node_if_missing.py +114 -0
- tests/orchestrator/strategies/run/test_add_key_if_missing.py +14 -0
- tests/orchestrator/strategies/run/test_always.py +5 -0
- tests/orchestrator/test_models.py +69 -0
- tests/orchestrator/test_orchestrator.py +27 -0
- tests/orchestrator/test_utils.py +109 -0
- {hestia_earth_models-0.65.5.dist-info → hestia_earth_models-0.65.7.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.65.5.dist-info → hestia_earth_models-0.65.7.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.65.5.dist-info → hestia_earth_models-0.65.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
from hestia_earth.orchestrator.strategies.run.add_blank_node_if_missing import should_run
|
|
4
|
+
|
|
5
|
+
class_path = 'hestia_earth.orchestrator.strategies.run.add_blank_node_if_missing'
|
|
6
|
+
FAKE_EMISSION = {'@id': 'n2OToAirExcretaDirect', 'termType': 'emission'}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@patch(f"{class_path}.get_required_model_param", return_value='')
|
|
10
|
+
@patch(f"{class_path}.find_term_match")
|
|
11
|
+
def test_should_run(mock_node_exists, *args):
|
|
12
|
+
data = {}
|
|
13
|
+
model = {}
|
|
14
|
+
|
|
15
|
+
# node does not exists => run
|
|
16
|
+
mock_node_exists.return_value = None
|
|
17
|
+
assert should_run(data, model) is True
|
|
18
|
+
|
|
19
|
+
# node exists but no value => run
|
|
20
|
+
mock_node_exists.return_value = {}
|
|
21
|
+
assert should_run(data, model) is True
|
|
22
|
+
|
|
23
|
+
# node exists with value + no params => no run
|
|
24
|
+
node = {'value': 10}
|
|
25
|
+
mock_node_exists.return_value = node
|
|
26
|
+
assert not should_run(data, model)
|
|
27
|
+
|
|
28
|
+
# node exists with added value `0` and `Emission` => run
|
|
29
|
+
node = {'@type': 'Emission', 'value': [0], 'added': ['value']}
|
|
30
|
+
mock_node_exists.return_value = node
|
|
31
|
+
assert should_run(data, model) is True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@patch(f"{class_path}.get_required_model_param", return_value='')
|
|
35
|
+
@patch(f"{class_path}.find_term_match")
|
|
36
|
+
def test_should_run_skipEmptyValue(mock_node_exists, *args):
|
|
37
|
+
data = {}
|
|
38
|
+
|
|
39
|
+
# no value and not skip => run
|
|
40
|
+
mock_node_exists.return_value = {}
|
|
41
|
+
model = {'runArgs': {'skipEmptyValue': False}}
|
|
42
|
+
assert should_run(data, model) is True
|
|
43
|
+
|
|
44
|
+
# no value and skip => no run
|
|
45
|
+
mock_node_exists.return_value = {}
|
|
46
|
+
model = {'runArgs': {'skipEmptyValue': True}}
|
|
47
|
+
assert not should_run(data, model)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@patch(f"{class_path}.get_required_model_param", return_value='')
|
|
51
|
+
def test_should_run_skipAggregated(*args):
|
|
52
|
+
data = {}
|
|
53
|
+
model = {'runArgs': {'skipAggregated': True}}
|
|
54
|
+
|
|
55
|
+
# not aggregated => run
|
|
56
|
+
data = {'aggregated': False}
|
|
57
|
+
assert should_run(data, model) is True
|
|
58
|
+
|
|
59
|
+
# aggregated => no run
|
|
60
|
+
data = {'aggregated': True}
|
|
61
|
+
assert not should_run(data, model)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@patch(f"{class_path}.get_required_model_param", return_value='')
|
|
65
|
+
@patch(f"{class_path}.find_term_match")
|
|
66
|
+
def test_should_run_runNonAddedTerm(mock_node_exists, *args):
|
|
67
|
+
data = {}
|
|
68
|
+
node = {'value': 10}
|
|
69
|
+
mock_node_exists.return_value = node
|
|
70
|
+
model = {'runArgs': {'runNonAddedTerm': True}}
|
|
71
|
+
|
|
72
|
+
# term has been added => no run
|
|
73
|
+
node['added'] = ['term']
|
|
74
|
+
assert not should_run(data, model)
|
|
75
|
+
|
|
76
|
+
# term has not been added => run
|
|
77
|
+
node['added'] = []
|
|
78
|
+
assert should_run(data, model) is True
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@patch(f"{class_path}.get_required_model_param", return_value='')
|
|
82
|
+
@patch(f"{class_path}.find_term_match")
|
|
83
|
+
def test_should_run_runNonMeasured(mock_node_exists, *args):
|
|
84
|
+
data = {}
|
|
85
|
+
node = {'value': 10}
|
|
86
|
+
mock_node_exists.return_value = node
|
|
87
|
+
model = {'runArgs': {'runNonMeasured': True}}
|
|
88
|
+
|
|
89
|
+
# term measured => no run
|
|
90
|
+
node['methodTier'] = 'measured'
|
|
91
|
+
assert not should_run(data, model)
|
|
92
|
+
|
|
93
|
+
# term not measured => run
|
|
94
|
+
node['methodTier'] = 'background'
|
|
95
|
+
assert should_run(data, model) is True
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@patch(f"{class_path}.get_table_value", return_value='Cycle')
|
|
99
|
+
@patch(f"{class_path}.download_hestia", return_value=FAKE_EMISSION)
|
|
100
|
+
@patch(f"{class_path}.get_required_model_param", return_value='')
|
|
101
|
+
@patch(f"{class_path}.find_term_match")
|
|
102
|
+
def test_should_run_check_typeAllowed(mock_node_exists, *args):
|
|
103
|
+
data = {}
|
|
104
|
+
node = {'term': FAKE_EMISSION}
|
|
105
|
+
mock_node_exists.return_value = node
|
|
106
|
+
model = {}
|
|
107
|
+
|
|
108
|
+
# type is not allowed => no run
|
|
109
|
+
data['@type'] = 'Transformation'
|
|
110
|
+
assert not should_run(data, model)
|
|
111
|
+
|
|
112
|
+
# type is allowed => run
|
|
113
|
+
data['@type'] = 'Cycle'
|
|
114
|
+
assert should_run(data, model) is True
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from hestia_earth.orchestrator.strategies.run.add_key_if_missing import should_run
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_should_run():
|
|
5
|
+
data = {}
|
|
6
|
+
key = 'model-key'
|
|
7
|
+
model = {'key': key}
|
|
8
|
+
|
|
9
|
+
# key not in data => run
|
|
10
|
+
assert should_run(data, model) is True
|
|
11
|
+
|
|
12
|
+
# key in data => no run
|
|
13
|
+
data[key] = 10
|
|
14
|
+
assert not should_run(data, model)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
import pytest
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from tests.utils import fixtures_path
|
|
7
|
+
from hestia_earth.orchestrator.models import run, _run_parallel, _filter_models_stage
|
|
8
|
+
|
|
9
|
+
class_path = 'hestia_earth.orchestrator.models'
|
|
10
|
+
folder_path = os.path.join(fixtures_path, 'orchestrator', 'cycle')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@patch('hestia_earth.orchestrator.strategies.merge._merge_version', return_value='0.0.0')
|
|
14
|
+
def test_run(*args):
|
|
15
|
+
with open(os.path.join(folder_path, 'config.json'), encoding='utf-8') as f:
|
|
16
|
+
config = json.load(f)
|
|
17
|
+
with open(os.path.join(folder_path, 'cycle.jsonld'), encoding='utf-8') as f:
|
|
18
|
+
cycle = json.load(f)
|
|
19
|
+
with open(os.path.join(folder_path, 'result.jsonld'), encoding='utf-8') as f:
|
|
20
|
+
expected = json.load(f)
|
|
21
|
+
|
|
22
|
+
result = run(cycle, config.get('models'))
|
|
23
|
+
assert result == expected
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@patch(f"{class_path}._run_model", side_effect=Exception('error'))
|
|
27
|
+
def test_run_parallel_with_errors(*args):
|
|
28
|
+
data = {
|
|
29
|
+
'@type': 'Cycle',
|
|
30
|
+
'@id': 'cycle'
|
|
31
|
+
}
|
|
32
|
+
model = [{'key': 'model1'}, {'key': 'model2'}]
|
|
33
|
+
|
|
34
|
+
with pytest.raises(Exception):
|
|
35
|
+
_run_parallel(data, model, [])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_filter_models_stage():
|
|
39
|
+
models = json.load(open(os.path.join(fixtures_path, 'orchestrator', 'stages', 'config.json'))).get('models')
|
|
40
|
+
assert _filter_models_stage(models) == models
|
|
41
|
+
assert _filter_models_stage(models, 1) == [
|
|
42
|
+
{
|
|
43
|
+
"key": "model1",
|
|
44
|
+
"stage": 1
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"key": "model2",
|
|
48
|
+
"stage": 1
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
assert _filter_models_stage(models, 2) == [
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
"key": "model3",
|
|
55
|
+
"stage": 2
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"key": "model4",
|
|
59
|
+
"stage": 2
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
]
|
|
63
|
+
assert _filter_models_stage(models, 3) == [
|
|
64
|
+
{
|
|
65
|
+
"key": "model5",
|
|
66
|
+
"stage": 3
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
assert _filter_models_stage(models, [1, 2, 3]) == models
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from hestia_earth.orchestrator import run
|
|
5
|
+
|
|
6
|
+
config = {'models': []}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@patch('hestia_earth.orchestrator.run_models', return_value={})
|
|
10
|
+
def test_run(mock_run_models, *args):
|
|
11
|
+
run({'@type': 'Cycle'}, config)
|
|
12
|
+
mock_run_models.assert_called_once()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_run_missing_type():
|
|
16
|
+
with pytest.raises(Exception, match='Please provide an "@type" key in your data.'):
|
|
17
|
+
run({}, config)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_run_missing_config():
|
|
21
|
+
with pytest.raises(Exception, match='Please provide a valid configuration.'):
|
|
22
|
+
run({'@type': 'Cycle'}, None)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_run_missing_models():
|
|
26
|
+
with pytest.raises(Exception, match='Please provide a valid configuration.'):
|
|
27
|
+
run({'@type': 'Cycle'}, {})
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from hestia_earth.orchestrator.utils import update_node_version
|
|
2
|
+
|
|
3
|
+
version = '2'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_update_node_version():
|
|
7
|
+
current_data = {
|
|
8
|
+
'key1': 50,
|
|
9
|
+
'key2': 100
|
|
10
|
+
}
|
|
11
|
+
new_data = {
|
|
12
|
+
'key2': 200,
|
|
13
|
+
'key3': 300,
|
|
14
|
+
'key4': {}
|
|
15
|
+
}
|
|
16
|
+
assert update_node_version(version, new_data, current_data) == {
|
|
17
|
+
**new_data,
|
|
18
|
+
'added': ['key3', 'key4'],
|
|
19
|
+
'addedVersion': [version, version],
|
|
20
|
+
'updated': ['key2'],
|
|
21
|
+
'updatedVersion': [version]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_update_node_version_deep():
|
|
26
|
+
current_data = {
|
|
27
|
+
'object': {
|
|
28
|
+
'first': True
|
|
29
|
+
},
|
|
30
|
+
'values': [
|
|
31
|
+
{
|
|
32
|
+
'term': {'@type': 'Term'},
|
|
33
|
+
'value': [500],
|
|
34
|
+
'properties': [
|
|
35
|
+
{
|
|
36
|
+
'term': {'@type': 'Term', '@id': 'Prop1'},
|
|
37
|
+
'value': 100
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
new_data = {
|
|
44
|
+
'object': {
|
|
45
|
+
'first': True,
|
|
46
|
+
'second': False
|
|
47
|
+
},
|
|
48
|
+
'values': [
|
|
49
|
+
{
|
|
50
|
+
'term': {'@type': 'Term'},
|
|
51
|
+
'value': [500],
|
|
52
|
+
'min': [100],
|
|
53
|
+
'properties': [
|
|
54
|
+
{
|
|
55
|
+
'term': {'@type': 'Term', '@id': 'Prop1'},
|
|
56
|
+
'value': 10
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
'term': {'@type': 'Term', '@id': 'Prop2'},
|
|
60
|
+
'value': 20
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
'term': {'@type': 'Term', '@id': 'Test2'}
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
result = update_node_version(version, new_data, current_data)
|
|
70
|
+
assert result == {
|
|
71
|
+
'object': {
|
|
72
|
+
'first': True,
|
|
73
|
+
'second': False,
|
|
74
|
+
'added': ['second'],
|
|
75
|
+
'addedVersion': [version]
|
|
76
|
+
},
|
|
77
|
+
'values': [
|
|
78
|
+
{
|
|
79
|
+
'term': {'@type': 'Term'},
|
|
80
|
+
'value': [500],
|
|
81
|
+
'min': [100],
|
|
82
|
+
'properties': [
|
|
83
|
+
{
|
|
84
|
+
'term': {'@type': 'Term', '@id': 'Prop1'},
|
|
85
|
+
'value': 10,
|
|
86
|
+
'updated': ['value'],
|
|
87
|
+
'updatedVersion': [version]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
'term': {'@type': 'Term', '@id': 'Prop2'},
|
|
91
|
+
'value': 20,
|
|
92
|
+
'added': ['term', 'value'],
|
|
93
|
+
'addedVersion': [version, version]
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
'added': ['min'],
|
|
97
|
+
'addedVersion': [version],
|
|
98
|
+
'updated': ['properties'],
|
|
99
|
+
'updatedVersion': [version]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
'term': {'@type': 'Term', '@id': 'Test2'},
|
|
103
|
+
'added': ['term'],
|
|
104
|
+
'addedVersion': [version]
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
'updated': ['object', 'values'],
|
|
108
|
+
'updatedVersion': [version, version]
|
|
109
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|