hestia-earth-models 0.64.14__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.

Files changed (112) hide show
  1. hestia_earth/models/agribalyse2016/fuelElectricity.py +1 -1
  2. hestia_earth/models/cache_sites.py +15 -24
  3. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +6 -9
  4. hestia_earth/models/cycle/input/hestiaAggregatedData.py +46 -22
  5. hestia_earth/models/cycle/pre_checks/cache_sources.py +3 -25
  6. hestia_earth/models/cycle/product/economicValueShare.py +2 -2
  7. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +11 -33
  8. hestia_earth/models/faostat2018/landTransformation100YearAverageDuringCycle.py +34 -0
  9. hestia_earth/models/faostat2018/landTransformation20YearAverageDuringCycle.py +34 -0
  10. hestia_earth/models/faostat2018/utils.py +47 -3
  11. hestia_earth/models/hestia/landCover.py +5 -5
  12. hestia_earth/models/hestia/seed_emissions.py +275 -0
  13. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +2 -2
  14. hestia_earth/models/ipcc2019/belowGroundBiomass.py +8 -2
  15. hestia_earth/models/ipcc2019/biomass_utils.py +11 -4
  16. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +19 -10
  17. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +2 -1
  18. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +2 -1
  19. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +8 -7
  20. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +2 -1
  21. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +28 -34
  22. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +8 -12
  23. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +13 -30
  24. hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland20YearAverageInputsProduction.py → landTransformation100YearAverageInputsProduction.py} +5 -2
  25. hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland100YearAverageInputsProduction.py → landTransformation20YearAverageInputsProduction.py} +5 -2
  26. hestia_earth/models/linkedImpactAssessment/utils.py +69 -12
  27. hestia_earth/models/mocking/search-results.json +444 -444
  28. hestia_earth/models/pooreNemecek2018/excretaKgN.py +45 -41
  29. hestia_earth/models/pooreNemecek2018/excretaKgVs.py +89 -63
  30. hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +8 -8
  31. hestia_earth/models/pooreNemecek2018/utils.py +60 -19
  32. hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +4 -3
  33. hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +4 -3
  34. hestia_earth/models/schererPfister2015/utils.py +12 -9
  35. hestia_earth/models/site/management.py +70 -55
  36. hestia_earth/models/site/pre_checks/cache_sources.py +2 -20
  37. hestia_earth/models/utils/__init__.py +12 -1
  38. hestia_earth/models/utils/aggregated.py +1 -1
  39. hestia_earth/models/utils/blank_node.py +20 -12
  40. hestia_earth/models/utils/cache_sources.py +15 -0
  41. hestia_earth/models/utils/crop.py +5 -0
  42. hestia_earth/models/utils/indicator.py +3 -1
  43. hestia_earth/models/version.py +1 -1
  44. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/METADATA +2 -2
  45. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/RECORD +75 -104
  46. tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +1 -1
  47. tests/models/cycle/input/test_hestiaAggregatedData.py +5 -2
  48. tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +39 -28
  49. tests/models/{hyde32/test_landTransformationFromForest20YearAverageDuringCycle.py → faostat2018/test_landTransformation100YearAverageDuringCycle.py} +5 -5
  50. tests/models/{hyde32/test_landTransformationFromForest100YearAverageDuringCycle.py → faostat2018/test_landTransformation20YearAverageDuringCycle.py} +5 -5
  51. tests/models/faostat2018/test_utils.py +28 -0
  52. tests/models/hestia/test_landCover.py +2 -1
  53. tests/models/hestia/test_seed_emissions.py +27 -0
  54. tests/models/ipcc2019/test_aboveGroundBiomass.py +40 -4
  55. tests/models/ipcc2019/test_belowGroundBiomass.py +40 -4
  56. tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +52 -15
  57. tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +50 -14
  58. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +53 -32
  59. tests/models/ipcc2019/test_organicCarbonPerHa.py +91 -108
  60. tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +33 -50
  61. tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -52
  62. tests/models/linkedImpactAssessment/test_freshwaterWithdrawalsInputsProduction.py +6 -4
  63. tests/models/linkedImpactAssessment/test_landOccupationInputsProduction.py +6 -4
  64. tests/models/linkedImpactAssessment/{test_landTransformationFromForest100YearAverageInputsProduction.py → test_landTransformation100YearAverageInputsProduction.py} +7 -5
  65. tests/models/linkedImpactAssessment/{test_landTransformationFromForest20YearAverageInputsProduction.py → test_landTransformation20YearAverageInputsProduction.py} +7 -5
  66. tests/models/pooreNemecek2018/test_excretaKgN.py +2 -2
  67. tests/models/pooreNemecek2018/test_excretaKgVs.py +1 -1
  68. tests/models/pooreNemecek2018/test_utils.py +26 -0
  69. tests/models/site/test_management.py +10 -27
  70. tests/models/test_cache_sites.py +40 -12
  71. tests/models/utils/test_blank_node.py +0 -8
  72. tests/models/utils/test_cache_sources.py +21 -0
  73. hestia_earth/models/blonkConsultants2016/landTransformationFromForest20YearAverageDuringCycle.py +0 -90
  74. hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +0 -74
  75. hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +0 -74
  76. hestia_earth/models/hyde32/__init__.py +0 -13
  77. hestia_earth/models/hyde32/landTransformationFromCropland100YearAverageDuringCycle.py +0 -60
  78. hestia_earth/models/hyde32/landTransformationFromCropland20YearAverageDuringCycle.py +0 -60
  79. hestia_earth/models/hyde32/landTransformationFromForest100YearAverageDuringCycle.py +0 -60
  80. hestia_earth/models/hyde32/landTransformationFromForest20YearAverageDuringCycle.py +0 -60
  81. hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -61
  82. hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -61
  83. hestia_earth/models/hyde32/landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -61
  84. hestia_earth/models/hyde32/landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -61
  85. hestia_earth/models/hyde32/utils.py +0 -72
  86. hestia_earth/models/linkedImpactAssessment/landTransformationFromForest100YearAverageInputsProduction.py +0 -36
  87. hestia_earth/models/linkedImpactAssessment/landTransformationFromForest20YearAverageInputsProduction.py +0 -36
  88. hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -36
  89. hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -36
  90. hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -36
  91. hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -36
  92. tests/models/blonkConsultants2016/test_landTransformationFromForest20YearAverageDuringCycle.py +0 -36
  93. tests/models/cycle/pre_checks/test_cache_sources.py +0 -25
  94. tests/models/faostat2018/test_landTransformationFromCropland100YearAverage.py +0 -40
  95. tests/models/faostat2018/test_landTransformationFromCropland20YearAverage.py +0 -40
  96. tests/models/hyde32/__init__.py +0 -0
  97. tests/models/hyde32/test_landTransformationFromCropland100YearAverageDuringCycle.py +0 -21
  98. tests/models/hyde32/test_landTransformationFromCropland20YearAverageDuringCycle.py +0 -21
  99. tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -23
  100. tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -21
  101. tests/models/hyde32/test_landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -21
  102. tests/models/hyde32/test_landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -21
  103. tests/models/linkedImpactAssessment/test_landTransformationFromCropland100YearAverageInputsProduction.py +0 -23
  104. tests/models/linkedImpactAssessment/test_landTransformationFromCropland20YearAverageInputsProduction.py +0 -23
  105. tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -23
  106. tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -23
  107. tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -24
  108. tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -24
  109. tests/models/site/pre_checks/test_cache_sources.py +0 -21
  110. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/LICENSE +0 -0
  111. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/WHEEL +0 -0
  112. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/top_level.txt +0 -0
@@ -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.co2ToAirBelowGroundBiomassStockChange 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}.co2ToAirBelowGroundBiomassStockChange"
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}/co2ToAirBelowGroundBiomassStockChange"
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),
@@ -21,18 +39,11 @@ RUN_SCENARIOS = [
21
39
  ("non-consecutive-biomass-measurements", 1), # Closes issue #827
22
40
  ("multiple-method-classifications", 5), # Closes issue #764
23
41
  ("non-soil-based-gohac-system", 3), # Closes issue #848
24
- ("with-gapfilled-start-date-end-date", 1) # Closes issue #972
42
+ ("with-gapfilled-start-date-end-date", 1), # Closes issue #972
43
+ ("forest-to-orchard-with-ground-cover", 3) # Closes issue #989
25
44
  ]
26
45
  """List of (subfolder: str, num_cycles: int)."""
27
46
 
28
-
29
- def _load_fixture(path: str, default=None):
30
- if isfile(path):
31
- with open(path, encoding="utf-8") as f:
32
- return json.load(f)
33
- return default
34
-
35
-
36
47
  RUN_PARAMS = reduce(
37
48
  lambda params, scenario: params + [(scenario[0], scenario[1], i) for i in range(scenario[1])],
38
49
  RUN_SCENARIOS,
@@ -47,7 +58,18 @@ RUN_IDS = [f"{param[0]}, cycle{param[2]}" for param in RUN_PARAMS]
47
58
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
48
59
  @patch(f"{utils_path}.related_cycles")
49
60
  @patch(f"{utils_path}._get_site")
50
- def test_run(_get_site_mock, related_cycles_mock, _new_emission_mock, subfolder, num_cycles, cycle_index):
61
+ @patch(f"{biomass_utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
62
+ @patch(f"{term_path}.search")
63
+ def test_run(
64
+ search_mock: MagicMock,
65
+ get_cover_crop_property_terms_mock: MagicMock,
66
+ get_site_mock: MagicMock,
67
+ related_cycles_mock: MagicMock,
68
+ _new_emission_mock: MagicMock,
69
+ subfolder: str,
70
+ num_cycles: int,
71
+ cycle_index: int
72
+ ):
51
73
  """
52
74
  Test `run` function for each cycle in each scenario.
53
75
  """
@@ -59,25 +81,39 @@ def test_run(_get_site_mock, related_cycles_mock, _new_emission_mock, subfolder,
59
81
  _load_fixture(f"{fixtures_folder}/{subfolder}/cycle{i}.jsonld") for i in range(num_cycles)
60
82
  ]
61
83
 
62
- _get_site_mock.return_value = site
84
+ get_site_mock.return_value = site
63
85
  related_cycles_mock.return_value = cycles
64
86
 
65
87
  result = run(cycle)
66
88
  assert order_list(result) == order_list(expected)
67
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
+
68
93
 
69
94
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
70
95
  @patch(f"{utils_path}.related_cycles")
71
96
  @patch(f"{utils_path}._get_site")
72
- def test_run_empty(_get_site_mock, related_cycles_mock, _new_emission_mock):
97
+ @patch(f"{biomass_utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
98
+ @patch(f"{term_path}.search")
99
+ def test_run_empty(
100
+ search_mock: MagicMock,
101
+ get_cover_crop_property_terms_mock: MagicMock,
102
+ get_site_mock: MagicMock,
103
+ related_cycles_mock: MagicMock,
104
+ _new_emission_mock: MagicMock
105
+ ):
73
106
  """
74
107
  Test `run` function for each cycle in each scenario.
75
108
  """
76
109
  CYCLE = {}
77
110
  EXPECTED = []
78
111
 
79
- _get_site_mock.return_value = {}
112
+ get_site_mock.return_value = {}
80
113
  related_cycles_mock.return_value = [CYCLE]
81
114
 
82
115
  result = run(CYCLE)
83
116
  assert result == EXPECTED
117
+
118
+ assert get_cover_crop_property_terms_mock.call_count <= 1 # assert the API call is only requested once
119
+ search_mock.assert_not_called() # assert the API call is properly mocked
@@ -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.co2ToAirSoilOrganicCarbonStockChange import MODEL, run
8
8
 
@@ -11,9 +11,17 @@ from tests.utils import fake_new_emission, fixtures_path, order_list
11
11
  class_path = f"hestia_earth.models.{MODEL}.co2ToAirSoilOrganicCarbonStockChange"
12
12
  utils_path = f"hestia_earth.models.{MODEL}.co2ToAirCarbonStockChange_utils"
13
13
  soc_utils_path = f"hestia_earth.models.{MODEL}.organicCarbonPerHa_utils"
14
- term_folder = "hestia_earth.models.utils.term"
14
+ soc_tier_1_utils_path = f"hestia_earth.models.{MODEL}.organicCarbonPerHa_tier_1_utils"
15
+ term_path = "hestia_earth.models.utils.term"
15
16
  fixtures_folder = f"{fixtures_path}/{MODEL}/co2ToAirSoilOrganicCarbonStockChange"
16
17
 
18
+ COVER_CROP_PROPERTY_TERM_IDS = [
19
+ "catchCrop",
20
+ "coverCrop",
21
+ "groundCover",
22
+ "longFallowCrop",
23
+ "shortFallowCrop"
24
+ ]
17
25
 
18
26
  IRRIGATED_TERM_IDS = [
19
27
  "rainfedDeepWater",
@@ -38,6 +46,14 @@ UPLAND_RICE_LAND_COVER_TERM_IDS = [
38
46
  "ricePlantUpland"
39
47
  ]
40
48
 
49
+
50
+ def _load_fixture(path: str, default=None):
51
+ if isfile(path):
52
+ with open(path, encoding="utf-8") as f:
53
+ return json.load(f)
54
+ return default
55
+
56
+
41
57
  RUN_SCENARIOS = [
42
58
  ("no-overlapping-cycles", 3),
43
59
  ("overlapping-cycles", 4),
@@ -47,18 +63,11 @@ RUN_SCENARIOS = [
47
63
  ("non-consecutive-organic-carbon-measurements", 1), # Closes issue #827
48
64
  ("multiple-method-classifications", 5), # Closes issue #764
49
65
  ("non-soil-based-gohac-system", 3), # Closes issue #848
50
- ("with-gapfilled-start-date-end-date", 1) # Closes issue #972
66
+ ("with-gapfilled-start-date-end-date", 1), # Closes issue #972
67
+ ("forest-to-orchard-with-ground-cover", 3) # Closes issue #989
51
68
  ]
52
69
  """List of (subfolder: str, num_cycles: int)."""
53
70
 
54
-
55
- def _load_fixture(path: str, default=None):
56
- if isfile(path):
57
- with open(path, encoding="utf-8") as f:
58
- return json.load(f)
59
- return default
60
-
61
-
62
71
  RUN_PARAMS = reduce(
63
72
  lambda params, scenario: params + [(scenario[0], scenario[1], i) for i in range(scenario[1])],
64
73
  RUN_SCENARIOS,
@@ -73,19 +82,21 @@ RUN_IDS = [f"{param[0]}, cycle{param[2]}" for param in RUN_PARAMS]
73
82
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
74
83
  @patch(f"{utils_path}.related_cycles")
75
84
  @patch(f"{utils_path}._get_site")
76
- @patch(f"{soc_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
85
+ @patch(f"{soc_tier_1_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
77
86
  @patch(f"{soc_utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
78
- @patch(f"{term_folder}.search")
87
+ @patch(f"{soc_utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
88
+ @patch(f"{term_path}.search")
79
89
  def test_run(
80
- search_mock,
81
- get_irrigated_terms_mock,
82
- get_upland_rice_land_cover_terms_mock,
83
- _get_site_mock,
84
- related_cycles_mock,
85
- _new_emission_mock,
86
- subfolder,
87
- num_cycles,
88
- cycle_index
90
+ search_mock: MagicMock,
91
+ _get_cover_crop_property_terms_mock: MagicMock,
92
+ _get_irrigated_terms_mock: MagicMock,
93
+ _get_upland_rice_land_cover_terms_mock: MagicMock,
94
+ get_site_mock: MagicMock,
95
+ related_cycles_mock: MagicMock,
96
+ _new_emission_mock: MagicMock,
97
+ subfolder: str,
98
+ num_cycles: int,
99
+ cycle_index: int
89
100
  ):
90
101
  """
91
102
  Test `run` function for each cycle in each scenario.
@@ -98,33 +109,43 @@ def test_run(
98
109
  _load_fixture(f"{fixtures_folder}/{subfolder}/cycle{i}.jsonld") for i in range(num_cycles)
99
110
  ]
100
111
 
101
- _get_site_mock.return_value = site
112
+ get_site_mock.return_value = site
102
113
  related_cycles_mock.return_value = cycles
103
114
 
104
115
  result = run(cycle)
116
+ assert order_list(result) == order_list(expected)
105
117
 
106
- # Ensure that API calls to retrieve term IDs are properly cached.
107
- get_irrigated_terms_mock.call_count <= 1
108
- get_upland_rice_land_cover_terms_mock.call_count <= 1
109
-
110
- # Ensure that the property and term utils are properly mocked.
118
+ # assert the API calls are properly mocked
111
119
  search_mock.assert_not_called()
112
120
 
113
- assert order_list(result) == order_list(expected)
114
-
115
121
 
116
122
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
117
123
  @patch(f"{utils_path}.related_cycles")
118
124
  @patch(f"{utils_path}._get_site")
119
- def test_run_empty(_get_site_mock, related_cycles_mock, _new_emission_mock):
125
+ @patch(f"{soc_tier_1_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
126
+ @patch(f"{soc_utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
127
+ @patch(f"{soc_utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
128
+ @patch(f"{term_path}.search")
129
+ def test_run_empty(
130
+ search_mock: MagicMock,
131
+ _get_cover_crop_property_terms_mock: MagicMock,
132
+ _get_irrigated_terms_mock: MagicMock,
133
+ _get_upland_rice_land_cover_terms_mock: MagicMock,
134
+ get_site_mock: MagicMock,
135
+ related_cycles_mock: MagicMock,
136
+ _new_emission_mock: MagicMock
137
+ ):
120
138
  """
121
139
  Test `run` function for each cycle in each scenario.
122
140
  """
123
141
  CYCLE = {}
124
142
  EXPECTED = []
125
143
 
126
- _get_site_mock.return_value = {}
144
+ get_site_mock.return_value = {}
127
145
  related_cycles_mock.return_value = [CYCLE]
128
146
 
129
147
  result = run(CYCLE)
130
148
  assert result == EXPECTED
149
+
150
+ # assert the API calls are properly mocked
151
+ search_mock.assert_not_called()
@@ -10,8 +10,8 @@ from hestia_earth.models.ipcc2019.organicCarbonPerHa_utils import sample_constan
10
10
  from tests.utils import fake_new_measurement, fixtures_path
11
11
 
12
12
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
13
- tier_1_path = f"hestia_earth.models.{MODEL}.{TERM_ID}_tier_1_utils"
14
- tier_2_path = f"hestia_earth.models.{MODEL}.{TERM_ID}_tier_2_utils"
13
+ tier_1_utils_path = f"hestia_earth.models.{MODEL}.{TERM_ID}_tier_1_utils"
14
+ tier_2_utils_path = f"hestia_earth.models.{MODEL}.{TERM_ID}_tier_2_utils"
15
15
  utils_path = f"hestia_earth.models.{MODEL}.{TERM_ID}_utils"
16
16
  term_path = "hestia_earth.models.utils.term"
17
17
  property_path = "hestia_earth.models.utils.property"
@@ -109,6 +109,8 @@ PARAMS_SHOULD_RUN = [
109
109
  ("tier-1/cropland-polar", False), # Closes issue 794
110
110
  ("tier-1/cropland-with-system-increasing-c-input", True), # Closes issue 851
111
111
  ("tier-1/with-gapfilled-start-date-end-date", False), # Closes issue 972
112
+ ("tier-1/forest-to-orchard-with-ground-cover", True), # Closes 989
113
+ ("tier-1/forest-to-other-with-ground-cover", True), # Closes 989
112
114
  ("tier-2/with-generalised-monthly-measurements", False), # Closes issue 600
113
115
  ("tier-2/with-incomplete-climate-data", False), # Closes issue 599
114
116
  ("tier-2/with-initial-soc", True),
@@ -125,27 +127,28 @@ PARAMS_SHOULD_RUN = [
125
127
  IDS_SHOULD_RUN = [p[0] for p in PARAMS_SHOULD_RUN]
126
128
 
127
129
 
128
- # TODO: update mocks
129
130
  @mark.parametrize("subfolder, should_run", PARAMS_SHOULD_RUN, ids=IDS_SHOULD_RUN)
130
- @patch(f"{term_path}.search")
131
- @patch(f"{property_path}.download_hestia")
132
- @patch(f"{property_path}.find_term_property", side_effect=fake_find_term_property)
133
- @patch(f"{utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
134
- @patch(f"{utils_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
135
- @patch(f"{utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
131
+ @patch(f"{tier_2_utils_path}.related_cycles")
132
+ @patch(f"{tier_2_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
133
+ @patch(f"{tier_2_utils_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
134
+ @patch(f"{tier_1_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
135
+ @patch(f"{tier_1_utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
136
136
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
137
137
  @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
138
- @patch(f"{tier_2_path}.related_cycles")
138
+ @patch(f"{term_path}.search")
139
+ @patch(f"{property_path}.find_term_property", side_effect=fake_find_term_property)
140
+ @patch(f"{property_path}.download_hestia")
139
141
  def test_should_run(
140
- mock_related_cycles: MagicMock,
141
- mock_get_cover_crop_property_terms: MagicMock, # utils mocks
142
- mock_get_irrigated_terms: MagicMock,
143
- mock_get_residue_removed_or_burnt_terms: MagicMock,
144
- mock_get_upland_rice_crop_terms: MagicMock,
145
- mock_get_upland_rice_land_cover_terms: MagicMock,
146
- _mock_find_term_property: MagicMock,
147
- mock_download_hestia: MagicMock,
148
- mock_search: MagicMock,
142
+ download_hestia_mock: MagicMock,
143
+ _find_term_property_mock: MagicMock,
144
+ search_mock: MagicMock,
145
+ _get_cover_crop_property_terms_mock: MagicMock,
146
+ _get_irrigated_terms_mock: MagicMock,
147
+ _get_residue_removed_or_burnt_terms_mock: MagicMock,
148
+ _get_upland_rice_land_cover_terms_mock_t1: MagicMock,
149
+ _get_upland_rice_crop_terms_mock: MagicMock,
150
+ _get_upland_rice_land_cover_terms_mock_t2: MagicMock,
151
+ related_cycles_mock: MagicMock,
149
152
  subfolder: str,
150
153
  should_run: bool
151
154
  ):
@@ -155,7 +158,7 @@ def test_should_run(
155
158
  with open(f"{folder}/cycles.jsonld", encoding='utf-8') as f:
156
159
  return json.load(f)
157
160
 
158
- mock_related_cycles.return_value = (
161
+ related_cycles_mock.return_value = (
159
162
  load_cycles_from_file() if isfile(f"{folder}/cycles.jsonld") else []
160
163
  )
161
164
 
@@ -163,75 +166,68 @@ def test_should_run(
163
166
  site = json.load(f)
164
167
 
165
168
  result, _ = _should_run(site)
166
-
167
- # Ensure that API calls to retrieve term IDs are properly cached.
168
- mock_get_cover_crop_property_terms.call_count <= 1
169
- mock_get_irrigated_terms.call_count <= 1
170
- mock_get_residue_removed_or_burnt_terms.call_count <= 1
171
- mock_get_upland_rice_crop_terms.call_count <= 1
172
- mock_get_upland_rice_land_cover_terms.call_count <= 1
169
+ assert result == should_run
173
170
 
174
171
  # Ensure that the property and term utils are properly mocked.
175
- mock_download_hestia.assert_not_called()
176
- mock_search.assert_not_called()
177
-
178
- assert result == should_run
172
+ download_hestia_mock.assert_not_called()
173
+ search_mock.assert_not_called()
179
174
 
180
175
 
176
+ @patch(f"{tier_2_utils_path}.related_cycles", return_value=[])
181
177
  @patch(f"{term_path}.search")
182
178
  @patch(f"{property_path}.download_hestia")
183
- @patch(f"{tier_2_path}.related_cycles", return_value=[])
184
179
  def test_should_run_no_data(
185
- _mock_related_cycles: MagicMock,
186
- mock_download_hestia: MagicMock,
187
- mock_search: MagicMock
180
+ download_hestia_mock: MagicMock,
181
+ search_mock: MagicMock,
182
+ _related_cycles_mock: MagicMock
188
183
  ):
189
184
  SITE = {}
190
185
  EXPECTED = []
191
186
 
192
187
  result = run(SITE)
193
188
 
194
- mock_download_hestia.assert_not_called()
195
- mock_search.assert_not_called()
189
+ download_hestia_mock.assert_not_called()
190
+ search_mock.assert_not_called()
196
191
  assert result == EXPECTED
197
192
 
198
193
 
199
194
  PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should_run]
200
195
 
201
196
 
202
- # TODO: update mocks
203
197
  @mark.parametrize("subfolder", PARAMS_RUN)
204
- @patch(f"{term_path}.search")
205
- @patch(f"{property_path}.download_hestia")
206
- @patch(f"{property_path}.find_term_property", side_effect=fake_find_term_property)
207
- @patch(f"{utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
208
- @patch(f"{utils_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
209
- @patch(f"{utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
198
+ @patch(f"{tier_2_utils_path}.related_cycles")
199
+ @patch(f"{tier_2_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
200
+ @patch(f"{tier_2_utils_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
201
+ @patch(f"{tier_2_utils_path}.calc_descriptive_stats", side_effect=fake_calc_descriptive_stats)
202
+ @patch(f"{tier_2_utils_path}._new_measurement", side_effect=fake_new_measurement)
203
+ @patch(f"{tier_2_utils_path}._get_sample_func", return_value=sample_constant)
204
+ @patch(f"{tier_1_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
205
+ @patch(f"{tier_1_utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
206
+ @patch(f"{tier_1_utils_path}.calc_descriptive_stats", side_effect=fake_calc_descriptive_stats)
207
+ @patch(f"{tier_1_utils_path}._new_measurement", side_effect=fake_new_measurement)
208
+ @patch(f"{tier_1_utils_path}._get_sample_func", return_value=sample_constant)
210
209
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
211
210
  @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
212
- @patch(f"{tier_2_path}.related_cycles")
213
- @patch(f"{tier_2_path}.calc_descriptive_stats", side_effect=fake_calc_descriptive_stats)
214
- @patch(f"{tier_2_path}._new_measurement", side_effect=fake_new_measurement)
215
- @patch(f"{tier_2_path}._get_sample_func", return_value=sample_constant)
216
- @patch(f"{tier_1_path}.calc_descriptive_stats", side_effect=fake_calc_descriptive_stats)
217
- @patch(f"{tier_1_path}._new_measurement", side_effect=fake_new_measurement)
218
- @patch(f"{tier_1_path}._get_sample_func", return_value=sample_constant)
211
+ @patch(f"{term_path}.search")
212
+ @patch(f"{property_path}.find_term_property", side_effect=fake_find_term_property)
213
+ @patch(f"{property_path}.download_hestia")
219
214
  def test_run(
220
- _mock_get_sample_func_t1: MagicMock,
221
- _mock_new_measurement_t1: MagicMock,
222
- _mock_calc_descriptive_stats_t1: MagicMock,
223
- _mock_get_sample_func_t2: MagicMock,
224
- _mock_new_measurement_t2: MagicMock,
215
+ download_hestia_mock: MagicMock,
216
+ _find_term_property_mock: MagicMock,
217
+ search_mock: MagicMock,
218
+ _get_cover_crop_property_terms_mock: MagicMock,
219
+ _get_irrigated_terms_mock: MagicMock,
220
+ _get_sample_func_mock_t1: MagicMock,
221
+ _new_measurement_mock_t1: MagicMock,
222
+ _calc_descriptive_stats_mock_t1: MagicMock,
223
+ _get_residue_removed_or_burnt_terms_mock: MagicMock,
224
+ _get_upland_rice_land_cover_terms_mock_t1: MagicMock,
225
+ _get_sample_func_mock_t2: MagicMock,
226
+ _new_measurement_mock_t2: MagicMock,
225
227
  _mock_calc_descriptive_stats_t2: MagicMock,
226
- mock_related_cycles: MagicMock,
227
- mock_get_cover_crop_property_terms: MagicMock, # utils mocks
228
- mock_get_irrigated_terms: MagicMock,
229
- mock_get_residue_removed_or_burnt_terms: MagicMock,
230
- mock_get_upland_rice_crop_terms: MagicMock,
231
- mock_get_upland_rice_land_cover_terms: MagicMock,
232
- _mock_find_term_property: MagicMock,
233
- mock_download_hestia: MagicMock,
234
- mock_search: MagicMock,
228
+ _get_upland_rice_crop_terms_mock: MagicMock,
229
+ _get_upland_rice_land_cover_terms_mock_t2: MagicMock,
230
+ related_cycles_mock: MagicMock,
235
231
  subfolder: str
236
232
  ):
237
233
  folder = f"{fixtures_folder}/{subfolder}"
@@ -240,7 +236,7 @@ def test_run(
240
236
  with open(f"{folder}/cycles.jsonld", encoding='utf-8') as f:
241
237
  return json.load(f)
242
238
 
243
- mock_related_cycles.return_value = (
239
+ related_cycles_mock.return_value = (
244
240
  load_cycles_from_file() if isfile(f"{folder}/cycles.jsonld") else []
245
241
  )
246
242
 
@@ -253,18 +249,11 @@ def test_run(
253
249
  with patch(f"{class_path}.ITERATIONS", ITERATIONS):
254
250
  result = run(site)
255
251
 
256
- # Ensure that API calls to retrieve term IDs are properly cached.
257
- mock_get_cover_crop_property_terms.call_count <= 1
258
- mock_get_irrigated_terms.call_count <= 1
259
- mock_get_residue_removed_or_burnt_terms.call_count <= 1
260
- mock_get_upland_rice_crop_terms.call_count <= 1
261
- mock_get_upland_rice_land_cover_terms.call_count <= 1
252
+ assert order_list(result) == order_list(expected)
262
253
 
263
254
  # Ensure that the property and term utils are properly mocked.
264
- mock_download_hestia.assert_not_called()
265
- mock_search.assert_not_called()
266
-
267
- assert order_list(result) == order_list(expected)
255
+ download_hestia_mock.assert_not_called()
256
+ search_mock.assert_not_called()
268
257
 
269
258
 
270
259
  PARAMS_RUN_WITH_STATS = [
@@ -276,31 +265,32 @@ PARAMS_RUN_WITH_STATS = [
276
265
  ]
277
266
 
278
267
 
279
- # TODO: update mocks
280
268
  @mark.parametrize("subfolder", PARAMS_RUN_WITH_STATS)
281
- @patch(f"{term_path}.search")
282
- @patch(f"{property_path}.download_hestia")
283
- @patch(f"{property_path}.find_term_property", side_effect=fake_find_term_property)
284
- @patch(f"{utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
285
- @patch(f"{utils_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
286
- @patch(f"{utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
269
+ @patch(f"{tier_2_utils_path}.related_cycles")
270
+ @patch(f"{tier_2_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
271
+ @patch(f"{tier_2_utils_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
272
+ @patch(f"{tier_2_utils_path}._new_measurement", side_effect=fake_new_measurement)
273
+ @patch(f"{tier_1_utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
274
+ @patch(f"{tier_1_utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
275
+ @patch(f"{tier_1_utils_path}._new_measurement", side_effect=fake_new_measurement)
287
276
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
288
277
  @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
289
- @patch(f"{tier_2_path}.related_cycles")
290
- @patch(f"{tier_2_path}._new_measurement", side_effect=fake_new_measurement)
291
- @patch(f"{tier_1_path}._new_measurement", side_effect=fake_new_measurement)
278
+ @patch(f"{term_path}.search")
279
+ @patch(f"{property_path}.find_term_property", side_effect=fake_find_term_property)
280
+ @patch(f"{property_path}.download_hestia")
292
281
  def test_run_with_stats(
293
- _mock_new_measurement_t1: MagicMock,
294
- _mock_new_measurement_t2: MagicMock,
295
- mock_related_cycles: MagicMock,
296
- mock_get_cover_crop_property_terms: MagicMock, # utils mocks
297
- mock_get_irrigated_terms: MagicMock,
298
- mock_get_residue_removed_or_burnt_terms: MagicMock,
299
- mock_get_upland_rice_crop_terms: MagicMock,
300
- mock_get_upland_rice_land_cover_terms: MagicMock,
301
- _mock_find_term_property: MagicMock,
302
- mock_download_hestia: MagicMock,
303
- mock_search: MagicMock,
282
+ download_hestia_mock: MagicMock,
283
+ _find_term_property_mock: MagicMock,
284
+ search_mock: MagicMock,
285
+ _get_cover_crop_property_terms_mock: MagicMock,
286
+ _get_irrigated_terms_mock: MagicMock,
287
+ _new_measurement_mock_t1: MagicMock,
288
+ _get_residue_removed_or_burnt_terms_mock: MagicMock,
289
+ _get_upland_rice_land_cover_terms_mock_t1: MagicMock,
290
+ _new_measurement_mock_t2: MagicMock,
291
+ _get_upland_rice_crop_terms_mock: MagicMock,
292
+ _get_upland_rice_land_cover_terms_mock_t2: MagicMock,
293
+ related_cycles_mock: MagicMock,
304
294
  subfolder: str
305
295
  ):
306
296
  folder = f"{fixtures_folder}/{subfolder}"
@@ -309,7 +299,7 @@ def test_run_with_stats(
309
299
  with open(f"{folder}/cycles.jsonld", encoding='utf-8') as f:
310
300
  return json.load(f)
311
301
 
312
- mock_related_cycles.return_value = (
302
+ related_cycles_mock.return_value = (
313
303
  load_cycles_from_file() if isfile(f"{folder}/cycles.jsonld") else []
314
304
  )
315
305
 
@@ -322,15 +312,8 @@ def test_run_with_stats(
322
312
  with patch(f"{class_path}.ITERATIONS", ITERATIONS):
323
313
  result = run(site)
324
314
 
325
- # Ensure that API calls to retrieve term IDs are properly cached.
326
- mock_get_cover_crop_property_terms.call_count <= 1
327
- mock_get_irrigated_terms.call_count <= 1
328
- mock_get_residue_removed_or_burnt_terms.call_count <= 1
329
- mock_get_upland_rice_crop_terms.call_count <= 1
330
- mock_get_upland_rice_land_cover_terms.call_count <= 1
315
+ assert order_list(result) == order_list(expected)
331
316
 
332
317
  # Ensure that the property and term utils are properly mocked.
333
- mock_download_hestia.assert_not_called()
334
- mock_search.assert_not_called()
335
-
336
- assert order_list(result) == order_list(expected)
318
+ download_hestia_mock.assert_not_called()
319
+ search_mock.assert_not_called()