@hestia-earth/data-validation 0.37.7 → 0.37.9

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 (411) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +17 -0
  3. package/dist/validations.d.ts +10 -0
  4. package/dist/validations.js +10 -0
  5. package/package.json +4 -3
  6. package/search-results.json +1 -1
  7. package/src/version.ts +1 -1
  8. package/validation.json +639 -0
  9. package/.coveragerc +0 -14
  10. package/.dockerignore +0 -19
  11. package/.eslintignore +0 -17
  12. package/.eslintrc.js +0 -11
  13. package/.flake8 +0 -5
  14. package/.gitlab/issue_templates/new validation.md +0 -82
  15. package/.gitlab-ci.yml +0 -216
  16. package/.readthedocs.yml +0 -24
  17. package/CODEOWNERS +0 -11
  18. package/Dockerfile +0 -13
  19. package/MANIFEST.in +0 -2
  20. package/bin/hestia-validate-data +0 -80
  21. package/build_mocking.py +0 -14
  22. package/commitlint.config.js +0 -1
  23. package/docs/Makefile +0 -20
  24. package/docs/_static/styles.css +0 -4
  25. package/docs/_templates/custom-class-template.rst +0 -34
  26. package/docs/_templates/custom-module-template.rst +0 -66
  27. package/docs/_templates/layout.html +0 -4
  28. package/docs/conf.py +0 -74
  29. package/docs/index.rst +0 -42
  30. package/docs/make.bat +0 -35
  31. package/docs/requirements.txt +0 -13
  32. package/envs/.develop.env +0 -1
  33. package/envs/.master.env +0 -1
  34. package/guide-assets/.gitkeep +0 -0
  35. package/hestia_earth/validation/README.md +0 -5
  36. package/hestia_earth/validation/__init__.py +0 -32
  37. package/hestia_earth/validation/distribution.py +0 -22
  38. package/hestia_earth/validation/gee.py +0 -162
  39. package/hestia_earth/validation/log.py +0 -44
  40. package/hestia_earth/validation/models.py +0 -141
  41. package/hestia_earth/validation/preload_requests.py +0 -61
  42. package/hestia_earth/validation/terms.py +0 -88
  43. package/hestia_earth/validation/utils.py +0 -444
  44. package/hestia_earth/validation/validators/__init__.py +0 -141
  45. package/hestia_earth/validation/validators/aggregated_cycle.py +0 -32
  46. package/hestia_earth/validation/validators/aggregated_shared.py +0 -37
  47. package/hestia_earth/validation/validators/animal.py +0 -88
  48. package/hestia_earth/validation/validators/completeness.py +0 -252
  49. package/hestia_earth/validation/validators/cycle.py +0 -1123
  50. package/hestia_earth/validation/validators/distribution.py +0 -86
  51. package/hestia_earth/validation/validators/emission.py +0 -109
  52. package/hestia_earth/validation/validators/impact_assessment.py +0 -138
  53. package/hestia_earth/validation/validators/indicator.py +0 -154
  54. package/hestia_earth/validation/validators/infrastructure.py +0 -25
  55. package/hestia_earth/validation/validators/input.py +0 -268
  56. package/hestia_earth/validation/validators/management.py +0 -131
  57. package/hestia_earth/validation/validators/measurement.py +0 -368
  58. package/hestia_earth/validation/validators/organisation.py +0 -43
  59. package/hestia_earth/validation/validators/practice.py +0 -590
  60. package/hestia_earth/validation/validators/product.py +0 -263
  61. package/hestia_earth/validation/validators/property.py +0 -266
  62. package/hestia_earth/validation/validators/shared.py +0 -940
  63. package/hestia_earth/validation/validators/site.py +0 -312
  64. package/hestia_earth/validation/validators/source.py +0 -20
  65. package/hestia_earth/validation/validators/transformation.py +0 -250
  66. package/hestia_earth/validation/version.py +0 -1
  67. package/layer/build.sh +0 -34
  68. package/layer/deploy.sh +0 -18
  69. package/release.sh +0 -11
  70. package/requirements-ci.txt +0 -6
  71. package/requirements-test.txt +0 -4
  72. package/requirements.txt +0 -2
  73. package/run-docker-test.sh +0 -7
  74. package/run-docker.sh +0 -9
  75. package/run.py +0 -99
  76. package/scripts/build_docs.py +0 -283
  77. package/scripts/build_validation_list.py +0 -160
  78. package/scripts/guide-create-branch.sh +0 -15
  79. package/scripts/update-package-version.js +0 -28
  80. package/setup.py +0 -35
  81. package/tests/Dockerfile +0 -13
  82. package/tests/__init__.py +0 -3
  83. package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/invalid-no-impactAssessment.json +0 -64
  84. package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/invalid-world.json +0 -69
  85. package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/valid.json +0 -69
  86. package/tests/fixtures/animal/duplicated-input-cycle/invalid.json +0 -98
  87. package/tests/fixtures/animal/duplicated-input-cycle/valid.json +0 -91
  88. package/tests/fixtures/animal/pregnancyRateTotal/invalid.json +0 -49
  89. package/tests/fixtures/animal/pregnancyRateTotal/valid.json +0 -60
  90. package/tests/fixtures/animal/required/invalid.json +0 -59
  91. package/tests/fixtures/animal/required/valid.json +0 -72
  92. package/tests/fixtures/completeness/all-values/warning.json +0 -22
  93. package/tests/fixtures/completeness/animalPopulation/invalid.json +0 -58
  94. package/tests/fixtures/completeness/animalPopulation/valid-animals.json +0 -71
  95. package/tests/fixtures/completeness/animalPopulation/valid-incomplete.json +0 -58
  96. package/tests/fixtures/completeness/animalPopulation/valid-no-liveAnimals.json +0 -37
  97. package/tests/fixtures/completeness/blank-nodes/agri-food processor-invalid.json +0 -52
  98. package/tests/fixtures/completeness/blank-nodes/invalid.json +0 -124
  99. package/tests/fixtures/completeness/blank-nodes/valid.json +0 -128
  100. package/tests/fixtures/completeness/cropland/site.json +0 -16
  101. package/tests/fixtures/completeness/cropland/valid.json +0 -22
  102. package/tests/fixtures/completeness/cropland/warning.json +0 -22
  103. package/tests/fixtures/completeness/freshForage/error-animals.json +0 -63
  104. package/tests/fixtures/completeness/freshForage/error-products.json +0 -65
  105. package/tests/fixtures/completeness/freshForage/valid-animal-inputs.json +0 -63
  106. package/tests/fixtures/completeness/freshForage/valid-animals.json +0 -63
  107. package/tests/fixtures/completeness/freshForage/valid-not-grazing-liveAnimal.json +0 -55
  108. package/tests/fixtures/completeness/freshForage/valid-not-liveAnimal.json +0 -47
  109. package/tests/fixtures/completeness/freshForage/valid-products.json +0 -68
  110. package/tests/fixtures/completeness/ingredient/invalid-agri-food-processor.json +0 -37
  111. package/tests/fixtures/completeness/ingredient/invalid.json +0 -49
  112. package/tests/fixtures/completeness/ingredient/valid-agri-food-processor-complete.json +0 -49
  113. package/tests/fixtures/completeness/ingredient/valid-agri-food-processor-incomplete.json +0 -37
  114. package/tests/fixtures/completeness/ingredient/valid.json +0 -49
  115. package/tests/fixtures/completeness/material/error.json +0 -49
  116. package/tests/fixtures/completeness/material/valid-fuel-material.json +0 -60
  117. package/tests/fixtures/completeness/material/valid-incomplete.json +0 -36
  118. package/tests/fixtures/completeness/material/valid-no-fuel.json +0 -36
  119. package/tests/fixtures/completeness/valid.json +0 -22
  120. package/tests/fixtures/cycle/aboveGroundCropResidue/invalid.json +0 -76
  121. package/tests/fixtures/cycle/aboveGroundCropResidue/valid.json +0 -76
  122. package/tests/fixtures/cycle/aggregated-valid.json +0 -102
  123. package/tests/fixtures/cycle/coverCrop/invalid.json +0 -64
  124. package/tests/fixtures/cycle/coverCrop/valid-not-coverCrop.json +0 -54
  125. package/tests/fixtures/cycle/coverCrop/valid.json +0 -64
  126. package/tests/fixtures/cycle/cropResidue/complete/invalid.json +0 -56
  127. package/tests/fixtures/cycle/cropResidue/complete/valid.json +0 -82
  128. package/tests/fixtures/cycle/cropResidue/incomplete/invalid.json +0 -42
  129. package/tests/fixtures/cycle/cropResidue/incomplete/valid.json +0 -56
  130. package/tests/fixtures/cycle/dates/invalid-emissions.json +0 -70
  131. package/tests/fixtures/cycle/liveAnimal-animalProduct-mapping/invalid.json +0 -63
  132. package/tests/fixtures/cycle/liveAnimal-animalProduct-mapping/valid.json +0 -63
  133. package/tests/fixtures/cycle/maximumCycleDuration/invalid-dates-year-only.json +0 -48
  134. package/tests/fixtures/cycle/maximumCycleDuration/invalid-dates.json +0 -48
  135. package/tests/fixtures/cycle/maximumCycleDuration/invalid.json +0 -48
  136. package/tests/fixtures/cycle/maximumCycleDuration/valid-dates-year-only.json +0 -48
  137. package/tests/fixtures/cycle/maximumCycleDuration/valid-dates.json +0 -48
  138. package/tests/fixtures/cycle/maximumCycleDuration/valid.json +0 -48
  139. package/tests/fixtures/cycle/otherSites/cycleDuration/invalid.json +0 -52
  140. package/tests/fixtures/cycle/otherSites/cycleDuration/valid-no-siteDuration.json +0 -40
  141. package/tests/fixtures/cycle/otherSites/cycleDuration/valid.json +0 -52
  142. package/tests/fixtures/cycle/practices/stockingDensityPermanentPastureAverage/invalid.json +0 -56
  143. package/tests/fixtures/cycle/practices/stockingDensityPermanentPastureAverage/valid.json +0 -65
  144. package/tests/fixtures/cycle/primary-product-as-input/invalid.json +0 -59
  145. package/tests/fixtures/cycle/primary-product-as-input/valid.json +0 -48
  146. package/tests/fixtures/cycle/product-linked-ia/cycle.json +0 -66
  147. package/tests/fixtures/cycle/product-linked-ia/invalid-multiple.json +0 -58
  148. package/tests/fixtures/cycle/product-linked-ia/valid.json +0 -57
  149. package/tests/fixtures/cycle/products/animals/invalid.json +0 -69
  150. package/tests/fixtures/cycle/products/animals/valid.json +0 -58
  151. package/tests/fixtures/cycle/riceGrainInHuskFlooded-minimumCycleDuration/invalid.json +0 -53
  152. package/tests/fixtures/cycle/riceGrainInHuskFlooded-minimumCycleDuration/valid.json +0 -53
  153. package/tests/fixtures/cycle/siteDuration/crop/invalid.json +0 -53
  154. package/tests/fixtures/cycle/siteDuration/crop/valid-different-duration.json +0 -53
  155. package/tests/fixtures/cycle/siteDuration/crop/valid-same-duration.json +0 -53
  156. package/tests/fixtures/cycle/siteDuration/invalid.json +0 -41
  157. package/tests/fixtures/cycle/siteDuration/valid-no-siteDuration.json +0 -40
  158. package/tests/fixtures/cycle/siteDuration/valid-otherSites.json +0 -48
  159. package/tests/fixtures/cycle/siteDuration/valid.json +0 -45
  160. package/tests/fixtures/cycle/substrate/required/invalid.json +0 -50
  161. package/tests/fixtures/cycle/substrate/required/valid.json +0 -60
  162. package/tests/fixtures/cycle/valid.json +0 -343
  163. package/tests/fixtures/emission/linked-terms/inputs/invalid.json +0 -78
  164. package/tests/fixtures/emission/linked-terms/inputs/valid.json +0 -106
  165. package/tests/fixtures/emission/linked-terms/transformation/error.json +0 -104
  166. package/tests/fixtures/emission/linked-terms/transformation/valid.json +0 -107
  167. package/tests/fixtures/emission/linked-terms/transformation/warning.json +0 -76
  168. package/tests/fixtures/emission/methodTier-background/invalid.json +0 -60
  169. package/tests/fixtures/emission/methodTier-background/valid.json +0 -60
  170. package/tests/fixtures/emission/not-relevant/invalid.json +0 -71
  171. package/tests/fixtures/emission/not-relevant/valid.json +0 -95
  172. package/tests/fixtures/emission/not-relevant-methodTier/invalid.json +0 -70
  173. package/tests/fixtures/emission/not-relevant-methodTier/valid.json +0 -95
  174. package/tests/fixtures/impactAssessment/aggregated-valid.json +0 -43
  175. package/tests/fixtures/impactAssessment/cycle-contains-product/invalid.json +0 -34
  176. package/tests/fixtures/impactAssessment/cycle-contains-product/valid.json +0 -34
  177. package/tests/fixtures/impactAssessment/cycle-endDate/invalid.json +0 -26
  178. package/tests/fixtures/impactAssessment/cycle-endDate/valid.json +0 -26
  179. package/tests/fixtures/impactAssessment/valid.json +0 -93
  180. package/tests/fixtures/indicator/characterisedIndicator-methodModel/invalid.json +0 -52
  181. package/tests/fixtures/indicator/characterisedIndicator-methodModel/valid.json +0 -52
  182. package/tests/fixtures/indicator/ionisingCompounds/invalid.json +0 -23
  183. package/tests/fixtures/indicator/ionisingCompounds/valid.json +0 -23
  184. package/tests/fixtures/indicator/landTransformation/invalid-grouped.json +0 -257
  185. package/tests/fixtures/indicator/landTransformation/invalid.json +0 -100
  186. package/tests/fixtures/indicator/landTransformation/valid-grouped-full.json +0 -507
  187. package/tests/fixtures/indicator/landTransformation/valid-grouped.json +0 -507
  188. package/tests/fixtures/indicator/landTransformation/valid.json +0 -100
  189. package/tests/fixtures/infrastructure/lifespan/invalid.json +0 -26
  190. package/tests/fixtures/infrastructure/lifespan/valid.json +0 -45
  191. package/tests/fixtures/input/animalFeed-fate/invalid.json +0 -103
  192. package/tests/fixtures/input/animalFeed-fate/valid.json +0 -90
  193. package/tests/fixtures/input/country/invalid.json +0 -64
  194. package/tests/fixtures/input/country/valid.json +0 -64
  195. package/tests/fixtures/input/distribution/animalHousing.json +0 -103
  196. package/tests/fixtures/input/distribution/complete/invalid.json +0 -177
  197. package/tests/fixtures/input/distribution/complete/valid.json +0 -163
  198. package/tests/fixtures/input/distribution/incomplete/valid.json +0 -139
  199. package/tests/fixtures/input/impactAssessment/invalid.json +0 -99
  200. package/tests/fixtures/input/impactAssessment/valid.json +0 -89
  201. package/tests/fixtures/input/input-as-product/invalid.json +0 -57
  202. package/tests/fixtures/input/input-as-product/valid.json +0 -59
  203. package/tests/fixtures/input/mustIncludeId/invalid.json +0 -13
  204. package/tests/fixtures/input/mustIncludeId/valid-multiple-ids.json +0 -31
  205. package/tests/fixtures/input/mustIncludeId/valid.json +0 -22
  206. package/tests/fixtures/input/saplings/invalid.json +0 -58
  207. package/tests/fixtures/input/saplings/valid-no-saplings.json +0 -58
  208. package/tests/fixtures/input/saplings/valid-not-plantation.json +0 -58
  209. package/tests/fixtures/input/saplings/valid.json +0 -58
  210. package/tests/fixtures/integration/distribution/product-yield-invalid.json +0 -54
  211. package/tests/fixtures/management/cycle-overlap/cycles.json +0 -39
  212. package/tests/fixtures/management/cycle-overlap/invalid.json +0 -26
  213. package/tests/fixtures/management/cycle-overlap/valid.json +0 -26
  214. package/tests/fixtures/management/exists/invalid.json +0 -13
  215. package/tests/fixtures/management/exists/valid.json +0 -25
  216. package/tests/fixtures/management/fallow-dates/invalid.json +0 -24
  217. package/tests/fixtures/management/fallow-dates/valid.json +0 -24
  218. package/tests/fixtures/management/termType/invalid-cropland.json +0 -35
  219. package/tests/fixtures/management/termType/invalid-permanent-pasture.json +0 -25
  220. package/tests/fixtures/management/termType/valid-cropland.json +0 -55
  221. package/tests/fixtures/management/termType/valid-no-management.json +0 -13
  222. package/tests/fixtures/management/termType/valid-permanent-pasture.json +0 -35
  223. package/tests/fixtures/measurement/depths/invalid.json +0 -44
  224. package/tests/fixtures/measurement/depths/valid.json +0 -50
  225. package/tests/fixtures/measurement/models/valid.json +0 -33
  226. package/tests/fixtures/measurement/models/warning-no-value.json +0 -30
  227. package/tests/fixtures/measurement/models/warning.json +0 -33
  228. package/tests/fixtures/measurement/pond-measurements/invalid.json +0 -11
  229. package/tests/fixtures/measurement/pond-measurements/valid.json +0 -23
  230. package/tests/fixtures/measurement/required-depths/error.json +0 -71
  231. package/tests/fixtures/measurement/required-depths/valid.json +0 -126
  232. package/tests/fixtures/measurement/required-depths/warning.json +0 -29
  233. package/tests/fixtures/measurement/soilTexture/missing-texture-value.json +0 -227
  234. package/tests/fixtures/measurement/soilTexture/percent-invalid.json +0 -110
  235. package/tests/fixtures/measurement/soilTexture/percent-missing-value.json +0 -43
  236. package/tests/fixtures/measurement/soilTexture/percent-valid.json +0 -110
  237. package/tests/fixtures/measurement/startDate-endDate-required/invalid.json +0 -32
  238. package/tests/fixtures/measurement/startDate-endDate-required/valid.json +0 -46
  239. package/tests/fixtures/measurement/unique/invalid.json +0 -28
  240. package/tests/fixtures/measurement/unique/valid.json +0 -16
  241. package/tests/fixtures/measurement/value-length/invalid.json +0 -46
  242. package/tests/fixtures/measurement/value-length/valid.json +0 -44
  243. package/tests/fixtures/measurement/water-salinity/invalid.json +0 -33
  244. package/tests/fixtures/measurement/water-salinity/valid-brakish.json +0 -40
  245. package/tests/fixtures/measurement/water-salinity/valid.json +0 -33
  246. package/tests/fixtures/organisation/valid.json +0 -26
  247. package/tests/fixtures/practice/croppingDuration/riceGrainInHuskFlooded/invalid.json +0 -63
  248. package/tests/fixtures/practice/croppingDuration/riceGrainInHuskFlooded/valid.json +0 -63
  249. package/tests/fixtures/practice/defaultValue/invalid.json +0 -12
  250. package/tests/fixtures/practice/defaultValue/valid.json +0 -15
  251. package/tests/fixtures/practice/excretaManagement/invalid.json +0 -50
  252. package/tests/fixtures/practice/excretaManagement/valid.json +0 -60
  253. package/tests/fixtures/practice/irrigated-complete/invalid.json +0 -47
  254. package/tests/fixtures/practice/irrigated-complete/valid-incomplete.json +0 -47
  255. package/tests/fixtures/practice/irrigated-complete/valid.json +0 -60
  256. package/tests/fixtures/practice/landCover-products/invalid.json +0 -58
  257. package/tests/fixtures/practice/landCover-products/valid-coverCrop.json +0 -69
  258. package/tests/fixtures/practice/landCover-products/valid.json +0 -58
  259. package/tests/fixtures/practice/liveAnimal-system/invalid.json +0 -58
  260. package/tests/fixtures/practice/liveAnimal-system/valid.json +0 -69
  261. package/tests/fixtures/practice/longFallowDuration/invalid.json +0 -20
  262. package/tests/fixtures/practice/longFallowDuration/valid.json +0 -20
  263. package/tests/fixtures/practice/noTillage/invalid.json +0 -23
  264. package/tests/fixtures/practice/noTillage/valid-value-not-100.json +0 -23
  265. package/tests/fixtures/practice/noTillage/valid.json +0 -21
  266. package/tests/fixtures/practice/pastureGrass/key-termType/invalid.json +0 -16
  267. package/tests/fixtures/practice/pastureGrass/key-termType/valid.json +0 -16
  268. package/tests/fixtures/practice/pastureGrass/key-value/invalid-numbers.json +0 -67
  269. package/tests/fixtures/practice/pastureGrass/key-value/invalid.json +0 -67
  270. package/tests/fixtures/practice/pastureGrass/key-value/valid.json +0 -67
  271. package/tests/fixtures/practice/pastureGrass/permanent-pasture/invalid.json +0 -37
  272. package/tests/fixtures/practice/pastureGrass/permanent-pasture/valid.json +0 -47
  273. package/tests/fixtures/practice/primaryPercent/invalid.json +0 -49
  274. package/tests/fixtures/practice/primaryPercent/valid.json +0 -49
  275. package/tests/fixtures/practice/processingOperation/invalid-no-primary.json +0 -48
  276. package/tests/fixtures/practice/processingOperation/invalid.json +0 -49
  277. package/tests/fixtures/practice/processingOperation/valid-cropland.json +0 -37
  278. package/tests/fixtures/practice/processingOperation/valid.json +0 -49
  279. package/tests/fixtures/practice/productivePhasePermanentCrops/invalid.json +0 -48
  280. package/tests/fixtures/practice/productivePhasePermanentCrops/valid-0-value.json +0 -58
  281. package/tests/fixtures/practice/productivePhasePermanentCrops/valid-no-value.json +0 -47
  282. package/tests/fixtures/practice/productivePhasePermanentCrops/valid.json +0 -48
  283. package/tests/fixtures/practice/site-management/invalid.json +0 -75
  284. package/tests/fixtures/practice/site-management/valid.json +0 -75
  285. package/tests/fixtures/practice/tillage-siteType/valid.json +0 -51
  286. package/tests/fixtures/practice/tillage-siteType/warning.json +0 -42
  287. package/tests/fixtures/practice/tillage-values/invalid-fullTillage.json +0 -61
  288. package/tests/fixtures/practice/tillage-values/invalid-noTillage.json +0 -61
  289. package/tests/fixtures/practice/tillage-values/valid.json +0 -61
  290. package/tests/fixtures/practice/waterRegime/rice/invalid.json +0 -59
  291. package/tests/fixtures/practice/waterRegime/rice/valid-0-value.json +0 -59
  292. package/tests/fixtures/practice/waterRegime/rice/valid.json +0 -58
  293. package/tests/fixtures/product/economicValueShare/invalid.json +0 -31
  294. package/tests/fixtures/product/economicValueShare/valid.json +0 -22
  295. package/tests/fixtures/product/excreta/invalid.json +0 -62
  296. package/tests/fixtures/product/excreta/valid.json +0 -62
  297. package/tests/fixtures/product/excreta/warning.json +0 -53
  298. package/tests/fixtures/product/excreta/with-system/invalid.json +0 -79
  299. package/tests/fixtures/product/excreta/with-system/valid.json +0 -88
  300. package/tests/fixtures/product/excreta/with-system/warning.json +0 -70
  301. package/tests/fixtures/product/fu_ha/invalid.json +0 -49
  302. package/tests/fixtures/product/fu_ha/valid.json +0 -49
  303. package/tests/fixtures/product/primary/invalid.json +0 -22
  304. package/tests/fixtures/product/primary/valid.json +0 -22
  305. package/tests/fixtures/product/value/valid.json +0 -26
  306. package/tests/fixtures/product/value/value-0/error.json +0 -40
  307. package/tests/fixtures/product/value/value-empty/warning.json +0 -23
  308. package/tests/fixtures/product/yield/invalid.json +0 -54
  309. package/tests/fixtures/product/yield/no-value.json +0 -75
  310. package/tests/fixtures/product/yield/valid.json +0 -54
  311. package/tests/fixtures/property/default-value/valid-allowed-exception.json +0 -61
  312. package/tests/fixtures/property/default-value/valid.json +0 -61
  313. package/tests/fixtures/property/default-value/warning.json +0 -61
  314. package/tests/fixtures/property/termType/invalid.json +0 -60
  315. package/tests/fixtures/property/termType/valid.json +0 -60
  316. package/tests/fixtures/property/value-min-max/invalid.json +0 -77
  317. package/tests/fixtures/property/value-min-max/valid-skip-maximum.json +0 -57
  318. package/tests/fixtures/property/value-min-max/valid.json +0 -78
  319. package/tests/fixtures/property/valueType/invalid.json +0 -79
  320. package/tests/fixtures/property/valueType/valid.json +0 -79
  321. package/tests/fixtures/property/volatileSolidsContent/invalid.json +0 -99
  322. package/tests/fixtures/property/volatileSolidsContent/valid.json +0 -99
  323. package/tests/fixtures/shared/coordinates/invalid.json +0 -18
  324. package/tests/fixtures/shared/coordinates/valid.json +0 -18
  325. package/tests/fixtures/shared/data-duplicates/valid.json +0 -113
  326. package/tests/fixtures/shared/data-duplicates/warning.json +0 -172
  327. package/tests/fixtures/shared/duplicated-term-units/invalid-animalProduct.json +0 -61
  328. package/tests/fixtures/shared/duplicated-term-units/invalid-organicFertiliser.json +0 -61
  329. package/tests/fixtures/shared/duplicated-term-units/valid.json +0 -49
  330. package/tests/fixtures/shared/list-country-region/invalid.json +0 -54
  331. package/tests/fixtures/shared/list-country-region/valid.json +0 -54
  332. package/tests/fixtures/shared/list-percent-value/invalid.json +0 -49
  333. package/tests/fixtures/shared/list-percent-value/valid.json +0 -52
  334. package/tests/fixtures/shared/list-valueType/invalid.json +0 -49
  335. package/tests/fixtures/shared/list-valueType/valid.json +0 -49
  336. package/tests/fixtures/shared/list-values-sum-100/management/with-properties/valid.json +0 -91
  337. package/tests/fixtures/shared/list-values-sum-100/measurements/missing-soil.json +0 -46
  338. package/tests/fixtures/shared/list-values-sum-100/measurements/no-depth-high-value.json +0 -63
  339. package/tests/fixtures/shared/list-values-sum-100/measurements/no-depth-valid.json +0 -40
  340. package/tests/fixtures/shared/list-values-sum-100/measurements/with-depth-high-value.json +0 -71
  341. package/tests/fixtures/shared/list-values-sum-100/practices/total-100.json +0 -61
  342. package/tests/fixtures/shared/list-values-sum-100/practices/total-110.json +0 -61
  343. package/tests/fixtures/shared/list-values-sum-100/practices/total-90.json +0 -61
  344. package/tests/fixtures/shared/min-max/value-above.json +0 -31
  345. package/tests/fixtures/shared/min-max/value-below.json +0 -31
  346. package/tests/fixtures/shared/min-max/value-valid.json +0 -45
  347. package/tests/fixtures/shared/model/emissions/invalid.json +0 -102
  348. package/tests/fixtures/shared/model/emissions/valid-variable-tolerance.json +0 -180
  349. package/tests/fixtures/shared/model/emissions/valid.json +0 -102
  350. package/tests/fixtures/shared/model/impacts/invalid.json +0 -75
  351. package/tests/fixtures/shared/model/impacts/valid.json +0 -75
  352. package/tests/fixtures/shared/model/inputs/valid-no-value.json +0 -84
  353. package/tests/fixtures/shared/model/inputs/valid.json +0 -87
  354. package/tests/fixtures/shared/model/inputs/warning.json +0 -87
  355. package/tests/fixtures/shared/model/products/valid-no-value.json +0 -88
  356. package/tests/fixtures/shared/model/products/valid.json +0 -91
  357. package/tests/fixtures/shared/model/products/warning.json +0 -91
  358. package/tests/fixtures/shared/otherModel/invalid.json +0 -69
  359. package/tests/fixtures/shared/otherModel/valid.json +0 -70
  360. package/tests/fixtures/shared/properties-duplicate-values/invalid.json +0 -61
  361. package/tests/fixtures/shared/properties-duplicate-values/valid.json +0 -57
  362. package/tests/fixtures/shared/properties-same-length/invalid.json +0 -62
  363. package/tests/fixtures/shared/properties-same-length/valid.json +0 -52
  364. package/tests/fixtures/shared/unit-percent/invalid.json +0 -34
  365. package/tests/fixtures/shared/unit-percent/valid.json +0 -60
  366. package/tests/fixtures/shared/unit-percent/warning.json +0 -52
  367. package/tests/fixtures/site/cycles-linked-ia/invalid.json +0 -129
  368. package/tests/fixtures/site/cycles-linked-ia/valid.json +0 -129
  369. package/tests/fixtures/site/valid.json +0 -138
  370. package/tests/fixtures/source/valid.json +0 -19
  371. package/tests/fixtures/transformation/excretaManagement/invalid.json +0 -47
  372. package/tests/fixtures/transformation/excretaManagement/valid.json +0 -59
  373. package/tests/fixtures/transformation/inputs-products/invalid.json +0 -43
  374. package/tests/fixtures/transformation/inputs-products/valid.json +0 -43
  375. package/tests/fixtures/transformation/linked-emission/invalid.json +0 -101
  376. package/tests/fixtures/transformation/linked-emission/valid.json +0 -107
  377. package/tests/fixtures/transformation/previousTransformationId/invalid-no-previous.json +0 -127
  378. package/tests/fixtures/transformation/previousTransformationId/invalid-previous-input.json +0 -100
  379. package/tests/fixtures/transformation/previousTransformationId/invalid-product-input.json +0 -106
  380. package/tests/fixtures/transformation/previousTransformationId/invalid-wrong-order.json +0 -136
  381. package/tests/fixtures/transformation/previousTransformationId/valid.json +0 -171
  382. package/tests/integration/__init__.py +0 -0
  383. package/tests/integration/test_product.py +0 -17
  384. package/tests/test_gee.py +0 -10
  385. package/tests/test_utils.py +0 -36
  386. package/tests/test_validation.py +0 -11
  387. package/tests/utils.py +0 -28
  388. package/tests/validators/__init__.py +0 -0
  389. package/tests/validators/test_aggregated_cycle.py +0 -44
  390. package/tests/validators/test_aggregated_shared.py +0 -63
  391. package/tests/validators/test_animal.py +0 -72
  392. package/tests/validators/test_completeness.py +0 -337
  393. package/tests/validators/test_cycle.py +0 -600
  394. package/tests/validators/test_emission.py +0 -170
  395. package/tests/validators/test_impact_assessment.py +0 -80
  396. package/tests/validators/test_indicator.py +0 -120
  397. package/tests/validators/test_infrastructure.py +0 -26
  398. package/tests/validators/test_input.py +0 -434
  399. package/tests/validators/test_management.py +0 -177
  400. package/tests/validators/test_measurement.py +0 -317
  401. package/tests/validators/test_organisation.py +0 -32
  402. package/tests/validators/test_practice.py +0 -490
  403. package/tests/validators/test_product.py +0 -291
  404. package/tests/validators/test_property.py +0 -143
  405. package/tests/validators/test_shared.py +0 -1139
  406. package/tests/validators/test_site.py +0 -151
  407. package/tests/validators/test_source.py +0 -15
  408. package/tests/validators/test_transformation.py +0 -151
  409. package/tests/validators/test_validators.py +0 -74
  410. package/tsconfig.dist.json +0 -9
  411. package/tsconfig.json +0 -25
@@ -1,444 +0,0 @@
1
- import json
2
- from typing import List
3
- from functools import reduce, lru_cache
4
- from datetime import datetime, timedelta
5
- from hestia_earth.schema import NodeType, TermTermType, UNIQUENESS_FIELDS
6
- from hestia_earth.utils.api import download_hestia
7
- from hestia_earth.utils.lookup import download_lookup, get_table_value
8
- from hestia_earth.utils.tools import (
9
- list_average,
10
- safe_parse_date,
11
- safe_parse_float,
12
- non_empty_list,
13
- is_number,
14
- is_boolean,
15
- get_dict_key,
16
- flatten,
17
- )
18
- from hestia_earth.utils.model import filter_list_term_type, find_primary_product
19
-
20
- ANIMAL_TERM_TYPES = [TermTermType.LIVEANIMAL, TermTermType.LIVEAQUATICSPECIES]
21
-
22
-
23
- @lru_cache()
24
- def _get_term_lookup_value(term_id: str, term_type: str, column: str):
25
- lookup = download_lookup(f"{term_type}.csv", keep_in_memory=True)
26
- return get_table_value(lookup, "term.id", term_id, column)
27
-
28
-
29
- def get_lookup_value(lookup_term: dict, column: str):
30
- value = (
31
- _get_term_lookup_value(
32
- lookup_term.get("@id"), lookup_term.get("termType"), column
33
- )
34
- if lookup_term
35
- else None
36
- )
37
- return value
38
-
39
-
40
- def _next_error(values: list):
41
- return next((x for x in values if x is not True), True)
42
-
43
-
44
- def _filter_list_errors(values: list, return_single=True):
45
- values = list(filter(lambda x: x is not True, values))
46
- return (
47
- True
48
- if return_single and len(values) == 0
49
- else (values[0] if return_single and len(values) == 1 else values)
50
- )
51
-
52
-
53
- def _flatten_errors(errors):
54
- errors_list = [
55
- [] if isinstance(v, bool) else v if isinstance(v, list) else [v] for v in errors
56
- ]
57
- return flatten(errors_list)
58
-
59
-
60
- def _list_except_item(values: list, item):
61
- try:
62
- idx = values.index(item)
63
- return values[:idx] + values[idx + 1 :]
64
- except ValueError:
65
- return values
66
-
67
-
68
- def update_error_path(error: dict, key: str, index=None):
69
- path = (
70
- f".{key}[{index}]{error.get('dataPath')}"
71
- if index is not None
72
- else f".{key}{error.get('dataPath')}"
73
- )
74
- return error | {"dataPath": path}
75
-
76
-
77
- def _safe_cast(val, to_type, default=None):
78
- try:
79
- return to_type(val)
80
- except (ValueError, TypeError):
81
- return default
82
-
83
-
84
- def hash_dict(value: dict):
85
- return json.dumps(value, sort_keys=True)
86
-
87
-
88
- def is_same_dict(a: dict, b: dict):
89
- return hash_dict(a) == hash_dict(b)
90
-
91
-
92
- def _dict_without_key(a: dict, key: str):
93
- no_key = a.copy()
94
- if key in no_key:
95
- no_key.pop(key)
96
- return no_key
97
-
98
-
99
- _GROUP_NODE_TYPES = [
100
- NodeType.CYCLE.value,
101
- NodeType.IMPACTASSESSMENT.value,
102
- NodeType.SITE.value,
103
- NodeType.SOURCE.value,
104
- ]
105
-
106
-
107
- def _is_node(value):
108
- return (
109
- isinstance(value, dict)
110
- and (value.get("type") or value.get("@type")) in _GROUP_NODE_TYPES
111
- and (value.get("id") or value.get("@id"))
112
- )
113
-
114
-
115
- def _nodes_grouper(nodes: List[dict], grouping_func):
116
- def group(groups: dict, node: dict):
117
- if _is_node(node):
118
- id = node.get("id") or node.get("@id")
119
- type = node.get("type") or node.get("@type")
120
- grouping_func(groups, node, type, id)
121
- return groups
122
-
123
- # check for nested nodes
124
- nested_nodes = flatten(
125
- [
126
- v
127
- for node in nodes
128
- for v in node.values()
129
- if _is_node(v) or (isinstance(v, list) and len(v) > 0 and _is_node(v[0]))
130
- ]
131
- )
132
- data = reduce(group, nested_nodes, {})
133
- return reduce(group, nodes, data)
134
-
135
-
136
- def _group_nodes(nodes: List[dict]):
137
- def group_by(groups: dict, node: dict, type: str, id: str):
138
- groups[type] = groups.get(type, {})
139
- groups[type][id] = node
140
-
141
- return _nodes_grouper(nodes, group_by)
142
-
143
-
144
- def _hash_nodes(nodes: List[dict]):
145
- def group_by(groups: dict, node: dict, type: str, id: str):
146
- # store the hash of the node without the `id` for uniqueness check
147
- key = hash_dict(_dict_without_key(node, "id"))
148
- groups[key] = groups.get(key, []) + [node]
149
-
150
- return _nodes_grouper(nodes, group_by)
151
-
152
-
153
- def _list_sum(values: list, prop: str):
154
- return sum(map(lambda v: _safe_cast(v.get(prop, 0), float, 0.0), values))
155
-
156
-
157
- def list_sum_terms(values: list, term_ids=[], default=None):
158
- average_values = non_empty_list(
159
- [
160
- _value_average(node, default=default)
161
- for node in values
162
- if node.get("term", {}).get("@id") in term_ids
163
- ]
164
- )
165
- return sum(average_values) if average_values else None
166
-
167
-
168
- def _compare_values(x, y):
169
- return (
170
- next((True for item in x if item in y), False)
171
- if isinstance(x, list) and isinstance(y, list)
172
- else x == y
173
- )
174
-
175
-
176
- def _same_properties(value: dict, props: List[str]):
177
- def identical(test: dict):
178
- same_values = list(
179
- filter(
180
- lambda x: _compare_values(
181
- get_dict_key(value, x), get_dict_key(test, x)
182
- ),
183
- props,
184
- )
185
- )
186
- return test if len(same_values) == len(props) else None
187
-
188
- return identical
189
-
190
-
191
- def _value_average(node: dict, default=0, key="value"):
192
- try:
193
- value = node.get(key)
194
- return (
195
- list_average(value, default)
196
- if isinstance(value, list)
197
- else (value or default)
198
- )
199
- except Exception:
200
- return default
201
-
202
-
203
- def term_id_prefix(term_id: str):
204
- return term_id.split("Kg")[0]
205
-
206
-
207
- def _download_linked_node(node: dict):
208
- data = (
209
- download_hestia(node.get("@id"), node.get("@type"))
210
- if node.get("@id") and node.get("@type")
211
- else None
212
- )
213
- return data if (data or {}).get("@id") == node.get("@id") else None
214
-
215
-
216
- def find_linked_node(node_map: dict, node: dict):
217
- """
218
- Find the Node by type and id in the list of nodes.
219
- """
220
- return node_map.get(node.get("type"), {}).get(
221
- node.get("id") or node.get("@id")
222
- ) or _download_linked_node(node)
223
-
224
-
225
- def _value_as_array(data: dict, key: str):
226
- value = data.get(key)
227
- return value if isinstance(value, list) else non_empty_list([value])
228
-
229
-
230
- def find_related_nodes(
231
- node_map: dict, node: dict, related_key: str, related_type: NodeType
232
- ):
233
- """
234
- Find all nodes related to the same node via a key.
235
- Example: find all Cycles related to a Site via the key "site".
236
-
237
- Parameters
238
- ----------
239
- node_map : dict
240
- The list of all nodes to do cross-validation, grouped by `type` and `id`.
241
- node : dict
242
- The node the other nodes should be related to.
243
- related_key : str
244
- How the other nodes are related to the `node`.
245
- related_type : NodeType
246
- The type of the related nodes.
247
-
248
- Returns
249
- -------
250
- List[dict]
251
- The list of nodes related to the `node`.
252
- """
253
- node_id = node.get("@id", node.get("id"))
254
- nodes = node_map.get(related_type.value, {}).values()
255
- return list(
256
- {
257
- n.get("@id", n.get("id")): n
258
- for n in nodes
259
- for related_node in _value_as_array(n, related_key)
260
- if (related_node.get("@id", related_node.get("id")) == node_id)
261
- }.values()
262
- )
263
-
264
-
265
- def _is_before_today(date: str):
266
- return safe_parse_date(date).date() <= datetime.now().date()
267
-
268
-
269
- def _node_year(node: dict):
270
- date = node.get("endDate", node.get("startDate"))
271
- date = safe_parse_date(date) if date else None
272
- return date.year if date else None
273
-
274
-
275
- def is_live_animal_cycle(cycle: dict):
276
- blank_nodes = cycle.get("animals", []) + cycle.get("products", [])
277
- animals = filter_list_term_type(blank_nodes, ANIMAL_TERM_TYPES)
278
- return len(animals) > 0
279
-
280
-
281
- def contains_grazing_animals(cycle: dict):
282
- blank_nodes = cycle.get("animals", []) + cycle.get("products", [])
283
- animals = filter_list_term_type(blank_nodes, ANIMAL_TERM_TYPES)
284
- return any(
285
- [v for v in animals if get_lookup_value(v.get("term", {}), "isGrazingAnimal")]
286
- )
287
-
288
-
289
- def _match_list_el(source: list, dest: list, key: str):
290
- src_values = non_empty_list([get_dict_key(x, key) for x in source])
291
- dest_values = non_empty_list([get_dict_key(x, key) for x in dest])
292
- return sorted(src_values) == sorted(dest_values)
293
-
294
-
295
- def _match_el(source: dict, dest: dict, fields: list):
296
- def match(key: str):
297
- keys = key.split(".")
298
- is_list = len(keys) >= 2 and (
299
- isinstance(get_dict_key(source, keys[0]), list)
300
- or isinstance(get_dict_key(dest, keys[0]), list)
301
- )
302
- return (
303
- _match_list_el(
304
- get_dict_key(source, keys[0]) or [],
305
- get_dict_key(dest, keys[0]) or [],
306
- ".".join(keys[1:]),
307
- )
308
- if is_list
309
- else get_dict_key(source, key) == get_dict_key(dest, key)
310
- )
311
-
312
- return all(map(match, fields))
313
-
314
-
315
- def find_by_unique_product(node: dict, product: dict, list_key: str = "products"):
316
- """
317
- Fallback to finding a product with unique keys if a single product has the same `term.@id`.
318
- """
319
- products = node.get(list_key, [])
320
- products = [p for p in products if _match_el(p, product, ["term.@id"])]
321
- return products[0] if len(products) == 1 else None
322
-
323
-
324
- def find_by_product(node: dict, product: dict, list_key: str = "products"):
325
- keys = UNIQUENESS_FIELDS.get(node.get("type", node.get("@type")), {}).get(
326
- list_key, ["term.@id"]
327
- )
328
- products = node.get(list_key, [])
329
- return next((p for p in products if _match_el(p, product, keys)), None)
330
-
331
-
332
- def is_same_product(p1: dict, p2: dict):
333
- return find_by_product({"type": NodeType.CYCLE.value, "products": [p1]}, p2)
334
-
335
-
336
- def _formatDepth(depth: str):
337
- # handle float values
338
- return str(int(depth)) if is_number(depth) else ""
339
-
340
-
341
- def blank_node_properties_group(blank_node: dict):
342
- def property_group(property: dict):
343
- return get_lookup_value(property.get("term", {}), "blankNodesGroup")
344
-
345
- properties = blank_node.get("properties", [])
346
- return "-".join(non_empty_list(map(property_group, properties)))
347
-
348
-
349
- def _blank_node_sum_groups(blank_node: dict, allow_sum_100: bool = True):
350
- term = blank_node.get("term", {})
351
- sum_below_100_group = get_lookup_value(term, "sumMax100Group")
352
- sum_equal_100_group = get_lookup_value(term, "sumIs100Group")
353
-
354
- return {
355
- "sumMax100Group": sum_below_100_group
356
- or (sum_equal_100_group if not allow_sum_100 else None),
357
- "sumIs100Group": sum_equal_100_group if allow_sum_100 else None,
358
- }
359
-
360
-
361
- def group_blank_nodes(nodes: list, by_sum: bool = True):
362
- """
363
- Group a list of blank nodes using:
364
- - the `depthUpper`, `depthLower`, `startDate`, `endDate`, `dates`
365
- - the lookup group `sumMax100Group` or `sumIs100Group` if specified
366
- - the lookup group `blankNodesGroup` on properties if any
367
-
368
- Parameters
369
- ----------
370
- nodes : list
371
- List of blank nodes with their index.
372
- by_sum : bool
373
- Group blank nodes using the key to sum to 100% (`sumMax100Group` and `sumIs100Group`).
374
- """
375
-
376
- def group_by(group: dict, values: tuple):
377
- index, blank_node = values
378
- properties_group = blank_node_properties_group(blank_node)
379
- # note: grouping of `properties` disables the grouping == 100
380
- sum_groups = _blank_node_sum_groups(
381
- blank_node, allow_sum_100=not properties_group
382
- )
383
- keys = non_empty_list(
384
- [
385
- _formatDepth(blank_node.get("depthUpper", "")),
386
- _formatDepth(blank_node.get("depthLower", "")),
387
- blank_node.get("startDate"),
388
- blank_node.get("endDate"),
389
- "-".join(blank_node.get("dates") or []),
390
- properties_group,
391
- ]
392
- + (list(sum_groups.values()) if by_sum else [])
393
- )
394
- key = "-".join(keys) if len(keys) > 0 else "default"
395
-
396
- if not by_sum or all(
397
- [blank_node.get("value", []), any(list(sum_groups.values()))]
398
- ):
399
- group[key] = group.get(key, []) + [
400
- {"index": index, "node": blank_node} | (sum_groups if by_sum else {})
401
- ]
402
-
403
- return group
404
-
405
- return reduce(group_by, nodes, {})
406
-
407
-
408
- def is_permanent_crop(cycle: dict):
409
- product = find_primary_product(cycle) or {}
410
- return (
411
- get_lookup_value(product.get("term", {}), "cropGroupingFAO")
412
- == "Permanent crops"
413
- )
414
-
415
-
416
- def term_valueType(term: dict):
417
- return get_lookup_value(term, "valueType")
418
-
419
-
420
- VALUE_TYPE_MATCH = {"number": is_number, "boolean": is_boolean}
421
-
422
-
423
- def match_value_type(value_type: str, value):
424
- values = non_empty_list(value if isinstance(value, list) else [value])
425
- return all([VALUE_TYPE_MATCH.get(value_type, lambda _: True)(v) for v in values])
426
-
427
-
428
- def cycle_start_date(cycle: dict) -> datetime:
429
- product = find_primary_product(cycle)
430
- max_cycleDuration = (
431
- cycle.get("cycleDuration")
432
- or safe_parse_float(
433
- value=get_lookup_value(product["term"], "maximumCycleDuration"), default=0
434
- )
435
- if product
436
- else 0
437
- )
438
- return (
439
- safe_parse_date(cycle.get("startDate"))
440
- if cycle.get("startDate")
441
- else (
442
- safe_parse_date(cycle.get("endDate")) - (timedelta(days=max_cycleDuration))
443
- )
444
- )
@@ -1,141 +0,0 @@
1
- import os
2
- from hestia_earth.schema import SchemaType
3
- from hestia_earth.utils.tools import flatten
4
-
5
- from ..log import logger
6
- from ..utils import update_error_path
7
- from .shared import validate_empty_fields, validate_nodes_duplicates
8
- from .cycle import validate_cycle
9
- from .impact_assessment import validate_impact_assessment
10
- from .organisation import validate_organisation
11
- from .site import validate_site
12
- from .source import validate_source
13
-
14
- # disable validation based on `@type`
15
- VALIDATE_EXISTING_NODES = os.getenv("VALIDATE_EXISTING_NODES", "false") == "true"
16
- VALIDATE_TYPE = {
17
- SchemaType.CYCLE.value: lambda n, nodes: validate_cycle(n, nodes),
18
- SchemaType.IMPACTASSESSMENT.value: lambda n, nodes: validate_impact_assessment(
19
- n, nodes
20
- ),
21
- SchemaType.ORGANISATION.value: lambda n, nodes: validate_organisation(n, nodes),
22
- SchemaType.SITE.value: lambda n, nodes: validate_site(n, nodes),
23
- SchemaType.SOURCE.value: lambda n, nodes: validate_source(n, nodes),
24
- }
25
- SKIP_VALIDATE_DUPLICATES = [
26
- SchemaType.ACTOR.value,
27
- SchemaType.IMPACTASSESSMENT.value,
28
- SchemaType.TERM.value,
29
- ]
30
-
31
-
32
- def _has_keys(node: dict):
33
- # ignore some keys that are automatically added to nested objects
34
- ignore_keys = ["type", "id", "@type", "@id", "name", "description", "siteType"]
35
- node_keys = [k for k in list(node.keys()) if k not in ignore_keys]
36
- return len(node_keys) > 0
37
-
38
-
39
- def _should_run(ntype: str, node: dict):
40
- return all([ntype in VALIDATE_TYPE, _has_keys(node)])
41
-
42
-
43
- def _validate_node_type(node_by_type: dict, node_by_hash: dict, ntype: str, node: dict):
44
- should_run = _should_run(ntype, node)
45
- if should_run:
46
- logger.debug(
47
- "Run validation on: type=%s, id=%s", ntype, node.get("id", node.get("@id"))
48
- )
49
- validator = VALIDATE_TYPE.get(ntype)
50
- validations = validator(node, node_by_type) if should_run else []
51
- return (
52
- validations
53
- + validate_empty_fields(node)
54
- + (
55
- []
56
- if any([ntype in SKIP_VALIDATE_DUPLICATES, not should_run])
57
- else validate_nodes_duplicates(node, node_by_hash)
58
- )
59
- )
60
-
61
-
62
- def _validate_node_children(node_by_type: dict, node_by_hash: dict, node: dict):
63
- validations = []
64
- for key, value in node.items():
65
- if isinstance(value, list):
66
- validations.extend(
67
- [
68
- _validate_node_child(node_by_type, node_by_hash, key, value, index)
69
- for index, value in enumerate(value)
70
- ]
71
- )
72
- if isinstance(value, dict):
73
- validations.append(
74
- _validate_node_child(node_by_type, node_by_hash, key, value)
75
- )
76
- return flatten(validations)
77
-
78
-
79
- def _validate_node_child(
80
- node_by_type: dict, node_by_hash: dict, key: str, value: dict, index=None
81
- ):
82
- values = validate_node(node_by_type, node_by_hash)(value)
83
- return list(
84
- map(
85
- lambda error: (
86
- update_error_path(error, key, index)
87
- if isinstance(error, dict)
88
- else error
89
- ),
90
- values,
91
- )
92
- )
93
-
94
-
95
- def validate_node(node_by_type: dict = {}, node_by_hash: dict = {}):
96
- def validate(node: dict):
97
- """
98
- Validates a single Node.
99
-
100
- Parameters
101
- ----------
102
- node : dict
103
- The JSON-Node to validate.
104
-
105
- Returns
106
- -------
107
- List
108
- The list of errors/warnings for the node, which can be empty if no errors/warnings detected.
109
- """
110
- try:
111
- ntype = (
112
- node.get("type", node.get("@type") if VALIDATE_EXISTING_NODES else None)
113
- if isinstance(node, dict)
114
- else None
115
- )
116
- return (
117
- []
118
- if ntype is None
119
- else list(
120
- filter(
121
- lambda v: v is not True,
122
- flatten(
123
- _validate_node_type(node_by_type, node_by_hash, ntype, node)
124
- + (
125
- []
126
- if node.get("aggregated")
127
- else _validate_node_children(
128
- node_by_type, node_by_hash, node
129
- )
130
- )
131
- ),
132
- )
133
- )
134
- )
135
- except Exception as e:
136
- logger.error(
137
- f"Error validating {ntype} with id '{node.get('id', node.get('@id'))}': {str(e)}"
138
- )
139
- raise e
140
-
141
- return validate
@@ -1,32 +0,0 @@
1
- from hestia_earth.utils.model import find_primary_product
2
-
3
- from hestia_earth.validation.utils import _filter_list_errors, get_lookup_value
4
-
5
-
6
- def validate_linked_impactAssessment(cycle: dict, list_key: str = "inputs"):
7
- primary_product = find_primary_product(cycle) or {}
8
- input_term_ids = (
9
- get_lookup_value(primary_product.get("term"), "aggregationInputTermIds") or ""
10
- ).split(";")
11
-
12
- def validate(values: tuple):
13
- index, blank_node = values
14
- is_aggregation_input = blank_node.get("term", {}).get("@id") in input_term_ids
15
- linked_id = blank_node.get("impactAssessment", {}).get("@id", "")
16
- is_valid = all([linked_id, "world" not in linked_id])
17
- return (
18
- not is_aggregation_input
19
- or is_valid
20
- or {
21
- "level": "error",
22
- "dataPath": f".{list_key}[{index}]{'.impactAssessment' if linked_id else ''}",
23
- "message": "must be linked to a verified country-level Impact Assessment",
24
- "params": {"expected": blank_node.get("country"), "current": linked_id},
25
- }
26
- )
27
-
28
- return (
29
- _filter_list_errors(map(validate, enumerate(cycle.get(list_key, []))))
30
- if input_term_ids
31
- else True
32
- )
@@ -1,37 +0,0 @@
1
- def validate_quality_score_min(node: dict, max_diff: int = 2):
2
- node_id = node.get("@id", node.get("id", ""))
3
- key = "aggregatedQualityScore"
4
- value = node.get(key, 0)
5
- max_value = node.get(key + "Max", 0)
6
- min_value = max_value - max_diff
7
- # ignore nodes that are organic or irrigated as they should not block the upload of other nodes
8
- level = (
9
- "warning" if any(["organic" in node_id, "irrigated" in node_id]) else "error"
10
- )
11
- return value >= min_value or {
12
- "level": level,
13
- "dataPath": f".{key}",
14
- "message": "must be at least equal to the minimum value",
15
- "params": {
16
- "expected": min_value,
17
- "current": value,
18
- "min": min_value,
19
- "max": max_value,
20
- },
21
- }
22
-
23
-
24
- def validate_id(node: dict):
25
- # make sure the ID contains a product ID, region ID, start and end year
26
- node_id = node.get("id", "")
27
- # there should be 4 different components to the id
28
- node_id_length = len(node_id.split("-"))
29
- return (
30
- not node_id
31
- or node_id_length >= 4
32
- or {
33
- "level": "error",
34
- "dataPath": ".id",
35
- "message": "aggregation id must contain a product, region, start, and end year",
36
- }
37
- )