@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.
- package/.coveragerc +14 -0
- package/.dockerignore +19 -0
- package/.eslintignore +17 -0
- package/.eslintrc.js +11 -0
- package/.flake8 +5 -0
- package/.gitlab/issue_templates/new validation.md +82 -0
- package/.gitlab-ci.yml +216 -0
- package/.readthedocs.yml +24 -0
- package/CODEOWNERS +11 -0
- package/Dockerfile +13 -0
- package/LICENSE +21 -0
- package/MANIFEST.in +2 -0
- package/bin/hestia-validate-data +80 -0
- package/build_mocking.py +14 -0
- package/commitlint.config.js +1 -0
- package/docs/Makefile +20 -0
- package/docs/_static/styles.css +4 -0
- package/docs/_templates/custom-class-template.rst +34 -0
- package/docs/_templates/custom-module-template.rst +66 -0
- package/docs/_templates/layout.html +4 -0
- package/docs/conf.py +74 -0
- package/docs/index.rst +42 -0
- package/docs/make.bat +35 -0
- package/docs/requirements.txt +13 -0
- package/envs/.develop.env +1 -0
- package/envs/.master.env +1 -0
- package/guide-assets/.gitkeep +0 -0
- package/hestia_earth/validation/README.md +5 -0
- package/hestia_earth/validation/__init__.py +32 -0
- package/hestia_earth/validation/distribution.py +22 -0
- package/hestia_earth/validation/gee.py +162 -0
- package/hestia_earth/validation/log.py +44 -0
- package/hestia_earth/validation/models.py +141 -0
- package/hestia_earth/validation/preload_requests.py +61 -0
- package/hestia_earth/validation/terms.py +88 -0
- package/hestia_earth/validation/utils.py +444 -0
- package/hestia_earth/validation/validators/__init__.py +141 -0
- package/hestia_earth/validation/validators/aggregated_cycle.py +32 -0
- package/hestia_earth/validation/validators/aggregated_shared.py +37 -0
- package/hestia_earth/validation/validators/animal.py +88 -0
- package/hestia_earth/validation/validators/completeness.py +252 -0
- package/hestia_earth/validation/validators/cycle.py +1123 -0
- package/hestia_earth/validation/validators/distribution.py +86 -0
- package/hestia_earth/validation/validators/emission.py +109 -0
- package/hestia_earth/validation/validators/impact_assessment.py +138 -0
- package/hestia_earth/validation/validators/indicator.py +154 -0
- package/hestia_earth/validation/validators/infrastructure.py +25 -0
- package/hestia_earth/validation/validators/input.py +268 -0
- package/hestia_earth/validation/validators/management.py +131 -0
- package/hestia_earth/validation/validators/measurement.py +368 -0
- package/hestia_earth/validation/validators/organisation.py +43 -0
- package/hestia_earth/validation/validators/practice.py +590 -0
- package/hestia_earth/validation/validators/product.py +263 -0
- package/hestia_earth/validation/validators/property.py +266 -0
- package/hestia_earth/validation/validators/shared.py +940 -0
- package/hestia_earth/validation/validators/site.py +312 -0
- package/hestia_earth/validation/validators/source.py +20 -0
- package/hestia_earth/validation/validators/transformation.py +250 -0
- package/hestia_earth/validation/version.py +1 -0
- package/layer/build.sh +34 -0
- package/layer/deploy.sh +18 -0
- package/package.json +59 -0
- package/release.sh +11 -0
- package/requirements-ci.txt +6 -0
- package/requirements-test.txt +4 -0
- package/requirements.txt +2 -0
- package/run-docker-test.sh +7 -0
- package/run-docker.sh +9 -0
- package/run.py +99 -0
- package/scripts/build_docs.py +283 -0
- package/scripts/build_validation_list.py +160 -0
- package/scripts/guide-create-branch.sh +15 -0
- package/scripts/update-package-version.js +28 -0
- package/search-results.json +384 -0
- package/setup.cfg +2 -0
- package/setup.py +35 -0
- package/src/index.ts +1 -0
- package/src/validations.ts +22 -0
- package/src/version.ts +1 -0
- package/tests/Dockerfile +13 -0
- package/tests/__init__.py +3 -0
- package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/invalid-no-impactAssessment.json +64 -0
- package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/invalid-world.json +69 -0
- package/tests/fixtures/aggregated/cycle/inputs-impactAssessment/valid.json +69 -0
- package/tests/fixtures/animal/duplicated-input-cycle/invalid.json +98 -0
- package/tests/fixtures/animal/duplicated-input-cycle/valid.json +91 -0
- package/tests/fixtures/animal/pregnancyRateTotal/invalid.json +49 -0
- package/tests/fixtures/animal/pregnancyRateTotal/valid.json +60 -0
- package/tests/fixtures/animal/required/invalid.json +59 -0
- package/tests/fixtures/animal/required/valid.json +72 -0
- package/tests/fixtures/completeness/all-values/warning.json +22 -0
- package/tests/fixtures/completeness/animalPopulation/invalid.json +58 -0
- package/tests/fixtures/completeness/animalPopulation/valid-animals.json +71 -0
- package/tests/fixtures/completeness/animalPopulation/valid-incomplete.json +58 -0
- package/tests/fixtures/completeness/animalPopulation/valid-no-liveAnimals.json +37 -0
- package/tests/fixtures/completeness/blank-nodes/agri-food processor-invalid.json +52 -0
- package/tests/fixtures/completeness/blank-nodes/invalid.json +124 -0
- package/tests/fixtures/completeness/blank-nodes/valid.json +128 -0
- package/tests/fixtures/completeness/cropland/site.json +16 -0
- package/tests/fixtures/completeness/cropland/valid.json +22 -0
- package/tests/fixtures/completeness/cropland/warning.json +22 -0
- package/tests/fixtures/completeness/freshForage/error-animals.json +63 -0
- package/tests/fixtures/completeness/freshForage/error-products.json +65 -0
- package/tests/fixtures/completeness/freshForage/valid-animal-inputs.json +63 -0
- package/tests/fixtures/completeness/freshForage/valid-animals.json +63 -0
- package/tests/fixtures/completeness/freshForage/valid-not-grazing-liveAnimal.json +55 -0
- package/tests/fixtures/completeness/freshForage/valid-not-liveAnimal.json +47 -0
- package/tests/fixtures/completeness/freshForage/valid-products.json +68 -0
- package/tests/fixtures/completeness/ingredient/invalid-agri-food-processor.json +37 -0
- package/tests/fixtures/completeness/ingredient/invalid.json +49 -0
- package/tests/fixtures/completeness/ingredient/valid-agri-food-processor-complete.json +49 -0
- package/tests/fixtures/completeness/ingredient/valid-agri-food-processor-incomplete.json +37 -0
- package/tests/fixtures/completeness/ingredient/valid.json +49 -0
- package/tests/fixtures/completeness/material/error.json +49 -0
- package/tests/fixtures/completeness/material/valid-fuel-material.json +60 -0
- package/tests/fixtures/completeness/material/valid-incomplete.json +36 -0
- package/tests/fixtures/completeness/material/valid-no-fuel.json +36 -0
- package/tests/fixtures/completeness/valid.json +22 -0
- package/tests/fixtures/cycle/aboveGroundCropResidue/invalid.json +76 -0
- package/tests/fixtures/cycle/aboveGroundCropResidue/valid.json +76 -0
- package/tests/fixtures/cycle/aggregated-valid.json +102 -0
- package/tests/fixtures/cycle/coverCrop/invalid.json +64 -0
- package/tests/fixtures/cycle/coverCrop/valid-not-coverCrop.json +54 -0
- package/tests/fixtures/cycle/coverCrop/valid.json +64 -0
- package/tests/fixtures/cycle/cropResidue/complete/invalid.json +56 -0
- package/tests/fixtures/cycle/cropResidue/complete/valid.json +82 -0
- package/tests/fixtures/cycle/cropResidue/incomplete/invalid.json +42 -0
- package/tests/fixtures/cycle/cropResidue/incomplete/valid.json +56 -0
- package/tests/fixtures/cycle/dates/invalid-emissions.json +70 -0
- package/tests/fixtures/cycle/liveAnimal-animalProduct-mapping/invalid.json +63 -0
- package/tests/fixtures/cycle/liveAnimal-animalProduct-mapping/valid.json +63 -0
- package/tests/fixtures/cycle/maximumCycleDuration/invalid-dates-year-only.json +48 -0
- package/tests/fixtures/cycle/maximumCycleDuration/invalid-dates.json +48 -0
- package/tests/fixtures/cycle/maximumCycleDuration/invalid.json +48 -0
- package/tests/fixtures/cycle/maximumCycleDuration/valid-dates-year-only.json +48 -0
- package/tests/fixtures/cycle/maximumCycleDuration/valid-dates.json +48 -0
- package/tests/fixtures/cycle/maximumCycleDuration/valid.json +48 -0
- package/tests/fixtures/cycle/otherSites/cycleDuration/invalid.json +52 -0
- package/tests/fixtures/cycle/otherSites/cycleDuration/valid-no-siteDuration.json +40 -0
- package/tests/fixtures/cycle/otherSites/cycleDuration/valid.json +52 -0
- package/tests/fixtures/cycle/practices/stockingDensityPermanentPastureAverage/invalid.json +56 -0
- package/tests/fixtures/cycle/practices/stockingDensityPermanentPastureAverage/valid.json +65 -0
- package/tests/fixtures/cycle/primary-product-as-input/invalid.json +59 -0
- package/tests/fixtures/cycle/primary-product-as-input/valid.json +48 -0
- package/tests/fixtures/cycle/product-linked-ia/cycle.json +66 -0
- package/tests/fixtures/cycle/product-linked-ia/invalid-multiple.json +58 -0
- package/tests/fixtures/cycle/product-linked-ia/valid.json +57 -0
- package/tests/fixtures/cycle/products/animals/invalid.json +69 -0
- package/tests/fixtures/cycle/products/animals/valid.json +58 -0
- package/tests/fixtures/cycle/riceGrainInHuskFlooded-minimumCycleDuration/invalid.json +53 -0
- package/tests/fixtures/cycle/riceGrainInHuskFlooded-minimumCycleDuration/valid.json +53 -0
- package/tests/fixtures/cycle/siteDuration/crop/invalid.json +53 -0
- package/tests/fixtures/cycle/siteDuration/crop/valid-different-duration.json +53 -0
- package/tests/fixtures/cycle/siteDuration/crop/valid-same-duration.json +53 -0
- package/tests/fixtures/cycle/siteDuration/invalid.json +41 -0
- package/tests/fixtures/cycle/siteDuration/valid-no-siteDuration.json +40 -0
- package/tests/fixtures/cycle/siteDuration/valid-otherSites.json +48 -0
- package/tests/fixtures/cycle/siteDuration/valid.json +45 -0
- package/tests/fixtures/cycle/substrate/required/invalid.json +50 -0
- package/tests/fixtures/cycle/substrate/required/valid.json +60 -0
- package/tests/fixtures/cycle/valid.json +343 -0
- package/tests/fixtures/emission/linked-terms/inputs/invalid.json +78 -0
- package/tests/fixtures/emission/linked-terms/inputs/valid.json +106 -0
- package/tests/fixtures/emission/linked-terms/transformation/error.json +104 -0
- package/tests/fixtures/emission/linked-terms/transformation/valid.json +107 -0
- package/tests/fixtures/emission/linked-terms/transformation/warning.json +76 -0
- package/tests/fixtures/emission/methodTier-background/invalid.json +60 -0
- package/tests/fixtures/emission/methodTier-background/valid.json +60 -0
- package/tests/fixtures/emission/not-relevant/invalid.json +71 -0
- package/tests/fixtures/emission/not-relevant/valid.json +95 -0
- package/tests/fixtures/emission/not-relevant-methodTier/invalid.json +70 -0
- package/tests/fixtures/emission/not-relevant-methodTier/valid.json +95 -0
- package/tests/fixtures/impactAssessment/aggregated-valid.json +43 -0
- package/tests/fixtures/impactAssessment/cycle-contains-product/invalid.json +34 -0
- package/tests/fixtures/impactAssessment/cycle-contains-product/valid.json +34 -0
- package/tests/fixtures/impactAssessment/cycle-endDate/invalid.json +26 -0
- package/tests/fixtures/impactAssessment/cycle-endDate/valid.json +26 -0
- package/tests/fixtures/impactAssessment/valid.json +93 -0
- package/tests/fixtures/indicator/characterisedIndicator-methodModel/invalid.json +52 -0
- package/tests/fixtures/indicator/characterisedIndicator-methodModel/valid.json +52 -0
- package/tests/fixtures/indicator/ionisingCompounds/invalid.json +23 -0
- package/tests/fixtures/indicator/ionisingCompounds/valid.json +23 -0
- package/tests/fixtures/indicator/landTransformation/invalid-grouped.json +257 -0
- package/tests/fixtures/indicator/landTransformation/invalid.json +100 -0
- package/tests/fixtures/indicator/landTransformation/valid-grouped-full.json +507 -0
- package/tests/fixtures/indicator/landTransformation/valid-grouped.json +507 -0
- package/tests/fixtures/indicator/landTransformation/valid.json +100 -0
- package/tests/fixtures/infrastructure/lifespan/invalid.json +26 -0
- package/tests/fixtures/infrastructure/lifespan/valid.json +45 -0
- package/tests/fixtures/input/animalFeed-fate/invalid.json +103 -0
- package/tests/fixtures/input/animalFeed-fate/valid.json +90 -0
- package/tests/fixtures/input/country/invalid.json +64 -0
- package/tests/fixtures/input/country/valid.json +64 -0
- package/tests/fixtures/input/distribution/animalHousing.json +103 -0
- package/tests/fixtures/input/distribution/complete/invalid.json +177 -0
- package/tests/fixtures/input/distribution/complete/valid.json +163 -0
- package/tests/fixtures/input/distribution/incomplete/valid.json +139 -0
- package/tests/fixtures/input/impactAssessment/invalid.json +99 -0
- package/tests/fixtures/input/impactAssessment/valid.json +89 -0
- package/tests/fixtures/input/input-as-product/invalid.json +57 -0
- package/tests/fixtures/input/input-as-product/valid.json +59 -0
- package/tests/fixtures/input/mustIncludeId/invalid.json +13 -0
- package/tests/fixtures/input/mustIncludeId/valid-multiple-ids.json +31 -0
- package/tests/fixtures/input/mustIncludeId/valid.json +22 -0
- package/tests/fixtures/input/saplings/invalid.json +58 -0
- package/tests/fixtures/input/saplings/valid-no-saplings.json +58 -0
- package/tests/fixtures/input/saplings/valid-not-plantation.json +58 -0
- package/tests/fixtures/input/saplings/valid.json +58 -0
- package/tests/fixtures/integration/distribution/product-yield-invalid.json +54 -0
- package/tests/fixtures/management/cycle-overlap/cycles.json +39 -0
- package/tests/fixtures/management/cycle-overlap/invalid.json +26 -0
- package/tests/fixtures/management/cycle-overlap/valid.json +26 -0
- package/tests/fixtures/management/exists/invalid.json +13 -0
- package/tests/fixtures/management/exists/valid.json +25 -0
- package/tests/fixtures/management/fallow-dates/invalid.json +24 -0
- package/tests/fixtures/management/fallow-dates/valid.json +24 -0
- package/tests/fixtures/management/termType/invalid-cropland.json +35 -0
- package/tests/fixtures/management/termType/invalid-permanent-pasture.json +25 -0
- package/tests/fixtures/management/termType/valid-cropland.json +55 -0
- package/tests/fixtures/management/termType/valid-no-management.json +13 -0
- package/tests/fixtures/management/termType/valid-permanent-pasture.json +35 -0
- package/tests/fixtures/measurement/depths/invalid.json +44 -0
- package/tests/fixtures/measurement/depths/valid.json +50 -0
- package/tests/fixtures/measurement/models/valid.json +33 -0
- package/tests/fixtures/measurement/models/warning-no-value.json +30 -0
- package/tests/fixtures/measurement/models/warning.json +33 -0
- package/tests/fixtures/measurement/pond-measurements/invalid.json +11 -0
- package/tests/fixtures/measurement/pond-measurements/valid.json +23 -0
- package/tests/fixtures/measurement/required-depths/error.json +71 -0
- package/tests/fixtures/measurement/required-depths/valid.json +126 -0
- package/tests/fixtures/measurement/required-depths/warning.json +29 -0
- package/tests/fixtures/measurement/soilTexture/missing-texture-value.json +227 -0
- package/tests/fixtures/measurement/soilTexture/percent-invalid.json +110 -0
- package/tests/fixtures/measurement/soilTexture/percent-missing-value.json +43 -0
- package/tests/fixtures/measurement/soilTexture/percent-valid.json +110 -0
- package/tests/fixtures/measurement/startDate-endDate-required/invalid.json +32 -0
- package/tests/fixtures/measurement/startDate-endDate-required/valid.json +46 -0
- package/tests/fixtures/measurement/unique/invalid.json +28 -0
- package/tests/fixtures/measurement/unique/valid.json +16 -0
- package/tests/fixtures/measurement/value-length/invalid.json +46 -0
- package/tests/fixtures/measurement/value-length/valid.json +44 -0
- package/tests/fixtures/measurement/water-salinity/invalid.json +33 -0
- package/tests/fixtures/measurement/water-salinity/valid-brakish.json +40 -0
- package/tests/fixtures/measurement/water-salinity/valid.json +33 -0
- package/tests/fixtures/organisation/valid.json +26 -0
- package/tests/fixtures/practice/croppingDuration/riceGrainInHuskFlooded/invalid.json +63 -0
- package/tests/fixtures/practice/croppingDuration/riceGrainInHuskFlooded/valid.json +63 -0
- package/tests/fixtures/practice/defaultValue/invalid.json +12 -0
- package/tests/fixtures/practice/defaultValue/valid.json +15 -0
- package/tests/fixtures/practice/excretaManagement/invalid.json +50 -0
- package/tests/fixtures/practice/excretaManagement/valid.json +60 -0
- package/tests/fixtures/practice/irrigated-complete/invalid.json +47 -0
- package/tests/fixtures/practice/irrigated-complete/valid-incomplete.json +47 -0
- package/tests/fixtures/practice/irrigated-complete/valid.json +60 -0
- package/tests/fixtures/practice/landCover-products/invalid.json +58 -0
- package/tests/fixtures/practice/landCover-products/valid-coverCrop.json +69 -0
- package/tests/fixtures/practice/landCover-products/valid.json +58 -0
- package/tests/fixtures/practice/liveAnimal-system/invalid.json +58 -0
- package/tests/fixtures/practice/liveAnimal-system/valid.json +69 -0
- package/tests/fixtures/practice/longFallowDuration/invalid.json +20 -0
- package/tests/fixtures/practice/longFallowDuration/valid.json +20 -0
- package/tests/fixtures/practice/noTillage/invalid.json +23 -0
- package/tests/fixtures/practice/noTillage/valid-value-not-100.json +23 -0
- package/tests/fixtures/practice/noTillage/valid.json +21 -0
- package/tests/fixtures/practice/pastureGrass/key-termType/invalid.json +16 -0
- package/tests/fixtures/practice/pastureGrass/key-termType/valid.json +16 -0
- package/tests/fixtures/practice/pastureGrass/key-value/invalid-numbers.json +67 -0
- package/tests/fixtures/practice/pastureGrass/key-value/invalid.json +67 -0
- package/tests/fixtures/practice/pastureGrass/key-value/valid.json +67 -0
- package/tests/fixtures/practice/pastureGrass/permanent-pasture/invalid.json +37 -0
- package/tests/fixtures/practice/pastureGrass/permanent-pasture/valid.json +47 -0
- package/tests/fixtures/practice/primaryPercent/invalid.json +49 -0
- package/tests/fixtures/practice/primaryPercent/valid.json +49 -0
- package/tests/fixtures/practice/processingOperation/invalid-no-primary.json +48 -0
- package/tests/fixtures/practice/processingOperation/invalid.json +49 -0
- package/tests/fixtures/practice/processingOperation/valid-cropland.json +37 -0
- package/tests/fixtures/practice/processingOperation/valid.json +49 -0
- package/tests/fixtures/practice/productivePhasePermanentCrops/invalid.json +48 -0
- package/tests/fixtures/practice/productivePhasePermanentCrops/valid-0-value.json +58 -0
- package/tests/fixtures/practice/productivePhasePermanentCrops/valid-no-value.json +47 -0
- package/tests/fixtures/practice/productivePhasePermanentCrops/valid.json +48 -0
- package/tests/fixtures/practice/site-management/invalid.json +75 -0
- package/tests/fixtures/practice/site-management/valid.json +75 -0
- package/tests/fixtures/practice/tillage-siteType/valid.json +51 -0
- package/tests/fixtures/practice/tillage-siteType/warning.json +42 -0
- package/tests/fixtures/practice/tillage-values/invalid-fullTillage.json +61 -0
- package/tests/fixtures/practice/tillage-values/invalid-noTillage.json +61 -0
- package/tests/fixtures/practice/tillage-values/valid.json +61 -0
- package/tests/fixtures/practice/waterRegime/rice/invalid.json +59 -0
- package/tests/fixtures/practice/waterRegime/rice/valid-0-value.json +59 -0
- package/tests/fixtures/practice/waterRegime/rice/valid.json +58 -0
- package/tests/fixtures/product/economicValueShare/invalid.json +31 -0
- package/tests/fixtures/product/economicValueShare/valid.json +22 -0
- package/tests/fixtures/product/excreta/invalid.json +62 -0
- package/tests/fixtures/product/excreta/valid.json +62 -0
- package/tests/fixtures/product/excreta/warning.json +53 -0
- package/tests/fixtures/product/excreta/with-system/invalid.json +79 -0
- package/tests/fixtures/product/excreta/with-system/valid.json +88 -0
- package/tests/fixtures/product/excreta/with-system/warning.json +70 -0
- package/tests/fixtures/product/fu_ha/invalid.json +49 -0
- package/tests/fixtures/product/fu_ha/valid.json +49 -0
- package/tests/fixtures/product/primary/invalid.json +22 -0
- package/tests/fixtures/product/primary/valid.json +22 -0
- package/tests/fixtures/product/value/valid.json +26 -0
- package/tests/fixtures/product/value/value-0/error.json +40 -0
- package/tests/fixtures/product/value/value-empty/warning.json +23 -0
- package/tests/fixtures/product/yield/invalid.json +54 -0
- package/tests/fixtures/product/yield/no-value.json +75 -0
- package/tests/fixtures/product/yield/valid.json +54 -0
- package/tests/fixtures/property/default-value/valid-allowed-exception.json +61 -0
- package/tests/fixtures/property/default-value/valid.json +61 -0
- package/tests/fixtures/property/default-value/warning.json +61 -0
- package/tests/fixtures/property/termType/invalid.json +60 -0
- package/tests/fixtures/property/termType/valid.json +60 -0
- package/tests/fixtures/property/value-min-max/invalid.json +77 -0
- package/tests/fixtures/property/value-min-max/valid-skip-maximum.json +57 -0
- package/tests/fixtures/property/value-min-max/valid.json +78 -0
- package/tests/fixtures/property/valueType/invalid.json +79 -0
- package/tests/fixtures/property/valueType/valid.json +79 -0
- package/tests/fixtures/property/volatileSolidsContent/invalid.json +99 -0
- package/tests/fixtures/property/volatileSolidsContent/valid.json +99 -0
- package/tests/fixtures/shared/coordinates/invalid.json +18 -0
- package/tests/fixtures/shared/coordinates/valid.json +18 -0
- package/tests/fixtures/shared/data-duplicates/valid.json +113 -0
- package/tests/fixtures/shared/data-duplicates/warning.json +172 -0
- package/tests/fixtures/shared/duplicated-term-units/invalid-animalProduct.json +61 -0
- package/tests/fixtures/shared/duplicated-term-units/invalid-organicFertiliser.json +61 -0
- package/tests/fixtures/shared/duplicated-term-units/valid.json +49 -0
- package/tests/fixtures/shared/list-country-region/invalid.json +54 -0
- package/tests/fixtures/shared/list-country-region/valid.json +54 -0
- package/tests/fixtures/shared/list-percent-value/invalid.json +49 -0
- package/tests/fixtures/shared/list-percent-value/valid.json +52 -0
- package/tests/fixtures/shared/list-valueType/invalid.json +49 -0
- package/tests/fixtures/shared/list-valueType/valid.json +49 -0
- package/tests/fixtures/shared/list-values-sum-100/management/with-properties/valid.json +91 -0
- package/tests/fixtures/shared/list-values-sum-100/measurements/missing-soil.json +46 -0
- package/tests/fixtures/shared/list-values-sum-100/measurements/no-depth-high-value.json +63 -0
- package/tests/fixtures/shared/list-values-sum-100/measurements/no-depth-valid.json +40 -0
- package/tests/fixtures/shared/list-values-sum-100/measurements/with-depth-high-value.json +71 -0
- package/tests/fixtures/shared/list-values-sum-100/practices/total-100.json +61 -0
- package/tests/fixtures/shared/list-values-sum-100/practices/total-110.json +61 -0
- package/tests/fixtures/shared/list-values-sum-100/practices/total-90.json +61 -0
- package/tests/fixtures/shared/min-max/value-above.json +31 -0
- package/tests/fixtures/shared/min-max/value-below.json +31 -0
- package/tests/fixtures/shared/min-max/value-valid.json +45 -0
- package/tests/fixtures/shared/model/emissions/invalid.json +102 -0
- package/tests/fixtures/shared/model/emissions/valid-variable-tolerance.json +180 -0
- package/tests/fixtures/shared/model/emissions/valid.json +102 -0
- package/tests/fixtures/shared/model/impacts/invalid.json +75 -0
- package/tests/fixtures/shared/model/impacts/valid.json +75 -0
- package/tests/fixtures/shared/model/inputs/valid-no-value.json +84 -0
- package/tests/fixtures/shared/model/inputs/valid.json +87 -0
- package/tests/fixtures/shared/model/inputs/warning.json +87 -0
- package/tests/fixtures/shared/model/products/valid-no-value.json +88 -0
- package/tests/fixtures/shared/model/products/valid.json +91 -0
- package/tests/fixtures/shared/model/products/warning.json +91 -0
- package/tests/fixtures/shared/otherModel/invalid.json +69 -0
- package/tests/fixtures/shared/otherModel/valid.json +70 -0
- package/tests/fixtures/shared/properties-duplicate-values/invalid.json +61 -0
- package/tests/fixtures/shared/properties-duplicate-values/valid.json +57 -0
- package/tests/fixtures/shared/properties-same-length/invalid.json +62 -0
- package/tests/fixtures/shared/properties-same-length/valid.json +52 -0
- package/tests/fixtures/shared/unit-percent/invalid.json +34 -0
- package/tests/fixtures/shared/unit-percent/valid.json +60 -0
- package/tests/fixtures/shared/unit-percent/warning.json +52 -0
- package/tests/fixtures/site/cycles-linked-ia/invalid.json +129 -0
- package/tests/fixtures/site/cycles-linked-ia/valid.json +129 -0
- package/tests/fixtures/site/valid.json +138 -0
- package/tests/fixtures/source/valid.json +19 -0
- package/tests/fixtures/transformation/excretaManagement/invalid.json +47 -0
- package/tests/fixtures/transformation/excretaManagement/valid.json +59 -0
- package/tests/fixtures/transformation/inputs-products/invalid.json +43 -0
- package/tests/fixtures/transformation/inputs-products/valid.json +43 -0
- package/tests/fixtures/transformation/linked-emission/invalid.json +101 -0
- package/tests/fixtures/transformation/linked-emission/valid.json +107 -0
- package/tests/fixtures/transformation/previousTransformationId/invalid-no-previous.json +127 -0
- package/tests/fixtures/transformation/previousTransformationId/invalid-previous-input.json +100 -0
- package/tests/fixtures/transformation/previousTransformationId/invalid-product-input.json +106 -0
- package/tests/fixtures/transformation/previousTransformationId/invalid-wrong-order.json +136 -0
- package/tests/fixtures/transformation/previousTransformationId/valid.json +171 -0
- package/tests/integration/__init__.py +0 -0
- package/tests/integration/test_product.py +17 -0
- package/tests/test_gee.py +10 -0
- package/tests/test_utils.py +36 -0
- package/tests/test_validation.py +11 -0
- package/tests/utils.py +28 -0
- package/tests/validators/__init__.py +0 -0
- package/tests/validators/test_aggregated_cycle.py +44 -0
- package/tests/validators/test_aggregated_shared.py +63 -0
- package/tests/validators/test_animal.py +72 -0
- package/tests/validators/test_completeness.py +337 -0
- package/tests/validators/test_cycle.py +600 -0
- package/tests/validators/test_emission.py +170 -0
- package/tests/validators/test_impact_assessment.py +80 -0
- package/tests/validators/test_indicator.py +120 -0
- package/tests/validators/test_infrastructure.py +26 -0
- package/tests/validators/test_input.py +434 -0
- package/tests/validators/test_management.py +177 -0
- package/tests/validators/test_measurement.py +317 -0
- package/tests/validators/test_organisation.py +32 -0
- package/tests/validators/test_practice.py +490 -0
- package/tests/validators/test_product.py +291 -0
- package/tests/validators/test_property.py +143 -0
- package/tests/validators/test_shared.py +1139 -0
- package/tests/validators/test_site.py +151 -0
- package/tests/validators/test_source.py +15 -0
- package/tests/validators/test_transformation.py +151 -0
- package/tests/validators/test_validators.py +74 -0
- package/tsconfig.dist.json +9 -0
- 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'
|
package/envs/.master.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export STAGE='prod'
|
|
File without changes
|
|
@@ -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)
|