hestia-earth-models 0.64.13__py3-none-any.whl → 0.65.0__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/agribalyse2016/fuelElectricity.py +1 -1
- hestia_earth/models/cache_sites.py +15 -24
- hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +6 -9
- hestia_earth/models/cycle/input/hestiaAggregatedData.py +46 -22
- hestia_earth/models/cycle/materialAndSubstrate.py +158 -0
- hestia_earth/models/cycle/pre_checks/cache_sources.py +3 -25
- hestia_earth/models/cycle/product/economicValueShare.py +2 -2
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +11 -33
- hestia_earth/models/faostat2018/landTransformation100YearAverageDuringCycle.py +34 -0
- hestia_earth/models/faostat2018/landTransformation20YearAverageDuringCycle.py +34 -0
- hestia_earth/models/faostat2018/utils.py +47 -3
- hestia_earth/models/hestia/landCover.py +5 -5
- hestia_earth/models/hestia/seed_emissions.py +275 -0
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +2 -2
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +8 -2
- hestia_earth/models/ipcc2019/biomass_utils.py +11 -4
- hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +21 -12
- hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -2
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +2 -1
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +2 -1
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +8 -7
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +2 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +28 -34
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +8 -12
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +13 -30
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland20YearAverageInputsProduction.py → landTransformation100YearAverageInputsProduction.py} +5 -2
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland100YearAverageInputsProduction.py → landTransformation20YearAverageInputsProduction.py} +5 -2
- hestia_earth/models/linkedImpactAssessment/utils.py +69 -12
- hestia_earth/models/mocking/__init__.py +1 -1
- hestia_earth/models/mocking/search-results.json +1026 -1026
- hestia_earth/models/pooreNemecek2018/excretaKgN.py +45 -41
- hestia_earth/models/pooreNemecek2018/excretaKgVs.py +89 -63
- hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +8 -8
- hestia_earth/models/pooreNemecek2018/utils.py +60 -19
- hestia_earth/models/preload_requests.py +24 -4
- hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +4 -3
- hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +4 -3
- hestia_earth/models/schererPfister2015/utils.py +12 -9
- hestia_earth/models/site/management.py +70 -55
- hestia_earth/models/site/pre_checks/cache_sources.py +2 -20
- hestia_earth/models/utils/__init__.py +12 -1
- hestia_earth/models/utils/aggregated.py +1 -1
- hestia_earth/models/utils/blank_node.py +20 -12
- hestia_earth/models/utils/cache_sources.py +15 -0
- hestia_earth/models/utils/constant.py +3 -0
- hestia_earth/models/utils/crop.py +5 -0
- hestia_earth/models/utils/indicator.py +3 -1
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/RECORD +81 -108
- tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +1 -1
- tests/models/cycle/input/test_hestiaAggregatedData.py +5 -2
- tests/models/cycle/test_materialsAndSubstrate.py +49 -0
- tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +39 -28
- tests/models/{hyde32/test_landTransformationFromForest20YearAverageDuringCycle.py → faostat2018/test_landTransformation100YearAverageDuringCycle.py} +5 -5
- tests/models/{hyde32/test_landTransformationFromForest100YearAverageDuringCycle.py → faostat2018/test_landTransformation20YearAverageDuringCycle.py} +5 -5
- tests/models/faostat2018/test_utils.py +28 -0
- tests/models/hestia/test_landCover.py +2 -1
- tests/models/hestia/test_seed_emissions.py +27 -0
- tests/models/ipcc2019/test_aboveGroundBiomass.py +40 -4
- tests/models/ipcc2019/test_belowGroundBiomass.py +40 -4
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +52 -15
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +50 -14
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +53 -32
- tests/models/ipcc2019/test_organicCarbonPerHa.py +91 -108
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +33 -50
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -52
- tests/models/linkedImpactAssessment/test_freshwaterWithdrawalsInputsProduction.py +6 -4
- tests/models/linkedImpactAssessment/test_landOccupationInputsProduction.py +6 -4
- tests/models/linkedImpactAssessment/{test_landTransformationFromForest100YearAverageInputsProduction.py → test_landTransformation100YearAverageInputsProduction.py} +7 -5
- tests/models/linkedImpactAssessment/{test_landTransformationFromForest20YearAverageInputsProduction.py → test_landTransformation20YearAverageInputsProduction.py} +7 -5
- tests/models/pooreNemecek2018/test_excretaKgN.py +2 -2
- tests/models/pooreNemecek2018/test_excretaKgVs.py +1 -1
- tests/models/pooreNemecek2018/test_utils.py +26 -0
- tests/models/site/test_management.py +10 -27
- tests/models/test_cache_sites.py +40 -12
- tests/models/utils/test_blank_node.py +0 -8
- tests/models/utils/test_cache_sources.py +21 -0
- hestia_earth/models/blonkConsultants2016/landTransformationFromForest20YearAverageDuringCycle.py +0 -90
- hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +0 -74
- hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +0 -74
- hestia_earth/models/hyde32/__init__.py +0 -13
- hestia_earth/models/hyde32/landTransformationFromCropland100YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromCropland20YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromForest100YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromForest20YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/utils.py +0 -72
- hestia_earth/models/linkedImpactAssessment/landTransformationFromForest100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromForest20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -36
- tests/models/blonkConsultants2016/test_landTransformationFromForest20YearAverageDuringCycle.py +0 -36
- tests/models/cycle/pre_checks/test_cache_sources.py +0 -25
- tests/models/faostat2018/test_landTransformationFromCropland100YearAverage.py +0 -40
- tests/models/faostat2018/test_landTransformationFromCropland20YearAverage.py +0 -40
- tests/models/hyde32/__init__.py +0 -0
- tests/models/hyde32/test_landTransformationFromCropland100YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromCropland20YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -23
- tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -21
- tests/models/linkedImpactAssessment/test_landTransformationFromCropland100YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromCropland20YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -24
- tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -24
- tests/models/site/pre_checks/test_cache_sources.py +0 -21
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from unittest.mock import patch
|
|
2
|
+
from unittest.mock import Mock, patch
|
|
3
3
|
|
|
4
4
|
from pytest import mark
|
|
5
5
|
|
|
6
|
-
from hestia_earth.models.environmentalFootprintV3.soilQualityIndexLandTransformation import
|
|
7
|
-
_should_run
|
|
6
|
+
from hestia_earth.models.environmentalFootprintV3.soilQualityIndexLandTransformation import (
|
|
7
|
+
MODEL, TERM_ID, run, _should_run
|
|
8
|
+
)
|
|
8
9
|
from tests.utils import fixtures_path, fake_new_indicator
|
|
9
10
|
|
|
10
11
|
class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
|
|
@@ -17,55 +18,70 @@ def fake_rounded_indicator(value: float):
|
|
|
17
18
|
return indicator
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
land_cover_terms = ['cropland', 'seaOrOcean', 'forest']
|
|
20
22
|
crop_land = {"@id": "cropland", "termType": "landCover"}
|
|
21
23
|
sea_land_cover = {"@id": "seaOrOcean", "termType": "landCover"}
|
|
22
24
|
forest = {"@id": "forest", "termType": "landCover"}
|
|
25
|
+
indicator = {
|
|
26
|
+
"@id": "landTransformation20YearAverageInputsProduction",
|
|
27
|
+
"termType": "resourceUse",
|
|
28
|
+
"units": "m2 / year"
|
|
29
|
+
}
|
|
23
30
|
|
|
24
31
|
wrong_indicator = {"term": {"@id": "NOT_VALID_INDICATOR_ID", "termType": "resourceUse", "units": "m2 / year"},
|
|
25
32
|
"value": 0.5, "landCover": crop_land}
|
|
26
33
|
|
|
27
34
|
indicator_no_land_cover = {
|
|
28
|
-
"term":
|
|
29
|
-
|
|
35
|
+
"term": indicator,
|
|
36
|
+
"previousLandCover": forest,
|
|
30
37
|
"value": 0.5}
|
|
31
38
|
|
|
32
39
|
indicator_no_unit = {
|
|
33
|
-
"term":
|
|
34
|
-
"
|
|
40
|
+
"term": indicator,
|
|
41
|
+
"previousLandCover": forest,
|
|
42
|
+
"value": 0.5,
|
|
43
|
+
"landCover": crop_land}
|
|
35
44
|
|
|
36
45
|
indicator_wrong_unit = {
|
|
37
|
-
"term":
|
|
38
|
-
|
|
46
|
+
"term": indicator,
|
|
47
|
+
"value": 0.5,
|
|
48
|
+
"previousLandCover": forest,
|
|
39
49
|
"landCover": crop_land}
|
|
40
50
|
|
|
41
51
|
indicator_bad_area_value = {
|
|
42
|
-
"term":
|
|
43
|
-
|
|
52
|
+
"term": indicator,
|
|
53
|
+
"value": -10,
|
|
54
|
+
"previousLandCover": forest,
|
|
44
55
|
"landCover": crop_land}
|
|
45
56
|
|
|
46
57
|
inputs_production_indicator_from_forest_to_no_cf = {
|
|
47
|
-
"term":
|
|
48
|
-
|
|
58
|
+
"term": indicator,
|
|
59
|
+
"value": 0.5,
|
|
60
|
+
"previousLandCover": forest,
|
|
49
61
|
"landCover": sea_land_cover}
|
|
50
62
|
|
|
51
63
|
good_inputs_production_indicator_from_forest_to_cropland = {
|
|
52
|
-
"term":
|
|
53
|
-
|
|
64
|
+
"term": indicator,
|
|
65
|
+
"value": 0.5,
|
|
66
|
+
"previousLandCover": forest,
|
|
54
67
|
"landCover": crop_land}
|
|
55
68
|
|
|
56
69
|
good_inputs_production_indicator_from_forest_to_forest = {
|
|
57
|
-
"term":
|
|
58
|
-
|
|
70
|
+
"term": indicator,
|
|
71
|
+
"value": 0.5,
|
|
72
|
+
"previousLandCover": forest,
|
|
59
73
|
"landCover": forest}
|
|
60
74
|
|
|
61
75
|
good_during_cycle_indicator_from_forest_to_cropland = {
|
|
62
|
-
"term":
|
|
63
|
-
|
|
76
|
+
"term": indicator,
|
|
77
|
+
"value": 0.5,
|
|
78
|
+
"previousLandCover": forest,
|
|
64
79
|
"landCover": crop_land}
|
|
65
80
|
|
|
66
81
|
good_during_cycle_indicator_from_forest_to_forest = {
|
|
67
|
-
"term":
|
|
68
|
-
|
|
82
|
+
"term": indicator,
|
|
83
|
+
"value": 0.5,
|
|
84
|
+
"previousLandCover": forest,
|
|
69
85
|
"landCover": forest}
|
|
70
86
|
|
|
71
87
|
|
|
@@ -75,8 +91,6 @@ good_during_cycle_indicator_from_forest_to_forest = {
|
|
|
75
91
|
([], True, 0),
|
|
76
92
|
([wrong_indicator], True, 0),
|
|
77
93
|
([indicator_no_land_cover], False, 0),
|
|
78
|
-
([indicator_no_unit], False, 0),
|
|
79
|
-
([indicator_wrong_unit], False, 0),
|
|
80
94
|
([indicator_bad_area_value], False, 0),
|
|
81
95
|
([good_during_cycle_indicator_from_forest_to_cropland], True, 1),
|
|
82
96
|
([good_during_cycle_indicator_from_forest_to_forest], True, 1),
|
|
@@ -89,8 +103,6 @@ good_during_cycle_indicator_from_forest_to_forest = {
|
|
|
89
103
|
ids=["No emissionsResourceUse => run, 0 dict",
|
|
90
104
|
"Wrong indicator termid => run, 0 dict",
|
|
91
105
|
"Indicator no landcover terms => no run",
|
|
92
|
-
"Missing unit => no run",
|
|
93
|
-
"Wrong unit => no run",
|
|
94
106
|
"Bad m2 / year value => no run",
|
|
95
107
|
"One good during cycle transformation => run, 1 dict",
|
|
96
108
|
"One 0 during cycle transformation => run, 1 dict",
|
|
@@ -100,8 +112,7 @@ good_during_cycle_indicator_from_forest_to_forest = {
|
|
|
100
112
|
"Multiple good indicators => run, 2 dict",
|
|
101
113
|
]
|
|
102
114
|
)
|
|
103
|
-
|
|
104
|
-
def test_should_run(mock_download, resources, expected, num_inputs):
|
|
115
|
+
def test_should_run(resources: list, expected: bool, num_inputs: int):
|
|
105
116
|
with open(f"{fixtures_folder}/multipleTransformations/impact-assessment.jsonld", encoding='utf-8') as f:
|
|
106
117
|
impact = json.load(f)
|
|
107
118
|
|
|
@@ -146,7 +157,7 @@ def test_run_italy(*args):
|
|
|
146
157
|
"region-europe not in the lookup file => default to region world"]
|
|
147
158
|
)
|
|
148
159
|
@patch(f"{class_path}._indicator", side_effect=fake_rounded_indicator)
|
|
149
|
-
def test_run_with_country_fallback(mocked_indicator, added_data):
|
|
160
|
+
def test_run_with_country_fallback(mocked_indicator: Mock, added_data: dict):
|
|
150
161
|
"""
|
|
151
162
|
When given valid sub-region or country not in the lookup file, default to country 'region-world' with value 574.56
|
|
152
163
|
"""
|
|
@@ -2,14 +2,14 @@ from unittest.mock import patch
|
|
|
2
2
|
import json
|
|
3
3
|
from tests.utils import fixtures_path, fake_new_indicator
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.
|
|
5
|
+
from hestia_earth.models.faostat2018 import MODEL
|
|
6
|
+
from hestia_earth.models.faostat2018.landTransformation100YearAverageDuringCycle import TERM_ID, run
|
|
6
7
|
|
|
7
|
-
class_path = f"hestia_earth.models.
|
|
8
|
-
fixtures_folder = f"{fixtures_path}/
|
|
8
|
+
class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
|
|
9
|
+
fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
@patch(
|
|
12
|
-
@patch('hestia_earth.models.hyde32.utils._new_indicator', side_effect=fake_new_indicator)
|
|
12
|
+
@patch(f"hestia_earth.models.{MODEL}.utils._new_indicator", side_effect=fake_new_indicator)
|
|
13
13
|
def test_run(*args):
|
|
14
14
|
with open(f"{fixtures_folder}/impact-assessment.jsonld", encoding='utf-8') as f:
|
|
15
15
|
cycle = json.load(f)
|
|
@@ -2,14 +2,14 @@ from unittest.mock import patch
|
|
|
2
2
|
import json
|
|
3
3
|
from tests.utils import fixtures_path, fake_new_indicator
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.
|
|
5
|
+
from hestia_earth.models.faostat2018 import MODEL
|
|
6
|
+
from hestia_earth.models.faostat2018.landTransformation20YearAverageDuringCycle import TERM_ID, run
|
|
6
7
|
|
|
7
|
-
class_path = f"hestia_earth.models.
|
|
8
|
-
fixtures_folder = f"{fixtures_path}/
|
|
8
|
+
class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
|
|
9
|
+
fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
@patch(
|
|
12
|
-
@patch('hestia_earth.models.hyde32.utils._new_indicator', side_effect=fake_new_indicator)
|
|
12
|
+
@patch(f"hestia_earth.models.{MODEL}.utils._new_indicator", side_effect=fake_new_indicator)
|
|
13
13
|
def test_run(*args):
|
|
14
14
|
with open(f"{fixtures_folder}/impact-assessment.jsonld", encoding='utf-8') as f:
|
|
15
15
|
cycle = json.load(f)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from hestia_earth.models.faostat2018.utils import should_run_landTransformationFromCropland
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_should_run_landTransformationFromCropland():
|
|
5
|
+
impact = {}
|
|
6
|
+
term_id = 'term'
|
|
7
|
+
|
|
8
|
+
# no indicator => no run
|
|
9
|
+
should_run, *args = should_run_landTransformationFromCropland(term_id, impact)
|
|
10
|
+
assert not should_run
|
|
11
|
+
|
|
12
|
+
# with indicator value 0 => no run
|
|
13
|
+
impact['emissionsResourceUse'] = [{
|
|
14
|
+
'term': {'@id': term_id},
|
|
15
|
+
'previousLandCover': {'@id': 'cropland'},
|
|
16
|
+
'value': 0
|
|
17
|
+
}]
|
|
18
|
+
should_run, *args = should_run_landTransformationFromCropland(term_id, impact)
|
|
19
|
+
assert not should_run
|
|
20
|
+
|
|
21
|
+
# with indicator => run
|
|
22
|
+
impact['emissionsResourceUse'] = [{
|
|
23
|
+
'term': {'@id': term_id},
|
|
24
|
+
'previousLandCover': {'@id': 'cropland'},
|
|
25
|
+
'value': 10
|
|
26
|
+
}]
|
|
27
|
+
should_run, *args = should_run_landTransformationFromCropland(term_id, impact)
|
|
28
|
+
assert should_run is True
|
|
@@ -194,7 +194,8 @@ def test_get_sums_of_crop_expansion():
|
|
|
194
194
|
"brazil_example",
|
|
195
195
|
"zimbabwe_example",
|
|
196
196
|
"brazil_empty_example",
|
|
197
|
-
"gbr_example"
|
|
197
|
+
"gbr_example",
|
|
198
|
+
"malaysia"
|
|
198
199
|
]
|
|
199
200
|
)
|
|
200
201
|
@patch(f"{CLASS_PATH}._new_management", side_effect=fake_new_management)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import pytest
|
|
4
|
+
from unittest.mock import patch, Mock
|
|
5
|
+
from tests.utils import fixtures_path, fake_new_emission
|
|
6
|
+
|
|
7
|
+
from hestia_earth.models.hestia.seed_emissions import MODEL, MODEL_KEY, run
|
|
8
|
+
|
|
9
|
+
class_path = f"hestia_earth.models.{MODEL}.{MODEL_KEY}"
|
|
10
|
+
fixtures_folder = os.path.join(fixtures_path, MODEL, MODEL_KEY)
|
|
11
|
+
|
|
12
|
+
_folders = [d for d in os.listdir(fixtures_folder) if os.path.isdir(os.path.join(fixtures_folder, d))]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.parametrize('folder', _folders)
|
|
16
|
+
@patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
|
|
17
|
+
def test_run(mock_emission: Mock, folder: str):
|
|
18
|
+
fixture_path = os.path.join(fixtures_folder, folder)
|
|
19
|
+
|
|
20
|
+
with open(f"{fixture_path}/cycle.jsonld", encoding='utf-8') as f:
|
|
21
|
+
cycle = json.load(f)
|
|
22
|
+
|
|
23
|
+
with open(f"{fixture_path}/result.jsonld", encoding='utf-8') as f:
|
|
24
|
+
expected = json.load(f)
|
|
25
|
+
|
|
26
|
+
result = run(cycle)
|
|
27
|
+
assert result == expected, folder
|
|
@@ -12,12 +12,18 @@ from tests.utils import fake_new_measurement, fixtures_path
|
|
|
12
12
|
class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
|
|
13
13
|
utils_path = f"hestia_earth.models.{MODEL}.biomass_utils"
|
|
14
14
|
term_path = "hestia_earth.models.utils.term"
|
|
15
|
-
property_path = "hestia_earth.models.utils.property"
|
|
16
|
-
|
|
17
15
|
fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
|
|
18
16
|
|
|
19
17
|
_ITERATIONS = 1000
|
|
20
18
|
|
|
19
|
+
COVER_CROP_PROPERTY_TERM_IDS = [
|
|
20
|
+
"catchCrop",
|
|
21
|
+
"coverCrop",
|
|
22
|
+
"groundCover",
|
|
23
|
+
"longFallowCrop",
|
|
24
|
+
"shortFallowCrop"
|
|
25
|
+
]
|
|
26
|
+
|
|
21
27
|
|
|
22
28
|
def _load_fixture(path: str, default=None):
|
|
23
29
|
if isfile(path):
|
|
@@ -40,6 +46,7 @@ PARAMS_SHOULD_RUN = [
|
|
|
40
46
|
("forest-to-cropland-lcc-q4", True),
|
|
41
47
|
("forest-to-gohac", False),
|
|
42
48
|
("forest-to-orchard", True),
|
|
49
|
+
("forest-to-orchard-with-ground-cover", True), # Closes 989
|
|
43
50
|
("forest-to-orchard-with-backup-factors", True),
|
|
44
51
|
("forest-to-orchard-with-in-category-lcc", True),
|
|
45
52
|
("historical-land-cover-mix", True),
|
|
@@ -52,7 +59,14 @@ IDS_SHOULD_RUN = [p[0] for p in PARAMS_SHOULD_RUN]
|
|
|
52
59
|
|
|
53
60
|
|
|
54
61
|
@mark.parametrize("subfolder, should_run", PARAMS_SHOULD_RUN, ids=IDS_SHOULD_RUN)
|
|
55
|
-
|
|
62
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
63
|
+
@patch(f"{term_path}.search")
|
|
64
|
+
def test_should_run(
|
|
65
|
+
search_mock: MagicMock,
|
|
66
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
67
|
+
subfolder: str,
|
|
68
|
+
should_run: bool
|
|
69
|
+
):
|
|
56
70
|
folder = f"{fixtures_folder}/{subfolder}"
|
|
57
71
|
|
|
58
72
|
site = _load_fixture(f"{folder}/site.jsonld", {})
|
|
@@ -60,14 +74,22 @@ def test_should_run(subfolder: str, should_run: bool):
|
|
|
60
74
|
result, *_ = _should_run(site)
|
|
61
75
|
assert result == should_run
|
|
62
76
|
|
|
77
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
78
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
63
79
|
|
|
64
|
-
|
|
80
|
+
|
|
81
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
82
|
+
@patch(f"{term_path}.search")
|
|
83
|
+
def test_should_run_no_data(search_mock: MagicMock, get_cover_crop_property_terms_mock: MagicMock,):
|
|
65
84
|
SITE = {}
|
|
66
85
|
EXPECTED = False
|
|
67
86
|
|
|
68
87
|
result, *_ = _should_run(SITE)
|
|
69
88
|
assert result == EXPECTED
|
|
70
89
|
|
|
90
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only performed once
|
|
91
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
92
|
+
|
|
71
93
|
|
|
72
94
|
PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should_run]
|
|
73
95
|
|
|
@@ -76,7 +98,11 @@ PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should
|
|
|
76
98
|
@patch(f"{class_path}.calc_descriptive_stats", side_effect=_fake_calc_descriptive_stats)
|
|
77
99
|
@patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
|
|
78
100
|
@patch(f"{utils_path}._get_sample_func", return_value=sample_constant)
|
|
101
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
102
|
+
@patch(f"{term_path}.search")
|
|
79
103
|
def test_run(
|
|
104
|
+
search_mock: MagicMock,
|
|
105
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
80
106
|
_get_sample_func_mock: MagicMock,
|
|
81
107
|
_new_measurement_mock: MagicMock,
|
|
82
108
|
_calc_descriptive_stats_mock: MagicMock,
|
|
@@ -92,6 +118,9 @@ def test_run(
|
|
|
92
118
|
|
|
93
119
|
assert result == expected
|
|
94
120
|
|
|
121
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only performed once
|
|
122
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
123
|
+
|
|
95
124
|
|
|
96
125
|
# subfolder
|
|
97
126
|
PARAMS_RUN_WITH_STATS = [
|
|
@@ -103,7 +132,11 @@ PARAMS_RUN_WITH_STATS = [
|
|
|
103
132
|
|
|
104
133
|
@mark.parametrize("subfolder", PARAMS_RUN_WITH_STATS)
|
|
105
134
|
@patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
|
|
135
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
136
|
+
@patch(f"{term_path}.search")
|
|
106
137
|
def test_run_with_stats(
|
|
138
|
+
search_mock: MagicMock,
|
|
139
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
107
140
|
_new_measurement_mock: MagicMock,
|
|
108
141
|
subfolder: str
|
|
109
142
|
):
|
|
@@ -117,6 +150,9 @@ def test_run_with_stats(
|
|
|
117
150
|
|
|
118
151
|
assert result == expected
|
|
119
152
|
|
|
153
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only performed once
|
|
154
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
155
|
+
|
|
120
156
|
|
|
121
157
|
# input, expected
|
|
122
158
|
PARAMS_BUILD_COLUMN_NAME = [
|
|
@@ -12,12 +12,18 @@ from tests.utils import fake_new_measurement, fixtures_path
|
|
|
12
12
|
class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
|
|
13
13
|
utils_path = f"hestia_earth.models.{MODEL}.biomass_utils"
|
|
14
14
|
term_path = "hestia_earth.models.utils.term"
|
|
15
|
-
property_path = "hestia_earth.models.utils.property"
|
|
16
|
-
|
|
17
15
|
fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
|
|
18
16
|
|
|
19
17
|
_ITERATIONS = 1000
|
|
20
18
|
|
|
19
|
+
COVER_CROP_PROPERTY_TERM_IDS = [
|
|
20
|
+
"catchCrop",
|
|
21
|
+
"coverCrop",
|
|
22
|
+
"groundCover",
|
|
23
|
+
"longFallowCrop",
|
|
24
|
+
"shortFallowCrop"
|
|
25
|
+
]
|
|
26
|
+
|
|
21
27
|
|
|
22
28
|
def _load_fixture(path: str, default=None):
|
|
23
29
|
if isfile(path):
|
|
@@ -41,6 +47,7 @@ PARAMS_SHOULD_RUN = [
|
|
|
41
47
|
("forest-to-cropland-lcc-q4", True),
|
|
42
48
|
("forest-to-gohac", False),
|
|
43
49
|
("forest-to-orchard", True),
|
|
50
|
+
("forest-to-orchard-with-ground-cover", True), # Closes 989
|
|
44
51
|
("forest-to-orchard-with-in-category-lcc", True),
|
|
45
52
|
("historical-land-cover-mix", True),
|
|
46
53
|
("historical-argentina-pasture", True),
|
|
@@ -52,7 +59,14 @@ IDS_SHOULD_RUN = [p[0] for p in PARAMS_SHOULD_RUN]
|
|
|
52
59
|
|
|
53
60
|
|
|
54
61
|
@mark.parametrize("subfolder, should_run", PARAMS_SHOULD_RUN, ids=IDS_SHOULD_RUN)
|
|
55
|
-
|
|
62
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
63
|
+
@patch(f"{term_path}.search")
|
|
64
|
+
def test_should_run(
|
|
65
|
+
search_mock: MagicMock,
|
|
66
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
67
|
+
subfolder: str,
|
|
68
|
+
should_run: bool
|
|
69
|
+
):
|
|
56
70
|
folder = f"{fixtures_folder}/{subfolder}"
|
|
57
71
|
|
|
58
72
|
site = _load_fixture(f"{folder}/site.jsonld", {})
|
|
@@ -60,14 +74,22 @@ def test_should_run(subfolder: str, should_run: bool):
|
|
|
60
74
|
result, *_ = _should_run(site)
|
|
61
75
|
assert result == should_run
|
|
62
76
|
|
|
77
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
78
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
63
79
|
|
|
64
|
-
|
|
80
|
+
|
|
81
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
82
|
+
@patch(f"{term_path}.search")
|
|
83
|
+
def test_should_run_no_data(search_mock: MagicMock, get_cover_crop_property_terms_mock: MagicMock):
|
|
65
84
|
SITE = {}
|
|
66
85
|
EXPECTED = False
|
|
67
86
|
|
|
68
87
|
result, *_ = _should_run(SITE)
|
|
69
88
|
assert result == EXPECTED
|
|
70
89
|
|
|
90
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
91
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
92
|
+
|
|
71
93
|
|
|
72
94
|
PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should_run]
|
|
73
95
|
|
|
@@ -76,7 +98,11 @@ PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should
|
|
|
76
98
|
@patch(f"{class_path}.calc_descriptive_stats", side_effect=_fake_calc_descriptive_stats)
|
|
77
99
|
@patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
|
|
78
100
|
@patch(f"{utils_path}._get_sample_func", return_value=sample_constant)
|
|
101
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
102
|
+
@patch(f"{term_path}.search")
|
|
79
103
|
def test_run(
|
|
104
|
+
search_mock: MagicMock,
|
|
105
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
80
106
|
_get_sample_func_mock: MagicMock,
|
|
81
107
|
_new_measurement_mock: MagicMock,
|
|
82
108
|
_calc_descriptive_stats_mock: MagicMock,
|
|
@@ -92,6 +118,9 @@ def test_run(
|
|
|
92
118
|
|
|
93
119
|
assert result == expected
|
|
94
120
|
|
|
121
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
122
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
123
|
+
|
|
95
124
|
|
|
96
125
|
# subfolder
|
|
97
126
|
PARAMS_RUN_WITH_STATS = [
|
|
@@ -103,7 +132,11 @@ PARAMS_RUN_WITH_STATS = [
|
|
|
103
132
|
|
|
104
133
|
@mark.parametrize("subfolder", PARAMS_RUN_WITH_STATS)
|
|
105
134
|
@patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
|
|
135
|
+
@patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
136
|
+
@patch(f"{term_path}.search")
|
|
106
137
|
def test_run_with_stats(
|
|
138
|
+
search_mock: MagicMock,
|
|
139
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
107
140
|
_new_measurement_mock: MagicMock,
|
|
108
141
|
subfolder: str
|
|
109
142
|
):
|
|
@@ -117,6 +150,9 @@ def test_run_with_stats(
|
|
|
117
150
|
|
|
118
151
|
assert result == expected
|
|
119
152
|
|
|
153
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
154
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
155
|
+
|
|
120
156
|
|
|
121
157
|
# input, expected
|
|
122
158
|
PARAMS_BUILD_COLUMN_NAME = [
|
|
@@ -2,7 +2,7 @@ from functools import reduce
|
|
|
2
2
|
import json
|
|
3
3
|
from os.path import isfile
|
|
4
4
|
from pytest import mark
|
|
5
|
-
from unittest.mock import patch
|
|
5
|
+
from unittest.mock import MagicMock, patch
|
|
6
6
|
|
|
7
7
|
from hestia_earth.models.ipcc2019.co2ToAirAboveGroundBiomassStockChange import MODEL, run
|
|
8
8
|
|
|
@@ -10,8 +10,26 @@ from tests.utils import fake_new_emission, fixtures_path, order_list
|
|
|
10
10
|
|
|
11
11
|
class_path = f"hestia_earth.models.{MODEL}.co2ToAirAboveGroundBiomassStockChange"
|
|
12
12
|
utils_path = f"hestia_earth.models.{MODEL}.co2ToAirCarbonStockChange_utils"
|
|
13
|
+
biomass_utils_path = f"hestia_earth.models.{MODEL}.biomass_utils"
|
|
14
|
+
term_path = "hestia_earth.models.utils.term"
|
|
13
15
|
fixtures_folder = f"{fixtures_path}/{MODEL}/co2ToAirAboveGroundBiomassStockChange"
|
|
14
16
|
|
|
17
|
+
COVER_CROP_PROPERTY_TERM_IDS = [
|
|
18
|
+
"catchCrop",
|
|
19
|
+
"coverCrop",
|
|
20
|
+
"groundCover",
|
|
21
|
+
"longFallowCrop",
|
|
22
|
+
"shortFallowCrop"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _load_fixture(path: str, default=None):
|
|
27
|
+
if isfile(path):
|
|
28
|
+
with open(path, encoding="utf-8") as f:
|
|
29
|
+
return json.load(f)
|
|
30
|
+
return default
|
|
31
|
+
|
|
32
|
+
|
|
15
33
|
RUN_SCENARIOS = [
|
|
16
34
|
("no-overlapping-cycles", 3),
|
|
17
35
|
("overlapping-cycles", 4),
|
|
@@ -22,18 +40,12 @@ RUN_SCENARIOS = [
|
|
|
22
40
|
("multiple-method-classifications", 5), # Closes issue #764
|
|
23
41
|
("non-soil-based-gohac-system", 3), # Closes issue #848
|
|
24
42
|
("soil-based-gohac-system", 3), # Closes issue #848
|
|
25
|
-
("with-gapfilled-start-date-end-date", 1)
|
|
43
|
+
("with-gapfilled-start-date-end-date", 1), # Closes issue #972
|
|
44
|
+
("forest-to-orchard-with-ground-cover", 3) # Closes issue #989
|
|
26
45
|
]
|
|
27
46
|
"""List of (subfolder: str, num_cycles: int)."""
|
|
28
47
|
|
|
29
48
|
|
|
30
|
-
def _load_fixture(path: str, default=None):
|
|
31
|
-
if isfile(path):
|
|
32
|
-
with open(path, encoding="utf-8") as f:
|
|
33
|
-
return json.load(f)
|
|
34
|
-
return default
|
|
35
|
-
|
|
36
|
-
|
|
37
49
|
RUN_PARAMS = reduce(
|
|
38
50
|
lambda params, scenario: params + [(scenario[0], scenario[1], i) for i in range(scenario[1])],
|
|
39
51
|
RUN_SCENARIOS,
|
|
@@ -47,8 +59,19 @@ RUN_IDS = [f"{param[0]}, cycle{param[2]}" for param in RUN_PARAMS]
|
|
|
47
59
|
@mark.parametrize("subfolder, num_cycles, cycle_index", RUN_PARAMS, ids=RUN_IDS)
|
|
48
60
|
@patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
|
|
49
61
|
@patch(f"{utils_path}.related_cycles")
|
|
50
|
-
@patch(f"{utils_path}._get_site")
|
|
51
|
-
|
|
62
|
+
@patch(f"{utils_path}._get_site")
|
|
63
|
+
@patch(f"{biomass_utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
64
|
+
@patch(f"{term_path}.search")
|
|
65
|
+
def test_run(
|
|
66
|
+
search_mock: MagicMock,
|
|
67
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
68
|
+
get_site_mock: MagicMock,
|
|
69
|
+
related_cycles_mock: MagicMock,
|
|
70
|
+
_new_emission_mock: MagicMock,
|
|
71
|
+
subfolder: str,
|
|
72
|
+
num_cycles: int,
|
|
73
|
+
cycle_index: int
|
|
74
|
+
):
|
|
52
75
|
"""
|
|
53
76
|
Test `run` function for each cycle in each scenario.
|
|
54
77
|
"""
|
|
@@ -60,25 +83,39 @@ def test_run(_get_site_mock, related_cycles_mock, _new_emission_mock, subfolder,
|
|
|
60
83
|
_load_fixture(f"{fixtures_folder}/{subfolder}/cycle{i}.jsonld") for i in range(num_cycles)
|
|
61
84
|
]
|
|
62
85
|
|
|
63
|
-
|
|
86
|
+
get_site_mock.return_value = site
|
|
64
87
|
related_cycles_mock.return_value = cycles
|
|
65
88
|
|
|
66
89
|
result = run(cycle)
|
|
67
90
|
assert order_list(result) == order_list(expected)
|
|
68
91
|
|
|
92
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
93
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|
|
94
|
+
|
|
69
95
|
|
|
70
96
|
@patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
|
|
71
97
|
@patch(f"{utils_path}.related_cycles")
|
|
72
|
-
@patch(f"{utils_path}._get_site")
|
|
73
|
-
|
|
98
|
+
@patch(f"{utils_path}._get_site")
|
|
99
|
+
@patch(f"{biomass_utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
|
|
100
|
+
@patch(f"{term_path}.search")
|
|
101
|
+
def test_run_empty(
|
|
102
|
+
search_mock: MagicMock,
|
|
103
|
+
get_cover_crop_property_terms_mock: MagicMock,
|
|
104
|
+
get_site_mock: MagicMock,
|
|
105
|
+
related_cycles_mock: MagicMock,
|
|
106
|
+
_new_emission_mock: MagicMock
|
|
107
|
+
):
|
|
74
108
|
"""
|
|
75
109
|
Test `run` function for each cycle in each scenario.
|
|
76
110
|
"""
|
|
77
111
|
CYCLE = {}
|
|
78
112
|
EXPECTED = []
|
|
79
113
|
|
|
80
|
-
|
|
114
|
+
get_site_mock.return_value = {}
|
|
81
115
|
related_cycles_mock.return_value = [CYCLE]
|
|
82
116
|
|
|
83
117
|
result = run(CYCLE)
|
|
84
118
|
assert result == EXPECTED
|
|
119
|
+
|
|
120
|
+
assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
|
|
121
|
+
search_mock.assert_not_called() # assert the API call is properly mocked
|