Coverage for tests/test_solar_prepare_epw.py: 99%
76 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-16 23:05 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-16 23:05 +0000
1"""Tests for NIWA EPW archive preparation."""
3import importlib.util
4import json
5import tarfile
6from pathlib import Path
9def load_solar_prepare_epw():
10 """
11 Load the script module directly from its path for test usage.
12 """
13 module_path = (
14 Path(__file__).resolve().parents[1]
15 / "scripts/stage_3_scenarios/electricity/solar_prepare_epw.py"
16 )
17 spec = importlib.util.spec_from_file_location("solar_prepare_epw", module_path)
18 module = importlib.util.module_from_spec(spec)
19 assert spec.loader is not None
20 spec.loader.exec_module(module)
21 return module
24def write_test_epw(path: Path, hour: str = "01", minute: str = "0"):
25 """
26 Write a minimal synthetic EPW file.
27 """
28 path.write_text(
29 "\n".join(
30 [
31 "LOCATION,Auckland,Auckland,New Zealand,TMY3 NIWA,0,0,0,0,0",
32 "DESIGN CONDITIONS,0",
33 "TYPICAL/EXTREME PERIODS,0",
34 "GROUND TEMPERATURES,0",
35 "HOLIDAYS/DAYLIGHT SAVING,No,0,0,0",
36 "COMMENTS 1,Test",
37 "COMMENTS 2,Test",
38 "DATA PERIODS,1,1,TMY3 Year,Sunday,1,365",
39 ]
40 + [f"2024,01,01,{hour},{minute}"] * 8760
41 ),
42 encoding="utf-8",
43 )
46def test_prepare_epw_files_can_extract_from_tar_gz(tmp_path):
47 """
48 Prepared EPW files should be extracted from a committed TMY3 tar.gz bundle.
49 """
50 module = load_solar_prepare_epw()
51 archive_path = tmp_path / "tmy3_epw.tar.gz"
52 archive_source_dir = tmp_path / "source"
53 archive_source_dir.mkdir()
54 for zone in sorted(module.EXPECTED_ZONES):
55 write_test_epw(archive_source_dir / f"TMY3_NZ_{zone}.epw")
56 with tarfile.open(archive_path, "w:gz") as handle:
57 for epw_source in sorted(archive_source_dir.glob("*.epw")):
58 handle.add(epw_source, arcname=f"tmy3_epw/{epw_source.name}")
60 prepared_dir = tmp_path / "prepared_epw"
61 metadata_dir = tmp_path / "metadata"
62 module.SOURCE_CANDIDATE = ("TMY3", "archive", archive_path)
63 module.PREPARED_EPW_DIR = prepared_dir
64 module.PREPARED_EPW_SENTINEL = prepared_dir / ".prepared"
65 module.METADATA_DIR = metadata_dir
67 module.prepare_epw_files()
69 extracted = prepared_dir / "TMY3_NZ_AK.epw"
70 assert extracted.exists()
71 assert module.PREPARED_EPW_SENTINEL.exists()
73 summary = json.loads((metadata_dir / "prepare_epw_summary.json").read_text())
74 assert summary["dataset"] == "TMY3"
75 assert summary["source_type"] == "archive"
76 assert summary["source_path"] == str(archive_path)
77 assert summary["copied_files"] == len(module.EXPECTED_ZONES)
78 assert len(summary["zones"]) == len(module.EXPECTED_ZONES)
81def test_prepare_epw_files_rejects_non_epw_hour_conventions(tmp_path):
82 """
83 Files using 00..23 hour notation should fail validation instead of being rewritten.
84 """
85 module = load_solar_prepare_epw()
86 archive_source_dir = tmp_path / "source"
87 archive_source_dir.mkdir()
88 for zone in sorted(module.EXPECTED_ZONES):
89 hour = "00" if zone == "AK" else "01"
90 write_test_epw(archive_source_dir / f"TMY3_NZ_{zone}.epw", hour=hour)
92 archive_path = tmp_path / "tmy3_epw.tar.gz"
93 with tarfile.open(archive_path, "w:gz") as handle:
94 for epw_source in sorted(archive_source_dir.glob("*.epw")):
95 handle.add(epw_source, arcname=f"tmy3_epw/{epw_source.name}")
97 module.SOURCE_CANDIDATE = ("TMY3", "archive", archive_path)
98 module.PREPARED_EPW_DIR = tmp_path / "prepared_epw"
99 module.PREPARED_EPW_SENTINEL = module.PREPARED_EPW_DIR / ".prepared"
100 module.METADATA_DIR = tmp_path / "metadata"
102 try:
103 module.prepare_epw_files()
104 raise AssertionError("Expected invalid hour convention to raise")
105 except ValueError as exc:
106 assert "validates EPW-standard 01..24 hours" in str(exc)
109def test_prepare_epw_files_accepts_supported_niwa_minute_conventions(tmp_path):
110 """
111 Validation should accept both minute 60 and MBIE TMY3 minute 0 files.
112 """
113 module = load_solar_prepare_epw()
114 archive_source_dir = tmp_path / "source"
115 archive_source_dir.mkdir()
116 for zone in sorted(module.EXPECTED_ZONES):
117 minute = "60" if zone == "AK" else "0"
118 write_test_epw(archive_source_dir / f"TMY3_NZ_{zone}.epw", minute=minute)
120 archive_path = tmp_path / "tmy3_epw.tar.gz"
121 with tarfile.open(archive_path, "w:gz") as handle:
122 for epw_source in sorted(archive_source_dir.glob("*.epw")):
123 handle.add(epw_source, arcname=f"tmy3_epw/{epw_source.name}")
125 module.SOURCE_CANDIDATE = ("TMY3", "archive", archive_path)
126 module.PREPARED_EPW_DIR = tmp_path / "prepared_epw"
127 module.PREPARED_EPW_SENTINEL = module.PREPARED_EPW_DIR / ".prepared"
128 module.METADATA_DIR = tmp_path / "metadata"
130 module.prepare_epw_files()
132 assert (module.PREPARED_EPW_DIR / "TMY3_NZ_AK.epw").exists()