From e56e26750e23e86bc6a47a77dddc155a2d0a48e0 Mon Sep 17 00:00:00 2001 From: Michael Dales Date: Tue, 30 Jun 2026 10:50:42 +0100 Subject: [PATCH 1/2] Updated for yet another snakefmt update --- workflow/Snakefile | 6 ++-- workflow/rules/aoh.smk | 40 ++++++++++----------- workflow/rules/delta_p.smk | 30 ++++++++-------- workflow/rules/habitat.smk | 66 +++++++++++++++++------------------ workflow/rules/prepare.smk | 32 ++++++++--------- workflow/rules/scenario.smk | 24 ++++++------- workflow/rules/species.smk | 14 ++++---- workflow/rules/validation.smk | 38 ++++++++++---------- 8 files changed, 125 insertions(+), 125 deletions(-) diff --git a/workflow/Snakefile b/workflow/Snakefile index 92a279e..7e26efa 100644 --- a/workflow/Snakefile +++ b/workflow/Snakefile @@ -146,9 +146,9 @@ rule life: rule summaries: """ -Target: generate species richness and endemism maps. -NOT included in 'all' — run explicitly with: snakemake summaries -""" + Target: generate species richness and endemism maps. + NOT included in 'all' — run explicitly with: snakemake summaries + """ input: DATADIR / "summaries" / "species_richness.tif", DATADIR / "summaries" / "endemism.tif", diff --git a/workflow/rules/aoh.smk b/workflow/rules/aoh.smk index e0c21c5..e923dc3 100644 --- a/workflow/rules/aoh.smk +++ b/workflow/rules/aoh.smk @@ -19,9 +19,9 @@ from pathlib import Path rule aoh_version_sentinel: """ -Track the aoh package version. AOH rules depend on this to trigger -rebuilds when the package updates. -""" + Track the aoh package version. AOH rules depend on this to trigger + rebuilds when the package updates. + """ output: sentinel=DATADIR / ".sentinels" / "aoh_version.txt", run: @@ -68,14 +68,14 @@ def aoh_species_inputs(wildcards): rule generate_aoh: """ -Generate Area of Habitat raster for a single species in a given scenario. + Generate Area of Habitat raster for a single species in a given scenario. -Parallelizable: run with `snakemake --cores N` to process multiple species -concurrently. Uses --force-habitat and --pixel-area flags (no mask). + Parallelizable: run with `snakemake --cores N` to process multiple species + concurrently. Uses --force-habitat and --pixel-area flags (no mask). -For current/scenario AOHs: uses current/ era species data. -For pnv AOHs: uses historic/ era species data. -""" + For current/scenario AOHs: uses current/ era species data. + For pnv AOHs: uses historic/ era species data. + """ input: unpack(aoh_species_inputs), output: @@ -114,12 +114,12 @@ For pnv AOHs: uses historic/ era species data. rule aggregate_aohs_per_taxa: """ -Checkpoint that ensures all AOHs for a taxa/scenario are generated. -Creates a sentinel file when complete. + Checkpoint that ensures all AOHs for a taxa/scenario are generated. + Creates a sentinel file when complete. -This is a checkpoint so downstream rules (delta P) can re-evaluate the DAG -after AOHs are created. -""" + This is a checkpoint so downstream rules (delta P) can re-evaluate the DAG + after AOHs are created. + """ input: metadata=get_all_aoh_metadata_for_taxa_scenario, version_sentinel=DATADIR / ".sentinels" / "aoh_version.txt", @@ -139,10 +139,10 @@ after AOHs are created. rule collate_aoh_data: """ -Collate metadata from all AOH JSON files for a scenario into a single CSV. + Collate metadata from all AOH JSON files for a scenario into a single CSV. -Used by validation (current scenario) and for downstream analysis. -""" + Used by validation (current scenario) and for downstream analysis. + """ input: sentinels=lambda wildcards: expand( str(DATADIR / "aohs" / "{scenario}" / "{taxa}" / ".complete"), @@ -173,10 +173,10 @@ Used by validation (current scenario) and for downstream analysis. rule footprint_of_humanity: """ -Compute the footprint of humanity metric for a given scenario. + Compute the footprint of humanity metric for a given scenario. -Compares current AOH data against PNV and the scenario CSVs. -""" + Compares current AOH data against PNV and the scenario CSVs. + """ input: pnv_csv=DATADIR / "aohs" / "pnv.csv", scenario_csv=DATADIR / "aohs" / "{scenario}.csv", diff --git a/workflow/rules/delta_p.smk b/workflow/rules/delta_p.smk index 9ee11dc..3245afa 100644 --- a/workflow/rules/delta_p.smk +++ b/workflow/rules/delta_p.smk @@ -23,12 +23,12 @@ from types import SimpleNamespace rule calculate_delta_p: """ -Calculate the change in probability of persistence for a single species -under a given scenario. + Calculate the change in probability of persistence for a single species + under a given scenario. -species_id wildcard is of the form T{taxon_id}A{assessment_id}_{SEASON}, -e.g. T22685505A261477056_RESIDENT. -""" + species_id wildcard is of the form T{taxon_id}A{assessment_id}_{SEASON}, + e.g. T22685505A261477056_RESIDENT. + """ input: current_sentinel=DATADIR / "aohs" / "current" / "{taxa}" / ".complete", scenario_sentinel=DATADIR / "aohs" / "{scenario}" / "{taxa}" / ".complete", @@ -69,9 +69,9 @@ e.g. T22685505A261477056_RESIDENT. rule raster_sum_per_taxa: """ -Sum all per-species delta P rasters for a taxa into a single raster. -Implicitly waits for all calculate_delta_p jobs via direct tif dependencies. -""" + Sum all per-species delta P rasters for a taxa into a single raster. + Implicitly waits for all calculate_delta_p jobs via direct tif dependencies. + """ input: rasters=get_delta_p_sentinels_for_taxa_scenario, output: @@ -105,9 +105,9 @@ def get_all_delta_p_tifs_for_scenario(wildcards): rule species_totals: """ -Count the number of species per taxa used in the delta P calculation. -Used by delta_p_scaled for normalisation. -""" + Count the number of species per taxa used in the delta P calculation. + Used by delta_p_scaled for normalisation. + """ input: rasters=get_all_delta_p_tifs_for_scenario, output: @@ -127,11 +127,11 @@ Used by delta_p_scaled for normalisation. rule delta_p_scaled: """ -Generate the final scaled delta P map for a scenario. + Generate the final scaled delta P map for a scenario. -Combines per-taxa delta P sums with the habitat difference map and -species totals to produce the final normalised LIFE output. -""" + Combines per-taxa delta P sums with the habitat difference map and + species totals to produce the final normalised LIFE output. + """ input: taxa_rasters=expand( str(DATADIR / "deltap_sum" / "{{scenario}}" / CURVE / "{taxa}.tif"), diff --git a/workflow/rules/habitat.smk b/workflow/rules/habitat.smk index b9eb054..79d2a82 100644 --- a/workflow/rules/habitat.smk +++ b/workflow/rules/habitat.smk @@ -25,8 +25,8 @@ from pathlib import Path rule gaez_download: """ -Fetch the compressed GAEZ data. -""" + Fetch the compressed GAEZ data. + """ output: archive=DATADIR / "food" / "LR.zip", log: @@ -123,9 +123,9 @@ rule hyde_expand_land_usage_raster: rule modify_hyde_pixel_scale: """ -Fix the pixel scale value in the HYDE data — the rounding is not precise -enough to align with the GAEZ data. -""" + Fix the pixel scale value in the HYDE data — the rounding is not precise + enough to align with the GAEZ data. + """ input: raw_hyde_raster=DATADIR / "food" / "grazing2017AD.asc", output: @@ -139,9 +139,9 @@ enough to align with the GAEZ data. rule add_hyde_projection_info: """ -The HYDE data ships without a projection, so add one so that -the rest of the workflow can mix it with projected raster data. -""" + The HYDE data ships without a projection, so add one so that + the rest of the workflow can mix it with projected raster data. + """ output: hyde_projection_file=DATADIR / "food" / "modified_grazing2017AD.prj", params: @@ -157,8 +157,8 @@ the rest of the workflow can mix it with projected raster data. # ============================================================================= rule combine_gaez_hyde: """ -Combine the GAEZ and Hyde data, adjusting for overflow in cells. -""" + Combine the GAEZ and Hyde data, adjusting for overflow in cells. + """ input: hyde_projection_file=DATADIR / "food" / "modified_grazing2017AD.prj", hyde_raster=DATADIR / "food" / "modified_grazing2017AD.asc", @@ -179,10 +179,10 @@ Combine the GAEZ and Hyde data, adjusting for overflow in cells. rule pnv_100m: """ -Rescale the PNV map to 100m resolution. -Yirgacheffe can rescale dynamically, but pre-scaling is faster at the cost -of some extra disk space. -""" + Rescale the PNV map to 100m resolution. + Yirgacheffe can rescale dynamically, but pre-scaling is faster at the cost + of some extra disk space. + """ input: pnv=DATADIR / "habitat" / "pnv_raw.tif", output: @@ -211,9 +211,9 @@ of some extra disk space. rule current_raws: """ -Build the LIFE current map, which is Jung with updates applied -and restricted to L1 to match the PNV map restrictions. -""" + Build the LIFE current map, which is Jung with updates applied + and restricted to L1 to match the PNV map restrictions. + """ input: updates_sentinel=DATADIR / "habitat" / ".downloaded_updates", habitat=DATADIR / "100m" / "jung_l2_raw.tif", @@ -230,12 +230,12 @@ and restricted to L1 to match the PNV map restrictions. rule build_food_map: """ -Build the food-enhanced current habitat map at 100m resolution by combining -the Jung current map with GAEZ/HYDE crop and pasture fractions. + Build the food-enhanced current habitat map at 100m resolution by combining + the Jung current map with GAEZ/HYDE crop and pasture fractions. -PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. -This is the most expensive step in the pipeline. -""" + PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. + This is the most expensive step in the pipeline. + """ input: jung=ancient(DATADIR / "100m" / "jung_current" / ".sentinel"), pnv=ancient(DATADIR / "100m" / "pnv.tif"), @@ -260,11 +260,11 @@ This is the most expensive step in the pipeline. rule warp_current: """ -Warp the food-enhanced current map from 100m to the target pixel scale -(5 arc-seconds, ~1.67km at the equator). + Warp the food-enhanced current map from 100m to the target pixel scale + (5 arc-seconds, ~1.67km at the equator). -PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. -""" + PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. + """ input: sentinel=ancient(DATADIR / "100m" / "current" / ".sentinel"), output: @@ -305,9 +305,9 @@ PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. rule land_cover_area: """ -Compare total land cover area between jung_current and current maps. -Produces a CSV with land cover class as rows and source map as columns. -""" + Compare total land cover area between jung_current and current maps. + Produces a CSV with land cover class as rows and source map as columns. + """ input: jung_current_sentinel=DATADIR / "100m" / "jung_current" / ".sentinel", current_sentinel=DATADIR / "100m" / "current" / ".sentinel", @@ -330,11 +330,11 @@ Produces a CSV with land cover class as rows and source map as columns. rule pnv_processed: """ -Process the PNV map into per-class fractional rasters at the target pixel scale -using aoh-habitat-process. + Process the PNV map into per-class fractional rasters at the target pixel scale + using aoh-habitat-process. -PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. -""" + PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. + """ input: pnv=ancient(DATADIR / "habitat" / "pnv_raw.tif"), output: diff --git a/workflow/rules/prepare.smk b/workflow/rules/prepare.smk index 1761510..b7665a2 100644 --- a/workflow/rules/prepare.smk +++ b/workflow/rules/prepare.smk @@ -18,8 +18,8 @@ from pathlib import Path rule convert_crosswalk: """ -Generate a crosswalk between IUCN Habitat classes and Jung raster pixel values. -""" + Generate a crosswalk between IUCN Habitat classes and Jung raster pixel values. + """ output: crosswalk=DATADIR / "crosswalk.csv", script: @@ -33,8 +33,8 @@ Generate a crosswalk between IUCN Habitat classes and Jung raster pixel values. rule jung_habitat_map: """ -Fetch the Jung L2 habitat map from Zenodo. -""" + Fetch the Jung L2 habitat map from Zenodo. + """ output: habitat=DATADIR / "100m" / "jung_l2_raw.tif", log: @@ -55,8 +55,8 @@ Fetch the Jung L2 habitat map from Zenodo. rule jung_habitat_updates: """ -Fetch the Jung habitat map update masks from Zenodo. -""" + Fetch the Jung habitat map update masks from Zenodo. + """ output: sentinel=DATADIR / "habitat" / ".downloaded_updates", log: @@ -84,8 +84,8 @@ Fetch the Jung habitat map update masks from Zenodo. rule jung_pnv_map: """ -Fetch the Jung PNV map from Zenodo. -""" + Fetch the Jung PNV map from Zenodo. + """ output: habitat=DATADIR / "habitat" / "pnv_raw.tif", log: @@ -111,8 +111,8 @@ Fetch the Jung PNV map from Zenodo. rule download_elevation: """ -Download raw elevation DEM from Zenodo. -""" + Download raw elevation DEM from Zenodo. + """ output: elevation=DATADIR / "elevation.tif", log: @@ -131,9 +131,9 @@ Download raw elevation DEM from Zenodo. rule elevation_max: """ -Warp elevation to target projection and scale using max resampling. -Precious: only runs if output doesn't exist. -""" + Warp elevation to target projection and scale using max resampling. + Precious: only runs if output doesn't exist. + """ input: elevation=ancient(DATADIR / "elevation.tif"), output: @@ -160,9 +160,9 @@ Precious: only runs if output doesn't exist. rule elevation_min: """ -Warp elevation to target projection and scale using min resampling. -Precious: only runs if output doesn't exist. -""" + Warp elevation to target projection and scale using min resampling. + Precious: only runs if output doesn't exist. + """ input: elevation=ancient(DATADIR / "elevation.tif"), output: diff --git a/workflow/rules/scenario.smk b/workflow/rules/scenario.smk index a923c23..8ef9c3c 100644 --- a/workflow/rules/scenario.smk +++ b/workflow/rules/scenario.smk @@ -32,9 +32,9 @@ COUNTERFACTUAL_SCENARIOS = ["arable"] + list(RESTORE_SCENARIOS.keys()) rule make_arable_map: """ -Generate the arable scenario map at 100m resolution. -All non-urban land is converted to arable. -""" + Generate the arable scenario map at 100m resolution. + All non-urban land is converted to arable. + """ input: current_sentinel=DATADIR / "100m" / "current" / ".sentinel", output: @@ -64,9 +64,9 @@ All non-urban land is converted to arable. rule make_restore_scenario: """ -Generate a restore scenario map at 100m resolution. -The IUCN habitat codes to restore are passed via --codes. -""" + Generate a restore scenario map at 100m resolution. + The IUCN habitat codes to restore are passed via --codes. + """ input: current_sentinel=DATADIR / "100m" / "current" / ".sentinel", pnv=DATADIR / "habitat" / "pnv_raw.tif", @@ -104,9 +104,9 @@ The IUCN habitat codes to restore are passed via --codes. rule warp_scenario: """ -Warp a scenario map from 100m to the target pixel scale. -PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. -""" + Warp a scenario map from 100m to the target pixel scale. + PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. + """ input: sentinel=ancient(DATADIR / "100m" / "{scenario}" / ".sentinel"), output: @@ -144,9 +144,9 @@ PRECIOUS: Only rebuilds if the sentinel is explicitly deleted. rule diff_map_scenario: """ -Generate the area difference map between current and a scenario's habitat layers. -Used by the delta P scaling step. -""" + Generate the area difference map between current and a scenario's habitat layers. + Used by the delta P scaling step. + """ input: current_sentinel=DATADIR / "habitat_layers" / "current" / ".sentinel", scenario_sentinel=DATADIR / "habitat_layers" / "{scenario}" / ".sentinel", diff --git a/workflow/rules/species.smk b/workflow/rules/species.smk index db9aa27..7e13132 100644 --- a/workflow/rules/species.smk +++ b/workflow/rules/species.smk @@ -16,15 +16,15 @@ checkpoint extract_species_data: """ -Extract species data from PostgreSQL database. + Extract species data from PostgreSQL database. -This is a checkpoint because the number of output GeoJSON files is only -known after extraction. Each taxa produces N species files in both current/ -and historic/ subdirectories. + This is a checkpoint because the number of output GeoJSON files is only + known after extraction. Each taxa produces N species files in both current/ + and historic/ subdirectories. -Environment variables required: - DB_HOST, DB_NAME, DB_USER, DB_PASSWORD -""" + Environment variables required: + DB_HOST, DB_NAME, DB_USER, DB_PASSWORD + """ output: current_report=DATADIR / "species-info" / "{taxa}" / "current" / "report.csv", historic_report=DATADIR / "species-info" / "{taxa}" / "historic" / "report.csv", diff --git a/workflow/rules/validation.smk b/workflow/rules/validation.smk index 48e20ec..afcc06f 100644 --- a/workflow/rules/validation.smk +++ b/workflow/rules/validation.smk @@ -13,9 +13,9 @@ rule model_validation: """ -Perform statistical validation of AOH models (Dahal et al. methodology). -Runs on the "current" scenario AOHs only. -""" + Perform statistical validation of AOH models (Dahal et al. methodology). + Runs on the "current" scenario AOHs only. + """ input: collated=DATADIR / "aohs" / "current.csv", version_sentinel=DATADIR / ".sentinels" / "aoh_version.txt", @@ -40,9 +40,9 @@ Runs on the "current" scenario AOHs only. rule species_richness: """ -Calculate species richness from current AOH rasters. -NOT included in 'all' — use the 'summaries' target explicitly. -""" + Calculate species richness from current AOH rasters. + NOT included in 'all' — use the 'summaries' target explicitly. + """ input: aoh_sentinel=DATADIR / "aohs" / "current.csv", version_sentinel=DATADIR / ".sentinels" / "aoh_version.txt", @@ -65,9 +65,9 @@ NOT included in 'all' — use the 'summaries' target explicitly. rule endemism: """ -Calculate endemism from current AOH rasters. -NOT included in 'all' — use the 'summaries' target explicitly. -""" + Calculate endemism from current AOH rasters. + NOT included in 'all' — use the 'summaries' target explicitly. + """ input: aoh_sentinel=DATADIR / "aohs" / "current.csv", species_richness=DATADIR / "summaries" / "species_richness.tif", @@ -96,12 +96,12 @@ NOT included in 'all' — use the 'summaries' target explicitly. rule fetch_gbif_data: """ -Fetch GBIF occurrence data for a taxa. -Expensive (hours) — only runs if output doesn't exist. + Fetch GBIF occurrence data for a taxa. + Expensive (hours) — only runs if output doesn't exist. -Environment variables required: - GBIF_USERNAME, GBIF_EMAIL, GBIF_PASSWORD -""" + Environment variables required: + GBIF_USERNAME, GBIF_EMAIL, GBIF_PASSWORD + """ input: collated=ancient(DATADIR / "aohs" / "current.csv"), output: @@ -124,8 +124,8 @@ Environment variables required: rule validate_gbif_occurrences: """ -Validate current AOH models against GBIF occurrence data. -""" + Validate current AOH models against GBIF occurrence data. + """ input: gbif_sentinel=DATADIR / "validation" / "occurrences" / ".{taxa}_fetched", aoh_sentinel=ancient(DATADIR / "aohs" / "current" / "{taxa}" / ".complete"), @@ -156,8 +156,8 @@ Validate current AOH models against GBIF occurrence data. rule occurrence_validation: """ -Target rule for GBIF validation for all taxa. -WARNING: Expensive. Only run explicitly: snakemake occurrence_validation -""" + Target rule for GBIF validation for all taxa. + WARNING: Expensive. Only run explicitly: snakemake occurrence_validation + """ input: expand(str(DATADIR / "validation" / "occurrences" / "{taxa}.csv"), taxa=TAXA), From d64946e14085278594a037f911cb18396f97023f Mon Sep 17 00:00:00 2001 From: Michael Dales Date: Tue, 30 Jun 2026 10:50:54 +0100 Subject: [PATCH 2/2] Pin snakefmt --- requirements.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 20c3fc9..a884bd3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,4 +34,7 @@ pandas-stubs types-requests yirgacheffe[dev] aoh[dev] -snakefmt + +# This is pinned because it changes so often and is a major +# cause of red-herring CI failures +snakefmt==2.0.3