hestia-earth-models 0.64.14__py3-none-any.whl → 0.65.1__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 (117) 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/ecoinventV3/__init__.py +3 -2
  8. hestia_earth/models/ecoinventV3/utils.py +1 -2
  9. hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +3 -2
  10. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +17 -37
  11. hestia_earth/models/faostat2018/landTransformation100YearAverageDuringCycle.py +34 -0
  12. hestia_earth/models/faostat2018/landTransformation20YearAverageDuringCycle.py +34 -0
  13. hestia_earth/models/faostat2018/utils.py +47 -3
  14. hestia_earth/models/hestia/landCover.py +5 -5
  15. hestia_earth/models/hestia/seed_emissions.py +284 -0
  16. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +2 -2
  17. hestia_earth/models/ipcc2019/belowGroundBiomass.py +8 -2
  18. hestia_earth/models/ipcc2019/biomass_utils.py +11 -4
  19. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +19 -10
  20. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +2 -1
  21. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +2 -1
  22. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +8 -7
  23. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +2 -1
  24. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +28 -34
  25. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +8 -12
  26. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +13 -30
  27. hestia_earth/models/linkedImpactAssessment/freshwaterWithdrawalsInputsProduction.py +4 -1
  28. hestia_earth/models/linkedImpactAssessment/landOccupationInputsProduction.py +16 -1
  29. hestia_earth/models/linkedImpactAssessment/{landTransformationFromForest100YearAverageInputsProduction.py → landTransformation100YearAverageInputsProduction.py} +8 -3
  30. hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland100YearAverageInputsProduction.py → landTransformation20YearAverageInputsProduction.py} +8 -3
  31. hestia_earth/models/linkedImpactAssessment/utils.py +80 -16
  32. hestia_earth/models/mocking/search-results.json +448 -448
  33. hestia_earth/models/pooreNemecek2018/excretaKgN.py +45 -41
  34. hestia_earth/models/pooreNemecek2018/excretaKgVs.py +89 -63
  35. hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +8 -8
  36. hestia_earth/models/pooreNemecek2018/utils.py +60 -19
  37. hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +4 -3
  38. hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +4 -3
  39. hestia_earth/models/schererPfister2015/utils.py +12 -9
  40. hestia_earth/models/site/management.py +70 -55
  41. hestia_earth/models/site/pre_checks/cache_sources.py +2 -20
  42. hestia_earth/models/utils/__init__.py +12 -1
  43. hestia_earth/models/utils/aggregated.py +1 -1
  44. hestia_earth/models/utils/blank_node.py +20 -12
  45. hestia_earth/models/utils/cache_sources.py +15 -0
  46. hestia_earth/models/utils/crop.py +5 -0
  47. hestia_earth/models/utils/indicator.py +3 -1
  48. hestia_earth/models/version.py +1 -1
  49. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/LICENSE +1 -1
  50. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/METADATA +3 -3
  51. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/RECORD +80 -109
  52. tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +1 -1
  53. tests/models/cycle/input/test_hestiaAggregatedData.py +5 -2
  54. tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +39 -28
  55. tests/models/{hyde32/test_landTransformationFromForest20YearAverageDuringCycle.py → faostat2018/test_landTransformation100YearAverageDuringCycle.py} +5 -5
  56. tests/models/{hyde32/test_landTransformationFromForest100YearAverageDuringCycle.py → faostat2018/test_landTransformation20YearAverageDuringCycle.py} +5 -5
  57. tests/models/faostat2018/test_utils.py +28 -0
  58. tests/models/hestia/test_landCover.py +2 -1
  59. tests/models/hestia/test_seed_emissions.py +27 -0
  60. tests/models/ipcc2019/test_aboveGroundBiomass.py +40 -4
  61. tests/models/ipcc2019/test_belowGroundBiomass.py +40 -4
  62. tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +52 -15
  63. tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +50 -14
  64. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +53 -32
  65. tests/models/ipcc2019/test_organicCarbonPerHa.py +91 -108
  66. tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +33 -50
  67. tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -52
  68. tests/models/linkedImpactAssessment/test_freshwaterWithdrawalsInputsProduction.py +6 -4
  69. tests/models/linkedImpactAssessment/test_landOccupationInputsProduction.py +6 -4
  70. tests/models/linkedImpactAssessment/{test_landTransformationFromForest100YearAverageInputsProduction.py → test_landTransformation100YearAverageInputsProduction.py} +7 -5
  71. tests/models/linkedImpactAssessment/{test_landTransformationFromForest20YearAverageInputsProduction.py → test_landTransformation20YearAverageInputsProduction.py} +7 -5
  72. tests/models/pooreNemecek2018/test_excretaKgN.py +2 -2
  73. tests/models/pooreNemecek2018/test_excretaKgVs.py +1 -1
  74. tests/models/pooreNemecek2018/test_utils.py +26 -0
  75. tests/models/site/test_management.py +10 -27
  76. tests/models/test_cache_sites.py +40 -12
  77. tests/models/utils/test_blank_node.py +0 -8
  78. tests/models/utils/test_cache_sources.py +21 -0
  79. hestia_earth/models/blonkConsultants2016/landTransformationFromForest20YearAverageDuringCycle.py +0 -90
  80. hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +0 -74
  81. hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +0 -74
  82. hestia_earth/models/hyde32/__init__.py +0 -13
  83. hestia_earth/models/hyde32/landTransformationFromCropland100YearAverageDuringCycle.py +0 -60
  84. hestia_earth/models/hyde32/landTransformationFromCropland20YearAverageDuringCycle.py +0 -60
  85. hestia_earth/models/hyde32/landTransformationFromForest100YearAverageDuringCycle.py +0 -60
  86. hestia_earth/models/hyde32/landTransformationFromForest20YearAverageDuringCycle.py +0 -60
  87. hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -61
  88. hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -61
  89. hestia_earth/models/hyde32/landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -61
  90. hestia_earth/models/hyde32/landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -61
  91. hestia_earth/models/hyde32/utils.py +0 -72
  92. hestia_earth/models/linkedImpactAssessment/landTransformationFromCropland20YearAverageInputsProduction.py +0 -36
  93. hestia_earth/models/linkedImpactAssessment/landTransformationFromForest20YearAverageInputsProduction.py +0 -36
  94. hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -36
  95. hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -36
  96. hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -36
  97. hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -36
  98. tests/models/blonkConsultants2016/test_landTransformationFromForest20YearAverageDuringCycle.py +0 -36
  99. tests/models/cycle/pre_checks/test_cache_sources.py +0 -25
  100. tests/models/faostat2018/test_landTransformationFromCropland100YearAverage.py +0 -40
  101. tests/models/faostat2018/test_landTransformationFromCropland20YearAverage.py +0 -40
  102. tests/models/hyde32/__init__.py +0 -0
  103. tests/models/hyde32/test_landTransformationFromCropland100YearAverageDuringCycle.py +0 -21
  104. tests/models/hyde32/test_landTransformationFromCropland20YearAverageDuringCycle.py +0 -21
  105. tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -23
  106. tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -21
  107. tests/models/hyde32/test_landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -21
  108. tests/models/hyde32/test_landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -21
  109. tests/models/linkedImpactAssessment/test_landTransformationFromCropland100YearAverageInputsProduction.py +0 -23
  110. tests/models/linkedImpactAssessment/test_landTransformationFromCropland20YearAverageInputsProduction.py +0 -23
  111. tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -23
  112. tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -23
  113. tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -24
  114. tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -24
  115. tests/models/site/pre_checks/test_cache_sources.py +0 -21
  116. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/WHEEL +0 -0
  117. {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/top_level.txt +0 -0
@@ -162,13 +162,15 @@ LAND_USE_CATEGORY_PARAMS = [
162
162
  LAND_USE_CATEGORY_PARAMS,
163
163
  ids=[params[0] for params in LAND_USE_CATEGORY_PARAMS]
164
164
  )
165
- @patch(f"{term_path}.search")
166
- @patch(f"{utils_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
165
+ @patch(f"{class_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
167
166
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
167
+ @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
168
+ @patch(f"{term_path}.search")
168
169
  def test_assign_ipcc_land_use_category(
169
- mock_get_irrigated_terms: MagicMock,
170
- mock_get_upland_rice_land_cover_terms: MagicMock,
171
- mock_search: MagicMock,
170
+ search_mock: MagicMock,
171
+ _get_cover_crop_property_terms_mock: MagicMock,
172
+ _get_irrigated_terms_mock: MagicMock,
173
+ _get_upland_rice_land_cover_terms_mock: MagicMock,
172
174
  subfolder: str,
173
175
  soil_category: IpccSoilCategory,
174
176
  expected: IpccLandUseCategory
@@ -179,14 +181,10 @@ def test_assign_ipcc_land_use_category(
179
181
  site = json.load(f)
180
182
 
181
183
  result = _assign_ipcc_land_use_category(site.get("management", []), soil_category)
182
-
183
- # Ensure that API calls to retrieve term IDs are properly cached.
184
- mock_get_irrigated_terms.call_count <= 1
185
- mock_get_upland_rice_land_cover_terms.call_count <= 1
186
-
187
- mock_search.assert_not_called() # Ensure that the term utils are properly mocked.
188
184
  assert result == expected
189
185
 
186
+ search_mock.assert_not_called() # Ensure that the term utils are properly mocked.
187
+
190
188
 
191
189
  # subfolder, land_use_category, expected
192
190
  MANAGEMENT_CATEGORY_PARAMS = [
@@ -225,15 +223,15 @@ def test_assign_ipcc_management_category(
225
223
 
226
224
 
227
225
  @mark.parametrize("key", [1, 2, 3, 4], ids=lambda key: f"scenario-{key}")
228
- @patch(f"{term_path}.search")
229
- @patch(f"{utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
226
+ @patch(f"{class_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
230
227
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
231
228
  @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
229
+ @patch(f"{term_path}.search")
232
230
  def test_check_cropland_medium_category(
233
- mock_get_cover_crop_property_terms: MagicMock,
234
- mock_get_irrigated_terms: MagicMock,
235
- mock_get_residue_removed_or_burnt_terms: MagicMock,
236
- mock_search: MagicMock,
231
+ search_mock: MagicMock,
232
+ _get_cover_crop_property_terms_mock: MagicMock,
233
+ _get_irrigated_terms_mock: MagicMock,
234
+ _get_residue_removed_or_burnt_terms_mock: MagicMock,
237
235
  key: int
238
236
  ):
239
237
  """
@@ -246,26 +244,21 @@ def test_check_cropland_medium_category(
246
244
  site = json.load(f)
247
245
 
248
246
  result = _check_cropland_medium_category(**_get_carbon_input_kwargs(site.get("management", [])))
249
-
250
- # Ensure that API calls to retrieve term IDs are properly cached.
251
- mock_get_cover_crop_property_terms.call_count <= 1
252
- mock_get_irrigated_terms.call_count <= 1
253
- mock_get_residue_removed_or_burnt_terms.call_count <= 1
254
-
255
- mock_search.assert_not_called() # Ensure that the term utils are properly mocked.
256
247
  assert result == key
257
248
 
249
+ search_mock.assert_not_called() # Ensure that the term utils are properly mocked.
250
+
258
251
 
259
252
  @mark.parametrize("key", [1, 2, 3], ids=lambda key: f"scenario-{key}")
260
- @patch(f"{term_path}.search")
261
- @patch(f"{utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
253
+ @patch(f"{class_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
262
254
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
263
255
  @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
256
+ @patch(f"{term_path}.search")
264
257
  def test_check_cropland_low_category(
265
- mock_get_cover_crop_property_terms: MagicMock,
266
- mock_get_irrigated_terms: MagicMock,
267
- mock_get_residue_removed_or_burnt_terms: MagicMock,
268
- mock_search: MagicMock,
258
+ search_mock: MagicMock,
259
+ _get_cover_crop_property_terms_mock: MagicMock,
260
+ _get_irrigated_terms_mock: MagicMock,
261
+ _get_residue_removed_or_burnt_terms_mock: MagicMock,
269
262
  key: int
270
263
  ):
271
264
  """
@@ -278,15 +271,10 @@ def test_check_cropland_low_category(
278
271
  site = json.load(f)
279
272
 
280
273
  result = _check_cropland_low_category(**_get_carbon_input_kwargs(site.get("management", [])))
281
-
282
- # Ensure that API calls to retrieve term IDs are properly cached.
283
- mock_get_cover_crop_property_terms.call_count <= 1
284
- mock_get_irrigated_terms.call_count <= 1
285
- mock_get_residue_removed_or_burnt_terms.call_count <= 1
286
-
287
- mock_search.assert_not_called() # Ensure that the term utils are properly mocked.
288
274
  assert result == key
289
275
 
276
+ search_mock.assert_not_called() # Ensure that the term utils are properly mocked.
277
+
290
278
 
291
279
  # subfolder, management_category, expected
292
280
  CARBON_INPUT_CATEGORY_PARAMS = [
@@ -331,15 +319,15 @@ CARBON_INPUT_CATEGORY_PARAMS = [
331
319
  CARBON_INPUT_CATEGORY_PARAMS,
332
320
  ids=[params[0] for params in CARBON_INPUT_CATEGORY_PARAMS]
333
321
  )
334
- @patch(f"{term_path}.search")
335
- @patch(f"{utils_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
322
+ @patch(f"{class_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
336
323
  @patch(f"{utils_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
337
324
  @patch(f"{utils_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
325
+ @patch(f"{term_path}.search")
338
326
  def test_assign_ipcc_carbon_input_category(
339
- mock_get_cover_crop_property_terms: MagicMock,
340
- mock_get_irrigated_terms: MagicMock,
341
- mock_get_residue_removed_or_burnt_terms: MagicMock,
342
- mock_search: MagicMock,
327
+ search_mock: MagicMock,
328
+ _get_cover_crop_property_terms_mock: MagicMock,
329
+ _get_irrigated_terms_mock: MagicMock,
330
+ _get_residue_removed_or_burnt_terms_mock: MagicMock,
343
331
  subfolder: str,
344
332
  management_category: IpccManagementCategory,
345
333
  expected: IpccCarbonInputCategory
@@ -350,15 +338,10 @@ def test_assign_ipcc_carbon_input_category(
350
338
  site = json.load(f)
351
339
 
352
340
  result = _assign_ipcc_carbon_input_category(site.get("management", []), management_category)
353
-
354
- # Ensure that API calls to retrieve term IDs are properly cached.
355
- mock_get_cover_crop_property_terms.call_count <= 1
356
- mock_get_irrigated_terms.call_count <= 1
357
- mock_get_residue_removed_or_burnt_terms.call_count <= 1
358
-
359
- mock_search.assert_not_called() # Ensure that the term utils are properly mocked.
360
341
  assert result == expected
361
342
 
343
+ search_mock.assert_not_called() # Ensure that the term utils are properly mocked.
344
+
362
345
 
363
346
  TIMESTAMPS_CALC_SOC_STOCK = [1990, 1995, 2000, 2005, 2010, 2015, 2020]
364
347
 
@@ -25,58 +25,6 @@ YEARS = 100
25
25
  MONTHS = 12
26
26
 
27
27
 
28
- IRRIGATED_TERM_IDS = [
29
- "rainfedDeepWater",
30
- "rainfedDeepWaterWaterDepth100Cm",
31
- "rainfedDeepWaterWaterDepth50100Cm",
32
- "irrigatedTypeUnspecified",
33
- "irrigatedCenterPivotIrrigation",
34
- "irrigatedContinuouslyFlooded",
35
- "irrigatedDripIrrigation",
36
- "irrigatedFurrowIrrigation",
37
- "irrigatedLateralMoveIrrigation",
38
- "irrigatedLocalizedIrrigation",
39
- "irrigatedManualIrrigation",
40
- "irrigatedSurfaceIrrigationMultipleDrainagePeriods",
41
- "irrigatedSurfaceIrrigationSingleDrainagePeriod",
42
- "irrigatedSprinklerIrrigation",
43
- "irrigatedSubIrrigation",
44
- "irrigatedSurfaceIrrigationDrainageRegimeUnspecified"
45
- ]
46
-
47
-
48
- UPLAND_RICE_LAND_COVER_TERM_IDS = [
49
- "ricePlantUpland"
50
- ]
51
-
52
- UPLAND_RICE_CROP_TERM_IDS = [
53
- "riceGrainInHuskUpland"
54
- ]
55
-
56
- DEFAULT_PROPERTIES = {
57
- "manureDryKgMass": {
58
- "carbonContent": {
59
- "value": 38.4
60
- },
61
- "nitrogenContent": {
62
- "value": 2.65
63
- },
64
- "ligninContent": {
65
- "value": 9.67
66
- }
67
- }
68
- }
69
-
70
-
71
- def fake_find_term_property(term: dict, property: str, *_):
72
- term_id = term.get('@id', None)
73
- return DEFAULT_PROPERTIES.get(term_id, {}).get(property, {})
74
-
75
-
76
- def fake_calc_descriptive_stats(arr: NDArray, *_args, **_kwargs):
77
- return {"value": [row[0] for row in arr]}
78
-
79
-
80
28
  def assert_elements_between(arr: NDArray, min: float, max: float):
81
29
  assert ((min <= arr) & (arr <= max)).all()
82
30
 
@@ -4,12 +4,14 @@ from tests.utils import fixtures_path, fake_new_indicator, fake_load_impacts
4
4
 
5
5
  from hestia_earth.models.linkedImpactAssessment.freshwaterWithdrawalsInputsProduction import TERM_ID, run
6
6
 
7
- class_path = f"hestia_earth.models.linkedImpactAssessment.{TERM_ID}"
8
- fixtures_folder = f"{fixtures_path}/linkedImpactAssessment/{TERM_ID}"
7
+ from hestia_earth.models.linkedImpactAssessment import MODEL
8
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
9
+ utils_class_path = f"hestia_earth.models.{MODEL}.utils"
10
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
11
 
10
12
 
11
- @patch('hestia_earth.models.utils.input.load_impacts', side_effect=fake_load_impacts)
12
- @patch('hestia_earth.models.linkedImpactAssessment.utils._new_indicator', side_effect=fake_new_indicator)
13
+ @patch(f"{utils_class_path}.load_impacts", side_effect=fake_load_impacts)
14
+ @patch(f"{utils_class_path}._new_indicator", side_effect=fake_new_indicator)
13
15
  def test_run(*args):
14
16
  with open(f"{fixtures_folder}/impact-assessment.jsonld", encoding='utf-8') as f:
15
17
  impact = json.load(f)
@@ -2,14 +2,16 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_indicator, fake_load_impacts
4
4
 
5
+ from hestia_earth.models.linkedImpactAssessment import MODEL
5
6
  from hestia_earth.models.linkedImpactAssessment.landOccupationInputsProduction import TERM_ID, run
6
7
 
7
- class_path = f"hestia_earth.models.linkedImpactAssessment.{TERM_ID}"
8
- fixtures_folder = f"{fixtures_path}/linkedImpactAssessment/{TERM_ID}"
8
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
9
+ utils_class_path = f"hestia_earth.models.{MODEL}.utils"
10
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
11
 
10
12
 
11
- @patch('hestia_earth.models.utils.input.load_impacts', side_effect=fake_load_impacts)
12
- @patch('hestia_earth.models.linkedImpactAssessment.utils._new_indicator', side_effect=fake_new_indicator)
13
+ @patch(f"{utils_class_path}.load_impacts", side_effect=fake_load_impacts)
14
+ @patch(f"{utils_class_path}._new_indicator", side_effect=fake_new_indicator)
13
15
  def test_run(*args):
14
16
  with open(f"{fixtures_folder}/impact-assessment.jsonld", encoding='utf-8') as f:
15
17
  impact = json.load(f)
@@ -2,16 +2,18 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_indicator, fake_load_impacts
4
4
 
5
- from hestia_earth.models.linkedImpactAssessment.landTransformationFromForest100YearAverageInputsProduction import (
5
+ from hestia_earth.models.linkedImpactAssessment import MODEL
6
+ from hestia_earth.models.linkedImpactAssessment.landTransformation100YearAverageInputsProduction import (
6
7
  TERM_ID, run
7
8
  )
8
9
 
9
- class_path = f"hestia_earth.models.linkedImpactAssessment.{TERM_ID}"
10
- fixtures_folder = f"{fixtures_path}/linkedImpactAssessment/{TERM_ID}"
10
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
11
+ utils_class_path = f"hestia_earth.models.{MODEL}.utils"
12
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
11
13
 
12
14
 
13
- @patch('hestia_earth.models.utils.input.load_impacts', side_effect=fake_load_impacts)
14
- @patch('hestia_earth.models.linkedImpactAssessment.utils._new_indicator', side_effect=fake_new_indicator)
15
+ @patch(f"{utils_class_path}.load_impacts", side_effect=fake_load_impacts)
16
+ @patch(f"{utils_class_path}._new_indicator", side_effect=fake_new_indicator)
15
17
  def test_run(*args):
16
18
  with open(f"{fixtures_folder}/impact-assessment.jsonld", encoding='utf-8') as f:
17
19
  impact = json.load(f)
@@ -2,16 +2,18 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_indicator, fake_load_impacts
4
4
 
5
- from hestia_earth.models.linkedImpactAssessment.landTransformationFromForest20YearAverageInputsProduction import (
5
+ from hestia_earth.models.linkedImpactAssessment import MODEL
6
+ from hestia_earth.models.linkedImpactAssessment.landTransformation20YearAverageInputsProduction import (
6
7
  TERM_ID, run
7
8
  )
8
9
 
9
- class_path = f"hestia_earth.models.linkedImpactAssessment.{TERM_ID}"
10
- fixtures_folder = f"{fixtures_path}/linkedImpactAssessment/{TERM_ID}"
10
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
11
+ utils_class_path = f"hestia_earth.models.{MODEL}.utils"
12
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
11
13
 
12
14
 
13
- @patch('hestia_earth.models.utils.input.load_impacts', side_effect=fake_load_impacts)
14
- @patch('hestia_earth.models.linkedImpactAssessment.utils._new_indicator', side_effect=fake_new_indicator)
15
+ @patch(f"{utils_class_path}.load_impacts", side_effect=fake_load_impacts)
16
+ @patch(f"{utils_class_path}._new_indicator", side_effect=fake_new_indicator)
15
17
  def test_run(*args):
16
18
  with open(f"{fixtures_folder}/impact-assessment.jsonld", encoding='utf-8') as f:
17
19
  impact = json.load(f)
@@ -28,7 +28,7 @@ def test_should_run(mock_animal_produced, mock_get_feed, *args):
28
28
  should_run, *args = _should_run(cycle)
29
29
  assert not should_run
30
30
 
31
- # completeness True => no run
31
+ # completeness True => run
32
32
  cycle = {
33
33
  'completeness': {
34
34
  'animalFeed': True,
@@ -38,7 +38,7 @@ def test_should_run(mock_animal_produced, mock_get_feed, *args):
38
38
  mock_get_feed.return_value = 5
39
39
  mock_animal_produced.return_value = 5
40
40
  should_run, *args = _should_run(cycle)
41
- assert not should_run
41
+ assert should_run is True
42
42
 
43
43
  # excreta already present with no value => run
44
44
  cycle['products'] = [
@@ -58,7 +58,7 @@ def test_should_run(*args):
58
58
  ]
59
59
  })
60
60
  should_run, *args = _should_run(cycle)
61
- assert not should_run
61
+ assert should_run is True
62
62
 
63
63
  # excreta already present with no value => run
64
64
  cycle['products'] = [
@@ -0,0 +1,26 @@
1
+ import os
2
+ import json
3
+ import pytest
4
+ from tests.utils import fixtures_path
5
+
6
+ from hestia_earth.models.pooreNemecek2018.utils import MODEL, get_excreta_product_with_ratio
7
+
8
+ fixtures_folder = os.path.join(fixtures_path, MODEL, 'utils')
9
+
10
+
11
+ @pytest.mark.parametrize(
12
+ 'folder',
13
+ [
14
+ ('no-system'),
15
+ ('single-system'),
16
+ ('multiple-systems'),
17
+ ]
18
+ )
19
+ def test_get_excreta_product_with_ratio(folder: str):
20
+ with open(os.path.join(fixtures_folder, folder, 'cycle.jsonld'), 'r') as f:
21
+ cycle = json.load(f)
22
+
23
+ with open(os.path.join(fixtures_folder, folder, 'result.jsonld'), 'r') as f:
24
+ expected = json.load(f)
25
+
26
+ assert get_excreta_product_with_ratio(cycle, lookup='excretaKgNTermIds') == expected, folder
@@ -1,43 +1,25 @@
1
+ import os
1
2
  import json
2
- from unittest.mock import Mock, patch
3
3
  import pytest
4
+ from unittest.mock import Mock, patch
4
5
  from hestia_earth.schema import SiteSiteType
5
6
 
6
7
  from tests.utils import fixtures_path, fake_new_management
7
8
  from hestia_earth.models.site.management import MODEL, MODEL_KEY, run
8
9
 
9
10
  class_path = f"hestia_earth.models.{MODEL}.{MODEL_KEY}"
10
- fixtures_folder = f"{fixtures_path}/{MODEL}/{MODEL_KEY}"
11
+ fixtures_folder = os.path.join(fixtures_path, MODEL, MODEL_KEY)
11
12
 
12
13
  _LAND_COVER_TERM_BY_SITE_TYPE = {
13
14
  SiteSiteType.ANIMAL_HOUSING.value: "animalHousing",
14
15
  SiteSiteType.CROPLAND.value: "cropland"
15
16
  }
17
+ _folders = [d for d in os.listdir(fixtures_folder) if os.path.isdir(os.path.join(fixtures_folder, d))]
16
18
 
17
19
 
18
20
  @pytest.mark.parametrize(
19
- "test_name,fixture_path",
20
- [
21
- ("Products and practices", f"{fixtures_folder}"),
22
- ("Example 1", f"{fixtures_folder}/inputs/example1"),
23
- ("Example 2", f"{fixtures_folder}/inputs/example2"),
24
- ("Example 3", f"{fixtures_folder}/inputs/example3"),
25
- ("Example 4", f"{fixtures_folder}/inputs/example4"),
26
- ("Condense Nodes", f"{fixtures_folder}/inputs/condense_nodes"),
27
- # Expected:
28
- # - appleTree (81) x 3 condenses 2020-03-01 to 2021-02-15
29
- # - animalManureUsed (true) x 2 condenses 2001-04-01 to 2001-12-31
30
- # - treeNutTree, lebbekTree (82) does not condense [different terms]
31
- # - organicFertiliserUsed (true|false) does not condense [different values]
32
- # - glassOrHighAccessibleCover (83) does not condense [different date ranges (overlapping)]
33
- # - durianTree (84) does not condense [different date ranges (disjoint)]
34
- # - irrigatedSurfaceIrrigationContinuouslyFlooded (85) does not condense ["%" units]
35
- # - sassafrasTree (86) x 2 condenses 2001-01-01 to 2004-12-31
36
- # - bananaPlant (87) does not condense [non-consecutive years]
37
- # - durianTree (89) does not condense [dates overwritten See 808]
38
- ("Site Type", f"{fixtures_folder}/inputs/site_type"),
39
- ("Multiple products but only 1 with landCover id", f"{fixtures_folder}/multiple-products"),
40
- ]
21
+ "folder",
22
+ _folders
41
23
  )
42
24
  @patch(
43
25
  f"{class_path}.get_landCover_term_id_from_site_type",
@@ -49,9 +31,10 @@ def test_run(
49
31
  mock_related_cycles: Mock,
50
32
  mock_new_management: Mock,
51
33
  mock_land_cover_lookup: Mock,
52
- test_name: str,
53
- fixture_path: str
34
+ folder: str
54
35
  ):
36
+ fixture_path = os.path.join(fixtures_folder, folder)
37
+
55
38
  with open(f"{fixture_path}/cycles.jsonld", encoding='utf-8') as f:
56
39
  cycles = json.load(f)
57
40
  mock_related_cycles.return_value = cycles
@@ -67,4 +50,4 @@ def test_run(
67
50
  expected = json.load(f)
68
51
 
69
52
  result = run(site)
70
- assert result == expected, test_name
53
+ assert result == expected, fixture_path
@@ -16,22 +16,36 @@ def test_run(mock_run_query, *args):
16
16
  data = json.load(f)
17
17
  with open(f"{fixtures_folder}/cache.json", encoding='utf-8') as f:
18
18
  cache = json.load(f)
19
- with open(f"{fixtures_folder}/params.json", encoding='utf-8') as f:
20
- params = json.load(f)
21
19
 
22
- mock_run_query.return_value = [10] * len(params.get('rasters', []) + params.get('vectors', []))
20
+ with open(f"{fixtures_folder}/rasters-no-years.json", encoding='utf-8') as f:
21
+ rasters_no_years = json.load(f)
22
+ with open(f"{fixtures_folder}/rasters-years.json", encoding='utf-8') as f:
23
+ rasters_years = json.load(f)
24
+ with open(f"{fixtures_folder}/vectors.json", encoding='utf-8') as f:
25
+ vectors = json.load(f)
23
26
 
24
- sites = run(data.get('nodes', []), [2019, 2020], include_region=False)
27
+ mock_run_query.side_effect = [
28
+ [10] * len(rasters_no_years),
29
+ [10] * len(vectors),
30
+ [10] * len(rasters_years)
31
+ ]
32
+
33
+ sites = run(sites=data.get('nodes', []), years=[2019, 2020], include_region=False)
25
34
 
26
35
  mock_run_query.assert_has_calls([
27
36
  call({
28
37
  "ee_type": "raster",
29
- "collections": params.get('rasters', []),
38
+ "collections": rasters_no_years,
30
39
  "coordinates": coordinates
31
40
  }),
32
41
  call({
33
42
  "ee_type": "vector",
34
- "collections": params.get('vectors', []),
43
+ "collections": vectors,
44
+ "coordinates": coordinates
45
+ }),
46
+ call({
47
+ "ee_type": "raster",
48
+ "collections": rasters_years,
35
49
  "coordinates": coordinates
36
50
  })
37
51
  ])
@@ -44,22 +58,36 @@ def test_run(mock_run_query, *args):
44
58
  def test_run_include_region(mock_run_query, *args):
45
59
  with open(f"{fixtures_folder}/data.json", encoding='utf-8') as f:
46
60
  data = json.load(f)
47
- with open(f"{fixtures_folder}/params.json", encoding='utf-8') as f:
48
- params = json.load(f)
49
61
 
50
- mock_run_query.return_value = [10] * len(params.get('rasters', []) + params.get('vectors', []))
62
+ with open(f"{fixtures_folder}/rasters-no-years.json", encoding='utf-8') as f:
63
+ rasters_no_years = json.load(f)
64
+ with open(f"{fixtures_folder}/rasters-years.json", encoding='utf-8') as f:
65
+ rasters_years = json.load(f)
66
+ with open(f"{fixtures_folder}/vectors-with-regions.json", encoding='utf-8') as f:
67
+ vectors_with_regions = json.load(f)
51
68
 
52
- run(data.get('nodes', []), [2019, 2020], include_region=True)
69
+ mock_run_query.side_effect = [
70
+ [10] * len(rasters_no_years),
71
+ [10] * len(vectors_with_regions),
72
+ [10] * len(rasters_years)
73
+ ]
74
+
75
+ run(sites=data.get('nodes', []), years=[2019, 2020], include_region=True)
53
76
 
54
77
  mock_run_query.assert_has_calls([
55
78
  call({
56
79
  "ee_type": "raster",
57
- "collections": params.get('rasters', []),
80
+ "collections": rasters_no_years,
58
81
  "coordinates": coordinates
59
82
  }),
60
83
  call({
61
84
  "ee_type": "vector",
62
- "collections": params.get('vectors-with-regions', []),
85
+ "collections": vectors_with_regions,
86
+ "coordinates": coordinates
87
+ }),
88
+ call({
89
+ "ee_type": "raster",
90
+ "collections": rasters_years,
63
91
  "coordinates": coordinates
64
92
  })
65
93
  ])
@@ -216,14 +216,6 @@ def test_run_required():
216
216
  'site': {'siteType': SiteSiteType.POND.value}
217
217
  }) is True
218
218
 
219
- term = {
220
- '@id': 'landTransformationFromCropland20YearAverageDuringCycle',
221
- 'termType': 'resourceUse'
222
- }
223
- assert not _run_required('hyde32', term, {
224
- 'site': {'siteType': SiteSiteType.CROPLAND.value}
225
- })
226
-
227
219
 
228
220
  def test_run_model_required():
229
221
  term = {
@@ -0,0 +1,21 @@
1
+ from unittest.mock import patch
2
+
3
+ from hestia_earth.models.utils.cache_sources import CACHE_KEY, CACHE_SOURCES_KEY, _has_value, cache_sources
4
+
5
+ class_path = 'hestia_earth.models.utils.cache_sources'
6
+ sources = {'source a': {'@type': 'Source', '@id': 'source-1'}}
7
+
8
+
9
+ def test_should_run():
10
+ # no existing cache => run
11
+ assert not _has_value({CACHE_KEY: {}})
12
+ assert not _has_value({CACHE_KEY: {CACHE_SOURCES_KEY: {}}})
13
+
14
+ # with existing cache => no run
15
+ assert _has_value({CACHE_KEY: {CACHE_SOURCES_KEY: {'sample': 'a'}}}) is True
16
+
17
+
18
+ @patch(f"{class_path}.find_sources", return_value=sources)
19
+ def test_run(*args):
20
+ result = cache_sources({})
21
+ assert result.get(CACHE_KEY).get(CACHE_SOURCES_KEY) == sources
@@ -1,90 +0,0 @@
1
- from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
2
- from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import get_product, get_site
4
- from hestia_earth.models.utils.cycle import land_occupation_per_kg
5
- from .utils import get_emission_factor
6
- from . import MODEL
7
-
8
- REQUIREMENTS = {
9
- "ImpactAssessment": {
10
- "product": {"@type": "Product", "term": {"@type": "Term"}},
11
- "site": {
12
- "@type": "Site",
13
- "siteType": ""
14
- },
15
- "cycle": {
16
- "@type": "Cycle",
17
- "products": [{
18
- "@type": "Product",
19
- "primary": "True",
20
- "value": "> 0",
21
- "economicValueShare": "> 0"
22
- }],
23
- "or": [
24
- {
25
- "@doc": "if the [cycle.functionalUnit](https://hestia.earth/schema/Cycle#functionalUnit) = 1 ha, additional properties are required", # noqa: E501
26
- "cycleDuration": "",
27
- "practices": [{"@type": "Practice", "value": "", "term.@id": "longFallowRatio"}]
28
- },
29
- {
30
- "@doc": "for plantations, additional properties are required",
31
- "practices": [
32
- {"@type": "Practice", "value": "", "term.@id": "nurseryDensity"},
33
- {"@type": "Practice", "value": "", "term.@id": "nurseryDuration"},
34
- {"@type": "Practice", "value": "", "term.@id": "plantationProductiveLifespan"},
35
- {"@type": "Practice", "value": "", "term.@id": "plantationDensity"},
36
- {"@type": "Practice", "value": "", "term.@id": "plantationLifespan"},
37
- {"@type": "Practice", "value": "", "term.@id": "rotationDuration"}
38
- ]
39
- }
40
- ]
41
- }
42
- }
43
- }
44
- LOOKUPS = {
45
- "crop": "cropGroupingFaostatArea",
46
- "region-crop-cropGroupingFaostatArea-landTransformation20YearsAverage": "use crop grouping above or default to site.siteType" # noqa: E501
47
- }
48
- RETURNS = {
49
- "Indicator": [{
50
- "value": ""
51
- }]
52
- }
53
- TERM_ID = 'landTransformationFromForest20YearAverageDuringCycle'
54
-
55
-
56
- def _indicator(term_id: str, value: float):
57
- indicator = _new_indicator(term_id, MODEL)
58
- indicator['value'] = value
59
- return indicator
60
-
61
-
62
- def _run(impact_assessment: dict, land_occupation_m2: float, factor: float):
63
- value = land_occupation_m2 * (factor or 0)
64
- debugValues(impact_assessment, model=MODEL, term=TERM_ID,
65
- value=value)
66
- return _indicator(TERM_ID, value)
67
-
68
-
69
- def _should_run(impact_assessment: dict):
70
- cycle = impact_assessment.get('cycle', {})
71
- product = get_product(impact_assessment)
72
- site = get_site(impact_assessment)
73
- land_occupation_m2_kg = land_occupation_per_kg(MODEL, TERM_ID, cycle, site, product)
74
- land_transformation_factor = get_emission_factor(TERM_ID, cycle, 'landTransformation20YearsAverage')
75
-
76
- logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
77
- land_occupation_m2_kg=land_occupation_m2_kg,
78
- land_transformation_factor=land_transformation_factor)
79
-
80
- should_run = all([
81
- land_occupation_m2_kg is not None,
82
- land_occupation_m2_kg == 0 or land_transformation_factor is not None
83
- ])
84
- logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
85
- return should_run, land_occupation_m2_kg, land_transformation_factor
86
-
87
-
88
- def run(impact_assessment: dict):
89
- should_run, land_occupation_m2, factor = _should_run(impact_assessment)
90
- return [_run(impact_assessment, land_occupation_m2, factor)] if should_run else []