|
10 | 10 | import shutil |
11 | 11 | import subprocess |
12 | 12 | import sys |
| 13 | +import tempfile |
13 | 14 | from pathlib import Path |
14 | 15 |
|
15 | 16 | import pytest |
@@ -46,71 +47,85 @@ def test_standard_file_existance(module_path, file): |
46 | 47 | assert Path(module_path / file).exists() |
47 | 48 |
|
48 | 49 |
|
49 | | -def test_snakemake_integration_testing(module_path, tmp_path): |
| 50 | +def test_snakemake_integration_testing(module_path): |
50 | 51 | """Run retrieval from scratch in its Conda environment and validate outputs.""" |
51 | 52 | log_dir = module_path / "tests/integration/logs" |
52 | 53 | log_dir.mkdir(parents=True, exist_ok=True) |
53 | 54 | run_log = log_dir / "integration.log" |
54 | 55 | conda_prefix = module_path / ".snakemake/conda" |
55 | | - try: |
56 | | - with run_log.open("w", encoding="utf-8") as log: |
57 | | - result = subprocess.run( |
58 | | - [ |
59 | | - sys.executable, |
60 | | - "-m", |
61 | | - "snakemake", |
62 | | - "--snakefile", |
63 | | - str(module_path / "tests/integration/Snakefile"), |
64 | | - "--directory", |
65 | | - str(tmp_path), |
66 | | - "--use-conda", |
67 | | - "--conda-prefix", |
68 | | - str(conda_prefix), |
69 | | - "--cores", |
70 | | - "1", |
71 | | - "--show-failed-logs", |
72 | | - ], |
73 | | - stdout=log, |
74 | | - stderr=subprocess.STDOUT, |
75 | | - timeout=600, |
76 | | - check=False, |
77 | | - env={**os.environ, "XDG_CACHE_HOME": str(tmp_path / "cache")}, |
| 56 | + |
| 57 | + # A directory under module_path, not pytest's tmp_path: on Windows CI, |
| 58 | + # tmp_path can land on a different drive than the checkout, and |
| 59 | + # Snakemake's relative-path handling then fails with "ValueError: path |
| 60 | + # is on mount 'D:', start on mount 'C:'". Keeping the working directory |
| 61 | + # on the same drive as the Snakefile/conda prefix avoids that. Every |
| 62 | + # assertion that reads from workdir has to stay inside this block - |
| 63 | + # TemporaryDirectory deletes it on exit. |
| 64 | + with tempfile.TemporaryDirectory( |
| 65 | + dir=module_path, prefix=".integration-", ignore_cleanup_errors=True |
| 66 | + ) as temporary_directory: |
| 67 | + workdir = Path(temporary_directory) |
| 68 | + try: |
| 69 | + with run_log.open("w", encoding="utf-8") as log: |
| 70 | + result = subprocess.run( |
| 71 | + [ |
| 72 | + sys.executable, |
| 73 | + "-m", |
| 74 | + "snakemake", |
| 75 | + "--snakefile", |
| 76 | + str(module_path / "tests/integration/Snakefile"), |
| 77 | + "--directory", |
| 78 | + str(workdir), |
| 79 | + "--use-conda", |
| 80 | + "--conda-prefix", |
| 81 | + str(conda_prefix), |
| 82 | + "--cores", |
| 83 | + "1", |
| 84 | + "--show-failed-logs", |
| 85 | + ], |
| 86 | + stdout=log, |
| 87 | + stderr=subprocess.STDOUT, |
| 88 | + timeout=600, |
| 89 | + check=False, |
| 90 | + env={**os.environ, "XDG_CACHE_HOME": str(workdir / "cache")}, |
| 91 | + ) |
| 92 | + finally: |
| 93 | + if (workdir / "logs").exists(): |
| 94 | + shutil.copytree(workdir / "logs", log_dir, dirs_exist_ok=True) |
| 95 | + |
| 96 | + assert result.returncode == 0, run_log.read_text(encoding="utf-8") |
| 97 | + output_dir = workdir / "resources/grid-builder/osm/retrieve" |
| 98 | + for feature in ("substations_way", "lines_way"): |
| 99 | + payload = json.loads( |
| 100 | + (output_dir / f"benin_{feature}.json").read_text(encoding="utf-8") |
78 | 101 | ) |
79 | | - finally: |
80 | | - if (tmp_path / "logs").exists(): |
81 | | - shutil.copytree(tmp_path / "logs", log_dir, dirs_exist_ok=True) |
82 | | - |
83 | | - assert result.returncode == 0, run_log.read_text(encoding="utf-8") |
84 | | - output_dir = tmp_path / "resources/grid-builder/osm/retrieve" |
85 | | - for feature in ("substations_way", "lines_way"): |
86 | | - payload = json.loads( |
87 | | - (output_dir / f"benin_{feature}.json").read_text(encoding="utf-8") |
88 | | - ) |
89 | | - elements = payload["elements"] |
90 | | - assert elements, f"No {feature} records retrieved" |
91 | | - assert all(item["geometry"] for item in elements) |
92 | | - |
93 | | - build_dir = tmp_path / "resources/grid-builder/osm/build" |
94 | | - for component in ("buses", "lines", "transformers"): |
95 | | - with (build_dir / "csv" / f"{component}.csv").open(encoding="utf-8") as file: |
96 | | - rows = list(csv.DictReader(file)) |
97 | | - assert rows or component == "transformers" |
98 | | - |
99 | | - with (build_dir / "csv" / "lines.csv").open(encoding="utf-8") as file: |
100 | | - built_lines = list(csv.DictReader(file)) |
101 | | - assert all(row["bus0"] != row["bus1"] for row in built_lines) |
102 | | - assert all(float(row["voltage_kv"]) >= 220 for row in built_lines) |
103 | | - |
104 | | - for geojson_name in ("stations_polygon", "buses_polygon"): |
105 | | - polygons = json.loads( |
106 | | - (build_dir / "geojson" / f"{geojson_name}.geojson").read_text( |
| 102 | + elements = payload["elements"] |
| 103 | + assert elements, f"No {feature} records retrieved" |
| 104 | + assert all(item["geometry"] for item in elements) |
| 105 | + |
| 106 | + build_dir = workdir / "resources/grid-builder/osm/build" |
| 107 | + for component in ("buses", "lines", "transformers"): |
| 108 | + with (build_dir / "csv" / f"{component}.csv").open( |
107 | 109 | encoding="utf-8" |
| 110 | + ) as file: |
| 111 | + rows = list(csv.DictReader(file)) |
| 112 | + assert rows or component == "transformers" |
| 113 | + |
| 114 | + with (build_dir / "csv" / "lines.csv").open(encoding="utf-8") as file: |
| 115 | + built_lines = list(csv.DictReader(file)) |
| 116 | + assert all(row["bus0"] != row["bus1"] for row in built_lines) |
| 117 | + assert all(float(row["voltage_kv"]) >= 220 for row in built_lines) |
| 118 | + |
| 119 | + for geojson_name in ("stations_polygon", "buses_polygon"): |
| 120 | + polygons = json.loads( |
| 121 | + (build_dir / "geojson" / f"{geojson_name}.geojson").read_text( |
| 122 | + encoding="utf-8" |
| 123 | + ) |
108 | 124 | ) |
109 | | - ) |
110 | | - assert polygons["type"] == "FeatureCollection" |
111 | | - |
112 | | - country_log = (tmp_path / "logs/grid-builder/retrieve_osm_pbf/benin.log").read_text( |
113 | | - encoding="utf-8" |
114 | | - ) |
115 | | - assert "Wrote" in country_log |
116 | | - assert str(conda_prefix) in country_log, "Retrieval must use its Conda Python" |
| 125 | + assert polygons["type"] == "FeatureCollection" |
| 126 | + |
| 127 | + country_log = ( |
| 128 | + workdir / "logs/grid-builder/retrieve_osm_pbf/benin.log" |
| 129 | + ).read_text(encoding="utf-8") |
| 130 | + assert "Wrote" in country_log |
| 131 | + assert str(conda_prefix) in country_log, "Retrieval must use its Conda Python" |
0 commit comments