hestia-earth-models 0.70.0__py3-none-any.whl → 0.70.2__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.
Files changed (192) hide show
  1. hestia_earth/models/aware/scarcityWeightedWaterUse.py +8 -16
  2. hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +2 -1
  3. hestia_earth/models/config/Cycle.json +98 -50
  4. hestia_earth/models/config/ImpactAssessment.json +12 -4
  5. hestia_earth/models/config/Site.json +40 -21
  6. hestia_earth/models/cycle/transformation.py +1 -1
  7. hestia_earth/models/cycle/utils.py +0 -6
  8. hestia_earth/models/data/ecoinventV3/__init__.py +15 -13
  9. hestia_earth/models/ecoalimV9/__init__.py +13 -0
  10. hestia_earth/models/ecoalimV9/cycle.py +128 -0
  11. hestia_earth/models/ecoalimV9/impact_assessment.py +125 -0
  12. hestia_earth/models/ecoalimV9/utils.py +31 -0
  13. hestia_earth/models/ecoinventV3/__init__.py +6 -14
  14. hestia_earth/models/ecoinventV3/utils.py +1 -29
  15. hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +8 -2
  16. hestia_earth/models/emissionNotRelevant/__init__.py +33 -8
  17. hestia_earth/models/{cycle → hestia}/aboveGroundCropResidue.py +4 -3
  18. hestia_earth/models/{cycle → hestia}/aboveGroundCropResidueTotal.py +1 -1
  19. hestia_earth/models/{site → hestia}/brackishWater.py +1 -1
  20. hestia_earth/models/{site → hestia}/cationExchangeCapacityPerKgSoil.py +1 -1
  21. hestia_earth/models/{cycle → hestia}/coldCarcassWeightPerHead.py +1 -1
  22. hestia_earth/models/{cycle → hestia}/coldDressedCarcassWeightPerHead.py +1 -1
  23. hestia_earth/models/{cycle → hestia}/concentrateFeed.py +1 -1
  24. hestia_earth/models/{cycle → hestia}/cropResidueManagement.py +1 -1
  25. hestia_earth/models/{cycle → hestia}/croppingIntensity.py +1 -1
  26. hestia_earth/models/{cycle → hestia}/energyContentLowerHeatingValue.py +1 -1
  27. hestia_earth/models/{cycle → hestia}/excretaKgMass.py +8 -3
  28. hestia_earth/models/{cycle → hestia}/excretaKgN.py +1 -1
  29. hestia_earth/models/{cycle → hestia}/excretaKgVs.py +1 -1
  30. hestia_earth/models/{cycle → hestia}/feedConversionRatio/__init__.py +1 -1
  31. hestia_earth/models/{site → hestia}/flowingWater.py +1 -1
  32. hestia_earth/models/{site → hestia}/freshWater.py +1 -1
  33. hestia_earth/models/{cycle → hestia}/inorganicFertiliser.py +1 -1
  34. hestia_earth/models/{cycle → hestia}/irrigatedTypeUnspecified.py +14 -19
  35. hestia_earth/models/hestia/landCover.py +30 -22
  36. hestia_earth/models/{cycle → hestia}/liveAnimal.py +1 -1
  37. hestia_earth/models/{cycle → hestia}/longFallowRatio.py +1 -1
  38. hestia_earth/models/{site → hestia}/management.py +4 -6
  39. hestia_earth/models/{cycle → hestia}/materialAndSubstrate.py +1 -1
  40. hestia_earth/models/{cycle → hestia}/milkYield.py +1 -1
  41. hestia_earth/models/{site → hestia}/netPrimaryProduction.py +1 -1
  42. hestia_earth/models/{site → hestia}/organicCarbonPerHa.py +1 -1
  43. hestia_earth/models/hestia/pToSurfaceWaterAquacultureSystems.py +148 -0
  44. hestia_earth/models/{cycle → hestia}/pastureGrass.py +1 -1
  45. hestia_earth/models/{cycle → hestia}/pastureSystem.py +1 -1
  46. hestia_earth/models/{site → hestia}/potentialEvapotranspirationAnnual.py +3 -3
  47. hestia_earth/models/{site → hestia}/potentialEvapotranspirationMonthly.py +3 -3
  48. hestia_earth/models/{site → hestia}/precipitationAnnual.py +3 -3
  49. hestia_earth/models/{site → hestia}/precipitationMonthly.py +3 -3
  50. hestia_earth/models/{site → hestia}/rainfallAnnual.py +3 -3
  51. hestia_earth/models/{site → hestia}/rainfallMonthly.py +3 -3
  52. hestia_earth/models/{cycle → hestia}/readyToCookWeightPerHead.py +1 -1
  53. hestia_earth/models/{cycle → hestia}/residueBurnt.py +1 -1
  54. hestia_earth/models/{cycle → hestia}/residueIncorporated.py +1 -1
  55. hestia_earth/models/{cycle → hestia}/residueLeftOnField.py +1 -1
  56. hestia_earth/models/hestia/residueRemoved.py +65 -13
  57. hestia_earth/models/{site → hestia}/salineWater.py +1 -1
  58. hestia_earth/models/{site → hestia}/soilMeasurement.py +1 -1
  59. hestia_earth/models/{cycle → hestia}/stockingDensityAnimalHousingAverage.py +1 -1
  60. hestia_earth/models/{site → hestia}/temperatureAnnual.py +3 -3
  61. hestia_earth/models/{site → hestia}/temperatureMonthly.py +3 -3
  62. hestia_earth/models/{site → hestia}/totalNitrogenPerKgSoil.py +1 -1
  63. hestia_earth/models/{cycle → hestia}/unknownPreSeasonWaterRegime.py +1 -1
  64. hestia_earth/models/hestia/utils.py +93 -0
  65. hestia_earth/models/{site → hestia}/waterDepth.py +1 -1
  66. hestia_earth/models/hestia/waterSalinity.py +78 -0
  67. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +1 -1
  68. hestia_earth/models/ipcc2019/belowGroundBiomass.py +1 -1
  69. hestia_earth/models/ipcc2019/biomass_utils.py +2 -4
  70. hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +166 -79
  71. hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +270 -0
  72. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +0 -3
  73. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +0 -3
  74. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +88 -63
  75. hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +7 -5
  76. hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +215 -0
  77. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +0 -3
  78. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +16 -9
  79. hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +161 -0
  80. hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +35 -47
  81. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1.py +86 -1
  82. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2.py +127 -1
  83. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +7 -5
  84. hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +159 -0
  85. hestia_earth/models/mocking/search-results.json +1113 -1113
  86. hestia_earth/models/pooreNemecek2018/utils.py +8 -2
  87. hestia_earth/models/schmidt2007/ch4ToAirWasteTreatment.py +1 -4
  88. hestia_earth/models/schmidt2007/h2SToAirWasteTreatment.py +1 -4
  89. hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +1 -4
  90. hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +1 -4
  91. hestia_earth/models/site/grouped_measurement.py +132 -0
  92. hestia_earth/models/utils/__init__.py +4 -3
  93. hestia_earth/models/utils/background_emissions.py +52 -0
  94. hestia_earth/models/utils/blank_node.py +47 -14
  95. hestia_earth/models/utils/constant.py +26 -20
  96. hestia_earth/models/utils/impact_assessment.py +26 -17
  97. hestia_earth/models/utils/lookup.py +48 -39
  98. hestia_earth/models/utils/measurement.py +3 -3
  99. hestia_earth/models/utils/product.py +39 -1
  100. hestia_earth/models/utils/property.py +14 -6
  101. hestia_earth/models/version.py +1 -1
  102. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/METADATA +2 -2
  103. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/RECORD +187 -171
  104. tests/models/aware/test_scarcityWeightedWaterUse.py +1 -12
  105. tests/models/ecoalimV9/__init__.py +0 -0
  106. tests/models/ecoalimV9/test_cycle.py +21 -0
  107. tests/models/ecoalimV9/test_impact_assessment.py +24 -0
  108. tests/models/environmentalFootprintV3_1/test_scarcityWeightedWaterUse.py +4 -2
  109. tests/models/{cycle → hestia}/test_aboveGroundCropResidue.py +1 -1
  110. tests/models/{cycle → hestia}/test_aboveGroundCropResidueTotal.py +1 -1
  111. tests/models/{site → hestia}/test_brackishWater.py +1 -1
  112. tests/models/{site → hestia}/test_cationExchangeCapacityPerKgSoil.py +1 -1
  113. tests/models/{cycle → hestia}/test_coldCarcassWeightPerHead.py +1 -1
  114. tests/models/{cycle → hestia}/test_coldDressedCarcassWeightPerHead.py +1 -1
  115. tests/models/{cycle → hestia}/test_concentrateFeed.py +1 -1
  116. tests/models/{cycle → hestia}/test_cropResidueManagement.py +1 -1
  117. tests/models/{cycle → hestia}/test_croppingIntensity.py +1 -1
  118. tests/models/{cycle → hestia}/test_energyContentLowerHeatingValue.py +5 -3
  119. tests/models/{cycle → hestia}/test_excretaKgMass.py +1 -1
  120. tests/models/{cycle → hestia}/test_excretaKgN.py +1 -1
  121. tests/models/{cycle → hestia}/test_excretaKgVs.py +1 -1
  122. tests/models/{cycle → hestia}/test_feedConversionRatio.py +3 -4
  123. tests/models/{site → hestia}/test_flowingWater.py +1 -1
  124. tests/models/{site → hestia}/test_freshWater.py +1 -1
  125. tests/models/{cycle → hestia}/test_inorganicFertiliser.py +1 -1
  126. tests/models/{cycle → hestia}/test_irrigatedTypeUnspecified.py +2 -5
  127. tests/models/hestia/test_landCover.py +4 -34
  128. tests/models/{cycle → hestia}/test_liveAnimal.py +1 -1
  129. tests/models/{cycle → hestia}/test_longFallowRatio.py +1 -1
  130. tests/models/{site → hestia}/test_management.py +1 -1
  131. tests/models/{cycle → hestia}/test_materialsAndSubstrate.py +1 -1
  132. tests/models/{cycle → hestia}/test_milkYield.py +1 -1
  133. tests/models/{site → hestia}/test_netPrimaryProduction.py +1 -1
  134. tests/models/{site → hestia}/test_organicCarbonPerHa.py +1 -1
  135. tests/models/{site → hestia}/test_organicCarbonPerKgSoil.py +1 -1
  136. tests/models/{site → hestia}/test_organicCarbonPerM3Soil.py +1 -1
  137. tests/models/{site → hestia}/test_organicMatterPerKgSoil.py +1 -1
  138. tests/models/{site → hestia}/test_organicMatterPerM3Soil.py +1 -1
  139. tests/models/hestia/test_pToSurfaceWaterAquacultureSystems.py +56 -0
  140. tests/models/{cycle → hestia}/test_pastureGrass.py +1 -1
  141. tests/models/{cycle → hestia}/test_pastureSystem.py +1 -1
  142. tests/models/{site → hestia}/test_potentialEvapotranspirationAnnual.py +1 -1
  143. tests/models/{site → hestia}/test_potentialEvapotranspirationMonthly.py +1 -1
  144. tests/models/{site → hestia}/test_precipitationAnnual.py +1 -1
  145. tests/models/{site → hestia}/test_precipitationMonthly.py +1 -1
  146. tests/models/{site → hestia}/test_rainfallAnnual.py +1 -1
  147. tests/models/{site → hestia}/test_rainfallMonthly.py +1 -1
  148. tests/models/{cycle → hestia}/test_readyToCookWeightPerHead.py +1 -1
  149. tests/models/{cycle → hestia}/test_residueBurnt.py +1 -1
  150. tests/models/{cycle → hestia}/test_residueIncorporated.py +1 -1
  151. tests/models/{cycle → hestia}/test_residueLeftOnField.py +1 -1
  152. tests/models/hestia/test_residueRemoved.py +15 -3
  153. tests/models/{site → hestia}/test_salineWater.py +1 -1
  154. tests/models/{site → hestia}/test_soilMeasurement.py +13 -21
  155. tests/models/{cycle → hestia}/test_stockingDensityAnimalHousingAverage.py +1 -1
  156. tests/models/{site → hestia}/test_temperatureAnnual.py +1 -1
  157. tests/models/{site → hestia}/test_temperatureMonthly.py +1 -1
  158. tests/models/{site → hestia}/test_totalNitrogenPerKgSoil.py +1 -1
  159. tests/models/{cycle → hestia}/test_unknownPreSeasonWaterRegime.py +1 -1
  160. tests/models/{site → hestia}/test_waterDepth.py +1 -1
  161. tests/models/hestia/test_waterSalinity.py +26 -0
  162. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +2 -5
  163. tests/models/ipcc2019/test_ch4ToAirFloodedRice.py +10 -42
  164. tests/models/ipcc2019/test_ch4ToAirOrganicSoilCultivation.py +61 -0
  165. tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +11 -9
  166. tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +10 -8
  167. tests/models/ipcc2019/test_co2ToAirLimeHydrolysis.py +1 -1
  168. tests/models/ipcc2019/test_co2ToAirOrganicSoilCultivation.py +62 -0
  169. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +11 -8
  170. tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationDirect.py +61 -0
  171. tests/models/ipcc2019/test_nonCo2EmissionsToAirNaturalVegetationBurning.py +3 -2
  172. tests/models/site/test_grouped_measurement.py +20 -0
  173. tests/models/test_ecoinventV3AndEmberClimate.py +2 -2
  174. tests/models/test_emissionNotRelevant.py +0 -8
  175. tests/models/utils/test_measurement.py +1 -1
  176. hestia_earth/models/cycle/residueRemoved.py +0 -54
  177. hestia_earth/models/hestia/nh3ToSurfaceWaterAquacultureSystems.py +0 -64
  178. hestia_earth/models/site/utils.py +0 -93
  179. tests/models/cycle/test_residueRemoved.py +0 -37
  180. tests/models/hestia/test_nh3ToSurfaceWaterAquacultureSystems.py +0 -51
  181. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioCarbon.py +0 -0
  182. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioDryMatter.py +0 -0
  183. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioEnergy.py +0 -0
  184. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioFedWeight.py +0 -0
  185. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioNitrogen.py +0 -0
  186. /hestia_earth/models/{site → hestia}/organicCarbonPerKgSoil.py +0 -0
  187. /hestia_earth/models/{site → hestia}/organicCarbonPerM3Soil.py +0 -0
  188. /hestia_earth/models/{site → hestia}/organicMatterPerKgSoil.py +0 -0
  189. /hestia_earth/models/{site → hestia}/organicMatterPerM3Soil.py +0 -0
  190. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/LICENSE +0 -0
  191. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/WHEEL +0 -0
  192. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fake_new_practice, fixtures_path
4
4
 
5
- from hestia_earth.models.cycle.residueBurnt import MODEL, TERM_ID, _should_run, run
5
+ from hestia_earth.models.hestia.residueBurnt import MODEL, TERM_ID, _should_run, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fake_new_practice, fixtures_path
4
4
 
5
- from hestia_earth.models.cycle.residueIncorporated import MODEL, TERM_ID, _should_run, run
5
+ from hestia_earth.models.hestia.residueIncorporated import MODEL, TERM_ID, _should_run, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fake_new_practice, fixtures_path
4
4
 
5
- from hestia_earth.models.cycle.residueLeftOnField import MODEL, TERM_ID, _should_run, run
5
+ from hestia_earth.models.hestia.residueLeftOnField import MODEL, TERM_ID, _should_run, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -9,11 +9,23 @@ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
10
 
11
11
  @patch(f"{class_path}._new_practice", side_effect=fake_new_practice)
12
- def test_run(*args):
13
- with open(f"{fixtures_folder}/cycle.jsonld", encoding='utf-8') as f:
12
+ def test_run_by_products(*args):
13
+ with open(f"{fixtures_folder}/by-products/cycle.jsonld", encoding='utf-8') as f:
14
14
  cycle = json.load(f)
15
15
 
16
- with open(f"{fixtures_folder}/result.jsonld", encoding='utf-8') as f:
16
+ with open(f"{fixtures_folder}/by-products/result.jsonld", encoding='utf-8') as f:
17
+ expected = json.load(f)
18
+
19
+ value = run(cycle)
20
+ assert value == expected
21
+
22
+
23
+ @patch(f"{class_path}._new_practice", side_effect=fake_new_practice)
24
+ def test_run_by_practices(*args):
25
+ with open(f"{fixtures_folder}/by-practices/cycle.jsonld", encoding='utf-8') as f:
26
+ cycle = json.load(f)
27
+
28
+ with open(f"{fixtures_folder}/by-practices/result.jsonld", encoding='utf-8') as f:
17
29
  expected = json.load(f)
18
30
 
19
31
  value = run(cycle)
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_measurement
4
4
 
5
- from hestia_earth.models.site.salineWater import MODEL, TERM_ID, _should_run, run
5
+ from hestia_earth.models.hestia.salineWater import MODEL, TERM_ID, _should_run, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -1,10 +1,11 @@
1
- from unittest.mock import patch
1
+ import os
2
+ from unittest.mock import Mock, patch
2
3
  import json
3
4
  import pytest
4
5
 
5
6
  from tests.utils import fixtures_path, fake_new_measurement
6
7
 
7
- from hestia_earth.models.site.soilMeasurement import (
8
+ from hestia_earth.models.hestia.soilMeasurement import (
8
9
  MODEL,
9
10
  MODEL_KEY,
10
11
  _get_overlap,
@@ -13,7 +14,8 @@ from hestia_earth.models.site.soilMeasurement import (
13
14
  )
14
15
 
15
16
  class_path = f"hestia_earth.models.{MODEL}.{MODEL_KEY}"
16
- fixtures_folder = f"{fixtures_path}/site/soilMeasurement"
17
+ fixtures_folder = f"{fixtures_path}/{MODEL}/soilMeasurement"
18
+ _folders = [d for d in os.listdir(fixtures_folder) if os.path.isdir(os.path.join(fixtures_folder, d))]
17
19
 
18
20
 
19
21
  @pytest.mark.parametrize(
@@ -140,25 +142,15 @@ def test_should_run(test_name, site, expected_should_run):
140
142
  assert should_run == expected_should_run, test_name
141
143
 
142
144
 
143
- @pytest.mark.parametrize(
144
- "test_name",
145
- [
146
- "missing-depth",
147
- "missing-value",
148
- "simple-soilPh",
149
- "clayContent",
150
- "non-unique-measurements",
151
- "arrays",
152
- "standard-intervals"
153
- ]
154
- )
145
+ @pytest.mark.parametrize('folder', _folders)
155
146
  @patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
156
- def test_run(mock_new_measurement, test_name):
157
- with open(f"{fixtures_folder}/{test_name}/site.jsonld", encoding='utf-8') as f:
147
+ def test_run(mock_new_measurement: Mock, folder):
148
+ with open(f"{fixtures_folder}/{folder}/site.jsonld", encoding='utf-8') as f:
158
149
  site = json.load(f)
159
150
 
160
- with open(f"{fixtures_folder}/{test_name}/result.jsonld", encoding='utf-8') as f:
161
- result = json.load(f)
151
+ with open(f"{fixtures_folder}/{folder}/result.jsonld", encoding='utf-8') as f:
152
+ expected = json.load(f)
162
153
 
163
- value = run(site)
164
- assert value == result
154
+ result = run(site)
155
+ print(json.dumps(result, indent=2))
156
+ assert result == expected, folder
@@ -3,7 +3,7 @@ import pytest
3
3
  import json
4
4
  from tests.utils import fixtures_path, fake_new_practice
5
5
 
6
- from hestia_earth.models.cycle.stockingDensityAnimalHousingAverage import MODEL, TERM_ID, run, _should_run
6
+ from hestia_earth.models.hestia.stockingDensityAnimalHousingAverage import MODEL, TERM_ID, run, _should_run
7
7
 
8
8
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
9
9
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_measurement
4
4
 
5
- from hestia_earth.models.site.temperatureAnnual import MODEL, TERM_ID, run, _should_run
5
+ from hestia_earth.models.hestia.temperatureAnnual import MODEL, TERM_ID, run, _should_run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_measurement
4
4
 
5
- from hestia_earth.models.site.temperatureMonthly import MODEL, TERM_ID, run, _should_run
5
+ from hestia_earth.models.hestia.temperatureMonthly import MODEL, TERM_ID, run, _should_run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_measurement
4
4
 
5
- from hestia_earth.models.site.totalNitrogenPerKgSoil import MODEL, TERM_ID, run, _should_run
5
+ from hestia_earth.models.hestia.totalNitrogenPerKgSoil import MODEL, TERM_ID, run, _should_run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fake_new_practice, fixtures_path
4
4
 
5
- from hestia_earth.models.cycle.unknownPreSeasonWaterRegime import MODEL, TERM_ID, _should_run, run
5
+ from hestia_earth.models.hestia.unknownPreSeasonWaterRegime import MODEL, TERM_ID, _should_run, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -2,7 +2,7 @@ from unittest.mock import patch
2
2
  import json
3
3
  from tests.utils import fixtures_path, fake_new_measurement
4
4
 
5
- from hestia_earth.models.site.waterDepth import MODEL, TERM_ID, run
5
+ from hestia_earth.models.hestia.waterDepth import MODEL, TERM_ID, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
@@ -0,0 +1,26 @@
1
+ from unittest.mock import Mock, patch
2
+ import json
3
+ from tests.utils import fixtures_path, fake_new_measurement
4
+
5
+ from hestia_earth.models.hestia.waterSalinity import MODEL, TERM_ID, run
6
+
7
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
+
10
+
11
+ @patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
12
+ @patch(f"{class_path}.related_cycles")
13
+ def test_run(mock_related_cycles: Mock, *args):
14
+ with open(f"{fixtures_folder}/site.jsonld", encoding='utf-8') as f:
15
+ site = json.load(f)
16
+
17
+ with open(f"{fixtures_folder}/cycles.jsonld", encoding='utf-8') as f:
18
+ cycles = json.load(f)
19
+
20
+ mock_related_cycles.return_value = cycles
21
+
22
+ with open(f"{fixtures_folder}/result.jsonld", encoding='utf-8') as f:
23
+ expected = json.load(f)
24
+
25
+ value = run(site)
26
+ assert value == expected
@@ -8,15 +8,12 @@ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
9
9
 
10
10
  TERMS_BY_ID = {
11
- 'energyContentHigherHeatingValue': {'units': 'MJ / kg'},
12
- 'energyDigestibilityRuminants': {'units': '%'},
13
- 'energyDigestibilityPoultry': {'units': '%'},
14
- 'neutralDetergentFibreContent': {'units': '%'}
11
+ 'energyContentHigherHeatingValue': {'units': 'MJ / kg'}
15
12
  }
16
13
  IONOPHORE_TERMS = ['ionophores', 'ionophoreAntibiotics']
17
14
 
18
15
 
19
- def fake_download_term(term_id: str, *args): return TERMS_BY_ID[term_id]
16
+ def fake_download_term(term_id: str, *args): return TERMS_BY_ID.get(term_id, {'@id': term_id, 'units': '%'})
20
17
 
21
18
 
22
19
  @patch(f"{class_path}.get_ionophore_terms", return_value=IONOPHORE_TERMS)
@@ -1,57 +1,25 @@
1
- from unittest.mock import patch
1
+ import os
2
+ import pytest
3
+ from unittest.mock import Mock, patch
2
4
  import json
3
5
  from tests.utils import fixtures_path, fake_new_emission, FLOODED_RICE_TERMS
4
6
 
5
- from hestia_earth.models.ipcc2019.ch4ToAirFloodedRice import MODEL, TERM_ID, run, _should_run
7
+ from hestia_earth.models.ipcc2019.ch4ToAirFloodedRice import MODEL, TERM_ID, run
6
8
 
7
9
  class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
8
10
  fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
11
+ _folders = [d for d in os.listdir(fixtures_folder) if os.path.isdir(os.path.join(fixtures_folder, d))]
9
12
 
10
13
 
11
- @patch(f"{class_path}.has_flooded_rice", return_value=False)
12
- def test_should_run(mock_flooded_rice):
13
- # no site => no run
14
- cycle = {'site': {}}
15
- should_run, *args = _should_run(cycle)
16
- assert not should_run
17
-
18
- # with site => no run
19
- cycle['site'] = {'country': {'@id': 'country'}}
20
- should_run, *args = _should_run(cycle)
21
- assert not should_run
22
-
23
- # with croppingDuration => no run
24
- cycle['practices'] = [{'term': {'@id': 'croppingDuration'}}]
25
- should_run, *args = _should_run(cycle)
26
- assert not should_run
27
-
28
- # with flooded rice => run
29
- mock_flooded_rice.return_value = True
30
- should_run, *args = _should_run(cycle)
31
- assert should_run is True
32
-
33
-
34
- @patch('hestia_earth.models.utils.product.get_rice_paddy_terms', return_value=FLOODED_RICE_TERMS)
35
- @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
36
- def test_run(*args):
37
- with open(f"{fixtures_folder}/cycle.jsonld", encoding="utf-8") as f:
38
- cycle = json.load(f)
39
-
40
- with open(f"{fixtures_folder}/result.jsonld", encoding="utf-8") as f:
41
- expected = json.load(f)
42
-
43
- result = run(cycle)
44
- assert result == expected
45
-
46
-
14
+ @pytest.mark.parametrize("folder", _folders)
47
15
  @patch('hestia_earth.models.utils.product.get_rice_paddy_terms', return_value=FLOODED_RICE_TERMS)
48
16
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
49
- def test_run_with_optional_data(*args):
50
- with open(f"{fixtures_folder}/with-optional-data/cycle.jsonld", encoding="utf-8") as f:
17
+ def test_run(mock_new_emission: Mock, mock_rice_terms: Mock, folder: str):
18
+ with open(f"{fixtures_folder}/{folder}/cycle.jsonld", encoding="utf-8") as f:
51
19
  cycle = json.load(f)
52
20
 
53
- with open(f"{fixtures_folder}/with-optional-data/result.jsonld", encoding="utf-8") as f:
21
+ with open(f"{fixtures_folder}/{folder}/result.jsonld", encoding="utf-8") as f:
54
22
  expected = json.load(f)
55
23
 
56
24
  result = run(cycle)
57
- assert result == expected
25
+ assert result == expected, folder
@@ -0,0 +1,61 @@
1
+ import json
2
+ from pytest import mark
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ from hestia_earth.models.ipcc2019.ch4ToAirOrganicSoilCultivation import MODEL, TERM_ID, _should_run, run
6
+ from tests.utils import fake_new_emission, fixtures_path
7
+
8
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
9
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
10
+
11
+ # subfolder, should_run
12
+ PARAMS_SHOULD_RUN = [
13
+ ("acacia", True),
14
+ ("annual-crops", True),
15
+ ("grassland", True),
16
+ ("oil-palm", True),
17
+ ("other", False),
18
+ ("paddy-rice-cultivation", True),
19
+ ("perennial-crops", True),
20
+ ("sago-palm", True),
21
+ ("polar", False),
22
+ ("mineral-soil", True),
23
+ ("unknown-soil", False),
24
+ ("unknown-land-occupation", False)
25
+ ]
26
+ IDS_SHOULD_RUN = [p[0] for p in PARAMS_SHOULD_RUN]
27
+
28
+
29
+ @mark.parametrize("subfolder, expected", PARAMS_SHOULD_RUN, ids=IDS_SHOULD_RUN)
30
+ def test_should_run(
31
+ subfolder: str,
32
+ expected: bool
33
+ ):
34
+ folder = f"{fixtures_folder}/{subfolder}"
35
+
36
+ with open(f"{folder}/cycle.jsonld", encoding="utf-8") as f:
37
+ cycle = json.load(f)
38
+
39
+ result, *_ = _should_run(cycle)
40
+ assert result == expected
41
+
42
+
43
+ PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should_run]
44
+
45
+
46
+ @mark.parametrize("subfolder", PARAMS_RUN)
47
+ @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
48
+ def test_run(
49
+ _mock_new_emission: MagicMock,
50
+ subfolder: str
51
+ ):
52
+ folder = f"{fixtures_folder}/{subfolder}"
53
+
54
+ with open(f"{folder}/cycle.jsonld", encoding="utf-8") as f:
55
+ cycle = json.load(f)
56
+
57
+ with open(f"{folder}/result.jsonld", encoding="utf-8") as f:
58
+ expected = json.load(f)
59
+
60
+ result = run(cycle)
61
+ assert result == expected
@@ -35,15 +35,17 @@ RUN_SCENARIOS = [
35
35
  ("overlapping-cycles", 4),
36
36
  ("complex-overlapping-cycles", 5),
37
37
  ("missing-measurement-dates", 3),
38
- ("no-biomass-measurements", 1), # Closes issue #700
39
- ("non-consecutive-biomass-measurements", 1), # Closes issue #827
40
- ("multiple-method-classifications", 5), # Closes issue #764
41
- ("non-soil-based-gohac-system", 3), # Closes issue #848
42
- ("soil-based-gohac-system", 3), # Closes issue #848
43
- ("with-gapfilled-start-date-end-date", 1), # Closes issue #972
44
- ("forest-to-orchard-with-ground-cover", 3), # Closes issue #989
45
- ("orchard-data-complete", 3), # Closes issue #1011
46
- ("orchard-data-partially-complete", 3) # Closes issue #1011
38
+ ("no-biomass-measurements", 1), # Closes #700
39
+ ("non-consecutive-biomass-measurements", 1), # Closes #827
40
+ ("multiple-method-classifications", 5), # Closes #764
41
+ ("non-soil-based-gohac-system", 3), # Closes #848
42
+ ("soil-based-gohac-system", 3), # Closes #848
43
+ ("with-gapfilled-start-date-end-date", 1), # Closes #972
44
+ ("forest-to-orchard-with-ground-cover", 3), # Closes #989
45
+ ("orchard-data-complete", 3), # Closes #1011
46
+ ("orchard-data-partially-complete", 3), # Closes #1011
47
+ ("no-measurements-data-complete", 1), # Closes #1227
48
+ ("no-measurements-data-incomplete", 1) # Closes #1227
47
49
  ]
48
50
  """List of (subfolder: str, num_cycles: int)."""
49
51
 
@@ -35,14 +35,16 @@ RUN_SCENARIOS = [
35
35
  ("overlapping-cycles", 4),
36
36
  ("complex-overlapping-cycles", 5),
37
37
  ("missing-measurement-dates", 3),
38
- ("no-biomass-measurements", 1), # Closes issue #700
39
- ("non-consecutive-biomass-measurements", 1), # Closes issue #827
40
- ("multiple-method-classifications", 5), # Closes issue #764
41
- ("non-soil-based-gohac-system", 3), # Closes issue #848
42
- ("with-gapfilled-start-date-end-date", 1), # Closes issue #972
43
- ("forest-to-orchard-with-ground-cover", 3), # Closes issue #989
44
- ("orchard-data-complete", 3), # Closes issue #1011
45
- ("orchard-data-partially-complete", 3) # Closes issue #1011
38
+ ("no-biomass-measurements", 1), # Closes #700
39
+ ("non-consecutive-biomass-measurements", 1), # Closes #827
40
+ ("multiple-method-classifications", 5), # Closes #764
41
+ ("non-soil-based-gohac-system", 3), # Closes #848
42
+ ("with-gapfilled-start-date-end-date", 1), # Closes #972
43
+ ("forest-to-orchard-with-ground-cover", 3), # Closes #989
44
+ ("orchard-data-complete", 3), # Closes #1011
45
+ ("orchard-data-partially-complete", 3), # Closes #1011
46
+ ("no-measurements-data-complete", 1), # Closes #1227
47
+ ("no-measurements-data-incomplete", 1) # Closes #1227
46
48
  ]
47
49
  """List of (subfolder: str, num_cycles: int)."""
48
50
 
@@ -28,7 +28,7 @@ def test_should_run():
28
28
  # with kg MgCO3 input => run
29
29
  cycle['inputs'].append({
30
30
  'term': {
31
- 'units': 'kg MgCO3',
31
+ 'units': 'kg CaMg(CO3)2',
32
32
  'termType': 'soilAmendment'
33
33
  },
34
34
  'value': [100]
@@ -0,0 +1,62 @@
1
+ import json
2
+ from pytest import mark
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ from hestia_earth.models.ipcc2019.co2ToAirOrganicSoilCultivation import MODEL, TERM_ID, _should_run, run
6
+ from tests.utils import fake_new_emission, fixtures_path
7
+
8
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
9
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
10
+
11
+
12
+ # subfolder, should_run
13
+ PARAMS_SHOULD_RUN = [
14
+ ("acacia", True),
15
+ ("annual-crops", True),
16
+ ("grassland", True),
17
+ ("oil-palm", True),
18
+ ("other", False),
19
+ ("paddy-rice-cultivation", True),
20
+ ("perennial-crops", True),
21
+ ("sago-palm", True),
22
+ ("polar", False),
23
+ ("mineral-soil", True),
24
+ ("unknown-soil", False),
25
+ ("unknown-land-occupation", False)
26
+ ]
27
+ IDS_SHOULD_RUN = [p[0] for p in PARAMS_SHOULD_RUN]
28
+
29
+
30
+ @mark.parametrize("subfolder, expected", PARAMS_SHOULD_RUN, ids=IDS_SHOULD_RUN)
31
+ def test_should_run(
32
+ subfolder: str,
33
+ expected: bool
34
+ ):
35
+ folder = f"{fixtures_folder}/{subfolder}"
36
+
37
+ with open(f"{folder}/cycle.jsonld", encoding="utf-8") as f:
38
+ cycle = json.load(f)
39
+
40
+ result, *_ = _should_run(cycle)
41
+ assert result == expected
42
+
43
+
44
+ PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should_run]
45
+
46
+
47
+ @mark.parametrize("subfolder", PARAMS_RUN)
48
+ @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
49
+ def test_run(
50
+ _mock_new_emission: MagicMock,
51
+ subfolder: str,
52
+ ):
53
+ folder = f"{fixtures_folder}/{subfolder}"
54
+
55
+ with open(f"{folder}/cycle.jsonld", encoding="utf-8") as f:
56
+ cycle = json.load(f)
57
+
58
+ with open(f"{folder}/result.jsonld", encoding="utf-8") as f:
59
+ expected = json.load(f)
60
+
61
+ result = run(cycle)
62
+ assert result == expected
@@ -59,14 +59,17 @@ RUN_SCENARIOS = [
59
59
  ("overlapping-cycles", 4),
60
60
  ("complex-overlapping-cycles", 5),
61
61
  ("missing-measurement-dates", 3),
62
- ("no-organic-carbon-measurements", 1), # Closes issue #700
63
- ("non-consecutive-organic-carbon-measurements", 1), # Closes issue #827
64
- ("multiple-method-classifications", 5), # Closes issue #764
65
- ("non-soil-based-gohac-system", 3), # Closes issue #848
66
- ("with-gapfilled-start-date-end-date", 1), # Closes issue #972
67
- ("forest-to-orchard-with-ground-cover", 3), # Closes issue #989
68
- ("orchard-data-complete", 3), # Closes issue #1011
69
- ("orchard-data-partially-complete", 3) # Closes issue #1011
62
+ ("no-organic-carbon-measurements", 1), # Closes #700
63
+ ("non-consecutive-organic-carbon-measurements", 1), # Closes #827
64
+ ("multiple-method-classifications", 5), # Closes #764
65
+ ("non-soil-based-gohac-system", 3), # Closes #848
66
+ ("with-gapfilled-start-date-end-date", 1), # Closes #972
67
+ ("forest-to-orchard-with-ground-cover", 3), # Closes #989
68
+ ("orchard-data-complete", 3), # Closes #1011
69
+ ("orchard-data-partially-complete", 3), # Closes #1011
70
+ ("with-linalgerror", 1),
71
+ ("no-measurements-data-complete", 1), # Closes #1227
72
+ ("no-measurements-data-incomplete", 1) # Closes #1227
70
73
  ]
71
74
  """List of (subfolder: str, num_cycles: int)."""
72
75
 
@@ -0,0 +1,61 @@
1
+ import json
2
+ from pytest import mark
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ from hestia_earth.models.ipcc2019.n2OToAirOrganicSoilCultivationDirect import MODEL, TERM_ID, _should_run, run
6
+ from tests.utils import fake_new_emission, fixtures_path
7
+
8
+ class_path = f"hestia_earth.models.{MODEL}.{TERM_ID}"
9
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{TERM_ID}"
10
+
11
+ # subfolder, should_run
12
+ PARAMS_SHOULD_RUN = [
13
+ ("acacia", True),
14
+ ("annual-crops", True),
15
+ ("grassland", True),
16
+ ("oil-palm", True),
17
+ ("other", False),
18
+ ("paddy-rice-cultivation", True),
19
+ ("perennial-crops", True),
20
+ ("sago-palm", True),
21
+ ("polar", False),
22
+ ("mineral-soil", True),
23
+ ("unknown-soil", False),
24
+ ("unknown-land-occupation", False)
25
+ ]
26
+ IDS_SHOULD_RUN = [p[0] for p in PARAMS_SHOULD_RUN]
27
+
28
+
29
+ @mark.parametrize("subfolder, expected", PARAMS_SHOULD_RUN, ids=IDS_SHOULD_RUN)
30
+ def test_should_run(
31
+ subfolder: str,
32
+ expected: bool
33
+ ):
34
+ folder = f"{fixtures_folder}/{subfolder}"
35
+
36
+ with open(f"{folder}/cycle.jsonld", encoding="utf-8") as f:
37
+ cycle = json.load(f)
38
+
39
+ result, *_ = _should_run(cycle)
40
+ assert result == expected
41
+
42
+
43
+ PARAMS_RUN = [subfolder for subfolder, should_run in PARAMS_SHOULD_RUN if should_run]
44
+
45
+
46
+ @mark.parametrize("subfolder", PARAMS_RUN,)
47
+ @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
48
+ def test_run(
49
+ _mock_new_emission: MagicMock,
50
+ subfolder: str
51
+ ):
52
+ folder = f"{fixtures_folder}/{subfolder}"
53
+
54
+ with open(f"{folder}/cycle.jsonld", encoding="utf-8") as f:
55
+ cycle = json.load(f)
56
+
57
+ with open(f"{folder}/result.jsonld", encoding="utf-8") as f:
58
+ expected = json.load(f)
59
+
60
+ result = run(cycle)
61
+ assert result == expected
@@ -32,8 +32,9 @@ RUN_SCENARIOS = [
32
32
  ("forest-to-cropland", 4),
33
33
  ("historical-land-cover-mix", 3),
34
34
  ("deforestation-reforestation", 1), # gains should not offset losses
35
- ("no-clearance-via-fire", 1), # LUC in the UK, which has a percentage burned factor of 0
36
- ("forest-to-cropland-with-ground-cover", 4) # Cover crops/ground covers should be ignored
35
+ ("no-clearance-via-fire", 1), # LUC in the UK, which has a percentage burned factor of 0, should run
36
+ ("forest-to-cropland-with-ground-cover", 4), # Cover crops/ground covers should be ignored
37
+ ("single-year", 1) # should not run, multiple years of land cover data required
37
38
  ]
38
39
 
39
40
 
@@ -0,0 +1,20 @@
1
+ import json
2
+ from unittest.mock import patch
3
+ from tests.utils import fixtures_path, fake_new_measurement
4
+
5
+ from hestia_earth.models.site.grouped_measurement import MODEL, MODEL_KEY, run
6
+
7
+ class_path = f"hestia_earth.models.{MODEL}.{MODEL_KEY}"
8
+ fixtures_folder = f"{fixtures_path}/{MODEL}/{MODEL_KEY}"
9
+
10
+
11
+ @patch(f"{class_path}._new_measurement", side_effect=fake_new_measurement)
12
+ def test_run(*args):
13
+ with open(f"{fixtures_folder}/site.jsonld", encoding='utf-8') as f:
14
+ site = json.load(f)
15
+
16
+ with open(f"{fixtures_folder}/result.jsonld", encoding='utf-8') as f:
17
+ expected = json.load(f)
18
+
19
+ result = run(site)
20
+ assert result == expected
@@ -22,5 +22,5 @@ def test_run(*args):
22
22
  with open(f"{fixtures_folder}/result.jsonld", encoding="utf-8") as f:
23
23
  expected = json.load(f)
24
24
 
25
- value = run('all', cycle)
26
- assert value == expected
25
+ result = run('all', cycle)
26
+ assert result == expected
@@ -6,15 +6,8 @@ from hestia_earth.models.emissionNotRelevant import MODEL, run
6
6
 
7
7
  class_path = f"hestia_earth.models.{MODEL}"
8
8
  fixtures_folder = f"{fixtures_path}/{MODEL}"
9
- EMISSION_IDS = [
10
- 'ch4ToAirCropResidueBurning',
11
- 'ch4ToAirExcreta',
12
- 'ch4ToAirFuelCombustion',
13
- 'n2OToAirAquacultureSystemsDirect'
14
- ]
15
9
 
16
10
 
17
- @patch(f"{class_path}.get_all_emission_terms", return_value=EMISSION_IDS)
18
11
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
19
12
  def test_run_cropland(*args):
20
13
  with open(f"{fixtures_folder}/cropland/cycle.jsonld", encoding='utf-8') as f:
@@ -27,7 +20,6 @@ def test_run_cropland(*args):
27
20
  assert result == expected
28
21
 
29
22
 
30
- @patch(f"{class_path}.get_all_emission_terms", return_value=EMISSION_IDS)
31
23
  @patch(f"{class_path}._new_emission", side_effect=fake_new_emission)
32
24
  def test_run_pond(*args):
33
25
  with open(f"{fixtures_folder}/pond/cycle.jsonld", encoding='utf-8') as f: