hestia-earth-models 0.59.6__py3-none-any.whl → 0.60.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 (49) hide show
  1. hestia_earth/models/cache_sites.py +8 -8
  2. hestia_earth/models/cycle/siteDuration.py +1 -1
  3. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +9 -6
  4. hestia_earth/models/faostat2018/product/price.py +14 -3
  5. hestia_earth/models/geospatialDatabase/utils.py +0 -1
  6. hestia_earth/models/ipcc2019/animal/__init__.py +0 -0
  7. hestia_earth/models/ipcc2019/animal/pastureGrass.py +298 -0
  8. hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +1 -1
  9. hestia_earth/models/ipcc2019/{co2ToAirSoilCarbonStockChangeManagementChange.py → co2ToAirSoilOrganicCarbonStockChangeManagementChange.py} +2 -2
  10. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +2 -7
  11. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +7 -2
  12. hestia_earth/models/ipcc2019/pastureGrass.py +73 -447
  13. hestia_earth/models/ipcc2019/pastureGrass_utils.py +415 -0
  14. hestia_earth/models/mocking/search-results.json +215 -207
  15. hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +14 -2
  16. hestia_earth/models/utils/completeness.py +17 -14
  17. hestia_earth/models/utils/feedipedia.py +23 -23
  18. hestia_earth/models/utils/property.py +4 -1
  19. hestia_earth/models/utils/site.py +7 -4
  20. hestia_earth/models/version.py +1 -1
  21. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/LICENSE +1 -1
  22. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/METADATA +1 -1
  23. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/RECORD +49 -44
  24. tests/models/cycle/animal/input/test_properties.py +3 -1
  25. tests/models/cycle/animal/test_properties.py +4 -2
  26. tests/models/cycle/input/test_properties.py +3 -1
  27. tests/models/cycle/product/test_properties.py +2 -1
  28. tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -0
  29. tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -0
  30. tests/models/cycle/test_energyContentLowerHeatingValue.py +1 -0
  31. tests/models/cycle/test_feedConversionRatio.py +10 -0
  32. tests/models/cycle/test_readyToCookWeightPerHead.py +1 -0
  33. tests/models/faostat2018/product/test_price.py +15 -3
  34. tests/models/ipcc2006/test_n2OToAirCropResidueDecompositionDirect.py +4 -1
  35. tests/models/ipcc2019/animal/__init__.py +0 -0
  36. tests/models/ipcc2019/animal/test_pastureGrass.py +45 -0
  37. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +32 -8
  38. tests/models/ipcc2019/{test_co2ToAirSoilCarbonStockChangeManagementChange.py → test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py} +1 -1
  39. tests/models/ipcc2019/test_n2OToAirCropResidueDecompositionDirect.py +6 -1
  40. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserDirect.py +6 -1
  41. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserDirect.py +6 -1
  42. tests/models/ipcc2019/test_organicCarbonPerHa.py +95 -40
  43. tests/models/ipcc2019/test_pastureGrass.py +32 -8
  44. tests/models/pooreNemecek2018/test_excretaKgN.py +5 -0
  45. tests/models/pooreNemecek2018/test_excretaKgVs.py +5 -0
  46. tests/models/pooreNemecek2018/test_no3ToGroundwaterSoilFlux.py +1 -0
  47. tests/models/test_cache_sites.py +22 -7
  48. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/WHEEL +0 -0
  49. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,14 @@ from hestia_earth.models.cycle.feedConversionRatio import MODEL, run, _should_ru
8
8
  class_path = f"hestia_earth.models.{MODEL}.feedConversionRatio"
9
9
  fixtures_folder = f"{fixtures_path}/{MODEL}/feedConversionRatio"
10
10
 
11
+ TERMS_BY_ID = {
12
+ 'energyContentHigherHeatingValue': {'units': 'MJ / kg'},
13
+ 'crudeProteinContent': {'units': '%'},
14
+ }
15
+
16
+
17
+ def fake_download_hestia(term_id: str, *args): return TERMS_BY_ID[term_id]
18
+
11
19
 
12
20
  @patch(f"{class_path}.get_total_value_converted_with_min_ratio", return_value=10)
13
21
  def test_should_run(*args):
@@ -29,6 +37,7 @@ def test_should_run(*args):
29
37
  assert should_run is True
30
38
 
31
39
 
40
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
32
41
  @patch(f"{class_path}.is_run_required", return_value=True)
33
42
  @patch(f"{class_path}._new_practice", side_effect=fake_new_practice)
34
43
  def test_run(*args):
@@ -42,6 +51,7 @@ def test_run(*args):
42
51
  assert value == expected
43
52
 
44
53
 
54
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
45
55
  @patch(f"{class_path}.is_run_required", return_value=True)
46
56
  @patch(f"{class_path}._new_practice", side_effect=fake_new_practice)
47
57
  def test_run_with_carcass(*args):
@@ -34,6 +34,7 @@ def test_should_run():
34
34
  assert should_run is True
35
35
 
36
36
 
37
+ @patch("hestia_earth.models.utils.property.download_hestia", return_value={'units': '%'})
37
38
  @patch(f"{class_path}._new_property", side_effect=fake_new_property)
38
39
  def test_run(*args):
39
40
  with open(f"{fixtures_folder}/cycle.jsonld", encoding='utf-8') as f:
@@ -27,11 +27,23 @@ def test_run_crop(*args):
27
27
 
28
28
 
29
29
  @patch(f"{class_path}.download_hestia", return_value={})
30
- def test_run_animalProduct(*args):
31
- with open(f"{fixtures_folder}/animalProduct/cycle.jsonld", encoding='utf-8') as f:
30
+ def test_run_animalProduct_kg(*args):
31
+ with open(f"{fixtures_folder}/animalProduct/kg/cycle.jsonld", encoding='utf-8') as f:
32
32
  cycle = json.load(f)
33
33
 
34
- with open(f"{fixtures_folder}/animalProduct/result.jsonld", encoding='utf-8') as f:
34
+ with open(f"{fixtures_folder}/animalProduct/kg/result.jsonld", encoding='utf-8') as f:
35
+ expected = json.load(f)
36
+
37
+ value = run(cycle)
38
+ assert value == expected
39
+
40
+
41
+ @patch(f"{class_path}.download_hestia", return_value={})
42
+ def test_run_animalProduct_number(*args):
43
+ with open(f"{fixtures_folder}/animalProduct/number/cycle.jsonld", encoding='utf-8') as f:
44
+ cycle = json.load(f)
45
+
46
+ with open(f"{fixtures_folder}/animalProduct/number/result.jsonld", encoding='utf-8') as f:
35
47
  expected = json.load(f)
36
48
 
37
49
  value = run(cycle)
@@ -8,9 +8,10 @@ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
10
 
11
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
11
12
  @patch(f"{class_path}._is_term_type_complete", return_value=False)
12
13
  @patch(f"{class_path}.get_crop_residue_decomposition_N_total", return_value=0)
13
- def test_should_run(mock_N_total, mock_complete):
14
+ def test_should_run(mock_N_total, mock_complete, *args):
14
15
  # no N => no run
15
16
  should_run, *args = _should_run({})
16
17
  assert not should_run
@@ -26,6 +27,7 @@ def test_should_run(mock_N_total, mock_complete):
26
27
  assert should_run is True
27
28
 
28
29
 
30
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
29
31
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
30
32
  def test_run(*args):
31
33
  with open(f"{fixtures_folder}/cycle.jsonld", encoding='utf-8') as f:
@@ -38,6 +40,7 @@ def test_run(*args):
38
40
  assert value == expected
39
41
 
40
42
 
43
+ @patch(f"{class_path}.has_flooded_rice", return_value=True)
41
44
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
42
45
  def test_run_flooded_rice(*args):
43
46
  with open(f"{fixtures_folder}/with-flooded-rice/cycle.jsonld", encoding='utf-8') as f:
File without changes
@@ -0,0 +1,45 @@
1
+ from unittest.mock import patch
2
+ import json
3
+ from tests.utils import fixtures_path, fake_new_input
4
+
5
+ from tests.models.ipcc2019.test_pastureGrass import MILK_YIELD_TERMS, WOOL_TERMS, TERMS_BY_ID
6
+ from hestia_earth.models.ipcc2019.animal.pastureGrass import MODEL, MODEL_KEY, run
7
+
8
+ class_path = f"hestia_earth.models.{MODEL}.{MODEL_KEY.replace('/', '.')}"
9
+ class_path_utils = f"hestia_earth.models.{MODEL}.pastureGrass_utils"
10
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{MODEL_KEY}"
11
+
12
+
13
+ def fake_download_hestia(term_id: str, *args): return TERMS_BY_ID[term_id]
14
+
15
+
16
+ @patch(f"{class_path_utils}.download_hestia", side_effect=fake_download_hestia)
17
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
18
+ @patch(f"{class_path}.get_wool_terms", return_value=WOOL_TERMS)
19
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=MILK_YIELD_TERMS)
20
+ @patch(f"{class_path}._new_input", side_effect=fake_new_input)
21
+ def test_run_with_feed(*args):
22
+ with open(f"{fixtures_folder}/with-feed/cycle.jsonld", encoding='utf-8') as f:
23
+ cycle = json.load(f)
24
+
25
+ with open(f"{fixtures_folder}/with-feed/result.jsonld", encoding='utf-8') as f:
26
+ expected = json.load(f)
27
+
28
+ value = run(cycle)
29
+ assert value == expected
30
+
31
+
32
+ @patch(f"{class_path_utils}.download_hestia", side_effect=fake_download_hestia)
33
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
34
+ @patch(f"{class_path}.get_wool_terms", return_value=WOOL_TERMS)
35
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=MILK_YIELD_TERMS)
36
+ @patch(f"{class_path}._new_input", side_effect=fake_new_input)
37
+ def test_run_with_goats(*args):
38
+ with open(f"{fixtures_folder}/with-goats/cycle.jsonld", encoding='utf-8') as f:
39
+ cycle = json.load(f)
40
+
41
+ with open(f"{fixtures_folder}/with-goats/result.jsonld", encoding='utf-8') as f:
42
+ expected = json.load(f)
43
+
44
+ value = run(cycle)
45
+ assert value == expected
@@ -7,7 +7,18 @@ from hestia_earth.models.ipcc2019.ch4ToAirEntericFermentation import MODEL, TERM
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
+ TERMS_BY_ID = {
11
+ 'energyContentHigherHeatingValue': {'units': 'MJ / kg'},
12
+ 'energyDigestibilityRuminants': {'units': '%'},
13
+ 'energyDigestibilityPoultry': {'units': '%'},
14
+ 'neutralDetergentFibreContent': {'units': '%'}
15
+ }
10
16
 
17
+
18
+ def fake_download_hestia(term_id: str, *args): return TERMS_BY_ID[term_id]
19
+
20
+
21
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
11
22
  @patch(f"{class_path}.get_default_digestibility", return_value=70)
12
23
  @patch(f"{class_path}.find_primary_product", return_value={'term': {'@id': 'pig'}})
13
24
  @patch(f"{class_path}._get_lookup_value", return_value=0)
@@ -41,6 +52,8 @@ def test_should_run(mock_feed, mock_lookup_value, *args):
41
52
  assert should_run is True
42
53
 
43
54
 
55
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
56
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
44
57
  # patch get_node_property to read value from lookups only
45
58
  @patch('hestia_earth.models.utils.property.get_node_property', return_value=None)
46
59
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
@@ -55,6 +68,8 @@ def test_run(*args):
55
68
  assert result == expected
56
69
 
57
70
 
71
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
72
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
58
73
  # patch get_node_property to read value from lookups only
59
74
  @patch('hestia_earth.models.utils.property.get_node_property', return_value=None)
60
75
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
@@ -70,9 +85,9 @@ def test_run_dairy(*args):
70
85
 
71
86
 
72
87
  @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=['milkYieldPerBuffaloRaw'])
88
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
73
89
  # patch get_node_property to read value from lookups only
74
90
  @patch('hestia_earth.models.utils.property.get_node_property', return_value={})
75
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
76
91
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
77
92
  def test_run_with_milkYield(*args):
78
93
  with open(f"{fixtures_folder}/with-milkYield/cycle.jsonld", encoding="utf-8") as f:
@@ -85,9 +100,10 @@ def test_run_with_milkYield(*args):
85
100
  assert result == expected
86
101
 
87
102
 
103
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
104
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
88
105
  # patch get_node_property to read value from lookups only
89
106
  @patch('hestia_earth.models.utils.property.get_node_property', return_value={})
90
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
91
107
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
92
108
  def test_run_non_dairy(*args):
93
109
  with open(f"{fixtures_folder}/non-dairy-buffalo-cows/cycle.jsonld", encoding="utf-8") as f:
@@ -100,9 +116,10 @@ def test_run_non_dairy(*args):
100
116
  assert result == expected
101
117
 
102
118
 
119
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
120
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
103
121
  # patch get_node_property to read value from lookups only
104
122
  @patch('hestia_earth.models.utils.property.get_node_property', return_value={})
105
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
106
123
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
107
124
  def test_run_with_ionophores(*args):
108
125
  with open(f"{fixtures_folder}/with-ionophores/cycle.jsonld", encoding="utf-8") as f:
@@ -115,9 +132,10 @@ def test_run_with_ionophores(*args):
115
132
  assert result == expected
116
133
 
117
134
 
135
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
136
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
118
137
  # patch get_node_property to read value from lookups only
119
138
  @patch('hestia_earth.models.utils.property.get_node_property', return_value={})
120
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
121
139
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
122
140
  def test_run_without_ionophores(*args):
123
141
  with open(f"{fixtures_folder}/without-ionophores/cycle.jsonld", encoding="utf-8") as f:
@@ -130,9 +148,10 @@ def test_run_without_ionophores(*args):
130
148
  assert result == expected
131
149
 
132
150
 
151
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
152
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
133
153
  # patch get_node_property to read value from lookups only
134
154
  @patch('hestia_earth.models.utils.property.get_node_property', return_value={})
135
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
136
155
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
137
156
  def test_run_no_feed(*args):
138
157
  with open(f"{fixtures_folder}/no-feed/cycle.jsonld", encoding="utf-8") as f:
@@ -142,9 +161,10 @@ def test_run_no_feed(*args):
142
161
  assert result == []
143
162
 
144
163
 
164
+ @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
165
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
145
166
  # patch get_node_property to read value from lookups only
146
167
  @patch('hestia_earth.models.utils.property.get_node_property', return_value={})
147
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
148
168
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
149
169
  def test_run_with_system(*args):
150
170
  with open(f"{fixtures_folder}/with-system/cycle.jsonld", encoding="utf-8") as f:
@@ -157,9 +177,13 @@ def test_run_with_system(*args):
157
177
  assert result == expected
158
178
 
159
179
 
180
+ def fake_get_node_property(*args):
181
+ print(*args)
182
+ return {}
183
+
184
+
160
185
  @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=[])
161
- # patch get_node_property to read value from lookups only
162
- @patch('hestia_earth.models.utils.property.download_hestia', return_value={})
186
+ @patch("hestia_earth.models.utils.property.download_hestia", return_value={})
163
187
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
164
188
  def test_run_default(*args):
165
189
  with open(f"{fixtures_folder}/default-value/cycle.jsonld", encoding="utf-8") as f:
@@ -5,7 +5,7 @@ from unittest.mock import patch
5
5
 
6
6
  from hestia_earth.schema import MeasurementMethodClassification
7
7
 
8
- from hestia_earth.models.ipcc2019.co2ToAirSoilCarbonStockChangeManagementChange import (
8
+ from hestia_earth.models.ipcc2019.co2ToAirSoilOrganicCarbonStockChangeManagementChange import (
9
9
  _calc_soc_stock_change,
10
10
  _convert_c_to_co2,
11
11
  _get_max_measurement_method,
@@ -8,9 +8,10 @@ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
10
 
11
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
11
12
  @patch(f"{class_path}._is_term_type_complete", return_value=False)
12
13
  @patch(f"{class_path}.get_crop_residue_decomposition_N_total", return_value=0)
13
- def test_should_run(mock_N_total, mock_complete):
14
+ def test_should_run(mock_N_total, mock_complete, *args):
14
15
  # no N => no run
15
16
  should_run, *args = _should_run({})
16
17
  assert not should_run
@@ -26,6 +27,7 @@ def test_should_run(mock_N_total, mock_complete):
26
27
  assert should_run is True
27
28
 
28
29
 
30
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
29
31
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
30
32
  def test_run(*args):
31
33
  with open(f"{fixtures_folder}/cycle.jsonld", encoding='utf-8') as f:
@@ -38,6 +40,7 @@ def test_run(*args):
38
40
  assert value == expected
39
41
 
40
42
 
43
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
41
44
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
42
45
  def test_run_wet(*args):
43
46
  with open(f"{fixtures_folder}/ecoClimateZone-wet/cycle.jsonld", encoding='utf-8') as f:
@@ -50,6 +53,7 @@ def test_run_wet(*args):
50
53
  assert value == expected
51
54
 
52
55
 
56
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
53
57
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
54
58
  def test_run_dry(*args):
55
59
  with open(f"{fixtures_folder}/ecoClimateZone-dry/cycle.jsonld", encoding='utf-8') as f:
@@ -62,6 +66,7 @@ def test_run_dry(*args):
62
66
  assert value == expected
63
67
 
64
68
 
69
+ @patch(f"{class_path}.has_flooded_rice", return_value=True)
65
70
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
66
71
  def test_run_flooded_rice(*args):
67
72
  with open(f"{fixtures_folder}/with-flooded-rice/cycle.jsonld", encoding='utf-8') as f:
@@ -8,9 +8,10 @@ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
10
 
11
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
11
12
  @patch(f"{class_path}._is_term_type_complete", return_value=False)
12
13
  @patch(f"{class_path}.get_inorganic_fertiliser_N_total", return_value=0)
13
- def test_should_run(mock_N_total, mock_complete):
14
+ def test_should_run(mock_N_total, mock_complete, *args):
14
15
  # no N => no run
15
16
  should_run, *args = _should_run({})
16
17
  assert not should_run
@@ -26,6 +27,7 @@ def test_should_run(mock_N_total, mock_complete):
26
27
  assert should_run is True
27
28
 
28
29
 
30
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
29
31
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
30
32
  def test_run(*args):
31
33
  with open(f"{fixtures_folder}/cycle.jsonld", encoding='utf-8') as f:
@@ -38,6 +40,7 @@ def test_run(*args):
38
40
  assert value == expected
39
41
 
40
42
 
43
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
41
44
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
42
45
  def test_run_wet(*args):
43
46
  with open(f"{fixtures_folder}/ecoClimateZone-wet/cycle.jsonld", encoding='utf-8') as f:
@@ -50,6 +53,7 @@ def test_run_wet(*args):
50
53
  assert value == expected
51
54
 
52
55
 
56
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
53
57
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
54
58
  def test_run_dry(*args):
55
59
  with open(f"{fixtures_folder}/ecoClimateZone-dry/cycle.jsonld", encoding='utf-8') as f:
@@ -62,6 +66,7 @@ def test_run_dry(*args):
62
66
  assert value == expected
63
67
 
64
68
 
69
+ @patch(f"{class_path}.has_flooded_rice", return_value=True)
65
70
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
66
71
  def test_run_flooded_rice(*args):
67
72
  with open(f"{fixtures_folder}/with-flooded-rice/cycle.jsonld", encoding='utf-8') as f:
@@ -8,9 +8,10 @@ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
10
 
11
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
11
12
  @patch(f"{class_path}._is_term_type_complete", return_value=False)
12
13
  @patch(f"{class_path}.get_organic_fertiliser_N_total", return_value=0)
13
- def test_should_run(mock_N_total, mock_complete):
14
+ def test_should_run(mock_N_total, mock_complete, *args):
14
15
  # no N => no run
15
16
  should_run, *args = _should_run({})
16
17
  assert not should_run
@@ -26,6 +27,7 @@ def test_should_run(mock_N_total, mock_complete):
26
27
  assert should_run is True
27
28
 
28
29
 
30
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
29
31
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
30
32
  def test_run(*args):
31
33
  with open(f"{fixtures_folder}/cycle.jsonld", encoding='utf-8') as f:
@@ -38,6 +40,7 @@ def test_run(*args):
38
40
  assert value == expected
39
41
 
40
42
 
43
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
41
44
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
42
45
  def test_run_wet(*args):
43
46
  with open(f"{fixtures_folder}/ecoClimateZone-wet/cycle.jsonld", encoding='utf-8') as f:
@@ -50,6 +53,7 @@ def test_run_wet(*args):
50
53
  assert value == expected
51
54
 
52
55
 
56
+ @patch(f"{class_path}.has_flooded_rice", return_value=False)
53
57
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
54
58
  def test_run_dry(*args):
55
59
  with open(f"{fixtures_folder}/ecoClimateZone-dry/cycle.jsonld", encoding='utf-8') as f:
@@ -62,6 +66,7 @@ def test_run_dry(*args):
62
66
  assert value == expected
63
67
 
64
68
 
69
+ @patch(f"{class_path}.has_flooded_rice", return_value=True)
65
70
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
66
71
  def test_run_flooded_rice(*args):
67
72
  with open(f"{fixtures_folder}/with-flooded-rice/cycle.jsonld", encoding='utf-8') as f:
@@ -20,6 +20,7 @@ from hestia_earth.models.ipcc2019.organicCarbonPerHa import (
20
20
  _check_cropland_medium_category,
21
21
  _get_carbon_input_kwargs,
22
22
  _iterate_soc_equilibriums,
23
+ _should_run,
23
24
  IpccCarbonInputCategory,
24
25
  IpccLandUseCategory,
25
26
  IpccManagementCategory,
@@ -103,37 +104,38 @@ def find_term_property_side_effect(term: dict, property: str, *_):
103
104
  # --- TIER 1 & TIER 2 TESTS ---
104
105
 
105
106
 
106
- # subfolder, load_cycles
107
- RUN_SUBFOLDERS = [
108
- ("tier-1-and-2/cropland", True),
109
- ("tier-1-and-2/with-zero-carbon-input", True), # Closes issue 777
110
- ("tier-2/with-generalised-monthly-measurements", True), # Closes issue 600
111
- ("tier-2/with-incomplete-climate-data", True), # Closes issue 599
112
- ("tier-2/with-initial-soc", True),
113
- ("tier-2/with-multi-year-cycles", True),
114
- ("tier-2/with-multi-year-cycles-and-missing-properties", True), # Closes issue 734
115
- ("tier-2/without-any-measurements", True), # Closes issue 594
116
- ("tier-2/without-initial-soc", True),
117
- ("tier-2/with-irrigation", True),
118
- ("tier-2/with-irrigation-dates", True),
119
- ("tier-2/with-paddy-rice", True),
120
- ("tier-2/with-sand-without-date", True), # Closes issue 739
121
- ("tier-2/with-irrigated-upland-rice", True),
122
- ("tier-1/cropland-depth-as-float", False),
123
- ("tier-1/cropland-with-measured-soc", False),
124
- ("tier-1/cropland-without-measured-soc", False),
125
- ("tier-1/permanent-pasture", False),
126
- ("tier-1/should-not-run", False),
127
- ("tier-1/without-management-with-measured-soc", False),
128
- ("tier-1/land-use-change", False), # Closes issue 755
129
- ("tier-1/run-with-site-type", False) # Closes issue 755
107
+ # subfolder, load_cycles, should_run
108
+ SHOULD_RUN_SUBFOLDERS = [
109
+ ("tier-1-and-2/cropland", True, True),
110
+ ("tier-1-and-2/with-zero-carbon-input", True, True), # Closes issue 777
111
+ ("tier-2/with-generalised-monthly-measurements", True, False), # Closes issue 600
112
+ ("tier-2/with-incomplete-climate-data", True, False), # Closes issue 599
113
+ ("tier-2/with-initial-soc", True, True),
114
+ ("tier-2/with-multi-year-cycles", True, True),
115
+ ("tier-2/with-multi-year-cycles-and-missing-properties", True, True), # Closes issue 734
116
+ ("tier-2/without-any-measurements", True, False), # Closes issue 594
117
+ ("tier-2/without-initial-soc", True, True),
118
+ ("tier-2/with-irrigation", True, True),
119
+ ("tier-2/with-irrigation-dates", True, True),
120
+ ("tier-2/with-paddy-rice", True, False),
121
+ ("tier-2/with-sand-without-date", True, True), # Closes issue 739
122
+ ("tier-2/with-irrigated-upland-rice", True, False),
123
+ ("tier-1/cropland-depth-as-float", False, True),
124
+ ("tier-1/cropland-with-measured-soc", False, True),
125
+ ("tier-1/cropland-without-measured-soc", False, True),
126
+ ("tier-1/permanent-pasture", False, True),
127
+ ("tier-1/should-not-run", False, False),
128
+ ("tier-1/without-management-with-measured-soc", False, False),
129
+ ("tier-1/land-use-change", False, True), # Closes issue 755
130
+ ("tier-1/run-with-site-type", False, True), # Closes issue 755
131
+ ("tier-1/cropland-polar", False, False) # Closes issue 794
130
132
  ]
131
133
 
132
134
 
133
135
  @mark.parametrize(
134
- "subfolder, load_cycles",
135
- RUN_SUBFOLDERS,
136
- ids=[params[0] for params in RUN_SUBFOLDERS]
136
+ "subfolder, load_cycles, should_run",
137
+ SHOULD_RUN_SUBFOLDERS,
138
+ ids=[params[0] for params in SHOULD_RUN_SUBFOLDERS]
137
139
  )
138
140
  @patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
139
141
  @patch(f"{class_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
@@ -143,8 +145,8 @@ RUN_SUBFOLDERS = [
143
145
  @patch(f"{class_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
144
146
  @patch(f"{class_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
145
147
  @patch(f"{class_path}.related_cycles")
146
- @patch("hestia_earth.models.utils.property.find_term_property")
147
- def test_run(
148
+ @patch("hestia_earth.models.utils.property.find_term_property", side_effect=find_term_property_side_effect)
149
+ def test_should_run(
148
150
  mock_find_term_property,
149
151
  mock_related_cycles,
150
152
  _mock_get_upland_rice_crop_terms,
@@ -155,7 +157,8 @@ def test_run(
155
157
  _mock_get_cover_crop_property_terms,
156
158
  _mock_new_measurement,
157
159
  subfolder,
158
- load_cycles
160
+ load_cycles,
161
+ should_run
159
162
  ):
160
163
  folder = f"{fixtures_folder}/{subfolder}"
161
164
 
@@ -163,20 +166,17 @@ def test_run(
163
166
  with open(f"{folder}/cycles.jsonld", encoding='utf-8') as f:
164
167
  return json.load(f)
165
168
 
166
- mock_find_term_property.side_effect = find_term_property_side_effect
167
169
  mock_related_cycles.return_value = load_cycles_from_file() if load_cycles else []
168
170
 
169
171
  with open(f"{folder}/site.jsonld", encoding='utf-8') as f:
170
172
  site = json.load(f)
171
173
 
172
- with open(f"{folder}/result.jsonld", encoding='utf-8') as f:
173
- expected = json.load(f)
174
+ should_run_tier_1, should_run_tier_2, *_ = _should_run(site)
175
+ should_run_ = should_run_tier_1 or should_run_tier_2
174
176
 
175
- result = run(site)
176
- assert result == expected
177
+ assert should_run_ == should_run
177
178
 
178
179
 
179
- @patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
180
180
  @patch(f"{class_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
181
181
  @patch(f"{class_path}.get_crop_residue_incorporated_or_left_on_field_terms", return_value=CROP_RESIDUE_INCORP_TERM_IDS)
182
182
  @patch(f"{class_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
@@ -184,11 +184,66 @@ def test_run(
184
184
  @patch(f"{class_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
185
185
  @patch(f"{class_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
186
186
  @patch(f"{class_path}.related_cycles", return_value=[])
187
- def test_run_no_data(*args):
187
+ @patch("hestia_earth.models.utils.property.find_term_property", side_effect=find_term_property_side_effect)
188
+ def test_should_run_no_data(*args):
188
189
  SITE = {}
189
- EXPECTED = []
190
- result = run(SITE)
191
- assert result == EXPECTED
190
+ EXPECTED = False
191
+
192
+ should_run_tier_1, should_run_tier_2, *_ = _should_run(SITE)
193
+ should_run = should_run_tier_1 or should_run_tier_2
194
+
195
+ assert should_run == EXPECTED
196
+
197
+
198
+ RUN_SUBFOLDERS = [
199
+ (subfolder, load_cycles) for subfolder, load_cycles, should_run in SHOULD_RUN_SUBFOLDERS
200
+ if should_run
201
+ ]
202
+
203
+
204
+ @mark.parametrize(
205
+ "subfolder, load_cycles",
206
+ RUN_SUBFOLDERS,
207
+ ids=[params[0] for params in RUN_SUBFOLDERS]
208
+ )
209
+ @patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
210
+ @patch(f"{class_path}.get_cover_crop_property_terms", return_value=COVER_CROP_PROPERTY_TERM_IDS)
211
+ @patch(f"{class_path}.get_crop_residue_incorporated_or_left_on_field_terms", return_value=CROP_RESIDUE_INCORP_TERM_IDS)
212
+ @patch(f"{class_path}.get_irrigated_terms", return_value=IRRIGATED_TERM_IDS)
213
+ @patch(f"{class_path}.get_residue_removed_or_burnt_terms", return_value=RESIDUE_REMOVED_OR_BURNT_TERM_IDS)
214
+ @patch(f"{class_path}.get_upland_rice_land_cover_terms", return_value=UPLAND_RICE_LAND_COVER_TERM_IDS)
215
+ @patch(f"{class_path}.get_upland_rice_crop_terms", return_value=UPLAND_RICE_CROP_TERM_IDS)
216
+ @patch(f"{class_path}.related_cycles")
217
+ @patch("hestia_earth.models.utils.property.find_term_property", side_effect=find_term_property_side_effect)
218
+ def test_run(
219
+ mock_find_term_property,
220
+ mock_related_cycles,
221
+ _mock_get_upland_rice_crop_terms,
222
+ _mock_get_upland_rice_land_cover_terms,
223
+ _mock_get_residue_removed_or_burnt_terms,
224
+ _mock_get_irrigated_terms,
225
+ _mock_get_crop_residue_incorporated_or_left_on_field_terms,
226
+ _mock_get_cover_crop_property_terms,
227
+ _mock_new_measurement,
228
+ subfolder,
229
+ load_cycles
230
+ ):
231
+ folder = f"{fixtures_folder}/{subfolder}"
232
+
233
+ def load_cycles_from_file():
234
+ with open(f"{folder}/cycles.jsonld", encoding='utf-8') as f:
235
+ return json.load(f)
236
+
237
+ mock_related_cycles.return_value = load_cycles_from_file() if load_cycles else []
238
+
239
+ with open(f"{folder}/site.jsonld", encoding='utf-8') as f:
240
+ site = json.load(f)
241
+
242
+ with open(f"{folder}/result.jsonld", encoding='utf-8') as f:
243
+ expected = json.load(f)
244
+
245
+ result = run(site)
246
+ assert result == expected
192
247
 
193
248
 
194
249
  # --- TIER 2 TESTS: SUB-MODELS ---
@@ -5,15 +5,37 @@ from tests.utils import fixtures_path, fake_new_input
5
5
  from hestia_earth.models.ipcc2019.pastureGrass import MODEL, MODEL_KEY, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{MODEL_KEY}"
8
+ class_path_utils = f"{class_path}_utils"
8
9
  fixtures_folder = f"{fixtures_path}/{MODEL}/{MODEL_KEY}"
9
10
  MILK_YIELD_TERMS = ['milkYieldPerCowRaw', 'milkYieldPerSheepRaw']
10
11
  WOOL_TERMS = ['woolSheepGreasy']
11
-
12
-
13
- def fake_download_hestia(term_id: str, *args): return {'@id': term_id, 'termType': 'forage'}
14
-
15
-
16
- @patch(f"{class_path}.download_hestia", side_effect=fake_download_hestia)
12
+ TERMS_BY_ID = {
13
+ 'surinameGrassFreshForage': {
14
+ '@id': 'surinameGrassFreshForage',
15
+ 'termType': 'forage',
16
+ 'defaultProperties': [
17
+ {'term': {'@id': 'energyContentHigherHeatingValue'}, 'value': 4.8508},
18
+ {'term': {'@id': 'energyDigestibilityRuminants'}, 'value': 52.7}
19
+ ]
20
+ },
21
+ 'alangAlangFreshForage': {
22
+ '@id': 'alangAlangFreshForage',
23
+ 'termType': 'forage',
24
+ 'defaultProperties': [
25
+ {'term': {'@id': 'energyContentHigherHeatingValue'}, 'value': 5.9334},
26
+ {'term': {'@id': 'energyDigestibilityRuminants'}, 'value': 54.7}
27
+ ]
28
+ },
29
+ 'energyContentHigherHeatingValue': {'units': 'MJ / kg'},
30
+ 'energyDigestibilityRuminants': {'units': '%'},
31
+ }
32
+
33
+
34
+ def fake_download_hestia(term_id: str, *args): return TERMS_BY_ID[term_id]
35
+
36
+
37
+ @patch(f"{class_path_utils}.download_hestia", side_effect=fake_download_hestia)
38
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
17
39
  @patch(f"{class_path}.get_wool_terms", return_value=WOOL_TERMS)
18
40
  @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=MILK_YIELD_TERMS)
19
41
  @patch(f"{class_path}._new_input", side_effect=fake_new_input)
@@ -28,7 +50,8 @@ def test_run(*args):
28
50
  assert value == expected
29
51
 
30
52
 
31
- @patch(f"{class_path}.download_hestia", side_effect=fake_download_hestia)
53
+ @patch(f"{class_path_utils}.download_hestia", side_effect=fake_download_hestia)
54
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
32
55
  @patch(f"{class_path}.get_wool_terms", return_value=WOOL_TERMS)
33
56
  @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=MILK_YIELD_TERMS)
34
57
  @patch(f"{class_path}._new_input", side_effect=fake_new_input)
@@ -43,7 +66,8 @@ def test_run_with_feed(*args):
43
66
  assert value == expected
44
67
 
45
68
 
46
- @patch(f"{class_path}.download_hestia", side_effect=fake_download_hestia)
69
+ @patch(f"{class_path_utils}.download_hestia", side_effect=fake_download_hestia)
70
+ @patch("hestia_earth.models.utils.property.download_hestia", side_effect=fake_download_hestia)
47
71
  @patch(f"{class_path}.get_wool_terms", return_value=WOOL_TERMS)
48
72
  @patch(f"hestia_earth.models.{MODEL}.utils.get_milkYield_terms", return_value=MILK_YIELD_TERMS)
49
73
  @patch(f"{class_path}._new_input", side_effect=fake_new_input)