@hestia-earth/data-validation 0.37.7

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 (410) hide show
  1. package/.coveragerc +14 -0
  2. package/.dockerignore +19 -0
  3. package/.eslintignore +17 -0
  4. package/.eslintrc.js +11 -0
  5. package/.flake8 +5 -0
  6. package/.gitlab/issue_templates/new validation.md +82 -0
  7. package/.gitlab-ci.yml +216 -0
  8. package/.readthedocs.yml +24 -0
  9. package/CODEOWNERS +11 -0
  10. package/Dockerfile +13 -0
  11. package/LICENSE +21 -0
  12. package/MANIFEST.in +2 -0
  13. package/bin/hestia-validate-data +80 -0
  14. package/build_mocking.py +14 -0
  15. package/commitlint.config.js +1 -0
  16. package/docs/Makefile +20 -0
  17. package/docs/_static/styles.css +4 -0
  18. package/docs/_templates/custom-class-template.rst +34 -0
  19. package/docs/_templates/custom-module-template.rst +66 -0
  20. package/docs/_templates/layout.html +4 -0
  21. package/docs/conf.py +74 -0
  22. package/docs/index.rst +42 -0
  23. package/docs/make.bat +35 -0
  24. package/docs/requirements.txt +13 -0
  25. package/envs/.develop.env +1 -0
  26. package/envs/.master.env +1 -0
  27. package/guide-assets/.gitkeep +0 -0
  28. package/hestia_earth/validation/README.md +5 -0
  29. package/hestia_earth/validation/__init__.py +32 -0
  30. package/hestia_earth/validation/distribution.py +22 -0
  31. package/hestia_earth/validation/gee.py +162 -0
  32. package/hestia_earth/validation/log.py +44 -0
  33. package/hestia_earth/validation/models.py +141 -0
  34. package/hestia_earth/validation/preload_requests.py +61 -0
  35. package/hestia_earth/validation/terms.py +88 -0
  36. package/hestia_earth/validation/utils.py +444 -0
  37. package/hestia_earth/validation/validators/__init__.py +141 -0
  38. package/hestia_earth/validation/validators/aggregated_cycle.py +32 -0
  39. package/hestia_earth/validation/validators/aggregated_shared.py +37 -0
  40. package/hestia_earth/validation/validators/animal.py +88 -0
  41. package/hestia_earth/validation/validators/completeness.py +252 -0
  42. package/hestia_earth/validation/validators/cycle.py +1123 -0
  43. package/hestia_earth/validation/validators/distribution.py +86 -0
  44. package/hestia_earth/validation/validators/emission.py +109 -0
  45. package/hestia_earth/validation/validators/impact_assessment.py +138 -0
  46. package/hestia_earth/validation/validators/indicator.py +154 -0
  47. package/hestia_earth/validation/validators/infrastructure.py +25 -0
  48. package/hestia_earth/validation/validators/input.py +268 -0
  49. package/hestia_earth/validation/validators/management.py +131 -0
  50. package/hestia_earth/validation/validators/measurement.py +368 -0
  51. package/hestia_earth/validation/validators/organisation.py +43 -0
  52. package/hestia_earth/validation/validators/practice.py +590 -0
  53. package/hestia_earth/validation/validators/product.py +263 -0
  54. package/hestia_earth/validation/validators/property.py +266 -0
  55. package/hestia_earth/validation/validators/shared.py +940 -0
  56. package/hestia_earth/validation/validators/site.py +312 -0
  57. package/hestia_earth/validation/validators/source.py +20 -0
  58. package/hestia_earth/validation/validators/transformation.py +250 -0
  59. package/hestia_earth/validation/version.py +1 -0
  60. package/layer/build.sh +34 -0
  61. package/layer/deploy.sh +18 -0
  62. package/package.json +59 -0
  63. package/release.sh +11 -0
  64. package/requirements-ci.txt +6 -0
  65. package/requirements-test.txt +4 -0
  66. package/requirements.txt +2 -0
  67. package/run-docker-test.sh +7 -0
  68. package/run-docker.sh +9 -0
  69. package/run.py +99 -0
  70. package/scripts/build_docs.py +283 -0
  71. package/scripts/build_validation_list.py +160 -0
  72. package/scripts/guide-create-branch.sh +15 -0
  73. package/scripts/update-package-version.js +28 -0
  74. package/search-results.json +384 -0
  75. package/setup.cfg +2 -0
  76. package/setup.py +35 -0
  77. package/src/index.ts +1 -0
  78. package/src/validations.ts +22 -0
  79. package/src/version.ts +1 -0
  80. package/tests/Dockerfile +13 -0
  81. package/tests/__init__.py +3 -0
  82. package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/invalid-no-impactAssessment.json +64 -0
  83. package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/invalid-world.json +69 -0
  84. package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/valid.json +69 -0
  85. package/tests/fixtures/animal/duplicated-input-cycle/invalid.json +98 -0
  86. package/tests/fixtures/animal/duplicated-input-cycle/valid.json +91 -0
  87. package/tests/fixtures/animal/pregnancyRateTotal/invalid.json +49 -0
  88. package/tests/fixtures/animal/pregnancyRateTotal/valid.json +60 -0
  89. package/tests/fixtures/animal/required/invalid.json +59 -0
  90. package/tests/fixtures/animal/required/valid.json +72 -0
  91. package/tests/fixtures/completeness/all-values/warning.json +22 -0
  92. package/tests/fixtures/completeness/animalPopulation/invalid.json +58 -0
  93. package/tests/fixtures/completeness/animalPopulation/valid-animals.json +71 -0
  94. package/tests/fixtures/completeness/animalPopulation/valid-incomplete.json +58 -0
  95. package/tests/fixtures/completeness/animalPopulation/valid-no-liveAnimals.json +37 -0
  96. package/tests/fixtures/completeness/blank-nodes/agri-food processor-invalid.json +52 -0
  97. package/tests/fixtures/completeness/blank-nodes/invalid.json +124 -0
  98. package/tests/fixtures/completeness/blank-nodes/valid.json +128 -0
  99. package/tests/fixtures/completeness/cropland/site.json +16 -0
  100. package/tests/fixtures/completeness/cropland/valid.json +22 -0
  101. package/tests/fixtures/completeness/cropland/warning.json +22 -0
  102. package/tests/fixtures/completeness/freshForage/error-animals.json +63 -0
  103. package/tests/fixtures/completeness/freshForage/error-products.json +65 -0
  104. package/tests/fixtures/completeness/freshForage/valid-animal-inputs.json +63 -0
  105. package/tests/fixtures/completeness/freshForage/valid-animals.json +63 -0
  106. package/tests/fixtures/completeness/freshForage/valid-not-grazing-liveAnimal.json +55 -0
  107. package/tests/fixtures/completeness/freshForage/valid-not-liveAnimal.json +47 -0
  108. package/tests/fixtures/completeness/freshForage/valid-products.json +68 -0
  109. package/tests/fixtures/completeness/ingredient/invalid-agri-food-processor.json +37 -0
  110. package/tests/fixtures/completeness/ingredient/invalid.json +49 -0
  111. package/tests/fixtures/completeness/ingredient/valid-agri-food-processor-complete.json +49 -0
  112. package/tests/fixtures/completeness/ingredient/valid-agri-food-processor-incomplete.json +37 -0
  113. package/tests/fixtures/completeness/ingredient/valid.json +49 -0
  114. package/tests/fixtures/completeness/material/error.json +49 -0
  115. package/tests/fixtures/completeness/material/valid-fuel-material.json +60 -0
  116. package/tests/fixtures/completeness/material/valid-incomplete.json +36 -0
  117. package/tests/fixtures/completeness/material/valid-no-fuel.json +36 -0
  118. package/tests/fixtures/completeness/valid.json +22 -0
  119. package/tests/fixtures/cycle/aboveGroundCropResidue/invalid.json +76 -0
  120. package/tests/fixtures/cycle/aboveGroundCropResidue/valid.json +76 -0
  121. package/tests/fixtures/cycle/aggregated-valid.json +102 -0
  122. package/tests/fixtures/cycle/coverCrop/invalid.json +64 -0
  123. package/tests/fixtures/cycle/coverCrop/valid-not-coverCrop.json +54 -0
  124. package/tests/fixtures/cycle/coverCrop/valid.json +64 -0
  125. package/tests/fixtures/cycle/cropResidue/complete/invalid.json +56 -0
  126. package/tests/fixtures/cycle/cropResidue/complete/valid.json +82 -0
  127. package/tests/fixtures/cycle/cropResidue/incomplete/invalid.json +42 -0
  128. package/tests/fixtures/cycle/cropResidue/incomplete/valid.json +56 -0
  129. package/tests/fixtures/cycle/dates/invalid-emissions.json +70 -0
  130. package/tests/fixtures/cycle/liveAnimal-animalProduct-mapping/invalid.json +63 -0
  131. package/tests/fixtures/cycle/liveAnimal-animalProduct-mapping/valid.json +63 -0
  132. package/tests/fixtures/cycle/maximumCycleDuration/invalid-dates-year-only.json +48 -0
  133. package/tests/fixtures/cycle/maximumCycleDuration/invalid-dates.json +48 -0
  134. package/tests/fixtures/cycle/maximumCycleDuration/invalid.json +48 -0
  135. package/tests/fixtures/cycle/maximumCycleDuration/valid-dates-year-only.json +48 -0
  136. package/tests/fixtures/cycle/maximumCycleDuration/valid-dates.json +48 -0
  137. package/tests/fixtures/cycle/maximumCycleDuration/valid.json +48 -0
  138. package/tests/fixtures/cycle/otherSites/cycleDuration/invalid.json +52 -0
  139. package/tests/fixtures/cycle/otherSites/cycleDuration/valid-no-siteDuration.json +40 -0
  140. package/tests/fixtures/cycle/otherSites/cycleDuration/valid.json +52 -0
  141. package/tests/fixtures/cycle/practices/stockingDensityPermanentPastureAverage/invalid.json +56 -0
  142. package/tests/fixtures/cycle/practices/stockingDensityPermanentPastureAverage/valid.json +65 -0
  143. package/tests/fixtures/cycle/primary-product-as-input/invalid.json +59 -0
  144. package/tests/fixtures/cycle/primary-product-as-input/valid.json +48 -0
  145. package/tests/fixtures/cycle/product-linked-ia/cycle.json +66 -0
  146. package/tests/fixtures/cycle/product-linked-ia/invalid-multiple.json +58 -0
  147. package/tests/fixtures/cycle/product-linked-ia/valid.json +57 -0
  148. package/tests/fixtures/cycle/products/animals/invalid.json +69 -0
  149. package/tests/fixtures/cycle/products/animals/valid.json +58 -0
  150. package/tests/fixtures/cycle/riceGrainInHuskFlooded-minimumCycleDuration/invalid.json +53 -0
  151. package/tests/fixtures/cycle/riceGrainInHuskFlooded-minimumCycleDuration/valid.json +53 -0
  152. package/tests/fixtures/cycle/siteDuration/crop/invalid.json +53 -0
  153. package/tests/fixtures/cycle/siteDuration/crop/valid-different-duration.json +53 -0
  154. package/tests/fixtures/cycle/siteDuration/crop/valid-same-duration.json +53 -0
  155. package/tests/fixtures/cycle/siteDuration/invalid.json +41 -0
  156. package/tests/fixtures/cycle/siteDuration/valid-no-siteDuration.json +40 -0
  157. package/tests/fixtures/cycle/siteDuration/valid-otherSites.json +48 -0
  158. package/tests/fixtures/cycle/siteDuration/valid.json +45 -0
  159. package/tests/fixtures/cycle/substrate/required/invalid.json +50 -0
  160. package/tests/fixtures/cycle/substrate/required/valid.json +60 -0
  161. package/tests/fixtures/cycle/valid.json +343 -0
  162. package/tests/fixtures/emission/linked-terms/inputs/invalid.json +78 -0
  163. package/tests/fixtures/emission/linked-terms/inputs/valid.json +106 -0
  164. package/tests/fixtures/emission/linked-terms/transformation/error.json +104 -0
  165. package/tests/fixtures/emission/linked-terms/transformation/valid.json +107 -0
  166. package/tests/fixtures/emission/linked-terms/transformation/warning.json +76 -0
  167. package/tests/fixtures/emission/methodTier-background/invalid.json +60 -0
  168. package/tests/fixtures/emission/methodTier-background/valid.json +60 -0
  169. package/tests/fixtures/emission/not-relevant/invalid.json +71 -0
  170. package/tests/fixtures/emission/not-relevant/valid.json +95 -0
  171. package/tests/fixtures/emission/not-relevant-methodTier/invalid.json +70 -0
  172. package/tests/fixtures/emission/not-relevant-methodTier/valid.json +95 -0
  173. package/tests/fixtures/impactAssessment/aggregated-valid.json +43 -0
  174. package/tests/fixtures/impactAssessment/cycle-contains-product/invalid.json +34 -0
  175. package/tests/fixtures/impactAssessment/cycle-contains-product/valid.json +34 -0
  176. package/tests/fixtures/impactAssessment/cycle-endDate/invalid.json +26 -0
  177. package/tests/fixtures/impactAssessment/cycle-endDate/valid.json +26 -0
  178. package/tests/fixtures/impactAssessment/valid.json +93 -0
  179. package/tests/fixtures/indicator/characterisedIndicator-methodModel/invalid.json +52 -0
  180. package/tests/fixtures/indicator/characterisedIndicator-methodModel/valid.json +52 -0
  181. package/tests/fixtures/indicator/ionisingCompounds/invalid.json +23 -0
  182. package/tests/fixtures/indicator/ionisingCompounds/valid.json +23 -0
  183. package/tests/fixtures/indicator/landTransformation/invalid-grouped.json +257 -0
  184. package/tests/fixtures/indicator/landTransformation/invalid.json +100 -0
  185. package/tests/fixtures/indicator/landTransformation/valid-grouped-full.json +507 -0
  186. package/tests/fixtures/indicator/landTransformation/valid-grouped.json +507 -0
  187. package/tests/fixtures/indicator/landTransformation/valid.json +100 -0
  188. package/tests/fixtures/infrastructure/lifespan/invalid.json +26 -0
  189. package/tests/fixtures/infrastructure/lifespan/valid.json +45 -0
  190. package/tests/fixtures/input/animalFeed-fate/invalid.json +103 -0
  191. package/tests/fixtures/input/animalFeed-fate/valid.json +90 -0
  192. package/tests/fixtures/input/country/invalid.json +64 -0
  193. package/tests/fixtures/input/country/valid.json +64 -0
  194. package/tests/fixtures/input/distribution/animalHousing.json +103 -0
  195. package/tests/fixtures/input/distribution/complete/invalid.json +177 -0
  196. package/tests/fixtures/input/distribution/complete/valid.json +163 -0
  197. package/tests/fixtures/input/distribution/incomplete/valid.json +139 -0
  198. package/tests/fixtures/input/impactAssessment/invalid.json +99 -0
  199. package/tests/fixtures/input/impactAssessment/valid.json +89 -0
  200. package/tests/fixtures/input/input-as-product/invalid.json +57 -0
  201. package/tests/fixtures/input/input-as-product/valid.json +59 -0
  202. package/tests/fixtures/input/mustIncludeId/invalid.json +13 -0
  203. package/tests/fixtures/input/mustIncludeId/valid-multiple-ids.json +31 -0
  204. package/tests/fixtures/input/mustIncludeId/valid.json +22 -0
  205. package/tests/fixtures/input/saplings/invalid.json +58 -0
  206. package/tests/fixtures/input/saplings/valid-no-saplings.json +58 -0
  207. package/tests/fixtures/input/saplings/valid-not-plantation.json +58 -0
  208. package/tests/fixtures/input/saplings/valid.json +58 -0
  209. package/tests/fixtures/integration/distribution/product-yield-invalid.json +54 -0
  210. package/tests/fixtures/management/cycle-overlap/cycles.json +39 -0
  211. package/tests/fixtures/management/cycle-overlap/invalid.json +26 -0
  212. package/tests/fixtures/management/cycle-overlap/valid.json +26 -0
  213. package/tests/fixtures/management/exists/invalid.json +13 -0
  214. package/tests/fixtures/management/exists/valid.json +25 -0
  215. package/tests/fixtures/management/fallow-dates/invalid.json +24 -0
  216. package/tests/fixtures/management/fallow-dates/valid.json +24 -0
  217. package/tests/fixtures/management/termType/invalid-cropland.json +35 -0
  218. package/tests/fixtures/management/termType/invalid-permanent-pasture.json +25 -0
  219. package/tests/fixtures/management/termType/valid-cropland.json +55 -0
  220. package/tests/fixtures/management/termType/valid-no-management.json +13 -0
  221. package/tests/fixtures/management/termType/valid-permanent-pasture.json +35 -0
  222. package/tests/fixtures/measurement/depths/invalid.json +44 -0
  223. package/tests/fixtures/measurement/depths/valid.json +50 -0
  224. package/tests/fixtures/measurement/models/valid.json +33 -0
  225. package/tests/fixtures/measurement/models/warning-no-value.json +30 -0
  226. package/tests/fixtures/measurement/models/warning.json +33 -0
  227. package/tests/fixtures/measurement/pond-measurements/invalid.json +11 -0
  228. package/tests/fixtures/measurement/pond-measurements/valid.json +23 -0
  229. package/tests/fixtures/measurement/required-depths/error.json +71 -0
  230. package/tests/fixtures/measurement/required-depths/valid.json +126 -0
  231. package/tests/fixtures/measurement/required-depths/warning.json +29 -0
  232. package/tests/fixtures/measurement/soilTexture/missing-texture-value.json +227 -0
  233. package/tests/fixtures/measurement/soilTexture/percent-invalid.json +110 -0
  234. package/tests/fixtures/measurement/soilTexture/percent-missing-value.json +43 -0
  235. package/tests/fixtures/measurement/soilTexture/percent-valid.json +110 -0
  236. package/tests/fixtures/measurement/startDate-endDate-required/invalid.json +32 -0
  237. package/tests/fixtures/measurement/startDate-endDate-required/valid.json +46 -0
  238. package/tests/fixtures/measurement/unique/invalid.json +28 -0
  239. package/tests/fixtures/measurement/unique/valid.json +16 -0
  240. package/tests/fixtures/measurement/value-length/invalid.json +46 -0
  241. package/tests/fixtures/measurement/value-length/valid.json +44 -0
  242. package/tests/fixtures/measurement/water-salinity/invalid.json +33 -0
  243. package/tests/fixtures/measurement/water-salinity/valid-brakish.json +40 -0
  244. package/tests/fixtures/measurement/water-salinity/valid.json +33 -0
  245. package/tests/fixtures/organisation/valid.json +26 -0
  246. package/tests/fixtures/practice/croppingDuration/riceGrainInHuskFlooded/invalid.json +63 -0
  247. package/tests/fixtures/practice/croppingDuration/riceGrainInHuskFlooded/valid.json +63 -0
  248. package/tests/fixtures/practice/defaultValue/invalid.json +12 -0
  249. package/tests/fixtures/practice/defaultValue/valid.json +15 -0
  250. package/tests/fixtures/practice/excretaManagement/invalid.json +50 -0
  251. package/tests/fixtures/practice/excretaManagement/valid.json +60 -0
  252. package/tests/fixtures/practice/irrigated-complete/invalid.json +47 -0
  253. package/tests/fixtures/practice/irrigated-complete/valid-incomplete.json +47 -0
  254. package/tests/fixtures/practice/irrigated-complete/valid.json +60 -0
  255. package/tests/fixtures/practice/landCover-products/invalid.json +58 -0
  256. package/tests/fixtures/practice/landCover-products/valid-coverCrop.json +69 -0
  257. package/tests/fixtures/practice/landCover-products/valid.json +58 -0
  258. package/tests/fixtures/practice/liveAnimal-system/invalid.json +58 -0
  259. package/tests/fixtures/practice/liveAnimal-system/valid.json +69 -0
  260. package/tests/fixtures/practice/longFallowDuration/invalid.json +20 -0
  261. package/tests/fixtures/practice/longFallowDuration/valid.json +20 -0
  262. package/tests/fixtures/practice/noTillage/invalid.json +23 -0
  263. package/tests/fixtures/practice/noTillage/valid-value-not-100.json +23 -0
  264. package/tests/fixtures/practice/noTillage/valid.json +21 -0
  265. package/tests/fixtures/practice/pastureGrass/key-termType/invalid.json +16 -0
  266. package/tests/fixtures/practice/pastureGrass/key-termType/valid.json +16 -0
  267. package/tests/fixtures/practice/pastureGrass/key-value/invalid-numbers.json +67 -0
  268. package/tests/fixtures/practice/pastureGrass/key-value/invalid.json +67 -0
  269. package/tests/fixtures/practice/pastureGrass/key-value/valid.json +67 -0
  270. package/tests/fixtures/practice/pastureGrass/permanent-pasture/invalid.json +37 -0
  271. package/tests/fixtures/practice/pastureGrass/permanent-pasture/valid.json +47 -0
  272. package/tests/fixtures/practice/primaryPercent/invalid.json +49 -0
  273. package/tests/fixtures/practice/primaryPercent/valid.json +49 -0
  274. package/tests/fixtures/practice/processingOperation/invalid-no-primary.json +48 -0
  275. package/tests/fixtures/practice/processingOperation/invalid.json +49 -0
  276. package/tests/fixtures/practice/processingOperation/valid-cropland.json +37 -0
  277. package/tests/fixtures/practice/processingOperation/valid.json +49 -0
  278. package/tests/fixtures/practice/productivePhasePermanentCrops/invalid.json +48 -0
  279. package/tests/fixtures/practice/productivePhasePermanentCrops/valid-0-value.json +58 -0
  280. package/tests/fixtures/practice/productivePhasePermanentCrops/valid-no-value.json +47 -0
  281. package/tests/fixtures/practice/productivePhasePermanentCrops/valid.json +48 -0
  282. package/tests/fixtures/practice/site-management/invalid.json +75 -0
  283. package/tests/fixtures/practice/site-management/valid.json +75 -0
  284. package/tests/fixtures/practice/tillage-siteType/valid.json +51 -0
  285. package/tests/fixtures/practice/tillage-siteType/warning.json +42 -0
  286. package/tests/fixtures/practice/tillage-values/invalid-fullTillage.json +61 -0
  287. package/tests/fixtures/practice/tillage-values/invalid-noTillage.json +61 -0
  288. package/tests/fixtures/practice/tillage-values/valid.json +61 -0
  289. package/tests/fixtures/practice/waterRegime/rice/invalid.json +59 -0
  290. package/tests/fixtures/practice/waterRegime/rice/valid-0-value.json +59 -0
  291. package/tests/fixtures/practice/waterRegime/rice/valid.json +58 -0
  292. package/tests/fixtures/product/economicValueShare/invalid.json +31 -0
  293. package/tests/fixtures/product/economicValueShare/valid.json +22 -0
  294. package/tests/fixtures/product/excreta/invalid.json +62 -0
  295. package/tests/fixtures/product/excreta/valid.json +62 -0
  296. package/tests/fixtures/product/excreta/warning.json +53 -0
  297. package/tests/fixtures/product/excreta/with-system/invalid.json +79 -0
  298. package/tests/fixtures/product/excreta/with-system/valid.json +88 -0
  299. package/tests/fixtures/product/excreta/with-system/warning.json +70 -0
  300. package/tests/fixtures/product/fu_ha/invalid.json +49 -0
  301. package/tests/fixtures/product/fu_ha/valid.json +49 -0
  302. package/tests/fixtures/product/primary/invalid.json +22 -0
  303. package/tests/fixtures/product/primary/valid.json +22 -0
  304. package/tests/fixtures/product/value/valid.json +26 -0
  305. package/tests/fixtures/product/value/value-0/error.json +40 -0
  306. package/tests/fixtures/product/value/value-empty/warning.json +23 -0
  307. package/tests/fixtures/product/yield/invalid.json +54 -0
  308. package/tests/fixtures/product/yield/no-value.json +75 -0
  309. package/tests/fixtures/product/yield/valid.json +54 -0
  310. package/tests/fixtures/property/default-value/valid-allowed-exception.json +61 -0
  311. package/tests/fixtures/property/default-value/valid.json +61 -0
  312. package/tests/fixtures/property/default-value/warning.json +61 -0
  313. package/tests/fixtures/property/termType/invalid.json +60 -0
  314. package/tests/fixtures/property/termType/valid.json +60 -0
  315. package/tests/fixtures/property/value-min-max/invalid.json +77 -0
  316. package/tests/fixtures/property/value-min-max/valid-skip-maximum.json +57 -0
  317. package/tests/fixtures/property/value-min-max/valid.json +78 -0
  318. package/tests/fixtures/property/valueType/invalid.json +79 -0
  319. package/tests/fixtures/property/valueType/valid.json +79 -0
  320. package/tests/fixtures/property/volatileSolidsContent/invalid.json +99 -0
  321. package/tests/fixtures/property/volatileSolidsContent/valid.json +99 -0
  322. package/tests/fixtures/shared/coordinates/invalid.json +18 -0
  323. package/tests/fixtures/shared/coordinates/valid.json +18 -0
  324. package/tests/fixtures/shared/data-duplicates/valid.json +113 -0
  325. package/tests/fixtures/shared/data-duplicates/warning.json +172 -0
  326. package/tests/fixtures/shared/duplicated-term-units/invalid-animalProduct.json +61 -0
  327. package/tests/fixtures/shared/duplicated-term-units/invalid-organicFertiliser.json +61 -0
  328. package/tests/fixtures/shared/duplicated-term-units/valid.json +49 -0
  329. package/tests/fixtures/shared/list-country-region/invalid.json +54 -0
  330. package/tests/fixtures/shared/list-country-region/valid.json +54 -0
  331. package/tests/fixtures/shared/list-percent-value/invalid.json +49 -0
  332. package/tests/fixtures/shared/list-percent-value/valid.json +52 -0
  333. package/tests/fixtures/shared/list-valueType/invalid.json +49 -0
  334. package/tests/fixtures/shared/list-valueType/valid.json +49 -0
  335. package/tests/fixtures/shared/list-values-sum-100/management/with-properties/valid.json +91 -0
  336. package/tests/fixtures/shared/list-values-sum-100/measurements/missing-soil.json +46 -0
  337. package/tests/fixtures/shared/list-values-sum-100/measurements/no-depth-high-value.json +63 -0
  338. package/tests/fixtures/shared/list-values-sum-100/measurements/no-depth-valid.json +40 -0
  339. package/tests/fixtures/shared/list-values-sum-100/measurements/with-depth-high-value.json +71 -0
  340. package/tests/fixtures/shared/list-values-sum-100/practices/total-100.json +61 -0
  341. package/tests/fixtures/shared/list-values-sum-100/practices/total-110.json +61 -0
  342. package/tests/fixtures/shared/list-values-sum-100/practices/total-90.json +61 -0
  343. package/tests/fixtures/shared/min-max/value-above.json +31 -0
  344. package/tests/fixtures/shared/min-max/value-below.json +31 -0
  345. package/tests/fixtures/shared/min-max/value-valid.json +45 -0
  346. package/tests/fixtures/shared/model/emissions/invalid.json +102 -0
  347. package/tests/fixtures/shared/model/emissions/valid-variable-tolerance.json +180 -0
  348. package/tests/fixtures/shared/model/emissions/valid.json +102 -0
  349. package/tests/fixtures/shared/model/impacts/invalid.json +75 -0
  350. package/tests/fixtures/shared/model/impacts/valid.json +75 -0
  351. package/tests/fixtures/shared/model/inputs/valid-no-value.json +84 -0
  352. package/tests/fixtures/shared/model/inputs/valid.json +87 -0
  353. package/tests/fixtures/shared/model/inputs/warning.json +87 -0
  354. package/tests/fixtures/shared/model/products/valid-no-value.json +88 -0
  355. package/tests/fixtures/shared/model/products/valid.json +91 -0
  356. package/tests/fixtures/shared/model/products/warning.json +91 -0
  357. package/tests/fixtures/shared/otherModel/invalid.json +69 -0
  358. package/tests/fixtures/shared/otherModel/valid.json +70 -0
  359. package/tests/fixtures/shared/properties-duplicate-values/invalid.json +61 -0
  360. package/tests/fixtures/shared/properties-duplicate-values/valid.json +57 -0
  361. package/tests/fixtures/shared/properties-same-length/invalid.json +62 -0
  362. package/tests/fixtures/shared/properties-same-length/valid.json +52 -0
  363. package/tests/fixtures/shared/unit-percent/invalid.json +34 -0
  364. package/tests/fixtures/shared/unit-percent/valid.json +60 -0
  365. package/tests/fixtures/shared/unit-percent/warning.json +52 -0
  366. package/tests/fixtures/site/cycles-linked-ia/invalid.json +129 -0
  367. package/tests/fixtures/site/cycles-linked-ia/valid.json +129 -0
  368. package/tests/fixtures/site/valid.json +138 -0
  369. package/tests/fixtures/source/valid.json +19 -0
  370. package/tests/fixtures/transformation/excretaManagement/invalid.json +47 -0
  371. package/tests/fixtures/transformation/excretaManagement/valid.json +59 -0
  372. package/tests/fixtures/transformation/inputs-products/invalid.json +43 -0
  373. package/tests/fixtures/transformation/inputs-products/valid.json +43 -0
  374. package/tests/fixtures/transformation/linked-emission/invalid.json +101 -0
  375. package/tests/fixtures/transformation/linked-emission/valid.json +107 -0
  376. package/tests/fixtures/transformation/previousTransformationId/invalid-no-previous.json +127 -0
  377. package/tests/fixtures/transformation/previousTransformationId/invalid-previous-input.json +100 -0
  378. package/tests/fixtures/transformation/previousTransformationId/invalid-product-input.json +106 -0
  379. package/tests/fixtures/transformation/previousTransformationId/invalid-wrong-order.json +136 -0
  380. package/tests/fixtures/transformation/previousTransformationId/valid.json +171 -0
  381. package/tests/integration/__init__.py +0 -0
  382. package/tests/integration/test_product.py +17 -0
  383. package/tests/test_gee.py +10 -0
  384. package/tests/test_utils.py +36 -0
  385. package/tests/test_validation.py +11 -0
  386. package/tests/utils.py +28 -0
  387. package/tests/validators/__init__.py +0 -0
  388. package/tests/validators/test_aggregated_cycle.py +44 -0
  389. package/tests/validators/test_aggregated_shared.py +63 -0
  390. package/tests/validators/test_animal.py +72 -0
  391. package/tests/validators/test_completeness.py +337 -0
  392. package/tests/validators/test_cycle.py +600 -0
  393. package/tests/validators/test_emission.py +170 -0
  394. package/tests/validators/test_impact_assessment.py +80 -0
  395. package/tests/validators/test_indicator.py +120 -0
  396. package/tests/validators/test_infrastructure.py +26 -0
  397. package/tests/validators/test_input.py +434 -0
  398. package/tests/validators/test_management.py +177 -0
  399. package/tests/validators/test_measurement.py +317 -0
  400. package/tests/validators/test_organisation.py +32 -0
  401. package/tests/validators/test_practice.py +490 -0
  402. package/tests/validators/test_product.py +291 -0
  403. package/tests/validators/test_property.py +143 -0
  404. package/tests/validators/test_shared.py +1139 -0
  405. package/tests/validators/test_site.py +151 -0
  406. package/tests/validators/test_source.py +15 -0
  407. package/tests/validators/test_transformation.py +151 -0
  408. package/tests/validators/test_validators.py +74 -0
  409. package/tsconfig.dist.json +9 -0
  410. package/tsconfig.json +25 -0
package/docs/conf.py ADDED
@@ -0,0 +1,74 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # This file only contains a selection of the most common options. For a full
4
+ # list see the documentation:
5
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
6
+
7
+ # -- Path setup --------------------------------------------------------------
8
+
9
+ # If extensions (or modules to document with autodoc) are in another directory,
10
+ # add these directories to sys.path here. If the directory is relative to the
11
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
12
+ #
13
+ import os
14
+ import sys
15
+
16
+ sys.path.insert(0, os.path.abspath(".."))
17
+
18
+
19
+ # -- Project information -----------------------------------------------------
20
+
21
+ project = "HESTIA Data Validation"
22
+ copyright = "2020, HESTIA Team"
23
+ author = "Guillaume Royer"
24
+
25
+ # The full version, including alpha/beta/rc tags
26
+ release = "0.0.1"
27
+
28
+
29
+ # -- General configuration ---------------------------------------------------
30
+
31
+ # Add any Sphinx extension module names here, as strings. They can be
32
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33
+ # ones.
34
+ extensions = [
35
+ "recommonmark",
36
+ "sphinx.ext.autodoc",
37
+ "sphinx.ext.napoleon",
38
+ "sphinx.ext.autosummary",
39
+ "sphinx.ext.viewcode",
40
+ "sphinx_autodoc_typehints",
41
+ ]
42
+
43
+ autosummary_generate = True
44
+
45
+ # Add any paths that contain templates here, relative to this directory.
46
+ templates_path = ["_templates"]
47
+
48
+ # List of patterns, relative to source directory, that match files and
49
+ # directories to ignore when looking for source files.
50
+ # This pattern also affects html_static_path and html_extra_path.
51
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
52
+
53
+
54
+ # -- Options for HTML output -------------------------------------------------
55
+
56
+ # The theme to use for HTML and HTML Help pages. See the documentation for
57
+ # a list of builtin themes.
58
+ #
59
+ html_theme = "sphinx_rtd_theme"
60
+
61
+ # -- Options for HTML output -------------------------------------------------
62
+
63
+ # on_rtd is whether on readthedocs.org, this line of code grabbed from docs.readthedocs.org...
64
+ on_rtd = os.getenv("READTHEDOCS", None) == "True"
65
+ if not on_rtd: # only import and set the theme if we're building docs locally
66
+ import sphinx_rtd_theme
67
+
68
+ html_theme = "sphinx_rtd_theme"
69
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
70
+
71
+ # Add any paths that contain custom static files (such as style sheets) here,
72
+ # relative to this directory. They are copied after the builtin static files,
73
+ # so a file named "default.css" will overwrite the builtin "default.css".
74
+ html_static_path = ["_static"]
package/docs/index.rst ADDED
@@ -0,0 +1,42 @@
1
+ Welcome to HESTIA Data Validation's documentation!
2
+ ========================================
3
+
4
+ This package contains the Data Validation module developed by HESTIA.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ Install from `PyPI <https://pypi.python.org/pypi>`_ using `pip <http://www.pip-installer.org/en/latest/>`_, a
10
+ package manager for Python.
11
+
12
+ .. code-block:: bash
13
+
14
+ pip install hestia_earth.validation
15
+
16
+
17
+ Requirements
18
+ ============
19
+
20
+ - `hestia_earth.schema <https://pypi.org/project/hestia-earth.schema/>`_
21
+ - `requests <https://pypi.org/project/requests/>`_
22
+ - `python-dateutil <https://pypi.org/project/python-dateutil/>`_
23
+ - `area <https://pypi.org/project/area/>`_
24
+
25
+ Contents
26
+ --------
27
+
28
+ .. autosummary::
29
+ :toctree: _autosummary
30
+ :caption: API Reference
31
+ :template: custom-module-template.rst
32
+ :recursive:
33
+
34
+ hestia_earth.validation
35
+
36
+
37
+ Indices and tables
38
+ ==================
39
+
40
+ * :ref:`genindex`
41
+ * :ref:`modindex`
42
+ * :ref:`search`
package/docs/make.bat ADDED
@@ -0,0 +1,35 @@
1
+ @ECHO OFF
2
+
3
+ pushd %~dp0
4
+
5
+ REM Command file for Sphinx documentation
6
+
7
+ if "%SPHINXBUILD%" == "" (
8
+ set SPHINXBUILD=sphinx-build
9
+ )
10
+ set SOURCEDIR=.
11
+ set BUILDDIR=_build
12
+
13
+ if "%1" == "" goto help
14
+
15
+ %SPHINXBUILD% >NUL 2>NUL
16
+ if errorlevel 9009 (
17
+ echo.
18
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19
+ echo.installed, then set the SPHINXBUILD environment variable to point
20
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
21
+ echo.may add the Sphinx directory to PATH.
22
+ echo.
23
+ echo.If you don't have Sphinx installed, grab it from
24
+ echo.http://sphinx-doc.org/
25
+ exit /b 1
26
+ )
27
+
28
+ %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29
+ goto end
30
+
31
+ :help
32
+ %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33
+
34
+ :end
35
+ popd
@@ -0,0 +1,13 @@
1
+ hestia_earth.validation
2
+ docutils==0.17.1
3
+ Jinja2==3.0.3
4
+ alabaster==0.7.13
5
+ sphinx-rtd-theme==0.5.0
6
+ sphinxcontrib-applehelp==1.0.4
7
+ sphinxcontrib-devhelp==1.0.2
8
+ sphinxcontrib-qthelp==1.0.3
9
+ sphinxcontrib-htmlhelp==2.0.1
10
+ sphinxcontrib-serializinghtml==1.1.5
11
+ sphinx-autodoc-typehints==1.12.0
12
+ sphinx==3.3.1
13
+ recommonmark
@@ -0,0 +1 @@
1
+ export STAGE='dev'
@@ -0,0 +1 @@
1
+ export STAGE='prod'
File without changes
@@ -0,0 +1,5 @@
1
+ # HESTIA Data Validation
2
+
3
+ See the complete list of validations available on the HESTIA format.
4
+
5
+ Each validation is divided by node type: `Cycle`, `Site`, `ImpactAssessment`, and `Organisation`.
@@ -0,0 +1,32 @@
1
+ from typing import List
2
+ from concurrent.futures import ThreadPoolExecutor
3
+ from hestia_earth.utils.tools import current_time_ms
4
+
5
+ from .log import logger
6
+ from .validators import validate_node
7
+ from .utils import _group_nodes, _hash_nodes
8
+ from .gee import init_gee_by_nodes
9
+
10
+
11
+ def validate(nodes: List[dict]):
12
+ """
13
+ Validates a list of HESTIA JSON-Nodes against a list of rules.
14
+
15
+ Parameters
16
+ ----------
17
+ nodes : List[dict]
18
+ The list of JSON-Nodes to validate.
19
+
20
+ Returns
21
+ -------
22
+ List
23
+ The list of errors for each node, which can be empty if no errors detected.
24
+ """
25
+ now = current_time_ms()
26
+ nodes = init_gee_by_nodes(nodes)
27
+ nodes_by_type = _group_nodes(nodes)
28
+ nodes_by_hash = _hash_nodes(nodes)
29
+ with ThreadPoolExecutor() as executor:
30
+ results = list(executor.map(validate_node(nodes_by_type, nodes_by_hash), nodes))
31
+ logger.info("time=%s, unit=ms", current_time_ms() - now)
32
+ return results
@@ -0,0 +1,22 @@
1
+ import os
2
+ from functools import lru_cache
3
+
4
+ from .log import logger
5
+
6
+ ENABLED = os.getenv("VALIDATE_DISTRIBUTION", "true") == "true"
7
+
8
+
9
+ @lru_cache()
10
+ def is_enabled():
11
+ if ENABLED:
12
+ try:
13
+ from hestia_earth.distribution.version import VERSION
14
+
15
+ logger.debug("Using distribution version %s", VERSION)
16
+ return True
17
+ except ImportError:
18
+ logger.error(
19
+ "Run `pip install hestia-earth-validation[distribution]` to use distribution validation"
20
+ )
21
+
22
+ return False
@@ -0,0 +1,162 @@
1
+ import os
2
+ from hestia_earth.utils.tools import current_time_ms
3
+ from hestia_earth.schema import NodeType
4
+
5
+ from .log import logger
6
+
7
+ _ENABLED = os.getenv("VALIDATE_SPATIAL", "true") == "true"
8
+ _ENABLE_TYPES = [NodeType.SITE.value, NodeType.ORGANISATION.value]
9
+ MAX_AREA_SIZE = int(os.getenv("MAX_AREA_SIZE", "5000"))
10
+ _CACHE_BATCH_SIZE = int(os.getenv("CACHE_SITES_BATCH_SIZE", "5000"))
11
+
12
+ _caching = {}
13
+ _RASTERS = [
14
+ {
15
+ "name": "siteType",
16
+ "collection": "MODIS/006/MCD12Q1",
17
+ "band_name": "LC_Prop2",
18
+ "year": "2019",
19
+ }
20
+ ]
21
+ _VECTORS = [
22
+ {
23
+ "name": f"region-{level}",
24
+ "collection": f"users/hestiaplatform/gadm36_{level}",
25
+ "fields": f"GID_{level}",
26
+ }
27
+ for level in range(0, 6)
28
+ ]
29
+
30
+
31
+ def _caching_key(func_name: str, args: dict):
32
+ return "-".join([func_name, str(args)])
33
+
34
+
35
+ def _run_with_cache(func_name: str, args: dict, func):
36
+ global _caching # noqa: F824
37
+ key = _caching_key(func_name, args)
38
+ _caching[key] = _caching.get(key, func())
39
+ return _caching[key]
40
+
41
+
42
+ def _should_cache_node(node: dict):
43
+ return all(
44
+ [
45
+ node.get("@type", node.get("type")) in _ENABLE_TYPES,
46
+ not node.get("aggregated", False),
47
+ "latitude" in node and "longitude" in node,
48
+ ]
49
+ )
50
+
51
+
52
+ def _node_key(node: dict):
53
+ return "/".join(
54
+ [node.get("type", node.get("@type")), node.get("id", node.get("@id"))]
55
+ )
56
+
57
+
58
+ def _pop_items(values: list, nb_items: int):
59
+ if len(values) < nb_items:
60
+ removed_items = values[:] # Get a copy of the entire array
61
+ values.clear() # Remove all items from the original array
62
+ else:
63
+ removed_items = values[:nb_items] # Get the first N items
64
+ del values[:nb_items] # Remove the first N items from the original array
65
+
66
+ return removed_items
67
+
68
+
69
+ def _cache_nodes(nodes: list, batch_size: int):
70
+ from hestia_earth.models.cache_sites import ParamType, _run_values
71
+
72
+ now = current_time_ms()
73
+
74
+ nodes_mapping = {_node_key(n): n for n in nodes}
75
+
76
+ cache_nodes = list(filter(_should_cache_node, nodes))
77
+ while len(cache_nodes) > 0:
78
+ batch_values = _pop_items(cache_nodes, batch_size)
79
+ logger.info(f"Caching {len(batch_values)} nodes. {len(cache_nodes)} remaining.")
80
+ results = _run_values(
81
+ [(n, 0) for n in batch_values], # expecting tuple with area_size
82
+ ParamType.COORDINATES,
83
+ _RASTERS,
84
+ _VECTORS,
85
+ years=[],
86
+ )
87
+
88
+ for result in results:
89
+ nodes_mapping[_node_key(result)] = result
90
+
91
+ logger.info("Done caching in %sms", current_time_ms() - now)
92
+
93
+ return list(nodes_mapping.values())
94
+
95
+
96
+ def _init_gee_by_nodes(nodes: list):
97
+ from hestia_earth.earth_engine import init_gee
98
+
99
+ init_gee()
100
+ try:
101
+ return _cache_nodes(nodes, _CACHE_BATCH_SIZE)
102
+ except Exception as e:
103
+ logger.error(f"An error occured while caching nodes on EE: {str(e)}")
104
+ if "User memory limit exceeded" in str(e) or "query aborted" in str(e):
105
+ return _cache_nodes(nodes, 100)
106
+
107
+
108
+ def init_gee_by_nodes(nodes: list):
109
+ # need to validate for non-aggregated Site or Oganisation with coordinates
110
+ enabled_nodes = list(filter(_should_cache_node, nodes))
111
+ should_init = len(enabled_nodes) > 0
112
+ return _init_gee_by_nodes(nodes) if should_init and is_enabled() else nodes
113
+
114
+
115
+ def is_enabled():
116
+ if _ENABLED:
117
+ try:
118
+ from hestia_earth.earth_engine.version import VERSION
119
+
120
+ return isinstance(VERSION, str)
121
+ except ImportError:
122
+ logger.error(
123
+ "Run `pip install hestia_earth.earth_engine` to use geospatial validation"
124
+ )
125
+
126
+ return False
127
+
128
+
129
+ def id_to_level(id: str):
130
+ return id.count(".")
131
+
132
+
133
+ def get_cached_data(site: dict, key: str, year: int = None):
134
+ from hestia_earth.models.geospatialDatabase.utils import _cached_value
135
+
136
+ value = _cached_value(site, key)
137
+ return value.get(str(year)) if value and year else value
138
+
139
+
140
+ def get_region_id(node: dict):
141
+ level = id_to_level(node.get("region", node.get("country")).get("@id"))
142
+ id = get_cached_data(node, f"region-{level}")
143
+ return None if id is None else f"GADM-{id}"
144
+
145
+
146
+ def get_region_distance(gid: str, latitude: float, longitude: float):
147
+ def exec_func():
148
+ return round(
149
+ get_distance_to_coordinates(gid, latitude=latitude, longitude=longitude)
150
+ / 1000
151
+ )
152
+
153
+ try:
154
+ from hestia_earth.earth_engine.gadm import get_distance_to_coordinates
155
+
156
+ return _run_with_cache(
157
+ "get_region_distance",
158
+ {"gid": gid, "latitude": latitude, "longitude": longitude},
159
+ exec_func,
160
+ )
161
+ except Exception:
162
+ return None
@@ -0,0 +1,44 @@
1
+ import os
2
+ import logging
3
+
4
+
5
+ def _add_handler(
6
+ logger: logging.Logger, formatter: logging.Formatter, handler: logging.Handler
7
+ ):
8
+ handler.setFormatter(formatter)
9
+ logger.addHandler(handler)
10
+
11
+
12
+ LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
13
+ logger = logging.getLogger("hestia_earth.validation")
14
+ logger.setLevel(logging.getLevelName(LOG_LEVEL))
15
+
16
+
17
+ def log_to_file(filepath: str):
18
+ """
19
+ By default, all logs are saved into a file with path stored in the env variable `LOG_FILENAME`.
20
+ If you do not set the environment variable `LOG_FILENAME`, you can use this function with the file path.
21
+
22
+ Parameters
23
+ ----------
24
+ filepath : str
25
+ Path of the file.
26
+ """
27
+ formatter = logging.Formatter(
28
+ '{"timestamp": "%(asctime)s", "level": "%(levelname)s", "logger": "%(name)s", '
29
+ '"filename": "%(filename)s", "message": "%(message)s"}',
30
+ "%Y-%m-%dT%H:%M:%S%z",
31
+ )
32
+ handler = logging.FileHandler(filepath, encoding="utf-8")
33
+ handler.setLevel(logging.getLevelName(LOG_LEVEL))
34
+ _add_handler(logger, formatter, handler)
35
+
36
+
37
+ _formatter = logging.Formatter(
38
+ "%(asctime)s - %(name)s - %(levelname)s - %(filename)s - %(message)s"
39
+ )
40
+ _add_handler(logger, _formatter, logging.StreamHandler())
41
+
42
+ LOG_FILENAME = os.getenv("LOG_FILENAME")
43
+ if LOG_FILENAME is not None:
44
+ log_to_file(LOG_FILENAME)
@@ -0,0 +1,141 @@
1
+ import importlib
2
+ import os
3
+ from functools import lru_cache
4
+ from hestia_earth.utils.tools import list_sum
5
+
6
+ from .log import logger
7
+
8
+ ENABLED = os.getenv("VALIDATE_MODELS", "true") == "true"
9
+
10
+
11
+ @lru_cache()
12
+ def is_enabled():
13
+ if ENABLED:
14
+ try:
15
+ from hestia_earth.models.version import VERSION
16
+
17
+ logger.debug("Using models version %s", VERSION)
18
+ return True
19
+ except ImportError:
20
+ logger.error(
21
+ "Run `pip install hestia-earth-validation[models]` to use models validation"
22
+ )
23
+
24
+ return False
25
+
26
+
27
+ def _model_value_from_list(results: list, default_value: float):
28
+ return (
29
+ results[0].get("value", [default_value]) if len(results) > 0 else default_value
30
+ )
31
+
32
+
33
+ def _model_value(result, default_value=0):
34
+ return (
35
+ default_value
36
+ if result is None
37
+ else (
38
+ _model_value_from_list(result, default_value)
39
+ if isinstance(result, list)
40
+ else (
41
+ result.get("value", [default_value])
42
+ if isinstance(result, dict)
43
+ else default_value
44
+ )
45
+ )
46
+ )
47
+
48
+
49
+ def value_from_model(result):
50
+ value = _model_value(result)
51
+ try:
52
+ # fix numpy.float64
53
+ # TODO: find a better way to handle this
54
+ return list_sum(value, float(value))
55
+ except Exception:
56
+ return list_sum(value, value)
57
+
58
+
59
+ def method_tier_from_model(result):
60
+ return (
61
+ None
62
+ if result is None
63
+ else (
64
+ method_tier_from_model(result[0])
65
+ if isinstance(result, list) and len(result) > 0
66
+ else (result.get("methodTier") if isinstance(result, dict) else None)
67
+ )
68
+ )
69
+
70
+
71
+ def _import_model(name: str):
72
+ return importlib.import_module(f"hestia_earth.models.{name}").run
73
+
74
+
75
+ def run_model(model: str, term_id: str, data: dict):
76
+ """
77
+ Run a HESTIA model from the engine models library.
78
+
79
+ Parameters
80
+ ----------
81
+ model : str
82
+ The name of the model to run.
83
+ term_id : str
84
+ The term to run the model on.
85
+ data : dict
86
+ The data used to run the model.
87
+
88
+ Returns
89
+ -------
90
+ Any
91
+ The result of the model, which can be a single `dict` or a list of `dict`s.
92
+ """
93
+ return _import_model(model)(term_id, data)
94
+
95
+
96
+ def run_model_from_node(node: dict, data: dict):
97
+ """
98
+ Run a HESTIA model from the engine models library.
99
+ To use this function, you need to use a Blank Node that contains a `methodModel` and a `term`,
100
+ otherwise you need to use the `run_model` method.
101
+
102
+ Parameters
103
+ ----------
104
+ node : dict
105
+ The Blank Node containing a `methodModel` and a `Term`.
106
+ data : dict
107
+ The data used to run the model.
108
+
109
+ Returns
110
+ -------
111
+ Any
112
+ The result of the model, which can be a single `dict` or a list of `dict`s.
113
+ """
114
+ methodModel = node.get("methodModel", {}).get("@id")
115
+ term_id = node.get("term", {}).get("@id")
116
+ return run_model(methodModel, term_id, data)
117
+
118
+
119
+ def run_models(node: dict, models: list):
120
+ """
121
+ Run a list of models, using the orchestrator, and return the updated node.
122
+
123
+ Parameters
124
+ ----------
125
+ node : dict
126
+ The Blank Node containing a `methodModel` and a `Term`.
127
+ models : list
128
+ List of models as defined in the orchestrator configurations.
129
+
130
+ Returns
131
+ -------
132
+ Any
133
+ The recalculated node after running all models
134
+ """
135
+ try:
136
+ from hestia_earth.orchestrator import run
137
+
138
+ return run(node, {"models": models})
139
+ except Exception as e:
140
+ logger.error(f"Error running models: {str(e)}")
141
+ return node
@@ -0,0 +1,61 @@
1
+ """
2
+ Preload all search requests to avoid making the same searches many times while running models.
3
+ """
4
+
5
+ import json
6
+ import os
7
+ from hestia_earth.utils.storage import _load_from_storage
8
+
9
+ from .log import logger
10
+ from .terms import RESULTS_PATH, get_all_terms, enable_mock
11
+
12
+
13
+ def _write_results(filepath: str, data: dict):
14
+ with open(filepath, "w") as f:
15
+ f.write(json.dumps(data, ensure_ascii=False))
16
+
17
+
18
+ def _load_data_from_glossary():
19
+ try:
20
+ return json.loads(
21
+ _load_from_storage(
22
+ os.path.join("glossary", "validation-search-results.json"),
23
+ glossary=True,
24
+ )
25
+ )
26
+ except Exception:
27
+ return None
28
+
29
+
30
+ def enable_preload(
31
+ filepath: str = RESULTS_PATH,
32
+ overwrite_existing: bool = True,
33
+ use_glossary: bool = False,
34
+ ):
35
+ """
36
+ Prefetch calls to HESTIA API in a local file.
37
+
38
+ Parameters
39
+ ----------
40
+ filepath : str
41
+ The path of the file containing the search results. Defaults to current library folder.
42
+ overwrite_existing : bool
43
+ Optional - If the file already exists, the file can be used instead of generating it again.
44
+ Will overwrite by default.
45
+ use_glossary : bool
46
+ Optional - Try to fetch search results from the glossary.
47
+ Only available with access to HESTIA infrastructure.
48
+ """
49
+ should_generate = overwrite_existing or not os.path.exists(filepath)
50
+
51
+ if should_generate:
52
+ logger.debug("Preloading search results and storing in %s", filepath)
53
+
54
+ # build the search results
55
+ data = (_load_data_from_glossary() if use_glossary else None) or get_all_terms()
56
+
57
+ # store in file
58
+ _write_results(filepath, data)
59
+
60
+ # enable mock search results from file
61
+ enable_mock(filepath=filepath)