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

1"""Tests for NIWA EPW archive preparation.""" 

2 

3import importlib.util 

4import json 

5import tarfile 

6from pathlib import Path 

7 

8 

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 

22 

23 

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 ) 

44 

45 

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}") 

59 

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 

66 

67 module.prepare_epw_files() 

68 

69 extracted = prepared_dir / "TMY3_NZ_AK.epw" 

70 assert extracted.exists() 

71 assert module.PREPARED_EPW_SENTINEL.exists() 

72 

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) 

79 

80 

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) 

91 

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}") 

96 

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" 

101 

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) 

107 

108 

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) 

119 

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}") 

124 

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" 

129 

130 module.prepare_epw_files() 

131 

132 assert (module.PREPARED_EPW_DIR / "TMY3_NZ_AK.epw").exists()